experiments.show_wobbler_states module

Warning

This experiment is deprecated. Use Show Signal (Wobbler) for a more convenient way of adjusting the Wobbler. It shows the resulting phase cycled signal in addition to the signal of the different wobbler states. This makes it substantially easier to minimize scattering. The only addition this experiment has in comparison to Show Signal (Wobbler) is that it plots the ADC sampling the Wobbler reference channel. But the reference channel is not needed for how the software processes data. ** In the I-Lab the Wobbler reference channel is not even connected to the ADC. ** (And if one were to connect it, one would not see the sine-wave that is displayed on the oscilloscope without using a voltage follower.)

Providing the “Show Wobbler States” experiment. In this experiment four different Wobbler states are displayed. One for each Wobbler window position. The positions are left, middle, right, middle. The experiment can be used to adjust the Wobblers phase, delay and amplitude to phase cycle the signal properly. The correct way to phase cycle is to phase cycle the intensities (voltages on detector). If the four signals are out of phase, phase cycling should work. The chopper and wobbler should be turned on for this experiment to work properly.

Note

General:

Sometimes when turning the chopper on an off, the wobbler phase switches from in phase to out of phase or vice versa. This might cause the user to think that he has adjusted the phase correctly, while it is not adjusted correctly. This probably results from incorrectly setting the chopper phase. It might come from the fact that the chopper reference is taken at a different point of the chopper blade than the laser pulse travels through. Setting the phase of the chopper correctly might solve this problem.

There is also the possibility to change duty cycle, phase and amplitude of the wobbler via external electronics. The duty cycle should in general be set to 50 %. Adjust the amplitude first since it also changes the phase relationship between laser and wobbler. Then adjust the phase. The resulting four dots (if wobbler frequency is 1/4 of laser frequency) should have two outer dots (wobbler left and right position) and two middle dots which should be overlapping. Adjust amplitude and phase to overlap the middel dots. The amplitude sets the phase cycle of the IR light and thus needs to be adjusted while looking at the software so that the desired part/interval of the signal is phase cycled.

Wobbler Adjustment with Multiple Choppers:

General procedure:

First turn off wobbler. Turn the chopper phase such that the four displayed lines are laying on top of each other. Turn on the wobbler and adjust it in a way that two pairs of line are opposite to each other (cancel out). This should reduce the scattering.

Detailed procedure:

For adjusting the wobbler the moveable path of the interferometer needs to be blocked. A pulse delay circuit which can also set the duty cycle is required for the choppers. The duty cycle of the outgoing chopper pulse (delayed pulse) should be tuned to 50 % with the delay electronics. Next step is to set the chopper phase correctly. For that it is necessary to tune the delay of the outgoing pulse. If only three lines are displayed (wobbler off) the chopper phase is not correct. If everything was set correctly (especially the phase of the chopper via the delay) and the wobbler is off, four overlapping lines can be observed in the show wobbler states/ show signal wobbler experiment. This may be because part of the pulse is chopped incorrectly and is “sliced” off (this is just a guess). Avoid that there is an offset and try to set it up such that the four lines are overlapping perfectly.

In show wobbler states experiment the colors of the lines swap with each other since there is no reference for the wobbler collected by the adc to pinpoint it’s position. Nevertheless it is still possible to tune the wobbler since the four different lines still represent the four different positions of the wobbler. Finally turning the wobbler on results in two pairs of overlapping lines. Which should be tuned se to enable phase cycling.

Step by Step Algorithm:

Acquisition:

  1. Preallocate dictionary (data container) which will contain data and information about scan index, delay index etc.

  2. Start the ADC task (in the later experiments this was done differently. See the source code for further details)

  3. Read the data from the ADC

  4. Place data into dictionary and hand it over to primary processing

Primary Processing:

  1. Preallocate arrays for data, counts, weights, chopper and wobbler states. Here there are 2 states. On (chopper high) and off (chopper low). Each position of the wobbler is also a different state

  2. Subtract background from raw data (dark noise)

  3. Linearize response of pixels

  4. Calculate average intensity for each pixel

  5. Calculate transmission, or more precisely, relative intensity (probe intensity / reference intensity) for each laser shot for each pixel pair

  6. Identify the chopper states for all laser shots using the corresponding channel(s) in the ADCs’ data

  7. Obtain the different wobbler states with the dataprocessing class’ “get_wobbler_states” method

  8. Sort the data (transmissions) for each state and calculate statistics

  9. Put this information into data container

  10. Calculate average by weighting with counts.

  11. Save data (and raw data) including counts, weights and s2s_std if respective checkboxes on GUI were checked. Save counts and weights

  12. Hand over the data container to secondary processing process

Secondary Processing:

  1. Calculate the phase cycled transmission by averaging (here it is done in the way that we think is the more correct way to phase cycle. Phase cycling away the scattering which occurs on the detector directly makes more sense than to phase cycle the difference spectra. Although a comparison yields differences on the 10^-5 precision, we still try to implement the correct method as shown in this experiment)

  2. Calculate the phase cycled absorption (-log10)

  3. Calculate the non phase cycled absorption (-log10) of the sorted data

  4. Calculate the pump probe difference signal (chopper high - chopper low)

  5. Calculate the first and second derivative of the signal

  6. Find maximum of first derivative of averaged data because this should be the t zero value

  7. Calculate the average intensities and standard deviation of the intensities for each pixel

  8. Put this information into data container

  9. Calculate the numbers which are displayed in the “statistics box” on the GUI

  10. Hand over data to Pyqtplotting thread

Pyqt Plotting:

  1. Remove old plots

  2. Setup the plot that displays:
    • Time-signal heatmap with histogram

    • Signal

    • Intensities and standard deviation of signal

    • Time-signal

    • Time-signal 1st derivative

    • Time-signal 2nd derivative

  3. Plot the plots for the first time

  4. Update plots

Saving:

programming data dimension:
[(2 ([0] is current average scan, [1] is last single scan), n_probe_pixels, n_wobbler_states, n_chopper_states)]

saving dimension:
[(n_probe_pixels, n_wobbler_states, n_chopper_states)]

raw data dimension:
[(n_channels, samples_to_acquire)]

Folder Structure

In scans/ the first file of 3 contains the data in the saving dimensions. The counts file contains weights to average equally weighted. The weights file contains the inverse variance for each saving dimension as weights. The dimensions of these files are as saving dimension suggests. These files can be averaged with different weights to obtain the complete resulting spectrum. It might be worth to check the actual code of the corresponding experiment to understand how to calculate the desired end result difference spectrum.

The data in /averaged_data is averaged equally weighted (using counts). Likewise to the scan data the difference spectrum still needs to be calculated from the transmissions for every state. Because the array contains the transmissions averaged with counts it is only intended to be used as a first indicator for the measurement.

The /figure folder is currently empty. It is possible to implement plotting of figures which are saved here while the experiment is running. This is however not implemented yet.

The /hardware config folder holds every file which contains hardware configuration parameters. This folder is a compressed copy of the hardware configuration folder in the software’s directory. Here it is possible to look up the ADC configuration to obtain what channel was connected to which hardware element (e.g. chopper - ai78). It is also possible to obtain the R-2R values, the FPAS configuration, the linearization parameters, etc.

The /raw data folder is in the experiments directory only if the “save raw data” checkbox on the GUI was checked. It contains the raw (unedited… as raw as it can get) data. Basically, the voltages which the ADC measured for each channel. The dimensions are as “raw data dimensions” suggests.

The background.npy file is a copy of the most recently collected dark noise background of the MCT detector array. It corrects for dark noise. If no new background was collected before the experiment was started the code will use the latest available background and display a warning in the log.

setupinfo.txt is a ReadMe file that contains the most relevant experimental parameters at first glance. Additionally, the user can decide to write a comment in the readme editor of the GUI. The content of this is written to the notes.txt file.

username/
├── date1_experimentname1_000/
│   ├── averaged_data
│   │   └──  date1_experimentname1_000.npy
│   ├── figures
│   ├── hardware config
│   ├── raw data
│   │   ├──  s000000_date1_experimentname1_000_raw.npy
│   │   ├──  ...
│   │   └──  s000099_date1_experimentname1_000_raw.npy
│   ├── scans
│   │   ├──  s000000_date1_experimentname1_000.npy
│   │   ├──  s000000_counts_date1_experimentname1_000.npy
│   │   ├──  s000000_weights_date1_experimentname1_000.npy
│   │   ├──  ...
│   │   └──  s000099_date1_experimentname1_000.npy
│   ├── setupinfo_date1_experimentname1_000.txt
│   ├── notes_date1_experimentname1_000.txt
│   └── background_date1_experimentname1_000.npy
├── date1_experimentname1_001/
├── date2_experimentname1_000/
└── date2_experimentname2_000/
class Acquisition(adc: analog_digital_converter.AnalogDigitalConverter, spectrometer: triax.Triax, acq_queue)[source]

Bases: threading.Thread

Acquisition class (python multithreaded). This is where the actual experiment is conducted.

This class is used to control the hardware devices required for the experiment. The sole purpose of it is to collect the data according to the parameters specified for the experiment by moving the delay stages, opening and closing shutters etc.

A dictionary which will contain data and other information (scan index etc.) is instantiated here. The acquisition class passes the collected information (raw data, scan index etc.) to the primary processing class.

Note

No data processing beyond what is required to conduct the experiment should be implemented in this class. The rationale behind this is to minimize down time/ maximize laser time. Data processing costs computation time and will, generally speaking, slow down the measurement process because the computer is busy while the rest of the hardware is idle. If implemented correctly the data processing could be carried out while the data acquisition is waiting for all data to become available. But even in this scenario the problem that the data processing takes longer than the acquisition time can occur and is thus best avoided through parallelisation.

The reason why this class is a child of the threading module instead of the multiprocessing module is that to use multiprocessing all objects passed to the function must be picklable. This is not the case for some of the objects interfacing with the hardware (e.g. ADC). In an ideal scenario the acquisition too, would run in its own process seperated from the GUI thread but this would only be possible with major restructuring of the software.

Parameters
  • adc (ADC) – Analog to digital converter hardware object which is used to communicate with and read data from the ADC.

  • spectrometer (Spectrometer) – Spectrometer/Triax hardware class which grants functionality to control the triax spectrometer. Needed to obtain e.g. wavenumber axis etc.

  • acq_queue (Queue) – Multiprocessing queue object that the acquisition thread uses to pass data to the primary processing process.

run()[source]

Method representing the thread’s activity.

You may override this method in a subclass. The standard run() method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.

shutdown()[source]
class PrimaryProcessing(acq_queue: multiprocessing.context.BaseContext.Queue, processing_queue: multiprocessing.context.BaseContext.Queue, laser_freq: int, wobbler_freq: float, pixel_idx: numpy.ndarray, probe_pixel_idx: numpy.ndarray, reference_pixel_idx: numpy.ndarray, index_dict: dict, prl: data_processing.PixelResponseLinearization, chopper_info: dict, background_handler: save_data.Background, saver: Optional[save_data.SaveData] = None)[source]

Bases: multiprocessing.context.Process

Primary processing class (python multiprocess). This class’ purpose is to process the raw data to a state where it can be saved onto the hard drive as npy (binary) files.

This step generally includes linearization, normalisation, sorting and averaging. Besides the actual data additional information that is required for post processing purposes is calculated and saved. I.e. counts and weights. The last step of primary processing should always be to pass the data to secondary processing and save it to the hard disk.

Note

The actual signal(s) are generally not intended to be calculated here. Signals and other information that is supposed to be displayed on the GUI should be calculated in secondary processing. The main reason for this is minimizing the risk of an error leading to a crash of the software which then in turn ruins the measurement. The more code that has to run the more likely a crash becomes. Others reasons mostly imply open questions regarding averaging. Generally, shot to shot normalized intensities that are sorted and averaged by their state are saved (m2 method). From this - for a simple experiment at least - the signal can be easily calculated while offering different choices of averaging in post processing. For more complex experiments e.g. VIPER or time domain experiments the argument of saving sorted transmissions instead of signals is even more compelling. In VIPER experiments more than one signal of interest is present in the different states. Saving each signal separately would actually increase the amount of data that has to be saved. For time domain experiments we want to save the data in the time domain for post processing reasons like zeropadding and apodization.

The goal of primary processing is to make the data as compact as possible while keeping as much information and flexibility as possible. Even if the processes later on crash, the data is secured and can be analysed in post processing.

Parameters
  • acq_queue (Queue) – Multiprocessing queue object that the acquisition thread uses to pass data to the primary processing process.

  • processing_queue (Queue) – Multiprocessing queue object that the primary processing process uses to pass data to the secondary processing process.

  • laser_freq (float) – Frequency (repetition rate) of the laser in Hz.

  • wobbler_freq (float) – Frequency in Hz with which the wobbler oscillates.

  • pixel_idx (ndarray) –

    Array that contains the indices of the rows in the ADCs’ data that correspond to pixel input channels. These are specified in the “analog input configuration.json” for each laboratory and can be easily accessed with the attribute “pixel_idx” of the ADC.

    • shape: 1D

    • E.g.: (64) or (128)

  • probe_pixel_idx (ndarray) –

    Array that contains the indices of the rows in the ADCs’ data that correspond to probe pixel input channels. These are specified in the “analog input configuration.json” for each laboratory and can be easily accessed with the attribute “probe_pixel_idx” of the ADC. It is highly relevant that the order the pixels are listed in this array match the order of the array in the reference_pixel_idx argument. This means that if reference pixel 3 is listed first in the other array here probe pixel 3 needs to be listed first as well and so on. Otherwise the intensities on the probe array are not going to be normalized correctly. For the plotting to work correctly the pixels also need to be listed in the order of the wavenumber axis array of the spectrometer.

    • shape: 1D

    • E.g.: (32) or (64)

  • reference_pixel_idx (ndarray) –

    Array that contains the indices of the rows in the ADCs’ data that correspond to reference pixel input channels. These are specified in the “analog input configuration.json” for each laboratory and can be easily accessed with the attribute “reference_pixel_idx” of the ADC. It is highly relevant that the order the pixels are listed in this array match the order of the array in the probe_pixel_idx argument. This means that if probe pixel 10 is listed first in the other array here reference pixel 10 needs to be listed first as well and so on. Otherwise the intensities on the probe array are not going to be normalized correctly. For the plotting to work correctly the pixels also need to be listed in the order of the wavenumber axis array of the spectrometer.

    • shape: 1D

    • E.g.: (32) or (64)

  • index_dict (dict) – Dictionary that maps the names of the input channels to their corresponding row in the ADCs’ data as they are specified in the “analog input configuration.json” for each laboratory. I.e.: It contains the information which entries of the ADCs’ data array belong choppers, wobblers etc. This dictionary can be easily accessed with the attribute “index_dict” of the ADC.

  • prl (PRL) – Pixel response linearization object which grants the functionality to linearize raw data according to the linearization parameters specified in the corresponding pixel_linearization_fit_parameters.json file (for each lab).

  • chopper_info (dict) – Contains the information that is necessary to identify the different chopper states of the chopper that chops the pump pulse. It contains the keys “high voltage level” and “name”. “high voltage level” is the voltage read by the ADC when the chopper reference output is high. It is needed as a reference for the digitization function that is used. The “name” key is required to determine to which channel of the adc the chopper is connected and its value needs to match the corresponding key in index_dict.

  • background_handler (Background) – Instance of Background class which can access the most recently collected background. This background is later subtracted from the raw data as dark noise correction.

  • saver (SaveData) – Object that manages saving of data (including counts, weights, probe wavenumber axis etc.) into their respective directories. If None is passed, no data is going to be saved. If the raw data checkbox was checked on the GUI the savers raw data attribute is set to True and the raw data is saved automatically. Defaults to None.

run()[source]

Method to be run in sub-process; can be overridden in sub-class

class PyqtPlotting(widget_pyqtgraph, adc: analog_digital_converter.AnalogDigitalConverter, plot_queue)[source]

Bases: object

Pyqt Plotting class (Qt multithreaded). This class is necessary for displaying plots on the GUI. PyQtGraph is used as the plotting engine. Generally the plots are set up first (type of plot, layout, title etc.). On the first run, the plots are drawn for the first time. Then the plots are updated every iteration. We update the same plot references every time to make it more efficient.

Parameters
  • widget_pyqtgraph (QWidget) – WidgetPyqtgraph object on which the plots are going to be displayed. Has methods for plot manipulation (i.e. removal of plots, autoscale).

  • adc (ADC) – Analog to digital converter hardware object which is used to communicate with and read data from the ADC.

  • plot_queue (Queue) – Multiprocessing queue object that the secondary processing process uses to pass data to the plot thread.

class Signals[source]

Bases: PyQt5.QtCore.QObject

new_data
run()[source]
update_plot(data_container)[source]
class SecondaryProcessing(processing_queue: multiprocessing.context.BaseContext.Queue, plot_queue: multiprocessing.context.BaseContext.Queue, info_queue: multiprocessing.context.BaseContext.Queue)[source]

Bases: multiprocessing.context.Process

Secondary processing class (python multiprocess). This class is used to process the data from the primary processing class such that it can be displayed on the GUI within plots and lineEdits. This generally implies (if applicable):

  • calculation of signals

  • calculation of statistics like standard deviation of intensities and shot to shot standard deviation of signal

  • interpolation for 2D / heatmap plots (see comments in code why this is necessary)

  • Fourier transform and phasing for time domain data

This data is handed over to the plotting thread.

Note

The feature of saving figures/plots to the hard drive should be implemented here if it is needed.

Parameters
  • processing_queue (Queue) – Multiprocessing queue object that the primary processing process uses to pass data to the secondary processing process.

  • plot_queue (Queue) – Multiprocessing queue object that the secondary processing process uses to pass data to the plot thread.

  • info_queue (Queue) – Multiprocessing queue object which is used to transfer/hand over information to lineEdits on GUI. Contains (if applicable) scan index, delay index, interleave index, values for statistics groupBox etc.

run()[source]

Method to be run in sub-process; can be overridden in sub-class

class ShowWobblerStates(wobbler_freq: float, widget_pyqtgraph, adc: analog_digital_converter.AnalogDigitalConverter, prl: data_processing.PixelResponseLinearization, chopper_info: dict, background_handler: save_data.Background, spectrometer: triax.Triax, info_queue: multiprocessing.context.BaseContext.Queue, saver: Optional[save_data.SaveData] = None)[source]

Bases: object

Parameters
  • wobbler_freq (float) – Frequency in Hz with which the wobbler oscillates.

  • widget_pyqtgraph (QWidget) – WidgetPyqtgraph object on which the plots are going to be displayed. Has methods for plot manipulation (i.e. removal of plots, autoscale).

  • adc (ADC) – Analog to digital converter hardware object which is used to communicate with and read data from the ADC.

  • prl (PRL) – Pixel response linearization object which grants the functionality to linearize raw data according to the linearization parameters specified in the corresponding pixel_linearization_fit_parameters.json file (for each lab).

  • chopper_info (dict) – Contains the information that is necessary to identify the different chopper states of the chopper that chops the pump pulse. It contains the keys “high voltage level” and “name”. “high voltage level” is the voltage read by the ADC when the chopper reference output is high. It is needed as a reference for the digitization function that is used. The “name” key is required to determine to which channel of the adc the chopper is connected and its value needs to match the corresponding key in index_dict.

  • background_handler (Background) – Instance of Background class which can access the most recently collected background. This background is later subtracted from the raw data as dark noise correction.

  • spectrometer (Spectrometer) – Spectrometer/Triax hardware class which grants functionality to control the triax spectrometer. Needed to obtain e.g. wavenumber axis etc.

  • info_queue (Queue) – Multiprocessing queue object which is used to transfer/hand over information to lineEdits on GUI. Contains (if applicable) scan index, delay index, interleave index, values for statistics groupBox etc.

  • saver (SaveData) – Object that manages saving of data (including counts, weights, probe wavenumber axis etc.) into their respective directories. If None is passed, no data is going to be saved. If the raw data checkbox was checked on the GUI the savers raw data attribute is set to True and the raw data is saved automatically. Defaults to None.

start()[source]