import numpy as np
from skcomponents.optics.component import OpticalComponent
[docs]class LinearRetarder(OpticalComponent):
def __init__(self, rotation, phase):
"""
Parameters
----------
rotation : float
Angle between the fast and slow axis
phase :
phase difference between fast and slow axis
"""
self._phase_difference = phase
self._rotation = rotation
[docs] def matrix(self, wavelength) -> np.array:
theta = 2 * self._rotation * np.pi / 180
phase = self._phase_difference * np.pi / 180
m_22 = (np.cos(theta) ** 2) + (np.sin(theta) ** 2) * np.cos(phase)
m_23 = np.cos(theta) * np.sin(theta) * (1 - np.cos(phase))
m_24 = np.sin(theta) * np.sin(phase)
m_32 = m_23
m_33 = (np.cos(theta) ** 2) * np.cos(phase) + (np.sin(theta) ** 2)
m_34 = -np.cos(theta) * np.sin(phase)
m_42 = -m_24
m_43 = -m_34
m_44 = np.cos(phase)
return np.array([[1, 0, 0, 0],
[0, m_22, m_23, m_24],
[0, m_32, m_33, m_34],
[0, m_42, m_43, m_44]])
[docs]class HalfWavePlate(LinearRetarder):
def __init__(self, rotation):
super().__init__(rotation=rotation, phase=180)
[docs]class QuarterWavePlate(LinearRetarder):
def __init__(self, rotation):
super().__init__(rotation=rotation, phase=90)
[docs]class LiquidCrystalRotator(OpticalComponent):
def __init__(self, twist_angle: float = 0.0, phase: float = 180.0, reference_wavelength: float = None):
"""
Liquid crystal rotator based on the principal of a twisted nematic cell.
Parameters
----------
twist_angle : float
Angle of twist in the cell in degrees.
phase : float
Retardance angle of the cell in degrees, 180 * d * dn / lambda. The birefringence, `dn`, is assumed to
vary with 1/lambda so that the phase is independent of wavelength.
Notes
-----
S. T. Tang, H. W. Chiu, and H. S. Kwok , "Optically optimized transmittive and reflective bistable twisted
nematic liquid crystal displays", Journal of Applied Physics 87, 632-637 (2000) https://doi.org/10.1063/1.371918
"""
self._twist_angle = twist_angle
self._phase = phase
self.reference_wavelength = reference_wavelength
@property
def twist_angle(self):
return self._twist_angle
@twist_angle.setter
def twist_angle(self, value):
self._twist_angle = value
@property
def phase(self):
return self._phase
@phase.setter
def phase(self, value):
self._phase = value
[docs] def matrix(self, wavelength) -> np.array:
if (self._phase == 0) and (self._twist_angle == 0):
return np.eye(4)
phi = self._twist_angle * np.pi / 180
if self.reference_wavelength is not None:
delta = self._phase * np.pi / 180 * (self.reference_wavelength / wavelength)
else:
delta = self._phase * np.pi / 180
x = np.sqrt(phi ** 2 + delta ** 2)
a = np.cos(phi) * np.cos(x) + phi / x * np.sin(phi) * np.sin(x)
b = delta / x * np.cos(phi) * np.sin(x)
c = np.sin(phi) * np.cos(x) - phi / x * np.cos(phi) * np.sin(x)
d = delta / x * np.sin(phi) * np.sin(x)
m22 = 1 - 2 * (c ** 2 + d ** 2)
m23 = 2 * (b * d - a * c)
m24 = -2 * (a * d + b * c)
m32 = 2 * (a * c + b * d)
m33 = 1 - 2 * (b ** 2 + c ** 2)
m34 = 2 * (a * b - c * d)
m42 = 2 * (a * d - b * c)
m43 = -2 * (a * b + c * d)
m44 = 1 - 2 * (b ** 2 + d ** 2)
return np.array([[1, 0, 0, 0],
[0, m22, m23, m24],
[0, m32, m33, m34],
[0, m42, m43, m44]])
[docs]class IdealLCR(LiquidCrystalRotator):
def __init__(self, twist_angle: float = 0.0):
"""
Same as LiquidCrystalRotator, however, the phase is compensated such that the polarization rotation is always
equal to `twist_angle`
"""
super().__init__(twist_angle=twist_angle, phase=np.sqrt(180 ** 2 - twist_angle ** 2))
@LiquidCrystalRotator.twist_angle.setter
def twist_angle(self, value):
self._twist_angle = value
self._phase = np.sqrt(180 ** 2 - value ** 2)