11. Interferencias

Autor:Luis Miguel Sánchez Brea
Revisor:José Luis Vilas Prieto

Herramientas utilizadas en este tutorial:

  • numpy: manipulación de datos
  • scipy: Herramientas matemáticas

Archivos necesarios para la clase interferencias:

  • camposXY.py. Archivo con las funciones principales de campos camposXY.py
  • fuentesXY.py. Archivo con las funciones principales de fuentes fuentesXY.py

Descarga de archivos:

11.1. Introducción

El efecto de las interferencias surge directamente de que las ecuaciones de Maxwell son lineales en los campos eléctricos y magnéticos. Supongamos que \mathbf{E}_{1} y \mathbf{E}_{2} son soluciones. Entonces

\mathbf{E}=\mathbf{E}_{1}+\mathbf{E}_{2}

también es una solución. Sin embargo, el campo no es un parámetro observable, sino que lo es el promedio temporal del vector de Poynting, que se define como

\mathbf{S}\equiv\frac{1}{\mu_{0}}\mathbf{E}\wedge\mathbf{B},

con tiene unidades de \left[\mathbf{S}\right]=W/m^{2}. Al particularizar al caso de ondas armónicas planas tenemos

\left\langle \mathbf{S}\right\rangle =\frac{1}{2}\sqrt{\frac{\varepsilon_{0}}{\mu_{0}}}\left\vert \mathbf{E}\right\vert ^{2}\mathbf{u}_{k},

que es cuadrático con el campo eléctrico.

Si definimos la intensidad como

I=\left\langle \left\vert \mathbf{E}\right\vert ^{2}\right\rangle,

entonces la intensidad de la composición de las dos ondas resulta

I   =       \left\langle \left\vert \mathbf{E}_{1}+\mathbf{E}_{2}\right\vert ^{2}\right\rangle =\left\langle \left\vert \mathbf{E}_{1}\right\vert ^{2}\right\rangle +\left\langle \left\vert \mathbf{E}_{2}\right\vert ^{2}\right\rangle +2\left\langle \left\vert \mathbf{E}_{1}\mathbf{E}_{2}^{*}\right\vert \right\rangle
    =       I_{1}+I_{2}+2\left\langle \left\vert \mathbf{E}_{1}\mathbf{E}_{2}^{*}\right\vert \right\rangle.

Si no existiera el tercer término, entonces ocurre que I=I_{1}+I_{2}, que es lo que normalmente vemos en la naturaleza.

Para que se cumplan las interferencias, pues necesitamos que la luz esté polarizada, sea bastante monocromática y sea coherente. En particular, se deben verificar:

  • Únicamente interfieren ondas con la misma frecuencia, \omega_1=\omega_2
  • Las ondas que interfieren deben tener estados de polarización no ortogonales. \mathbf{E}_{01}\cdot \mathbf{E}_{02}\neq 0
  • Coherencia: Las fases en el término interferencial deben tener poca dependencia de (t,r)

En este capítulo asumiremos las mejores condiciones para producir las interferencias. Las 2 ondas tienen la misma polarización, son puramente monocromáticas y coherentes. De esta forma, desaparece el carácter vectorial de las interferencias.

11.2. Programación

Debido a la sencillez conceptual de las interferencias, las utilizaremos para analizar los distintos tipos de programación que se puede realizar con Python, como es la programación con scripts (todo el código en un mismo archivo lineal), la programación funcional (se escriben funciones que simplifican lo cálculos) y la programación con clases (donde funciones y datos están íntimamente relacionados). Finalmente veremos un procedimiento sencillo para desarrollar vídeos, simulando un interferómetro de Michelson.

11.3. Interferencia entre dos ondas plana

En representación compleja una onda plana se expresa como

E(\mathbf{r},t)=A\, e^{i(\mathbf{k}\,\mathbf{r}-\omega t)}

Podemos desciribr el vector \mathbf{k} en coordenadas esfericas, de forma que tenemos

\mathbf{k}=\frac{2\pi}{\lambda}(\sin\theta \sin\phi,\cos\theta \sin\phi,\cos\phi).

Entonces, en el plano z=0, la componente \mathbf{k\cdot r}=\frac{2\pi}{\lambda}(sin\theta sin\phi\, x+cos\theta sin\phi\, y).

Esto se puede programar en Python como

k*(X*sp.sin(theta1)*sp.sin(phi1)+Y*sp.cos(theta1)*sp.sin(phi1))

para poder representar esta ecuación en muchas posiciones x,y entonces X e Y son matrices generadas como

tamano=100*um
x=sp.linspace(-tamano,tamano, 256)
y=sp.linspace(-tamano,tamano, 256)
X,Y=sp.meshgrid(x,y)

11.3.1. Método lineal

El método lineal es quizás el más sencillo para iniciarse, pues la programación está en el mismo archivo y el código se ejecuta de arriba hacia abajo en el programa. Un ejemplo de esta programación está en la función interferencias_ondasPlanas1.py. El archivo consiste en la definición de dos ondas de la misma longitud de onda y la posterior superposición de las mismas, para finalmente obtener la intensidad. Así se obtiene el patrón de franjas de la figura.

#!/usr/local/bin/python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#------------------------------------
# Autor:	Luis Miguel Sanchez Brea
# Fecha		2013/10/24 (version 1.0)
# Licencia:	GPL
#-------------------------------------
"""
Interferencia entre ondas planas.
Programacion lineal.
"""

#Carga de paquetes y librerias
import scipy as sp
import matplotlib.pyplot as plt

#variables globales
um=1
grados=sp.pi/180

#Longitud de onda y vector de onda
wavelength=0.6328*um
k=2*sp.pi/wavelength

#Tamano
tamano=100*um
x=sp.linspace(-tamano,tamano, 256)
y=sp.linspace(-tamano,tamano, 256)
X,Y=sp.meshgrid(x,y)

#amplitud y direccion de la primera onda
A1=1
theta1=90*grados
phi1=-1*grados

#direccion de la segunda onda (distinta direccion)
A2=1
theta2=90*grados
phi2=1*grados

#definicion de una onda plana (observese la generacion de numeros complejos)
u1=A1*sp.exp(1.j*k*(X*sp.sin(theta1)*sp.sin(phi1)+Y*sp.cos(theta1)*sp.sin(phi1)))
u2=A2*sp.exp(1.j*k*(X*sp.sin(theta2)*sp.sin(phi2)+Y*sp.cos(theta2)*sp.sin(phi2)))

#proceso interferencial
u=u1+u2

#calculo de la intensidad
I=abs(u)**2

#grafica de la intensidad
plt.figure()   #creacion de la figura

#datos para ajustar el dibujo a la escala
extension = [x.min(), x.max(), y.min(), y.max()]

#dibujar intensidad + acondicionamiento de la grafica
h1 = plt.imshow(I, interpolation = 'bilinear', aspect = 'auto',
	origin = 'lower', extent = extension)

#escalado de la grafica
plt.axis('scaled')

#etiquetas
plt.xlabel("$x  (\mu m)$", fontsize = 22)
plt.ylabel("$y  (\mu m)$", fontsize = 22)
plt.title("$Intensidad(x,y)$", fontsize = 22)

#color
h1.set_cmap("gist_heat")

#dibujar barra de colores
plt.colorbar()

#muestra la grafica
plt.show()

(Source code, png, hires.png, pdf)

../../_images/interferencias_ondasPlanas1.png

11.3.2. Método funcional

Si nos damos cuenta en el código anterior, la onda plana se generar dos veces, una para E_{1}, y otra para E_{2}. Esto se puede evitar definiendo una función que denominamos onda_plana() a la cual llamamos dos veces. Los parámetros de entrada de la función son aquellos que alguna vez podemos variar. También podemos generar una función que realiza la gráfica. De esta forma la podemos llamar también varias veces.

#!/usr/local/bin/python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#------------------------------------
# Autor:	Luis Miguel Sanchez Brea
# Fecha		2013/10/24 (version 1.0)
# Licencia:	GPL
#-------------------------------------
"""
Interferencia entre ondas planas.
Programacion con funciones.
"""

#Carga de librerias y paquetes.
import scipy as sp
import matplotlib.pyplot as plt

#variables globales
um=1
grados=sp.pi/180

#parametros opticos
wavelength=0.6328*um
k=2*sp.pi/wavelength

#Tamano
tamano=100*um
x=sp.linspace(-tamano,tamano, 256)
y=sp.linspace(-tamano,tamano, 256)
X,Y=sp.meshgrid(x,y)

def onda_plana(A, theta, phi):
	#definicion de una onda plana (observese la generacion de numeros complejos)
	u=A*sp.exp(1.j*k*(X*sp.sin(theta)*sp.sin(phi)+Y*sp.cos(theta)*sp.sin(phi)))
	return u

#definicion de la grafica
def dibujar_grafica(I):
	#grafica de la intensidad
	plt.figure()   #creacion de la figura
	#datos para ajustar el dibujo a la escala
	extension = [x.min(), x.max(), y.min(), y.max()]
	#dibujar intensidad + acondicionamiento de la grafica
	h1 = plt.imshow(I, interpolation = 'bilinear', aspect = 'auto',
		origin = 'lower', extent = extension)
	#escalado de la grafica
	plt.axis('scaled')
	#etiquetas
	plt.xlabel("$x  (\mu m)$", fontsize = 22)
	plt.ylabel("$y  (\mu m)$", fontsize = 22)
	plt.title("$Intensidad(x,y)$", fontsize = 22)
	#color
	h1.set_cmap("gist_heat") #RdBu
	#dibujar barra de colores
	plt.colorbar()

#generacion de las ondas planas,
#ahora no es necesario definir los parametros globalmente, sino como parametros de la funcion
u1=onda_plana(A=1,theta=90*grados,phi=-1*grados)
u2=onda_plana(A=1,theta=90*grados,phi=1*grados)
#proceso interferencial
u=u1+u2
#calculo de la intensidad
I=abs(u)**2
dibujar_grafica(I)

#El codigo se puede reutilizar para otro ejemplo
u3=onda_plana(A=1,theta=90*grados,phi=0*grados)
u4=onda_plana(A=1,theta=90*grados,phi=4*grados)
#proceso interferencial
u=u3+u4
#calculo de la intensidad
I=abs(u)**2
dibujar_grafica(I)
plt.show()

(Source code)

Como se ve, el código incluido en las funciones se puede reutilizar. No obstante, las variables que utiliza la funcion onda_plana() tienen dos orígenes. Uno como variables globales definidas anteriormente (como puede ser k, X, Y y otras variables que se introducen a través de la definción de la función A, \theta, \phi.

11.3.3. Método con clases

En las clases, las funciones y los datos están todos bajo un mismo marco, por lo que no existe el peligro de modificar las variables globales de forma inadvertida. Normalmente la clase se define en una función (compleja) y las aplicaciones de la clase llaman a esta función. Esta forma permite generar las figuras mostradas debajo del código

#!/usr/local/bin/python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#------------------------------------
# Autor:	Luis Miguel Sanchez Brea
# Fecha		2013/10/24 (version 1.0)
# Licencia:	GPL
#-------------------------------------
"""
Metodo que utiliza las clases
"""

#Carga de paquetes y librerias
import scipy as sp
import matplotlib.pyplot as plt
import sys
sys.path.append('../')
from fuentesXY import fuenteXY, grados

#genera una instancia a una fuente
#estamos utilizando los parametros predeterminados para las variables de inicializacion
# (x, y, wavelength)

u1 = fuenteXY()
u2 = fuenteXY()

#rellena la instancia con una onda plana
u1.onda_plana(A = 1, theta = sp.pi / 2, phi = .5 * grados)
u2.onda_plana(A = 1, theta = sp.pi / 2, phi = -.5 * grados)

#segun la definicion de la clase la suma de dos ondas tambien es una onda
u12 = u1 + u2

#llama a la funcion de dibujar,
#esta funcion tiene varios metodos y elegimos dibujar la intensidad
u12.dibujar(tipo='intensidad')

#ahora elegimos dibujar el campo
u12.dibujar(tipo='campo')

plt.show()

(Source code)

Dentro de la clase fuentesXY (no es necesario comprender todas las funciones todavía), las funciones que hemos utilizado son:

  • __init__()
  • onda_plana()
	def __init__(self, x = x0, y = y0, wavelength = lambda0):
		"""Se inicia un nuevo experimento"""
                #arrays de entrada
		self.x = x
		self.y = y
                #Longitud de onda
		self.wavelength = wavelength
                #Generacion de un mallado
		self.X, self.Y = sp.meshgrid(x, y)
		#Predefinicion del campo
		self.u = sp.zeros(sp.shape(self.X), dtype = complex)

	
	def onda_plana(self, A = 1, theta = 0 * grados, phi = 0 * grados):
		"""onda plana"""
		#Definicion del vector de onda
		k = 2 * sp.pi / self.wavelength

		#Definicion de la onda plana (coordenadas esfericas)
		self.u = A * sp.exp(1.j * k * (self.X * sp.sin(theta) * sp.sin(phi) \
				+ self.Y * sp.cos(theta) * sp.sin(phi)))

11.4. Interferencia entre dos haces de Gauss

Veamos ahora el proceso de interferencia de 2 haces de Gauss. Estos hace se pueden definir como

E(x,y,z)=A_{0}\frac{\omega_{0}}{\omega(z)}\exp\left(-\frac{\rho^{2}}{\omega^{2}(z)}\right)\exp\left(ikz+ik\frac{\rho^{2}}{2R(z)}-i\zeta(z)\right)

donde

\omega_{0}^{2}=\frac{z_{0}\lambda}{\pi}

\omega(z)=\omega_{0}\sqrt{1+\left(\frac{z}{z_{0}}\right)^{2}}

R(z)=z\left[1+(\frac{z}{z_{0}})^{2}\right]

Este tipo de haces se puede programar fácilmente. Asumamos que estamos en el foco del haz z=0 y los haces están rotados. Entonces también se van a producir interferencias entre los haces.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#------------------------------------
# Autor:	Luis Miguel Sanchez Brea
# Fecha		2013/10/24 (version 1.0)
# Licencia:	GPL
#-------------------------------------
"""
ejemplos de interferencias
"""

#Carga de paquetes y librerias
import scipy as sp
import matplotlib.pyplot as plt

#variables globales
um=1
grados=sp.pi/180

#Longitud de onda y mallado
wavelength=0.6328*um
tamano=100*um
x=sp.linspace(-tamano,tamano, 256)
y=sp.linspace(-tamano,tamano, 256)
X,Y=sp.meshgrid(x,y)

def gauss(A=1, r0=(0*um,0*um), w=100*um, theta=0.*grados, phi=0*grados):
	"""haz gaussiano."""
	x0,y0=r0
	#vector de onda
	k=2*sp.pi/wavelength
	#Amplitud de la onda
	amplitud=A*sp.exp(-(X-x0)**2/(2*w**2)-(Y-y0)**2/(2*w**2))
	#Fase de la onda
	fase=sp.exp(1.j*k*(X*sp.sin(theta)*sp.sin(phi)+Y*sp.cos(theta)*sp.sin(phi))) #rotacion
	#Campo
	u=amplitud*fase
	return u

def dibujar(Intensidad, titulo):
	"""Dibuja el patron de intensidad"""
	#Creamos una figura
	plt.figure()
	h1 = plt.imshow(Intensidad)
	#Mapa de color
	h1.set_cmap("gist_heat") #RdBu
	#Titulo y escala de color
	plt.title(titulo, fontsize=28)
	plt.colorbar()


def interferenciasGauss(theta, titulo=''):
	#Campos de las ondas que interfieren
	u1=gauss(A=1, r0=(0*um,0*um), w=50*um, theta=theta, phi=2*grados)
	u2=gauss(A=1, r0=(0*um,0*um), w=50*um, theta=-theta, phi=2*grados)
	#Superposicion
	u=u1+u2
	#Intensidad de la superposicion
	Intensidad=abs(u)**2
	#Representacion
	dibujar(Intensidad, titulo)


if __name__ == '__main__':
	interferenciasGauss(theta=20*grados, titulo=r'$\theta=20^{0}$')
	interferenciasGauss(theta=40*grados, titulo=r'$\theta=40^{0}$')
	plt.show()

(Source code)

Aquí está todo programado en funciones, tanto la amplitud del haz de Gauss en z=0, como el procedimiento de dibujar y la función de ejecución __main__. De esta forma se puede reutilizar el código de una forma muy eficiente, además de entenderse mejor el código. Los parámetros entre las funciones se pasan a través de las variables de entrada.

Finalmente, vemos cómo se puede representar esto a partir de la clase FuenteXY. La forma de programar las interferencias es mucho más sencilla y clara, casi pseudocódigo

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#------------------------------------
# Autor:	Luis Miguel Sanchez Brea
# Fecha		2013/10/24 (version 1.0)
# Licencia:	GPL
#-------------------------------------
"""
ejemplos de interferencias
"""
#Carga de paquetes y librerias
import scipy as sp
import matplotlib.pyplot as plt
import sys
sys.path.append('../')
from fuentesXY import fuenteXY, grados, um

#definicion de parametros
x=sp.linspace(-100*um,100*um,256)
y=sp.linspace(-100*um,100*um,256)
wavelength=0.6328*um
#onda 1
u1 = fuenteXY(x,y,wavelength)
u1.haz_gauss(A=1, r0=(0*um,0*um), w=(50*um, 50*um), theta=20.*grados, phi=2*grados)
#onda 2
u2 = fuenteXY(x,y,wavelength)
u2.haz_gauss(A=1, r0=(0*um,0*um), w=(50*um, 50*um), theta=-20.*grados, phi=2*grados)
#Superposicion
u12 = u1 + u2
#Representacion
u12.dibujar(tipo='intensidad')
plt.show()

(Source code, png, hires.png, pdf)

../../_images/interferencias_gauss2.png

11.5. Interferencia entre dos ondas esféricas

Como ejemplo de programación con clases veremos las interferencias entre ondas esféricas. Estas son de gran importancia teórica pues nos permiten analizar los interferómetros de Young y de Michelson. La diferencia fundamental estriba en la posición de las fuentes. Mientras que en el interferómetro de Young las dos fuentes están desplazadas en el eje x, en el interferometro de Michelson están desplzadas en el eje z.

Como veremos, la programación con clases nos permite centrarnos en el problema, ya que la programación es de alto nivel (el profesor ya desarrolla las funciones de generación de las fuentes).

11.5.1. Interferómetro de Young

Como hemos dicho las dos fuentes están desplazadas en el eje x. Esto genera una distribución de intensidad en forma de elipses que, si nos centramos en el eje, son muy próximas a franjas verticales, como puede ver en la siguiente función.

#!/usr/local/bin/python
# -*- coding: utf-8 -*-
#------------------------------------
# Autor:	Luis Miguel Sanchez Brea
# Fecha		2013/10/24 (version 1.0)
# Licencia:	GPL
# Objetivo:	Interferencias entre 2 ondas esfericas desplazadas en el eje x
#-------------------------------------

#Carga de librerias y paquetas
import scipy as sp
import matplotlib.pyplot as plt
import sys
sys.path.append('../')
from fuentesXY import fuenteXY, grados, um

#definicion de las ondas
u1 = fuenteXY();
u1.onda_esferica(A = 1, r0 = (-10 * um, 0 * um), z0 = -1000 * um, radio = 200 * um, mascara = True, normalizar=True)
u2 = fuenteXY()
u2.onda_esferica(A = 1, r0 = (+10 * um, 0 * um), z0 = -1000 * um, radio = 200 * um, mascara = True, normalizar=True)

#definicion de las interferencias
u12 = u1 + u2
u12.dibujar(tipo='intensidad')

plt.show()

(Source code, png, hires.png, pdf)

../../_images/interferencias_ondasEsfericas1.png

11.5.2. Interferómetro de Michelson

Ahora las fuentes están desplazadas en el eje z. Esto genera una distribución de intensidad en forma de anillos, como se puede ver en la siguiente función.

#!/usr/local/bin/python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#------------------------------------
# Autor:	Luis Miguel Sanchez Brea
# Fecha		2013/10/24 (version 1.0)
# Licencia:	GPL
#-------------------------------------
"""
Interferencias
"""
#Carga de paquetes y librerias
import scipy as sp
import matplotlib.pyplot as plt
import sys
sys.path.append('../')
from fuentesXY import fuenteXY, grados, um

#Definicion de las ondas
u1 = fuenteXY()
u1.onda_esferica(A = 1, r0 = (0 * um, 0 * um), z0 = -1000 * um, radio = 200 * um, mascara = True)
u2 = fuenteXY()
u2.onda_esferica(A = 1, r0 = (0 * um, 0 * um), z0 = -1500 * um, radio = 200 * um, mascara = True)

#Superposicion y dibujo de la intensidad
u12 = u1 + u2
u12.dibujar()

plt.show()

(Source code, png, hires.png, pdf)

../../_images/interferencias_ondasEsfericas2.png

11.5.3. Desplazamiento combinado

Cuando tenemos un desplazamiento combinado x-z entre las dos fuentes, entonces la situación no es tan sencilla, apareciendo unas elipses que nos son familiares si hemos ajustado un interferómetro de Michelson.

#!/usr/local/bin/python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#------------------------------------
# Autor:	Luis Miguel Sanchez Brea
# Fecha		2013/10/24 (version 1.0)
# Licencia:	GPL
#-------------------------------------
"""
Interferencias
"""

#Carga de paquetes y librerias
import scipy as sp
import matplotlib.pyplot as plt
import sys
sys.path.append('../')
from fuentesXY import fuenteXY, grados, um

#Definicion de las ondas
u1 = fuenteXY()
u1.onda_esferica(A = 1, r0 = (-20 * um, 0 * um), z0 = -1000 * um, radio = 100 * um, mascara = False)
u2 = fuenteXY()
u2.onda_esferica(A = 1, r0 = (+20 * um, 0 * um), z0 = -1100 * um, radio = 100 * um, mascara = False)

#Superposicion de las ondas
u12 = u1 + u2

#Representacion
u12.dibujar(tipo='intensidad')
plt.show()

(Source code, png, hires.png, pdf)

../../_images/interferencias_ondasEsfericas3.png

11.5.4. Simulación del interferómetro de Michelson

Para finalizar mostramos un código que ejecuta un vídeo de qué ocurre en un interferómetro de Michelson cuando uno de los espejos se desplaza.

#!/usr/local/bin/python
# -*- coding: utf-8 -*-
#------------------------------------
# Autor:	Luis Miguel Sanchez Brea
# Fecha		2013/10/24 (version 1.0)
# Licencia:	GPL
# Objetivo:	grafica animada simulando un interferometro de Michelson
#-------------------------------------


import time
import gobject
import gtk #@UnusedImport

import scipy as sp

import matplotlib
matplotlib.use('GTKAgg')
import matplotlib.pyplot as plt
import matplotlib.cm as cm

um=1;
mm=1000*um;

fig = plt.figure(1)
a = plt.subplot(111)

wavelength=0.6328*um
k=2*sp.pi/wavelength

d=.25*mm #separacion entre espejos
x=sp.linspace(-15*mm,15*mm,256)
y=sp.linspace(-15*mm,15*mm,256)
z=250*mm    #camino recorrido por la luz

X,Y=sp.meshgrid(x,y)

#acelera los calculos
cos_theta=z/sp.sqrt(X**2+Y**2+z**2)

I=1+sp.cos(2*k*d*cos_theta)

im = a.imshow( I, cmap=cm.gist_heat)

manager = plt.get_current_fig_manager()
cnt = 0
tstart = time.time()

def updatefig(*args):
	#parametros globales definidos fuera de la funcion
	global x, y, cnt, start, k, cos_theta, d
	d-=.025*um
	I=1+sp.cos(2*k*d*cos_theta)
	im.set_array(I)
	manager.canvas.draw()
	cnt += 1
	if cnt==250:
		FPS=cnt/(time.time() - tstart)
		print "FPS: %4.2f" %FPS
		return False
	return True

cnt = 0

gobject.idle_add(updatefig)
plt.show()
tmp=raw_input("pulse enter para cerrar:")

(Source code)