Fresnel Rhomb

Scott Prahl

April 2018

[1]:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import pypolar.jones as jones
import pypolar.mueller as mueller
import pypolar.fresnel as fresnel
import pypolar.visualization as vis
from scipy.optimize import brentq

Description

The Fresnel rhomb uses the phenomenon that total internal reflection introduces a phase shift between the parallel and perpendicular electric fields. Fresnel noted that the phase shift varies with the angle of incidence, and more specifically, that a phase shift of 45° could be achieved with a single reflection.

Two total internal reflection bounces would cause a 90° phase shift between the fields (quarter-wave) and bouncing four times will create a 180° shift (half-wave)

5a74410bd7e94feca997b2704416dba8

Wikipedia has a surprisingly detailed page about the Fresnel Rhomb, and says

The rhomb usually takes the form of a right parallelepiped — that is, a right parallelogram-based prism. If the incident ray is perpendicular to one of the smaller rectangular faces, the angle of incidence and reflection at the next face is equal to the acute angle of the parallelogram. This angle is chosen so that each reflection introduces a phase difference of 45° between the components polarized parallel and perpendicular to the plane of reflection.

LightMachinery succinctly describes the advantages of a Fresnel Rhomb over a birefringent waveplate:

A Fresnel rhomb is a type of waveplate that has certain advantages over the more standard waveplates that use a material’s birefringence. In a Fresnel rhomb, the induced phase change between \(s-\) and \(p-\) polarized light depends only on the material’s index of refraction and the geometry, and not explicitly on the design wavelength. Fresnel rhombs typically operate over a much larger wavelength range than a typical zero-order birefringence-based waveplate. For some wavelength ranges (for example, 10.6 μm CO\(_2\) lasers), there are no convenient birefringent materials for standard waveplates. Since Fresnel rhombs only need transparent non-birefringent materials, they can be used over virtually any wavelength range.

Induced Phase Change a Function of Rhomb Angle

If the acute angle of the rhombus is \(\theta\) then the incident angle \(\phi\) (from the normal to the rhombus face) will be \(\phi=\pi/2-\theta\).

The Fresnel field reflection will light hitting the inside face of the glass rhombus (with index n) will be described by m=1/n.

For a glass such as BK7, a commonly used optical glass made by Schott, the refractive index n at a wavelength of 632.8 nm (He–Ne wavelength) is 1.5151.

[2]:
n = 1.5151
m=1/n

# only consider total internal reflection ==> angles > critical angle
critical = fresnel.critical(m, deg=True)
theta = np.linspace(critical,90,50)

rp = fresnel.r_par_amplitude(m, theta, deg=True)
rs = fresnel.r_per_amplitude(m, theta, deg=True)

plt.plot(theta, np.angle(rp, deg=True), color='blue')
plt.plot(theta, np.angle(rs, deg=True), color='red')
plt.plot(theta, np.angle(rp, deg=True)-np.angle(rs, deg=True),'k')

plt.annotate(r'$\Delta_p$', xy=(45,100), color='blue')
plt.annotate(r'$\Delta_s$', xy=(50,75), color='red')
plt.annotate(r'$\Delta_p$-$\Delta_s$', xy=(77,25))

plt.plot([critical,critical],[0,180],':k')
plt.annotate(r' $\theta_C$',  xy=(critical, 180), va='top')
plt.title('Phase Change upon Total Internal Reflection')

plt.xlabel("Acute angle of Fresnel rhomb (degrees)")
plt.ylabel("Phase change (degrees)")

plt.show()
_images/08-Fresnel-Rhomb_4_0.png
[3]:
plt.plot(theta, np.angle(rp, deg=True)-np.angle(rs, deg=True))
plt.axhline(45,color='blue',ls=':')
plt.text(41, 45, 'Desired 45° change', color='blue', va='bottom')

plt.xlabel("Corner Angle of Fresnel Rhomb (degrees)")
plt.ylabel("Net Phase Change (degrees)")
plt.title("Fresnel Rhomb n=%.3f"%n)
plt.ylim(36,46)
plt.xlim(40,65)
plt.show()
_images/08-Fresnel-Rhomb_5_0.png

Solve for the exact angles using the scipy.optimize.brentq method.

[4]:
n=1.5151                # refractive index of Fresnel Rhomb

def min_rhomb(theta):
    m = 1/n
    rp = fresnel.r_par_amplitude(m,theta, deg=True)
    rs = fresnel.r_per_amplitude(m,theta, deg=True)
    delta = 45 - (np.angle(rp, deg=True)-np.angle(rs, deg=True))
    return delta

# brentq requires that the zero fall between two points
theta1 = brentq(min_rhomb,46,51)
theta2 = brentq(min_rhomb,51,60)

plt.plot(theta, np.angle(rp, deg=True)-np.angle(rs, deg=True))
plt.plot([40,65],[45,45],':b')
plt.plot([theta1,theta2],[45,45],'or')
plt.text(57, 45.2, 'Desired 45° change', color='blue', va='bottom')

plt.xlabel("Corner Angle of Fresnel Rhomb (degrees)")
plt.ylabel("Net Phase Change (degrees)")
plt.title("Fresnel Rhomb n=%.3f"%n)
plt.ylim(36,46)
plt.xlim(40,65)
plt.show()
_images/08-Fresnel-Rhomb_7_0.png
[5]:
print('The first  possible Fresnel rhomb corner angle is %.4f°'%theta1)
print('The second possible Fresnel rhomb corner angle is %.4f°'%theta2)
The first  possible Fresnel rhomb corner angle is 48.0440°
The second possible Fresnel rhomb corner angle is 55.0822°

Validation using Jones calculus

The Fresnel rhomb should convert linearly polarized light at 45° to left circularly polarized light after two bounces

[6]:
m=1/1.5151
angle = 48.0440*np.pi/180

P = jones.field_linear(45*np.pi/180)
R = jones.op_fresnel_reflection(m, angle)

out = R @ R @ P

print(jones.interpret(out))

Intensity is 1.000
Phase is 270.0°
Left circular polarization
[7]:
m=1/1.5151
angle = 55.0822*np.pi/180

P = jones.field_linear(45*np.pi/180)
R = jones.op_fresnel_reflection(m, angle)

out = R @ R @ P

print(jones.interpret(out))

Intensity is 1.000
Phase is 270.0°
Left circular polarization

The Poincaré sphere shows how the two bounces result in left circular polarized light if one starts with 45° linear polarization.

[8]:
m=1/1.5151
angle = 55.0822*np.pi/180
R = jones.op_fresnel_reflection(m, angle)

fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(111, projection='3d')
vis.draw_empty_sphere(ax)

J1 = jones.field_linear(np.radians(45))
J2 = R @ J1
J3 = R @ J2

vis.draw_jones_poincare(J1, ax, label='  start', color='red')
vis.draw_jones_poincare(J2, ax, label='  1', color='blue')
vis.draw_jones_poincare(J3, ax, label='  2', color='blue')

vis.join_jones_poincare(J1, J2, ax, color='blue', lw=2, linestyle=':')
vis.join_jones_poincare(J2, J3, ax, color='blue', lw=2, linestyle=':')

plt.show()
_images/08-Fresnel-Rhomb_13_0.png

The Poincaré sphere shows how the two bounces result in right circular polarized light if one starts with -45° linear polarization.

[9]:
m=1/1.5151
angle = 55.0822*np.pi/180
R = jones.op_fresnel_reflection(m, angle)

fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(111, projection='3d')
vis.draw_empty_sphere(ax)

J1 = jones.field_linear(np.radians(-45))
J2 = R @ J1
J3 = R @ J2

vis.draw_jones_poincare(J1, ax, label='  start', color='red')
vis.draw_jones_poincare(J2, ax, label='  1', color='blue')
vis.draw_jones_poincare(J3, ax, label='  2', color='blue')

vis.join_jones_poincare(J1, J2, ax, color='blue', lw=2, linestyle=':')
vis.join_jones_poincare(J2, J3, ax, color='blue', lw=2, linestyle=':')

plt.show()
_images/08-Fresnel-Rhomb_15_0.png

The Poincaré sphere shows how the two bounces result in -45° linear polarization if one starts with left circular polarized light

[10]:
m=1/1.5151
angle = 55.0822*np.pi/180
R = jones.op_fresnel_reflection(m, angle)

fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(111, projection='3d')
vis.draw_empty_sphere(ax)

J1 = jones.field_left_circular()
J2 = R @ J1
J3 = R @ J2

vis.draw_jones_poincare(J1, ax, label='  start', color='red')
vis.draw_jones_poincare(J2, ax, label='  1', color='blue')
vis.draw_jones_poincare(J3, ax, label='  2', color='blue')

vis.join_jones_poincare(J1, J2, ax, color='blue', lw=2, linestyle=':')
vis.join_jones_poincare(J2, J3, ax, color='blue', lw=2, linestyle=':')

plt.show()
_images/08-Fresnel-Rhomb_17_0.png

Validation using Mueller calculus

[11]:
m=1/1.5151
angle = 48.0440*np.pi/180

R = mueller.op_fresnel_reflection(m, angle)
P = mueller.stokes_linear(45*np.pi/180)

out = R @ R @ P

print('Mueller matrix result')
print(out)
print('Left Circular Polarization is:')
print(mueller.stokes_left_circular())

Mueller matrix result
[1.00000000e+00+0.j         6.12323400e-17+0.j
 6.02925295e-01-0.79779765j 0.00000000e+00+0.j        ]
Left Circular Polarization is:
[ 1  0  0 -1]
[12]:
m=1/1.5151
angle = 55.0822*np.pi/180

R = mueller.op_fresnel_reflection(m, angle)
P = mueller.stokes_linear(45*np.pi/180)

out = R @ R @ P

print('Mueller matrix result')
print(out)
print('Left Circular Polarization is:')
print(mueller.stokes_left_circular())

Mueller matrix result
[1.00000000e+00+0.j         2.83276945e-16+0.j
 6.02939401e-01+0.79778699j 0.00000000e+00+0.j        ]
Left Circular Polarization is:
[ 1  0  0 -1]
[ ]: