Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Laser Scanning Toolchain #169

Draft
wants to merge 80 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
89b19d9
first results reading from wavemeter with callbacks. still crashes wh…
ksenkalla Dec 2, 2022
f7dcbdf
playing around with mutex and signals
ksenkalla Dec 2, 2022
c1d88a0
towards a working model
ksenkalla Dec 2, 2022
6f51132
cleaning up the debug stuff to have some base for discussions
ksenkalla Dec 5, 2022
9202d59
towards running wavemeter as counter
ksenkalla Dec 14, 2022
3c2b805
read_available_data returns the current number of read samples and do…
ksenkalla Jan 18, 2023
0987a0a
WIP
ksenkalla Mar 15, 2023
3ab6113
Rudimentary Gui for wavemeter on new core, 1st commit:
ksenkalla Mar 15, 2023
8370bfb
Progress of Wavemeter ToolChain:
ksenkalla Mar 31, 2023
27cf034
Progress of Wavemeter ToolChain:
ksenkalla Apr 18, 2023
d11577e
Progress of Wavemeter ToolChain:
ksenkalla Apr 26, 2023
d70e015
Progress of Wavemeter ToolChain:
ksenkalla Jun 1, 2023
6f0d3fd
W.I.P Wavemeter:
ksenkalla Jun 6, 2023
a13b9be
W.I.P Wavemeter:
ksenkalla Jun 9, 2023
430e067
W.I.P Wavemeter:
ksenkalla Jun 27, 2023
a3fb60d
W.I.P Wavemeter:
ksenkalla Jul 12, 2023
c7a867a
Merge branch 'main' into wavemeter_development
ksenkalla Jul 12, 2023
a291067
W.I.P Wavemeter:
ksenkalla Jul 14, 2023
c0cf7fd
W.I.P Wavemeter:
ksenkalla Jul 14, 2023
43bf18a
bugfix
ksenkalla Jul 20, 2023
029081b
WIP
ksenkalla Jul 28, 2023
2390ad3
Merge branch 'main' into wavemeter_development
ksenkalla Jul 28, 2023
d56b792
WIP:
ksenkalla Aug 29, 2023
6548e6a
Updated/added all files regarding latest version of wavemeter hardwar…
ksenkalla Sep 13, 2023
f628996
Updated all files regarding latest version of wavemeter hardware PR.
ksenkalla Sep 27, 2023
d81c23e
-Raising a flag when high finesse GUI is manually stopped and let the…
ksenkalla Sep 28, 2023
fde56df
-Updated on newest version of wavemeter hardware PR and corrected "PL…
ksenkalla Oct 10, 2023
e45cbfc
Merge branch 'main' into wavemeter_development
ksenkalla Oct 17, 2023
f037e1b
-Raise TimeoutError at high_finesse_wavemeter.py side and check at lo…
ksenkalla Oct 24, 2023
5993945
fix weird postfix for sequences
ksenkalla Nov 3, 2023
b3d9d2f
WIP dummy hardware file for wavemeter. There is a bug where starting …
prithviulm Nov 14, 2023
8fd6d6c
nuclear swap gate seq
ksenkalla Nov 28, 2023
605e900
Updated odmr logic and pulsed measurements logic s.t. fit is saved.
ksenkalla Nov 28, 2023
c539daa
Preparations for Wavemeter PR:
ksenkalla Jan 22, 2024
b44bdb4
Merge remote-tracking branch 'origin/wavemeter_development' into wave…
ksenkalla Jan 22, 2024
868ff56
Commit changes of release
ksenkalla Jan 23, 2024
baeb6f2
adding blank line
ksenkalla Jan 23, 2024
91bf0bd
adding blank line
ksenkalla Jan 23, 2024
3f26e81
Deleted redundant files
Nick-Grimm Jan 23, 2024
ae062ee
undo of minor changes, these will be handled in a separate PR
Nick-Grimm Jan 23, 2024
8afe3aa
same default config
Nick-Grimm Jan 23, 2024
b580a10
Updated config
Nick-Grimm Jan 23, 2024
b0f7420
Scannable laser interface and dummy drafts
LukePiewalker May 15, 2024
45122b5
Correct file docstrings
LukePiewalker May 15, 2024
e1118ab
Added different dummy lasers to default config
LukePiewalker May 15, 2024
a7f4df1
Merge branch 'refs/heads/main' into scannable_laser_interface
Neverhorst Jul 10, 2024
c8d3f4a
Merge branch 'refs/heads/main' into wavemeter_scanning
Neverhorst Jul 15, 2024
1416aa6
Duplicate file
Neverhorst Jul 16, 2024
b6de6bc
Restore duplicated file
Neverhorst Jul 16, 2024
286dc2c
Merge branch laser-scanning-toolchain-temp
Neverhorst Jul 16, 2024
2a1f037
move original file to new location
Neverhorst Jul 16, 2024
b02129c
Removed old, non-working laser_scanner_logic.py
Neverhorst Jul 16, 2024
4b4820d
instream_buffer.py is working with regular time traces in dummy config.
Neverhorst Jul 20, 2024
f00d638
Timestamp mode now supported in new DataInStreamBuffer interfuse
Neverhorst Jul 20, 2024
2159ffc
Better code structure for new `DataInStreamInterface` buffer multiple…
Neverhorst Jul 25, 2024
a155b0b
Better buffered stream distribution
Neverhorst Jul 29, 2024
2e3aa26
Working sync interfuse for two `DataInStreamInterface` hardware modules
Neverhorst Jul 30, 2024
61a9edc
WIP
Neverhorst Aug 5, 2024
80dba1a
WIP
Neverhorst Aug 10, 2024
43cd676
WIP
Neverhorst Aug 15, 2024
b03033b
Removed old testing config
Neverhorst Aug 15, 2024
8a0c8a9
GUI tweaks
Neverhorst Aug 15, 2024
1b59578
WIP
Neverhorst Aug 17, 2024
ad19357
WIP
Neverhorst Aug 17, 2024
fe03a6a
Automatic laser channel type lookup
Neverhorst Aug 17, 2024
99ee244
Automatic laser channel type lookup
Neverhorst Aug 17, 2024
ac58c26
Fully working wavemeter scanning functionality
Neverhorst Aug 18, 2024
7c10e06
Fully working wavemeter scanning functionality
Neverhorst Aug 18, 2024
46ffce0
Merge branch 'main' into laser-scanning-toolchain
Neverhorst Aug 18, 2024
ec21285
Removed old testing modules
Neverhorst Aug 18, 2024
278e5de
Merge branch 'main' into scannable_laser_interface
Neverhorst Aug 18, 2024
d9ed12c
Merge branch 'scannable_laser_interface' into laser-scanning-toolchain
Neverhorst Aug 18, 2024
b903d49
Bare minimum Scannable Laser Interface and dummy
Neverhorst Aug 18, 2024
23eb0ed
Integrated scannable laser configuration and start/stop into laser sc…
Neverhorst Aug 18, 2024
f2528ff
Improved stability and functionality of instream buffers
Neverhorst Aug 18, 2024
44d6f40
Made laserscanning toolchain and interfuses more remote-proof
Neverhorst Aug 21, 2024
7943552
Refactor for better code structure
Neverhorst Aug 21, 2024
63d2212
made instream_buffer.py and instream_sync.py remote module compatible
Neverhorst Aug 21, 2024
2435b52
Added some additional documentation for new laser scanning toolchain.
Neverhorst Sep 12, 2024
3d06ce1
Merge branch 'main' into laser-scanning-toolchain
Neverhorst Nov 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions docs/setup_laserscanning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# About

The laserscanning toolchain can visualize and process data from specialized streaming modules based
on [`DataInStreamInterface`](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/interface/data_instream_interface.py)
that contain one stream channel with laser frequency (Hz) or wavelength (m) data.

Optionally, it can also connect to a
[`ScannableLaserInterface`](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/interface/scannable_laser_interface.py)
module to actively control laser scanning (settings/start/stop) during data acquisition.
In the absence of a scannable laser hardware module, the data stream is just recorded and the
actual laser scanning is assumed to be controlled from elsewhere.

While the laser scanning toolchain just requires a streaming module to work, this requirement has
some pitfalls in common experiment setups:
1. Streaming modules (and in extension the laser scanning toolchain) assume all data channels to be
in-sync with each other. However laser frequency/wavelength feedback is often provided by an
independent device, e.g. a wavemeter, and additional data by another device, e.g. NI-DAQ.
This requires synchronization of two data streams into a virtual combined stream
[as described here](./using_instream_sync.md).
2. It is often required to feed the same data stream into multiple toolchains, e.g. the laser
scanning toolchain _and_ the time series toolchain. To this end you can make use of a stream buffer
interfuse to "multiply" the stream data for multiple consumers [as described here](./using_instream_buffer.md).

A typical working toolchain consists out of the following qudi modules:

gui:
- [laserscanning.laser_scanning_gui](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/gui/laserscanning/laser_scanning_gui.py)

logic:
- [laser_scanning_logic](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/logic/laser_scanning_logic.py)

hardware (here: NI X-series streamer and high finesse wavemeter):
- [wavemeter.high_finesse_wavemeter](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/hardware/wavemeter/high_finesse_wavemeter.py)
- [ni_x_series.ni_x_series_in_streamer](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/hardware/ni_x_series/ni_x_series_in_streamer.py)
- ([qudi.interface.scannable_laser_interface.ScannableLaserInterface](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/interface/scannable_laser_interface.py), optional)
- [interfuse.instream_sync](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/hardware/interfuse/instream_sync.py)
- [interfuse.instream_buffer](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/hardware/interfuse/instream_buffer.py)


# Example config

These modules need to be configured and connected in your qudi config file.
We here provide an exemplary config for a toolchain based on a NI X-series streamer and high
finesse wavemeter.

Note: This readme file might not be up-to-date with the most recent development. We advise to check
the examplary config present in the docstring of every module's Python file. In the list above, a
direct link for every module is provided:

```yaml
gui:
laser_scanning_gui:
module.Class: 'laserscanning.laser_scanning_gui.LaserScanningGui'
options:
max_display_points: 1000 # optional, Maximum number of simultaneously displayed data points
connect:
laser_scanning_logic: 'laser_scanning_logic'

logic:
laser_scanning_logic:
module.Class: 'laser_scanning_logic.LaserScanningLogic'
connect:
streamer: 'wavemeter_ni_sync_interfuse'
# laser: '<scannable_laser>' # optional, ScannableLaserInterface
options:
laser_channel: 'red_laser'
max_update_rate: 30.0
max_samples: -1

hardware:
wavemeter_ni_sync_interfuse:
module.Class: 'interfuse.instream_sync.DataInStreamSync'
options:
allow_overwrite: False # optional, allow ringbuffer overflows
max_poll_rate: 100.0 # optional, maximum data poll rate (1/s) for connected hardware
min_interpolation_samples: 2 # optional, minimum samples per frame to interpolate (must be >= 2)
delay_time: 0 # optional, time offset for secondary stream interpolation
connect:
primary_streamer: ni_buffer1
secondary_streamer: wavemeter_buffer1

ni_buffer1:
module.Class: 'interfuse.instream_buffer.DataInStreamBuffer'
options:
allow_overwrite: False # optional, allow ringbuffer overflows
max_poll_rate: 100.0 # optional, maximum data poll rate (1/s) for connected hardware
connect:
streamer: 'ni_streamer'

ni_buffer2:
module.Class: 'interfuse.instream_buffer.DataInStreamBuffer'
options:
allow_overwrite: False # optional, allow ringbuffer overflows
max_poll_rate: 100.0 # optional, maximum data poll rate (1/s) for connected hardware
connect:
streamer: 'ni_streamer'

wavemeter_buffer1:
module.Class: 'interfuse.instream_buffer.DataInStreamBuffer'
options:
allow_overwrite: False # optional, allow ringbuffer overflows
max_poll_rate: 100.0 # optional, maximum data poll rate (1/s) for connected hardware
connect:
streamer: 'wavemeter'

wavemeter_buffer2:
module.Class: 'interfuse.instream_buffer.DataInStreamBuffer'
options:
allow_overwrite: False # optional, allow ringbuffer overflows
max_poll_rate: 100.0 # optional, maximum data poll rate (1/s) for connected hardware
connect:
streamer: 'wavemeter'

ni_streamer:
module.Class: 'ni_x_series.ni_x_series_in_streamer.NIXSeriesInStreamer'
options:
device_name: 'Dev1'
digital_sources: # optional
- 'PFI15'
analog_sources: # optional
- 'ai0'
# external_sample_clock_source: 'PFI0' # optional
# external_sample_clock_frequency: 1000 # optional
adc_voltage_range: [-10, 10] # optional
max_channel_samples_buffer: 10000000 # optional
read_write_timeout: 10 # optional

wavemeter:
module.Class: 'wavemeter.high_finesse_wavemeter.HighFinesseWavemeter'
connect:
proxy: 'wavemeter_proxy'
options:
channels:
red_laser:
switch_ch: 1 # channel on the wavemeter switch
unit: 'm' # wavelength (m) or frequency (Hz)
exposure: 10 # exposure time in ms, optional
green_laser:
switch_ch: 2
unit: 'Hz'
exposure: 10

wavemeter_proxy:
module.Class: 'wavemeter.high_finesse_proxy.HighFinesseProxy'
options:
watchdog_interval: 1.0 # how often the watchdog checks for errors/changes in s
```
112 changes: 112 additions & 0 deletions docs/using_instream_buffer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# About

The data instream buffer interfuse can be used to buffer a data stream from any streaming modules
based on [`DataInStreamInterface`](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/interface/data_instream_interface.py).
Connecting multiple of these instream buffers to the same streaming hardware module will allow for
multiple independent consumers to read the same data stream.

Since the buffer is implemented as a ringbuffer, you can choose in the configuratio
(`allow_overwrite: True|False`) if you want to raise an exception in case of overwriting unread
data or ignore this silently instead.

The actual hardware module is only stopped if the calling buffer interfuse is the last active buffer
interfuse. Configuration changes of the hardware are also only possible once all buffer interfuses
have been stopped.

Be aware that each instance of the data instream buffer interfuse will copy the stream data and
thus increase memory consumption. Depending on the configured `max_poll_rate`, this can
also increase CPU load noticeably. If you encounter problems with these resources, use only as many
instances as are absolutely necessary for your application and reduce the maximum poll rate as much
as possible.

Be also advised that all instream buffer instances that connect to the same streaming hardware
need to be run in the same qudi process. Connecting some buffers via remote connection and some
locally does not work if they connect to the same hardware module.


# Example config

Here we demonstrate a dummy streaming module being buffered and distributed to two separate time
series toolchains. For this we need the following qudi modules:

gui:
- [time_series.time_series_gui](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/gui/time_series/time_series_gui.py)

logic:
- [time_series_reader_logic](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/logic/time_series_reader_logic.py)

hardware:
- [dummy.data_instream_dummy](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/hardware/dummy/data_instream_dummy.py)
- [interfuse.instream_buffer](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/hardware/interfuse/instream_buffer.py)

Note: This readme file might not be up-to-date with the most recent development. We advise to check
the examplary config present in the docstring of every module's Python file. In the list above, a
direct link for every module is provided:

```yaml
gui:
time_series_gui1:
module.Class: 'time_series.time_series_gui.TimeSeriesGui'
options:
use_antialias: True # optional, set to False if you encounter performance issues
connect:
_time_series_logic_con: 'time_series_logic1'

time_series_gui2:
module.Class: 'time_series.time_series_gui.TimeSeriesGui'
options:
use_antialias: True # optional, set to False if you encounter performance issues
connect:
_time_series_logic_con: 'time_series_logic2'

logic:
time_series_logic1:
module.Class: 'time_series_reader_logic.TimeSeriesReaderLogic'
options:
max_frame_rate: 30 # optional (10Hz by default)
channel_buffer_size: 1048576 # optional (default: 1MSample)
calc_digital_freq: True # optional (True by default)
connect:
streamer: 'stream_buffer1'

time_series_logic2:
module.Class: 'time_series_reader_logic.TimeSeriesReaderLogic'
options:
max_frame_rate: 30 # optional (10Hz by default)
channel_buffer_size: 1048576 # optional (default: 1MSample)
calc_digital_freq: True # optional (True by default)
connect:
streamer: 'stream_buffer2'

hardware:
instream_dummy:
module.Class: 'dummy.data_instream_dummy.InStreamDummy'
options:
channel_names:
- 'APD'
- 'analog 1'
channel_units:
- 'Hz'
- 'V'
channel_signals: # Can be 'counts' or 'sine'
- 'counts'
- 'sine'
data_type: 'float64'
sample_timing: 'CONSTANT' # Can be 'CONSTANT', 'TIMESTAMP' or 'RANDOM'

stream_buffer1:
module.Class: 'interfuse.instream_buffer.DataInStreamBuffer'
options:
allow_overwrite: False
max_poll_rate: 30.0
connect:
streamer: 'instream_dummy'

stream_buffer2:
module.Class: 'interfuse.instream_buffer.DataInStreamBuffer'
options:
allow_overwrite: False
max_poll_rate: 30.0
connect:
streamer: 'instream_dummy'
```
99 changes: 99 additions & 0 deletions docs/using_instream_sync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# About

The data instream sync interfuse can be used to synchronize 2 data streams from any streaming modules
based on [`DataInStreamInterface`](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/interface/data_instream_interface.py)
via simple linear interpolation.

Since the interpolated data stream is stored in a ringbuffer, you can choose in the configuration
(`allow_overwrite: True|False`) if you want to raise an exception in case of overwriting unread
data or ignore this silently instead.

Configuration of the connected streaming devices is generally only possible for the primary
streamer. The same applies for reading the configuration back.
The only case where the secondary streamer will be configured and read back is when no active
primary streamer channels are set.

The interpolation will always take the primary streamer as timebase and interpolate the secondary
stream on this grid. Optionally, you can displace the relative timing between both streams by
setting the configuration option `delay_time` to a non-zero value (in seconds).
The configuration option `min_interpolation_samples` will ensure a minimum number of samples for
both streams needs to be acquired to attempt a new interpolation frame (minimum 2).


# Example config

Here we demonstrate two dummy streaming modules being synced and fed into a time series toolchain.
For this we need the following qudi modules:

gui:
- [time_series.time_series_gui](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/gui/time_series/time_series_gui.py)

logic:
- [time_series_reader_logic](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/logic/time_series_reader_logic.py)

hardware:
- [dummy.data_instream_dummy](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/hardware/dummy/data_instream_dummy.py)
- [interfuse.instream_sync](https://github.com/Ulm-IQO/qudi-iqo-modules/blob/main/src/qudi/hardware/interfuse/instream_sync.py)

Note: This readme file might not be up-to-date with the most recent development. We advise to check
the examplary config present in the docstring of every module's Python file. In the list above, a
direct link for every module is provided:

```yaml
gui:
time_series_gui:
module.Class: 'time_series.time_series_gui.TimeSeriesGui'
options:
use_antialias: True # optional, set to False if you encounter performance issues
connect:
_time_series_logic_con: 'time_series_logic'

logic:
time_series_logic:
module.Class: 'time_series_reader_logic.TimeSeriesReaderLogic'
options:
max_frame_rate: 30.0 # optional (10Hz by default)
channel_buffer_size: 1048576 # optional (default: 1MSample)
calc_digital_freq: True # optional (True by default)
connect:
streamer: 'sync_interfuse'

hardware:
instream_dummy1:
module.Class: 'dummy.data_instream_dummy.InStreamDummy'
options:
channel_names:
- 'APD'
- 'analog 1'
channel_units:
- 'Hz'
- 'V'
channel_signals: # Can be 'counts' or 'sine'
- 'counts'
- 'sine'
data_type: 'float64'
sample_timing: 'CONSTANT' # Can be 'CONSTANT', 'TIMESTAMP' or 'RANDOM'

instream_dummy2:
module.Class: 'dummy.data_instream_dummy.InStreamDummy'
options:
channel_names:
- 'analog 2'
channel_units:
- 'V'
channel_signals: # Can be 'counts' or 'sine'
- 'sine'
data_type: 'float64'
sample_timing: 'CONSTANT' # Can be 'CONSTANT', 'TIMESTAMP' or 'RANDOM'

sync_interfuse:
module.Class: 'interfuse.instream_sync.DataInStreamSync'
options:
min_interpolation_samples: 3
allow_overwrite: False
delay_time: 0
max_poll_rate: 30.0
connect:
primary_streamer: 'instream_dummy1'
secondary_streamer: 'instream_dummy2'
```
12 changes: 12 additions & 0 deletions src/qudi/default.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,18 @@ logic:
module_tasks: {}

hardware:
scan_laser:
module.Class: 'dummy.scannable_laser_dummy.ScannableLaserDummy'

stabilizable_scan_laser:
module.Class: 'dummy.scannable_laser_dummy.StabilizableScannableLaserDummy'

scan_laser_with_setpoins:
module.Class: 'dummy.scannable_laser_dummy.ScannableLaserSetpointsDummy'

scan_laser_with_process_control:
module.Class: 'dummy.scannable_laser_dummy.ScannableLaserProcessControlDummy'

instream_dummy:
module.Class: 'dummy.data_instream_dummy.InStreamDummy'
options:
Expand Down
Loading