# Helper modules
from typing import List, Tuple
import logging
# Import relevant modules
import nidaqmx as ni
from nidaqmx import task as ni_task
import time
# Set up logger
logger = logging.getLogger(__name__)
[docs]class Polarizer:
"""
This class can be used to change polarization of a polarizer from
parallel to perpendicular by applying 5V or 0V to their inputs.
It is assumed that a National Instruments nidaqmx capable device is
used to provide the output voltage. For this a digital output port
is used. By default, applying 5V means parallel polarization, while
perpendicular polarization implies 0 V. The time it takes for a
polarizer to rotate is around 10 ms. Waiting 500 ms should be enough
to ensure that the process of rotating finishes.
Args:
device_name (str): Name of device on which the appropriate
voltage-out port is located. The name can be found and
configured in the National Instruments Software: 'Measurement
and Automation Explorer' (MAX). The device name should also be
displayed in a pop-up when plugging in the device.
* E.g.: "Dev0", "Dev1" etc.
channel (str): Name of channel, that is used to send signal.
* E.g.: "do0", "do1", "PFI0", "PFI1" etc.
waiting_time (float, optional): Time in milliseconds to wait for
the polarizer to turn. Defaults to 50 ms.
default_position (bool, optional): Set to True if default state
is parallel. Set to False if default state is perpendicular.
Defaults to False.
parallel_electrical_state (bool, optional): Set to True if to
set parallel polarization a digital high signal (5V) needs to be
sent. Set to False if to set parallel polarization polarizer a
digital low (0V) needs to be applied. Defaults to True.
name (str, optional): Name / Identifier to give to this
polarizer. This is relevant for log statements, especially when
there is more than one polarizer in the setup. Defaults to "XYZ
polarizer".
Attributes:
task (object): Represents a DAQmx Task object, through which all
communication with device is managed.
current_position (bool): True when polarizer is parallel. False
when polarizer is perpendicular.
channel (object): DAQmx channel object representing the output
channel.
References:
| https://nidaqmx-python.readthedocs.io/en/latest/index.html
| https://nidaqmx-python.readthedocs.io/en/latest/task.html
"""
def __init__(
self,
device_name: str,
channel: str,
waiting_time: float = 500,
default_position: bool = False,
parallel_electrical_state: bool = True,
name: str = "XYZ Polarizer",
) -> "Polarizer":
# Set attributes
self.name = name
self.default_position = default_position
self.parallel_electrical_state = parallel_electrical_state
self.waiting_time = waiting_time
self.current_position = None
# Initialise nidaqmx task object
self.task = ni_task.Task(self.name)
logger.info("Initialized nidaqmx task for {}.".format(self.name))
# Connect to appropriate digital out channel
self.channel = self.task.do_channels.add_do_chan(
r"/{}/{}".format(device_name, channel)
) # See nidaqmx.task.do_channel documentation
logger.info(
"Set {} as digital output channel for {}.".format(self.channel, self.name)
)
# Set polarisator to default state
self.set_to_default_polarization()
def __wait(self):
"""
Puts thread to sleep for specified waiting time in milliseconds
using the time module.
"""
logger.info(
"Waiting {} ms for {} to complete movement.".format(
self.waiting_time, self.name
)
)
time.sleep(self.waiting_time / 1000) # Put thread to sleep
logger.info("Waiting time for {} completed.".format(self.name))
[docs] def set_parallel(self):
"""
Sets polarizer to parallel polarization. Then waits for
specified waiting time.
"""
# Check whether if polarizer is already set to parallel polarization
if self.current_position == True:
logger.info(
"{} is already set to parallel polarization. Doing nothing.".format(
self.name
)
)
return # Exit function / Skip rest of code
if (
self.parallel_electrical_state == True
): # Decide whether high or low needs to be sent.
self.task.write(True)
logger.info(
"{} is set to parallel polarization by sending 5V signal.".format(
self.name
)
)
elif self.parallel_electrical_state == False:
self.task.write(False)
logger.info(
"{} is set to parallel polarization by sending 0V signal.".format(
self.name
)
)
self.__wait()
self.current_position = True
[docs] def set_perpendicular(self):
"""
Sets polarizer to perpendicular polarization. Then waits for
specified waiting time.
"""
# Check whether if polarizer is already at perpendicular polarization
if self.current_position == False:
logger.info(
"{} is already at perpendicular polarization. Doing nothing.".format(
self.name
)
)
return # Exit function / Skip rest of code
if (
self.parallel_electrical_state == True
): # Decide whether high or low needs to be sent.
self.task.write(False)
logger.info(
"{} is set to perpendicular polarization by sending 0V signal.".format(
self.name
)
)
elif self.parallel_electrical_state == False:
self.task.write(True)
logger.info(
"{} is set to perpendicular polarization by sending 5V signal.".format(
self.name
)
)
self.__wait()
self.current_position = False
[docs] def set_to_default_polarization(self):
"""
Set polarizer to its default position/ polarization.
"""
logger.info("Setting {} to default position/ polarization.".format(self.name))
# Manage initialization by setting current position/
# polarization to opposite of default position/ polarization.
if self.current_position == None:
self.current_position = not self.default_position
# Set polarizer to default postion/ polarization
if self.default_position == True:
self.set_parallel()
elif self.default_position == False:
self.set_perpendicular()
[docs] def end(self):
"""
Set polarizer to default position/ polarization and ends nidaqmx
task.
"""
logger.info("Setting {} to default polarization to end task.".format(self.name))
self.set_to_default_polarization()
self.task.close()
logger.info("Connection to {} terminated.".format(self.name))
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.end()