experiments.ft_2d_ir module

Providing the “FT-2D-IR” experiment. This experiment is an IR pump time domain experiment. The pump pulse is split into two with a Michelson interferometer. These pulses spatially overlap while the temporal overlap is “scanned” with the movable path of the interferometer. During the measurement, a motorized stage “scans” the temporal overlap with a user defined frequency and amplitude (see pi_control.py). A probe pulse is then used to determine the molecular response. To reduce IR pump light scattering on the detector, a wobbler is used to phase cycle the pump pulse.

The interferometer has two levels. The upper path is used to trace the position of the stage. For this, a special counter electronics is used. The two photodiodes on the upper path of the interferometer detect the interference of coherent monochromatic light (generally a Helium-Neon laser at approx. 632 nm). The signal (light) on one photodiode is phase shifted 90° relative to the other photodiode. The counter registers each time the sine wave-shaped interference resulting from the stage motion passes a threshold. Depending on which of the two photodiodes passed their threshold first, the counter counts up or down. By measuring the stage positions this way it is possible to obtain a resolution of the wavelength of the light source which is used (here He-Ne = 632.8 nm). The bottom path is used for the IR pump light. Here a pyroelectric detector is used for the detection of the interferogram that results from the two broadband IR pump pulses. This interferogram is needed to cut off the time domain data at the point where the movable pulse arrives after the static pulse and for the phase correction of the Fourier Transformed (frequency domain) data.

Note

Adjusting/Alignment of interferometer:

The basic advice for the overall alignment is: Everything should go into and out of the interferometer in a straight/parallel way. Make everything right angled.

The method of alignment as described in the report “A straightforward approach to FT2D-IT spectroscopy in the pump-probe geometry” by J.S. Engler does not yield a good result.

For this reason it is recommended to use the following method of alignment:

  1. It is necessary to have a coherent light source (such as a He-Ne laser) which has a high and stable intensity. Due to the special beamsplitter used in the bottom interferometer path (IR path), it can be difficult to observe good interference in a subsequent step of the alignment. A good laser diode which costs a couple of euros can work too.

  2. Use (only!) three poles of same, and preferably setup adequate, height and screw them to the interferometer baseplate. The more identical the height of the poles are, the better. Do not use four poles. If even one of the poles has a slightly different height, this can warp the baseplate of the interferometer. This torsion will be dependent on the torque applied to the screws that clamp the interferometer to the table. (In 3D space three points will always form a plane, ergo use only 3 posts.) To dampen vibrations (e.g. door slamming, heavy footsteps, etc.) it is advisable to use rubber material at the foot of the poles. Use a ring puncher to create rings of appropriate size (for underneath the feet of the poles and for underneath the clamps which are used to fix the poles to the table). When tightening down the clamps (try to position them under the interferometer to save space) less force is required than expected. We observed that screwing until the rubber bends upwards (due to clamp pressure) is already too much. If the interferometer is screwed on too tightly the rubber deforms changing the effective height of a pole, this can cause the alignment to change. Additionally, it is advisable to decouple the table from the floor to dampen lower frequencies. To position the interferometer parallel to the holes in the table, aluminum rails (extrusions) can be used. These are typically standardized and have precise dimensions (precise enough). Put a few screws (their heads need to have the same diameter!) into holes the in direction or line along which you want to position the interferometer. Now use clamps to fix the aluminum extrusion against these screws. Now you have a straight reference line parallel to the screws and holes of the table. Push the interferometer against the extrusion while fastening it to the table.

  3. Place two irises in a straight line and the same height on the table. Make sure the height is at the center of the bottom beam splitter. The irises should have a distance of at least 1.5 m. Make sure there is enough space in between or behind for the interferometer. The irises are going to be used to align the alignment beam parallel to the table. Now align the beam on to the irises using two mirrors. When starting to walk the beam start by overshooting for faster convergence. Only for the fine-tuning align onto the apertures. Another important factor for convergence is the distance of the mirrors relative to each other and to the irises. The distance between the second mirror and the first iris has to be smaller than the distance between the first and the second mirror. Additional information and a good guide on walking the beam can be found in “Understanding Walking the Beam” by S. Agha and D. Minkin Stony Brook Laser Teaching Center (July 2007). To see whether the beam pointing is correct, slowly close the iris and observe if the beam illuminates one side of the iris earlier at one side than the other. If the illumination is symmetric, the beam is properly aligned. Furthermore, it is possible to use a piece of paper behind the iris. It might help if the beam is being cutoff asymmetrically. Repeat these steps until the beam moves through the center of the irises. It is also advisable to repeat this adjustment every day.

  4. The first component to place onto the empty interferometer base plate is the first beamsplitter. The angle between the incident and the reflected beam should be 90°. Make sure the beam is parallel to the table and does not change its height. (Even over a distance of several meters.)

  5. Place the movable path of the interferometer onto the baseplate. The movable path consists of the PI stage, a stage baseplate, and a mirror mount. First, screw the stage to the interferometer baseplate. Now the stage base plate needs to be placed on top of the stage. This step is important because it can determine the maximal coherence time which can be scanned with the interferometer stage. If the movable mirrors cannot move far enough in the right direction, the coherence time is too small for practical use. We noticed that the temporal overlap is relatively far back on the stage if the stage base plate is placed flush with the stage. For this, it is again advisable to use an aluminum rail (get help from a second person since this step is not easy to perform alone). When screwing down the stage baseplate, check the maximum torque which is allowed for the specific stage that you are using in the datasheet. (It is basically no force at all.) To prevent unnecessary point load, it is advisable to use washers. Be careful when moving the stage around. It is advisable to use some tape to secure it when does not need to be moved (e.g.: for most of the alignment operations on the interferometer).

  6. Screw the mirror mount onto the stage base plate. Use screws that have proper length. A screw that is too long may result in damage to the stage itself. Once the mirror mount is attached, make sure the mirrors are positioned low enough within the mount. If the mirrors are placed too high, the lower half of the beam that is reflected off the first beam splitter might be cut off.

  7. Align the second mirror of the movable path (the first mirror is not adjustable) such that the reflected beam is parallel to the incident beam. This implies that the angle between the two mirrors is perfect 90°. Technically when the stage moves back and forth (use PIMikroMove software to move the stage) the beam pointing should not change if it was aligned correctly. However, we noticed that the beam moved up and down when moving the stage back and forth. In our case, the beam moved up and down the same extent at a short distance (e.g. 3 cm) and a long distance (e.g. 5m). This indicates that the movement of the stage itself is not perfectly level and that, nevertheless, the alignment is correct. This effect is negligible but can confuse. We suspect that the “bend” might come from a bad interferometer baseplate or too much weight on the stage (this should be checked). For further adjustment the interferometer stage does not have to be moved back and forth anymore.

  8. Place the second beamsplitter into the interferometer. Again, make sure the incident and reflected beam are at a right angle. For this, the interferometer either needs to be rotated or a second alignment path has to be constructed (i.e. via a folding mirror). The beam again has to go out of the beamsplitter in a 90° angle and the beam pointing still has to stay the same at different distances

  9. Place the mirror tower (four mirrors) which is the static path of the interferometer onto the interferometer baseplate. Now the interference has to be aligned. First, try to position the mirror tower approximately such that the two beams overlap. Place alignment screws into the four screw holes of the tower. This ensures that the interference does not get destroyed when pulling out a screwdriver etc. (since these screws stay inside). If you don’t have the screws, buy them and postpone the further alignment until they have arrived. From this point onwards it is advisable to use a quadrant diode (A beam block can also be used. Nevertheless, the interference is significantly better with the quadrant diode). Check the specification of your diode and what inputs do what (electronics datasheet). In /utils a program “quadrant_diode.py” is provided to use the diode. However, an analog to digital converter is required. Alternatively, an oscilloscope displaying in xy-mode can be used. But this is only going to work if the light intensity is high enough, as otherwise averaging needs to be done. Place the quadrant diode directly behind the second beamsplitter, block only the static path, and adjust the diode itself such that the beam is close to (0,0) (zoom in for higher precision). Reset the position with the provided button. Unblock the static path and block the movable path. Use the first mirror of the static path to align the beam to (0,0). Place the quadrant diode further away. Now repeat the procedure, but use the second mirror of the static arm to align onto the (0,0). During the first few iterations, it is advisable to overshoot when the quadrant diode is in the front position. After some iterations, the second position will converge automatically, if everything is done correctly. In the last iterations, the interference (at the distant position) needs to be optimized by eye. Two people may be needed. Place the dots next to each other with slight overlap, using the second mirror of the static path. Slowly move the dot down until they are at the same height. A good indicator is the interference. The interference lines will be more straight and vertical (not bend anymore) if the dots have the same height. When the same height is set, slowly move one dot over the other. There is a point at which the interference lines change their orientation. This point needs to be reached. Then, interference is maximal. We observed that the dot basically has two states, bright and dark, if the maximal interference is reached. By carefully tapping on the stage the switch between dark and bright can be observed. Note that maximal interference is not reached with just a thick black line in the dot. Adjust the interference for both levels.

  10. Place the tower with the detectors (photodiodes, pyroelectric detector) onto the interferometer baseplate. Try to clamp down the cables in such a way the no force is transferred to the interferometer when someone pulls on them. It is not necessary to glue the detectors in place.

  11. Place the spherical mirrors onto the interferometer baseplate. Align the respective beam onto the detectors using the spherical mirrors. The beam should fall on the center of the detectors. If the interferogram “saturates” a beamsplitter can be placed in front of the pyroelectric detector.

  12. Place the lambda quarter plate between the second mirror of the static path (top level) and the second beamsplitter. The beam should pass through the middle. Now the He-Ne (or different light source) intensity needs to be optimized. For that, filters can be used. Turn on the X-Y display setting on the oscilloscope and move the stage via PIMikroMove. The amplitude of the photodiodes should be 4 V. At the same time, make sure the photodiodes don’t saturate. If you see an oval form it is necessary to turn the lambda quarter plate such that a circle is observed. The circle should also touch the X- and Y-axis. This indicates that the interference is optimal because the destructive interference is at 100%. If the intensity and the polarization are not adjusted correctly, the counter will fail. This step should be repeated and checked every once in a while (or when the counter fails). The counter can also fail because the light source which is sent into the interferometer is misaligned (i.e. due to pulling the cables). Align the light source properly back into the interferometer. The circle can be used to optimize this.

  13. If the spatial overlap of the IR path (bottom level) has to be readjusted, the screw of the second mirror of the static path can be used. One should be careful not to destroy the interference.

Pyroelectric Detector and Counter Electronics:

The counter electronics caused problems at the in and outputs of the pyroelectric detector. We advise shielding the cables going in and out of the pins for the pyroelectric detector. The shielding should be connected to ground. Note that the pyroelectric detector itself should be connected with two separate BNC cables (or something equivalent). Else the pyroelectric detector is not properly shielded. This is done incorrectly in the H-Lab. Additionally, it is recommended to block ambient light (from halogen lamps, etc.) to reduce noise on the photodiodes.

The photodiodes need to have enough intensity and the correct polarization (see step 12 of interferometer alignment). If the counter fails it can also be that the light source is not aligned properly into the interferometer.

For a more explicit explanation of the counter algorithms see interferometer_counter.py

R-2R (Resistor-2xResistor Network):

The R-2R is used to “compress” the 16 (parallel) outputs of the counter electronics to only four outputs, mainly to save analog inputs on the ADC. There are a few characteristics that are necessary for a well designed R-2R network. The R-2R used in the previous implementation was not correctly dimensioned and prone to error (the curve was not monotonically increasing). The resistances in the old version allowed more current to flow than the counter electronics could provide resulting in the voltage dropping. The key is to use resistors in the mega Ohm range. It is also advisable to use precise resistors. The high resistance makes current flow impossible. We observed that the output of the interferometer counter would not set the voltages correctly if current could flow. Behind the R-2R, voltage followers need to be used because the ADC needs a certain amount of current to be able to measure voltages in the first place. To check if the R-2R is working properly see /utils testing_r2r_with_adc.py and testing_r2r_measure_voltages.py. The resulting output of the R-2R should always yield a straight line, reproducible for any R-2R build with the same circuit plan.

Interferogram:

The interferogram is an essential part of the time domain experiments. It has to be set up precisely (see step 9 of interferometer alignment). It is also necessary to shield the pyroelectric detector and the cables within the box of the counter electronics to reduce noise. We suspect that the noise comes from the laser trigger not being galvanically isolated from the electronics. The noise may also result from inductance caused by the switch within the PCB which is used to trigger the pyroelectric detector. It may be advisable to redesign the pyroelectrical amplifier for a better result. Another noise source is the power supply. Make sure to use a good and stable power supply. To get a clean interferogram approximately 120s acquisition time was set with a 1kHz laser system. If the interferogram saturates it is necessary to attenuate some IR light e.g. with a beamsplitter or filter in front of the pyroelectric detector.

Wavegeneration parameters:

Setting up and optimizing the wavegeneration can be tricky. The wavegeneration is used to move the stage back and forth continuously. If this movement is set up incorrectly the algorithms will not be able to compute the frequency domain spectrum. However, the experiment is designed in such a way that it will always display the interferogram, the OPA spectrum, how many counts were counted for each position of the interferometer. To start the wavegeneration, 4 parameters need to be specified: frequency, amplitude, speedupdown, and overshoot factor. What these parameters are needed for looked up within the GUI (tooltips) and also in pi_control.py. The wavegeneration should be set up in a way that every interferometer position/bin is observed several times. Else the algorithm will not average properly and raise a “weights sum to zero” error. If a position was not filled/hit, it can be observed in the bottom middle graph. There would be spikes going down to zero. If set correctly no zero would be observed. When running properly, there might be an underlying frequency (looking like a wave) which can be seen in the graph. Using a laser that pulses with a certain frequency and a stage that is moving at a certain frequency results in a beat. The experiment still works as long as the positions are “roughly” equally filled/hit. The solution to a proper wavegeneration lies in a combination of the parameters. For instance, the overshoot should be chosen in such a way, that every bin is recorded but is also as small as possible (to not waste laser shots). We observed that a loss of approx. 3% of laser shots can be achieved (for certain less is possible). A well-working setting was: coherence time = 2ps, frequency = 0.4 Hz, speedupdown = 150, overshoot factor = 0.1. The rightmost plot in the bottom displays the interferometer stage position for a given laser shot. One would assume that a sinewave/ramp etc. should be observed. There are “spikes” that go up to 32767 which can be observed when everything is running as intended. They are a result of an underflow (For more explanation see ft_2d_ir.py code comments).

Counts:

When the interferometer stage moves beyond the calculated/predicted coherence time limits (due to imprecision and overshoot) the sort_data function (data_processing.py) sorts these states into the last available state. See comments for further explanation.

Step by Step Algorithm:

Acquisition:

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

  2. Move the interferometer stage to the position where the interferometer counter needs to be reset (this is a position a few hundred femto seconds after the t zero, but not as far as the starting position of the wavegeneration)

  3. Reset the interferometer counter value to zero

  4. Move the interferometer stage to the starting position of the wavegeneration

  5. Start wavegeneration

  6. Move IR delay stage to IR delay(s)

  7. Read the data from the ADC

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

Primary Processing:

  1. Preallocate arrays for data, counts, weights.

  2. Calculate the number of wobbler states: there are generally 4 different wobbler states (left, center, right, center position of wobbler)

  3. Subtract background from raw data (dark noise)

  4. Linearize response of pixels

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

  6. Calculate interferometer positions from R-2R data for each laser shot. Check if minimum and maximum interferometer positions were observed.

  7. Identify the different wobbler states for all laser shots

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

  9. Phase cycle by averaging the wobbler states in the transmission space. Calculate the resulting phase cycled counts and weights

  10. Average the phase cycled data by weighting equally. If averaging fails because not all states were observed ignore exception so that the graphs still will be displayed later

  11. Put this information into data container and hand it over to secondary processing

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

Secondary Processing:

  1. Preallocate arrays and variables to hold time domain 2d spectrum, frequency domain 2d spectrum, zerobin, pump frequency axis, opa range, central pump wavenumber, opa spectrum and interpolated phase cycled signal

  2. Obtain the interferogram from the sorted data

  3. Calculate time domain 2D absorption spectrum

  4. Process single scan data. Calculate frequency domain 2D absorption spectrum

  5. Extract the relevant information regarding the spectrum (from single scan data) of the OPA

  6. Obtain pump axis (single scan data)

  7. Process averaged data to obtain average frequency domain data

  8. Extract the relevant information regarding the spectrum of the OPA (from averaged data)

  9. Obtain pump axis (averaged data)

  10. Calculate 2D time domain spectrum for each wobbler state

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

  12. Put this information into data container and hand it over to Pyqtplotting thread

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

Pyqt Plotting:

  1. Remove old plots

  2. Setup the plot that displays:
    • Single 2d signal heatmap with histogram

    • Average 2d signal heatmap with histogram

    • Interferogram

    • Opa spectrum

    • Time domain spectrum of central pixel for all wobbler states

    • Intensities and their standard deviation (multiplied by 5)

    • Counts (How often a position was measured)

    • Stage position

  3. Plot the plots for the first time

  4. Update plots

Saving:

Note that the phase cycled transmission is saved. Therefore there exists no dimension for the Wobbler states.

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

saving dimension:
[(n_probe_pixels, n_interferometer_states, n_wobbler_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 the number of times a given state was observed. This should be used as weights when averaging equally weighted. The weights file contains the inverse variances of a given state for all pixels, etc. The dimensions of these files are as the saving dimension suggests. These files can be used to average in different ways in order to obtain the complete resulting spectrum. 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. Here time domain data was averaged. Please note that better quality can be achieved when Fourier transforming first and averaging in the frequency domain. This has to with the phasing that varies from scan to scan.

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.

probe_wn_axis.npy contains the wavenumber axis which is generated by the spectrometer triax.py class.

delays.npy contains the delays including weights.

username/
├── date1_experimentname1_000/
│   ├── averaged_data
│   │   ├──  d000_date1_experimentname1_000.npy
│   │   ├──  ...
│   │   └──  d999_date1_experimentname1_000.npy
│   ├── figures
│   ├── hardware config
│   ├── raw data
│   │   ├──  delay000
│   │   │   ├──  s000000_d000_date1_experimentname1_000_raw.npy
│   │   │   ├──  ...
│   │   │   └──  s000099_d000_date1_experimentname1_000_raw.npy
│   │   ├──  ...
│   │   └──  delay999
│   ├── scans
│   │   ├──  delay000
│   │   │   ├──  s000000_d000_date1_experimentname1_000.npy
│   │   │   ├──  s000000_d000_counts_date1_experimentname1_000.npy
│   │   │   ├──  s000000_d000_weights_date1_experimentname1_000.npy
│   │   │   ├──  ...
│   │   │   └──  s000099_d000_date1_experimentname1_000.npy
│   │   ├──  ...
│   │   └──  delay999
│   ├── probe_wn_axis_date1_experimentname1_000.npy
│   ├── delays_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(delays: numpy.ndarray, adc: analog_digital_converter.AnalogDigitalConverter, delay_stage: pi_control.PiStage, interferometer_stage: pi_control.PiStage, interferometer_counter: interferometer_counter.InterferometerCounter, spectrometer: triax.Triax, acq_queue: multiprocessing.context.BaseContext.Queue)[source]

Bases: threading.Thread

Parameters
  • delays (ndarray) –

    Array containing the delays in fs that are supposed to be measured in the 0th column and their corresponding weights in the 1st column. I.e.: loaded from a delay file which can be generated via the delay file editor.

    • shape: 2D

    • E.g.: (number of delays, 2)

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

  • delay_stage (PiStage) – PiStage hardware control object which provides the interface to the delay stage needed for this experiment.

  • interferometer_stage (PiStage) – PiStage hardware control object which provides the interface to the interferometer stage.

  • interferometer_counter (InterferometerCounter) – InterferometerCounter object which provides the functionalities necessary to use the interferometer counter electronics.

  • 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 Ft2dIr(widget_pyqtgraph, delays: numpy.ndarray, adc: analog_digital_converter.AnalogDigitalConverter, delay_stage: pi_control.PiStage, interferometer_stage: pi_control.PiStage, interferometer_counter: interferometer_counter.InterferometerCounter, prl: data_processing.PixelResponseLinearization, he_ne_wl: float, wobbler_freq: float, background_handler: save_data.Background, spectrometer: triax.Triax, info_queue: multiprocessing.context.BaseContext.Queue, saver: Optional[save_data.SaveData] = None)[source]

Bases: object

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).

  • delays (ndarray) –

    Array containing the delays in fs that are supposed to be measured in the 0th column and their corresponding weights in the 1st column. I.e.: loaded from a delay file which can be generated via the delay file editor.

    • shape: 2D

    • E.g.: (number of delays, 2)

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

  • delay_stage (PiStage) – PiStage hardware control object which provides the interface to the delay stage needed for this experiment.

  • interferometer_stage (PiStage) – PiStage hardware control object which provides the interface to the interferometer stage.

  • interferometer_counter (InterferometerCounter) – InterferometerCounter object which provides the functionalities necessary to use the interferometer counter electronics.

  • 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).

  • he_ne_wl (float) – Wavelength of the light source (generally a Helium-Neon laser) which is used for determining the position of the interferometer stage via the photodiodes and the counter electronics.

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

  • 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]
class MplPlotting(mpl_widget, adc: analog_digital_converter.AnalogDigitalConverter, plot_queue, delays: numpy.ndarray)[source]

Bases: object

class Signals[source]

Bases: PyQt5.QtCore.QObject

new_data
run()[source]
update_plot(data_container)[source]
class PrimaryProcessing(acq_queue: multiprocessing.context.BaseContext.Queue, processing_queue: multiprocessing.context.BaseContext.Queue, delays: numpy.ndarray, pixel_idx: numpy.ndarray, probe_pixel_idx: numpy.ndarray, reference_pixel_idx: numpy.ndarray, index_dict: dict, r2r_indices: numpy.ndarray, prl: data_processing.PixelResponseLinearization, wobbler_freq: float, laser_freq: float, interferometer_states: int, bin_reference_values: numpy.ndarray, background_handler: save_data.Background, saver: Optional[save_data.SaveData] = None)[source]

Bases: multiprocessing.context.Process

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.

  • delays (ndarray) –

    Array containing the delays in fs that are supposed to be measured in the 0th column and their corresponding weights in the 1st column. I.e.: loaded from a delay file which can be generated via the delay file editor.

    • shape: 2D

    • E.g.: (number of delays, 2)

  • 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.

  • r2r_indices (ndarray) –

    Array that contains the indices of the rows in the ADCs’ data that correspond to R-2R input channels in ascending order of significance (LSB channel first, etc.)

    • shape: 1D

    • E.g.: (4)

  • 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).

  • interferometer_states (int) – Number of interferometer states that are expected to be observed given a coherence time.

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

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

  • bin_reference_values (ndarray) –

    Reference values for each of the R-2R networks.

    • shape: 2D (4, 15) 4 rows for each of the R-2R Networks, 15 values for the 16 levels of the R-2R.

  • 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: multiprocessing.context.BaseContext.Queue, delays: numpy.ndarray, central_pixel: int)[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.

  • delays (ndarray) –

    Array containing the delays in fs that are supposed to be measured in the 0th column and their corresponding weights in the 1st column. I.e.: loaded from a delay file which can be generated via the delay file editor.

    • shape: 2D

    • E.g.: (number of delays, 2)

  • central_pixel (int) – Index of the central pixel of the detector. Used to display the signal on the central pixel.

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, delays: numpy.ndarray, probe_pixel_idx: numpy.ndarray, interferometer_states: int, central_pixel: int, saver: Optional[save_data.SaveData] = None)[source]

Bases: multiprocessing.context.Process

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.

  • delays (ndarray) –

    Array containing the delays in fs that are supposed to be measured in the 0th column and their corresponding weights in the 1st column. I.e.: loaded from a delay file which can be generated via the delay file editor.

    • shape: 2D

    • E.g.: (number of delays, 2)

  • 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)

  • interferometer_states (int) – Number of interferometer states that are expected to be observed given a coherence time.

  • central_pixel (int) – Index of the central pixel of the detector. Used to display the signal on the central pixel.

  • 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