From fe907505a247ea7032f20d594ee0f9a15a351763 Mon Sep 17 00:00:00 2001 From: crnbaker Date: Fri, 19 Jan 2024 17:01:55 +0000 Subject: [PATCH] #46 fixed star hub Generics bug preventing access to correct channel types --- README.md | 160 ++++++++++++++---- ...wg_standard_single_restart_mode_example.py | 2 +- src/spectrumdevice/__init__.py | 5 +- .../abstract_device/abstract_spectrum_card.py | 2 +- .../abstract_device/abstract_spectrum_hub.py | 22 +-- .../abstract_device/device_interface.py | 2 +- .../devices/digitiser/digitiser_star_hub.py | 24 ++- src/spectrumdevice/settings/__init__.py | 16 ++ src/tests/configuration.py | 2 +- src/tests/test_single_card.py | 4 +- src/tests/test_star_hub.py | 55 +++++- 11 files changed, 240 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 796412a..1897587 100644 --- a/README.md +++ b/README.md @@ -18,11 +18,11 @@ for controlling devices: |--------------------------------|-------------------------------------------------------------------| | `MockSpectrumDigitiserCard` | Mocking individual digitiser cards | | `MockSpectrumDigitiserStarHub` | Mocking digitiser cards aggregated with a StarHub | -| `MockSpectrumAWGCard` | Mocking individual AWG cards (Not yet implemented) | +| `MockSpectrumAWGCard` | Mocking individual AWG cards | | `MockSpectrumAWGStarHub` | Mocking AWG cards aggregated with a StarHub (Not yet implemented) | -For digitisers, `spectrumdevice` currently only supports 'Standard Single' and 'Multi FIFO' acquisition modes. See the -Limitations section for more information. +For digitisers, `spectrumdevice` currently only supports 'Standard Single' and 'Multi FIFO' acquisition modes. For AWGs, +'Standard Single' and Standard Single Restart' modes are supported. See the Limitations section for more information. * [Examples](https://github.com/KCL-BMEIS/spectrumdevice/tree/main/example_scripts) * [API reference documentation](https://kcl-bmeis.github.io/spectrumdevice/) @@ -55,29 +55,32 @@ pip install https://github.com/KCL-BMEIS/spectrumdevice/tarball/main. ``` `spectrumdevice` depends only on NumPy. `spectrumdevice` includes a module called `spectrum_gmbh` containing a few -files taken from the `spcm_examples` directory, provided with Spectrum hardware. The files in this module were written by Spectrum GMBH and are included with their permission. The files provide `spectrumdevice` with a low-level Python interface to the Spectrum driver and define global constants which are used throughout `spectrumdevice`. +files taken from the `spcm_examples` directory, provided with Spectrum hardware. The files in this module were written +by Spectrum GMBH and are included with their permission. The files provide `spectrumdevice` with a low-level Python +interface to the Spectrum driver and define global constants which are used throughout `spectrumdevice`. ## Limitations * Currently, `spectrumdevice` only supports Standard Single and Multi FIFO digitiser acquisition modes. See the Spectrum documentation for more information. +* Only Standard Single and Standard Single Restart modes have been implemented for AWGs. * If timestamping is enabled, timestamps are acquired using Spectrum's 'polling' mode. This seems to add around 5 to 10 ms of latency to the acquisition. * Only current digitisers from the [59xx](https://spectrum-instrumentation.com/de/59xx-16-bit-digitizer-125-mss), [44xx](https://spectrum-instrumentation.com/de/44xx-1416-bit-digitizers-500-mss) and [22xx](https://spectrum-instrumentation.com/de/22xx-8-bit-digitizers-5-gss) families are currently supported, and -`spectrumdevice` has only been tested on 59xx devices. However, `spectrumdevice` may work fine on older devices. If -you've tried `spectrumdevice` on an older device, please let us know if it works and raise any issues you encounter in -the issue tracker. It's likely possible to add support with minimal effort. +`spectrumdevice` has only been tested on 59xx digitisers and 65xx AWGs. However, `spectrumdevice` may work fine on older +devices. If you've tried `spectrumdevice` on an older device, please let us know if it works and raise any issues you +encounter in the issue tracker. It's likely possible to add support with minimal effort. ## Usage ### Connect to devices Connect to local (PCIe) cards: ```python -from spectrumdevice import SpectrumDigitiserCard +from spectrumdevice import SpectrumDigitiserCard, SpectrumAWGCard -card_0 = SpectrumDigitiserCard(device_number=0) -card_1 = SpectrumDigitiserCard(device_number=1) +digitiser_1 = SpectrumDigitiserCard(device_number=0) +awg_1 = SpectrumAWGCard(device_number=1) ``` Connect to networked cards (you can find a card's IP using the [Spectrum Control Centre](https://spectrum-instrumentation.com/en/spectrum-control-center) software): @@ -120,29 +123,39 @@ modules in a hardware device using the of the mock data source must also be set on construction. ```python -from spectrumdevice import MockSpectrumDigitiserCard, MockSpectrumDigitiserStarHub +from spectrumdevice import MockSpectrumDigitiserCard, MockSpectrumDigitiserStarHub, MockSpectrumAWGCard from spectrumdevice.settings import ModelNumber -mock_card = MockSpectrumDigitiserCard(device_number=0, model=ModelNumber.TYP_M2P5966_X4, - mock_source_frame_rate_hz=10.0, - num_modules=2, num_channels_per_module=4) -mock_hub = MockSpectrumDigitiserStarHub(device_number=0, child_cards=[mock_card], master_card_index=0) +mock_digitiser = MockSpectrumDigitiserCard( + device_number=0, + model=ModelNumber.TYP_M2P5966_X4, + mock_source_frame_rate_hz=10.0, + num_modules=2, + num_channels_per_module=4 +) +mock_hub = MockSpectrumDigitiserStarHub(device_number=0, child_cards=[mock_digitiser], master_card_index=0) +mock_awg = MockSpectrumAWGCard( + device_number=0, + model=ModelNumber.TYP_M2P6560_X4, + num_modules=1, + num_channels_per_module=1 +) ``` After construction, mock devices can be used identically to real devices. ### Configuring device settings -`SpectrumDigitiserCard` and `SpectrumDigitiserStarHub` provide methods for reading and writing device settings located -within on-device registers. Some settings must be set using Enums imported from the `settings` module. Others are set -using integer values. For example, to put a card in 'Standard Single' acquisition mode and set the sample rate to 10 -MHz: +`SpectrumDigitiserCard`, `SpectrumDigitiserStarHub` and `SpectrumAWGCard` provide methods for reading and writing device +settings located within on-device registers. Some settings must be set using Enums imported from the `settings` module. + Others are set using integer values. For example, to put a digitiser card in 'Standard Single' acquisition mode and set +the sample rate to 10 MHz: ```python from spectrumdevice import SpectrumDigitiserCard from spectrumdevice.settings import AcquisitionMode -card = SpectrumDigitiserCard(device_number=0) -card.set_acquisition_mode(AcquisitionMode.SPC_REC_STD_SINGLE) -card.set_sample_rate_in_hz(10000000) +digitiser_card = SpectrumDigitiserCard(device_number=0) +digitiser_card.set_acquisition_mode(AcquisitionMode.SPC_REC_STD_SINGLE) +digitiser_card.set_sample_rate_in_hz(10000000) ``` and to print the currently set sample rate: @@ -151,34 +164,41 @@ print(card.sample_rate_in_hz) ``` ### Configuring channel settings -The channels available to a spectrum device (card or StarHub) can be accessed via the `channels` property. This -property contains a list of `SpectrumDigitiserChannel` or `SpectrumAWGChannel` objects which provide methods for -independently configuring each channel. -For example, to change the vertical range of channel 2 of a digitiser card to 1V: +The analog channels available to a spectrum device (card or StarHub) can be accessed via the `analog_channels` property. + This property contains a list of `SpectrumDigitiserChannel` or `SpectrumAWGChannel` objects which provide methods for +independently configuring each channel. For example, to change the vertical range of channel 2 of a digitiser card to 1V: ```python -card.analog_channels[2].set_vertical_range_in_mv(1000) +digitiser_card.analog_channels[2].set_vertical_range_in_mv(1000) ``` and then print the vertical offset: ```python -print(card.analog_channels[2].vertical_offset_in_percent) +print(digitiser_card.analog_channels[2].vertical_offset_in_percent) ``` ### Configuring everything at once -You can set multiple settings at once using the `TriggerSettings` and `AcquisitionSettings` dataclasses and the -`configure_trigger()` and `configure_acquisition()` methods: +You can set multiple settings at once using the `TriggerSettings`, `AcquisitionSettings` and `GenerationSettings` +dataclasses and the `configure_trigger()`, `configure_acquisition()` and `configure_generation()` methods: ```python +import numpy as np + +from spectrumdevice import SpectrumDigitiserCard, SpectrumAWGCard from spectrumdevice.settings import TriggerSettings, AcquisitionSettings, TriggerSource, ExternalTriggerMode, \ -AcquisitionMode +AcquisitionMode, GenerationSettings, GenerationMode, OutputChannelFilter, OutputChannelStopLevelMode from spectrumdevice.settings.channel import InputImpedance +digitiser_card = SpectrumDigitiserCard(device_number=0) +awg_card = SpectrumAWGCard(device_number=1) + trigger_settings = TriggerSettings( trigger_sources=[TriggerSource.SPC_TMASK_EXT0], external_trigger_mode=ExternalTriggerMode.SPC_TM_POS, external_trigger_level_in_mv=1000, ) +digitiser_card.configure_trigger(trigger_settings) +awg_card.configure_trigger(trigger_settings) acquisition_settings = AcquisitionSettings( acquisition_mode=AcquisitionMode.SPC_REC_FIFO_MULTI, @@ -193,9 +213,20 @@ acquisition_settings = AcquisitionSettings( timestamping_enabled=True, batch_size=1 ) - -card.configure_trigger(trigger_settings) -card.configure_acquisition(acquisition_settings) +digitiser_card.configure_acquisition(acquisition_settings) + +generation_settings = GenerationSettings( + generation_mode=GenerationMode.SPC_REP_STD_SINGLERESTART, + waveform=np.array(np.ones(16), dtype=np.int16), + sample_rate_in_hz=40000000, + num_loops=5, + enabled_channels=[0], + signal_amplitudes_in_mv=[1000], + dc_offsets_in_mv=[0], + output_filters=[OutputChannelFilter.LOW_PASS_70_MHZ], + stop_level_modes=[OutputChannelStopLevelMode.SPCM_STOPLVL_ZERO], +) +awg_card.configure_generation(generation_settings) ``` ### Acquiring waveforms from a digitiser (standard single mode) @@ -272,6 +303,67 @@ card.stop() ``` and execute some logic to exit the `while` loop. +### Generating a signal with an AWG +After configuring your trigger and generation settings as shown above, you can start your card: +```python +awg_card.start() +``` +The card is now waiting for a trigger. If the card is in software trigger mode, you can trigger its output manually: +```python +awg_card.force_trigger() +``` +Then stop and disconnect when finished: +```python +awg_card.stop() +awg_card.disconnect() +``` + +### Using the optional Pulse Generator firmware add-on +For both AWGs and Digitisers, Spectrum provide an optional pulse generator feature which can be activated retrospectively. + +Each of the card's four multipurpose IO lines (X0, X1, X2 and X3) has a pulse generator. Choose the one you would like +to use and set it to pulse gen mode. Here we are using X0 (index 0) +```python +from spectrumdevice.settings import IOLineMode + +io_line_index = 0 +card.io_lines[io_line_index].set_mode(IOLineMode.SPCM_XMODE_PULSEGEN) +``` +Then get its pulse generator and configure its trigger and output settings +```python +from spectrumdevice.settings import ( + PulseGeneratorTriggerSettings, + PulseGeneratorTriggerMode, + PulseGeneratorTriggerDetectionMode, + PulseGeneratorMultiplexer1TriggerSource, + PulseGeneratorMultiplexer2TriggerSource, + PulseGeneratorOutputSettings +) + +pulse_gen = card.io_lines[io_line_index].pulse_generator +pg_trigger_settings = PulseGeneratorTriggerSettings( + trigger_mode=PulseGeneratorTriggerMode.SPCM_PULSEGEN_MODE_SINGLESHOT, + trigger_detection_mode=PulseGeneratorTriggerDetectionMode.RISING_EDGE, + multiplexer_1_source=PulseGeneratorMultiplexer1TriggerSource.SPCM_PULSEGEN_MUX1_SRC_UNUSED, + multiplexer_1_output_inversion=False, + multiplexer_2_source=PulseGeneratorMultiplexer2TriggerSource.SPCM_PULSEGEN_MUX2_SRC_SOFTWARE, + multiplexer_2_output_inversion=False, +) +pulse_gen.configure_trigger(pg_trigger_settings) +pulse_output_settings = PulseGeneratorOutputSettings( + period_in_seconds=1e-3, duty_cycle=0.5, num_pulses=10, delay_in_seconds=0.0, output_inversion=False +) +pulse_gen.configure_output(pulse_output_settings) +# Enable the pulse generator +pulse_gen.enable() +``` +We have set the pulse generator to use a software trigger, so you can manually trigger it to start pulsing: +```python +pulse_gen.force_trigger() + +card.stop() +card.disconnect() +``` ## Examples See the `example_scripts` directory. diff --git a/src/example_scripts/awg_standard_single_restart_mode_example.py b/src/example_scripts/awg_standard_single_restart_mode_example.py index f8d0540..4765929 100644 --- a/src/example_scripts/awg_standard_single_restart_mode_example.py +++ b/src/example_scripts/awg_standard_single_restart_mode_example.py @@ -68,7 +68,7 @@ def awg_single_restart_mode_example(mock_mode: bool) -> None: # is trigger, until "num_loops" triggers have been detected. card.start() for _ in range(number_of_generations): - card.force_trigger_event() + card.force_trigger() sleep(100e-3) # here we are waiting 0.1 seconds between triggers print("generated pulse") card.stop() diff --git a/src/spectrumdevice/__init__.py b/src/spectrumdevice/__init__.py index 1c4a46f..d7886e9 100644 --- a/src/spectrumdevice/__init__.py +++ b/src/spectrumdevice/__init__.py @@ -60,7 +60,8 @@ from .devices.digitiser.digitiser_card import SpectrumDigitiserCard from .devices.digitiser.digitiser_channel import SpectrumDigitiserAnalogChannel from .devices.digitiser.digitiser_star_hub import SpectrumDigitiserStarHub -from .devices.mocks import MockSpectrumDigitiserCard, MockSpectrumDigitiserStarHub +from .devices.awg.awg_card import SpectrumAWGCard +from .devices.mocks import MockSpectrumDigitiserCard, MockSpectrumDigitiserStarHub, MockSpectrumAWGCard from .devices.abstract_device import ( AbstractSpectrumDevice, AbstractSpectrumCard, @@ -82,6 +83,8 @@ "AbstractSpectrumChannel", "settings", "Measurement", + "SpectrumAWGCard", + "MockSpectrumAWGCard", ] diff --git a/src/spectrumdevice/devices/abstract_device/abstract_spectrum_card.py b/src/spectrumdevice/devices/abstract_device/abstract_spectrum_card.py index e0f7d29..8fa8800 100644 --- a/src/spectrumdevice/devices/abstract_device/abstract_spectrum_card.py +++ b/src/spectrumdevice/devices/abstract_device/abstract_spectrum_card.py @@ -484,7 +484,7 @@ def __str__(self) -> str: def type(self) -> CardType: return CardType(self.read_spectrum_device_register(SPC_FNCTYPE)) - def force_trigger_event(self) -> None: + def force_trigger(self) -> None: """Force a trigger event to occur""" self.write_to_spectrum_device_register(SPC_M2CMD, M2CMD_CARD_FORCETRIGGER) diff --git a/src/spectrumdevice/devices/abstract_device/abstract_spectrum_hub.py b/src/spectrumdevice/devices/abstract_device/abstract_spectrum_hub.py index e5f0e74..4c4a1dd 100644 --- a/src/spectrumdevice/devices/abstract_device/abstract_spectrum_hub.py +++ b/src/spectrumdevice/devices/abstract_device/abstract_spectrum_hub.py @@ -12,13 +12,13 @@ from numpy import arange -from spectrum_gmbh.regs import SPC_SYNC_ENABLEMASK +from spectrum_gmbh.py_header.regs import SPC_SYNC_ENABLEMASK from spectrumdevice.devices.abstract_device.abstract_spectrum_device import AbstractSpectrumDevice -from spectrumdevice.devices.abstract_device.channel_interfaces import ( - SpectrumAnalogChannelInterface, - SpectrumIOLineInterface, +from spectrumdevice.devices.abstract_device.device_interface import ( + SpectrumDeviceInterface, + IOLineInterfaceType, + AnalogChannelInterfaceType, ) -from spectrumdevice.devices.abstract_device.device_interface import SpectrumDeviceInterface from spectrumdevice.exceptions import SpectrumSettingsMismatchError from spectrumdevice.settings import ( AdvancedCardFeature, @@ -36,7 +36,9 @@ CardType = TypeVar("CardType", bound=SpectrumDeviceInterface) -class AbstractSpectrumStarHub(AbstractSpectrumDevice, Generic[CardType], ABC): +class AbstractSpectrumStarHub( + AbstractSpectrumDevice, Generic[CardType, AnalogChannelInterfaceType, IOLineInterfaceType], ABC +): """Composite abstract class of `AbstractSpectrumCard` implementing methods common to all StarHubs. StarHubs are composites of more than one Spectrum card. Acquisition and generation from the child cards of a StarHub is synchronised, aggregating the channels of all child cards.""" @@ -274,26 +276,26 @@ def transfer_buffers(self) -> List[TransferBuffer]: return [card.transfer_buffers[0] for card in self._child_cards] @property - def analog_channels(self) -> Sequence[SpectrumAnalogChannelInterface]: + def analog_channels(self) -> Sequence[AnalogChannelInterfaceType]: """A tuple containing of all the channels of the child cards of the hub. See `AbstractSpectrumCard.channels` for more information. Returns: channels (Sequence[`SpectrumChannelInterface`]): A tuple of `SpectrumDigitiserChannel` objects. """ - channels: List[SpectrumAnalogChannelInterface] = [] + channels: List[AnalogChannelInterfaceType] = [] for device in self._child_cards: channels += device.analog_channels return tuple(channels) @property - def io_lines(self) -> Sequence[SpectrumIOLineInterface]: + def io_lines(self) -> Sequence[IOLineInterfaceType]: """A tuple containing of all the Multipurpose IO Lines of the child cards of the hub. Returns: channels (Sequence[`SpectrumIOLineInterface`]): A tuple of `SpectrumIOLineInterface` objects. """ - io_lines: List[SpectrumIOLineInterface] = [] + io_lines: List[IOLineInterfaceType] = [] for device in self._child_cards: io_lines += device.io_lines return tuple(io_lines) # todo: this is probably wrong. I don't think both cards in a netbox have IO lines diff --git a/src/spectrumdevice/devices/abstract_device/device_interface.py b/src/spectrumdevice/devices/abstract_device/device_interface.py index 7601a78..b57f79a 100644 --- a/src/spectrumdevice/devices/abstract_device/device_interface.py +++ b/src/spectrumdevice/devices/abstract_device/device_interface.py @@ -201,7 +201,7 @@ def set_timeout_in_ms(self, timeout_in_ms: int) -> None: raise NotImplementedError() @abstractmethod - def force_trigger_event(self) -> None: + def force_trigger(self) -> None: raise NotImplementedError() @property diff --git a/src/spectrumdevice/devices/digitiser/digitiser_star_hub.py b/src/spectrumdevice/devices/digitiser/digitiser_star_hub.py index bf59a68..f2970a2 100644 --- a/src/spectrumdevice/devices/digitiser/digitiser_star_hub.py +++ b/src/spectrumdevice/devices/digitiser/digitiser_star_hub.py @@ -14,14 +14,21 @@ AbstractSpectrumStarHub, ) from spectrumdevice.devices.abstract_device.abstract_spectrum_hub import check_settings_constant_across_devices +from spectrumdevice.devices.digitiser import SpectrumDigitiserAnalogChannelInterface from spectrumdevice.devices.digitiser.digitiser_card import SpectrumDigitiserCard from spectrumdevice.devices.digitiser.abstract_spectrum_digitiser import AbstractSpectrumDigitiser +from spectrumdevice.devices.digitiser.digitiser_interface import SpectrumDigitiserIOLineInterface from spectrumdevice.settings import ModelNumber, TransferBuffer from spectrumdevice.settings.card_dependent_properties import CardType from spectrumdevice.settings.device_modes import AcquisitionMode -class SpectrumDigitiserStarHub(AbstractSpectrumStarHub[SpectrumDigitiserCard], AbstractSpectrumDigitiser): +class SpectrumDigitiserStarHub( + AbstractSpectrumStarHub[ + SpectrumDigitiserCard, SpectrumDigitiserAnalogChannelInterface, SpectrumDigitiserIOLineInterface + ], + AbstractSpectrumDigitiser, +): """Composite class of `SpectrumDigitiserCard` for controlling a StarHub digitiser device, for example the Spectrum NetBox. StarHub digitiser devices are composites of more than one Spectrum digitiser card. Acquisition from the child cards of a StarHub is synchronised, aggregating the channels of all child cards. This class enables the @@ -184,9 +191,9 @@ def set_batch_size(self, batch_size: int) -> None: for d in self._child_cards: d.set_batch_size(batch_size) - def force_trigger_event(self) -> None: + def force_trigger(self) -> None: for d in self._child_cards: - d.force_trigger_event() + d.force_trigger() @property def type(self) -> CardType: @@ -195,3 +202,14 @@ def type(self) -> CardType: @property def model_number(self) -> ModelNumber: return self._child_cards[0].model_number + + @property + def analog_channels(self) -> Sequence[SpectrumDigitiserAnalogChannelInterface]: + """A tuple containing of all the channels of the child cards of the hub. See `AbstractSpectrumCard.channels` for + more information. + + Returns: + channels (Sequence[`SpectrumDigitiserAnalogChannelInterface`]): + A tuple of `SpectrumDigitiserAnalogChannelInterface` objects. + """ + return super().analog_channels diff --git a/src/spectrumdevice/settings/__init__.py b/src/spectrumdevice/settings/__init__.py index 628aa87..6d1a507 100644 --- a/src/spectrumdevice/settings/__init__.py +++ b/src/spectrumdevice/settings/__init__.py @@ -28,6 +28,14 @@ ) from spectrumdevice.settings.triggering import TriggerSource, ExternalTriggerMode from spectrumdevice.settings.status import CARD_STATUS_TYPE, DEVICE_STATUS_TYPE, StatusCode +from spectrumdevice.settings.pulse_generator import ( + PulseGeneratorTriggerSettings, + PulseGeneratorTriggerMode, + PulseGeneratorTriggerDetectionMode, + PulseGeneratorMultiplexer1TriggerSource, + PulseGeneratorMultiplexer2TriggerSource, + PulseGeneratorOutputSettings, +) __all__ = [ @@ -49,6 +57,14 @@ "ModelNumber", "GenerationSettings", "OutputChannelFilter", + "OutputChannelStopLevelMode", + "GenerationMode", + "PulseGeneratorTriggerSettings", + "PulseGeneratorTriggerMode", + "PulseGeneratorTriggerDetectionMode", + "PulseGeneratorMultiplexer1TriggerSource", + "PulseGeneratorMultiplexer2TriggerSource", + "PulseGeneratorOutputSettings", ] diff --git a/src/tests/configuration.py b/src/tests/configuration.py index 6b61a9f..38bf32c 100644 --- a/src/tests/configuration.py +++ b/src/tests/configuration.py @@ -14,7 +14,7 @@ class SpectrumTestMode(Enum): # Set to TestMode.REAL_HARDWARE to run tests on a real hardware device as configured below. SINGLE_DIGITISER_CARD_TEST_MODE = SpectrumTestMode.MOCK_HARDWARE DIGITISER_STAR_HUB_TEST_MODE = SpectrumTestMode.MOCK_HARDWARE -SINGLE_AWG_CARD_TEST_MODE = SpectrumTestMode.MOCK_HARDWARE +SINGLE_AWG_CARD_TEST_MODE = SpectrumTestMode.REAL_HARDWARE # Set IP address of real spectrum device (for use if TestMode.REAL_HARDWARE is set above). Set to None to run tests on # a local (PCIe) card. diff --git a/src/tests/test_single_card.py b/src/tests/test_single_card.py index a8457c3..b029240 100644 --- a/src/tests/test_single_card.py +++ b/src/tests/test_single_card.py @@ -228,7 +228,9 @@ def test_configure_acquisition(self) -> None: acquisition_settings.vertical_offsets_in_percent[0], self._device.analog_channels[channel_to_enable].vertical_offset_in_percent, ) - self.assertEqual(acquisition_settings.input_impedances[0], self._device.analog_channels[1].input_impedance) + self.assertEqual( + acquisition_settings.input_impedances[0], self._device.analog_channels[channel_to_enable].input_impedance + ) class AWGCardTest(SingleCardTest[SpectrumAWGInterface]): diff --git a/src/tests/test_star_hub.py b/src/tests/test_star_hub.py index 875048d..766c85f 100644 --- a/src/tests/test_star_hub.py +++ b/src/tests/test_star_hub.py @@ -1,9 +1,10 @@ import pytest from numpy import array -from spectrum_gmbh.regs import SPC_CHENABLE +from spectrum_gmbh.py_header.regs import SPC_CHENABLE from spectrumdevice import SpectrumDigitiserAnalogChannel, SpectrumDigitiserStarHub from spectrumdevice.exceptions import SpectrumInvalidNumberOfEnabledChannels +from spectrumdevice.settings import AcquisitionSettings, InputImpedance, AcquisitionMode from spectrumdevice.settings.channel import SpectrumAnalogChannelName from spectrumdevice.settings.transfer_buffer import create_samples_acquisition_transfer_buffer from tests.configuration import ( @@ -32,6 +33,58 @@ def setUp(self) -> None: def tearDown(self) -> None: self._device.disconnect() + def test_configure_acquisition(self) -> None: + channels_to_enable = [0, 8] + acquisition_settings = AcquisitionSettings( + acquisition_mode=AcquisitionMode.SPC_REC_STD_SINGLE, + sample_rate_in_hz=int(4e6), + acquisition_length_in_samples=400, + pre_trigger_length_in_samples=0, + timeout_in_ms=1000, + enabled_channels=channels_to_enable, # enable only second channel + vertical_ranges_in_mv=[1000, 2000], + vertical_offsets_in_percent=[10, 20], + input_impedances=[InputImpedance.FIFTY_OHM, InputImpedance.ONE_MEGA_OHM], + timestamping_enabled=False, + ) + + self._device.configure_acquisition(acquisition_settings) + + expected_posttrigger_len = ( + acquisition_settings.acquisition_length_in_samples - acquisition_settings.pre_trigger_length_in_samples + ) + + self.assertEqual(acquisition_settings.acquisition_mode, self._device.acquisition_mode) + self.assertEqual(acquisition_settings.sample_rate_in_hz, self._device.sample_rate_in_hz) + self.assertEqual(acquisition_settings.acquisition_length_in_samples, self._device.acquisition_length_in_samples) + self.assertEqual(expected_posttrigger_len, self._device.post_trigger_length_in_samples) + self.assertEqual(acquisition_settings.timeout_in_ms, self._device.timeout_in_ms) + self.assertEqual(acquisition_settings.enabled_channels, self._device.enabled_analog_channel_nums) + self.assertEqual( + acquisition_settings.vertical_ranges_in_mv[0], + self._device.analog_channels[channels_to_enable[0]].vertical_range_in_mv, + ) + self.assertEqual( + acquisition_settings.vertical_offsets_in_percent[0], + self._device.analog_channels[channels_to_enable[0]].vertical_offset_in_percent, + ) + self.assertEqual( + acquisition_settings.input_impedances[0], + self._device.analog_channels[channels_to_enable[0]].input_impedance, + ) + self.assertEqual( + acquisition_settings.vertical_ranges_in_mv[1], + self._device.analog_channels[channels_to_enable[1]].vertical_range_in_mv, + ) + self.assertEqual( + acquisition_settings.vertical_offsets_in_percent[1], + self._device.analog_channels[channels_to_enable[1]].vertical_offset_in_percent, + ) + self.assertEqual( + acquisition_settings.input_impedances[1], + self._device.analog_channels[channels_to_enable[1]].input_impedance, + ) + def test_count_channels(self) -> None: channels = self._device.analog_channels self.assertEqual(len(channels), self._expected_total_num_channels)