Skip to content

Commit

Permalink
Merge pull request #35 from KCL-BMEIS/35_unit_testing_on_hardware
Browse files Browse the repository at this point in the history
35 unit testing on hardware
  • Loading branch information
crnbaker authored Oct 13, 2023
2 parents a9c1d3a + 754d0e4 commit 61b2089
Show file tree
Hide file tree
Showing 12 changed files with 161 additions and 65 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@ acquisition_settings = AcquisitionSettings(
enabled_channels=[0, 1, 2, 3],
vertical_ranges_in_mv=[200, 200, 200, 200],
vertical_offsets_in_percent=[0, 0, 0, 0],
timestamping_enabled=True
timestamping_enabled=True,
batch_size=1
)

card.configure_trigger(trigger_settings)
Expand Down
43 changes: 0 additions & 43 deletions src/example_scripts/connect_to_star_hub.py

This file was deleted.

19 changes: 12 additions & 7 deletions src/example_scripts/continuous_multi_fifo_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@

def continuous_multi_fifo_example(
mock_mode: bool,
acquisition_duration_in_seconds: float,
time_to_keep_acquiring_for_in_seconds: float,
batch_size: int,
trigger_source: TriggerSource,
device_number: int,
ip_address: Optional[str] = None,
acquisition_length: int = 400,
single_acquisition_length_in_samples: int = 400,
) -> List[Measurement]:

if not mock_mode:
Expand All @@ -48,14 +49,15 @@ def continuous_multi_fifo_example(
# Acquisition settings
acquisition_settings = AcquisitionSettings(
acquisition_mode=AcquisitionMode.SPC_REC_FIFO_MULTI,
sample_rate_in_hz=40000000,
acquisition_length_in_samples=acquisition_length,
sample_rate_in_hz=5000,
acquisition_length_in_samples=single_acquisition_length_in_samples,
pre_trigger_length_in_samples=0,
timeout_in_ms=5000,
enabled_channels=[0],
vertical_ranges_in_mv=[200],
vertical_offsets_in_percent=[0],
timestamping_enabled=True,
batch_size=batch_size,
)

try:
Expand All @@ -69,7 +71,7 @@ def continuous_multi_fifo_example(

# Retrieve streamed waveform data until desired time has elapsed
measurements_list = []
while (monotonic() - start_time) < acquisition_duration_in_seconds:
while (monotonic() - start_time) < time_to_keep_acquiring_for_in_seconds:

measurements_list += [
Measurement(waveforms=frame, timestamp=card.get_timestamp()) for frame in card.get_waveforms()
Expand All @@ -95,10 +97,13 @@ def continuous_multi_fifo_example(

measurements = continuous_multi_fifo_example(
mock_mode=False,
acquisition_duration_in_seconds=0.5,
time_to_keep_acquiring_for_in_seconds=2, # continuous acquisition will stop after this many seconds (after
# waiting for the final batch to be acquired and transferred). Make sure you expect to receive (and finish
# transferring) at least 1 batch in this time! otherwise you will likely receive a timeout error
batch_size=5, # number of measurements to acquire before they are returned by get_waveforms()
trigger_source=TriggerSource.SPC_TMASK_EXT0,
device_number=1,
ip_address="169.254.45.181",
ip_address="169.254.13.35",
)

# Plot waveforms
Expand Down
9 changes: 6 additions & 3 deletions src/example_scripts/finite_multi_fifo_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
def finite_multi_fifo_example(
mock_mode: bool,
num_measurements: int,
batch_size: int,
trigger_source: TriggerSource,
device_number: int,
ip_address: Optional[str] = None,
Expand Down Expand Up @@ -54,7 +55,7 @@ def finite_multi_fifo_example(
vertical_ranges_in_mv=[200],
vertical_offsets_in_percent=[0],
timestamping_enabled=True,
batch_size=5,
batch_size=batch_size,
)

# Apply settings
Expand All @@ -72,12 +73,14 @@ def finite_multi_fifo_example(

from matplotlib.pyplot import plot, show, figure, title

# Only a few parameters are included as arguments here. See contents of the example function for other settings
measurements = finite_multi_fifo_example(
mock_mode=False,
num_measurements=5,
num_measurements=10, # number of waveforms to acquire from each enabled channel
batch_size=5, # number of measurements to acquire before they are returned by get_waveforms()
trigger_source=TriggerSource.SPC_TMASK_EXT0,
device_number=1,
ip_address="169.254.45.181",
ip_address="169.254.13.35",
)

# Plot waveforms
Expand Down
2 changes: 1 addition & 1 deletion src/example_scripts/standard_single_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def standard_single_mode_example(
from matplotlib.pyplot import plot, show, xlabel, tight_layout, ylabel

meas = standard_single_mode_example(
mock_mode=False, trigger_source=TriggerSource.SPC_TMASK_EXT0, device_number=1, ip_address="169.254.45.181"
mock_mode=False, trigger_source=TriggerSource.SPC_TMASK_EXT0, device_number=1, ip_address="169.254.13.35"
)

# Plot waveforms
Expand Down
100 changes: 100 additions & 0 deletions src/example_scripts/star_hub_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
from spectrumdevice.devices.mocks import MockSpectrumDigitiserCard, MockSpectrumDigitiserStarHub
from spectrumdevice.devices.digitiser import SpectrumDigitiserCard
from spectrumdevice.devices.digitiser import SpectrumDigitiserStarHub
from spectrumdevice.settings import (
ModelNumber,
TriggerSettings,
TriggerSource,
ExternalTriggerMode,
AcquisitionMode,
AcquisitionSettings,
)


def connect_to_star_hub_example(
mock_mode: bool, num_cards: int, master_card_index: int, ip_address: str
) -> SpectrumDigitiserStarHub:

if not mock_mode:
child_cards = []
for n in range(num_cards):
# Connect to each card in the hub.
child_cards.append(SpectrumDigitiserCard(device_number=n, ip_address=ip_address))
# Connect to the hub itself
return SpectrumDigitiserStarHub(device_number=0, child_cards=child_cards, master_card_index=master_card_index)
else:
mock_child_cards = []
for n in range(num_cards):
# Create a mock device for each card in the hub
mock_child_cards.append(
MockSpectrumDigitiserCard(
device_number=n,
model=ModelNumber.TYP_M2P5966_X4,
mock_source_frame_rate_hz=10.0, # Mock devices need to be provided with a mock source frame rate
num_modules=2, # (For real devices, this and num_channels_per_module are read from the hardware).
num_channels_per_module=4,
)
)
# Create a mock hub containing the above devices
return MockSpectrumDigitiserStarHub(
device_number=0, child_cards=mock_child_cards, master_card_index=master_card_index
)


if __name__ == "__main__":

from matplotlib.pyplot import figure, title, plot, show

num_measurements = 5
hub = connect_to_star_hub_example(mock_mode=False, num_cards=2, master_card_index=1, ip_address="169.254.13.35")

print(f"{hub} contains {len(hub.channels)} channels in total:")
for channel in hub.channels:
print(channel)

# Trigger settings
trigger_settings = TriggerSettings(
trigger_sources=[TriggerSource.SPC_TMASK_EXT0],
external_trigger_mode=ExternalTriggerMode.SPC_TM_POS,
external_trigger_level_in_mv=1000,
)

# Acquisition settings
acquisition_settings = AcquisitionSettings(
acquisition_mode=AcquisitionMode.SPC_REC_FIFO_MULTI,
sample_rate_in_hz=40000000,
acquisition_length_in_samples=400,
pre_trigger_length_in_samples=0,
timeout_in_ms=1000,
enabled_channels=[0, 8], # at least 1 channel from each child card must be enabled
vertical_ranges_in_mv=[200],
vertical_offsets_in_percent=[0],
timestamping_enabled=True,
batch_size=5,
)

# Apply settings
hub.configure_trigger(trigger_settings)
hub.configure_acquisition(acquisition_settings)

# Execute acquisition
measurements = hub.execute_finite_fifo_acquisition(num_measurements)

# Plot waveforms
for n, measurement in enumerate(measurements):
figure()
title(f"Measurement {n}")
for wfm in measurement.waveforms:
plot(wfm)

ts_format = "%Y-%m-%d %H:%M:%S.%f"
print(f"Completed {len(measurements)} measurements each containing {len(measurements[0].waveforms)} waveforms.")
print(f"Waveforms had the following shape: {measurements[0].waveforms[0].shape}")
print(f"and the following timestamps:")
for measurement in measurements:
print(measurement.timestamp.strftime(ts_format) if measurement.timestamp else "Timestamping disabled")

hub.reset()
hub.disconnect()

show()
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def configure_acquisition(self, settings: AcquisitionSettings) -> None:
if settings.batch_size > 1 and settings.acquisition_mode == AcquisitionMode.SPC_REC_STD_SINGLE:
raise ValueError("In standard single mode, only 1 acquisition can be downloaded at a time.")
self._acquisition_mode = settings.acquisition_mode
self._batch_size = settings.batch_size
self.set_batch_size(settings.batch_size)
self.set_acquisition_mode(settings.acquisition_mode)
self.set_sample_rate_in_hz(settings.sample_rate_in_hz)
self.set_acquisition_length_in_samples(settings.acquisition_length_in_samples)
Expand Down Expand Up @@ -101,14 +101,14 @@ def execute_finite_fifo_acquisition(self, num_measurements: int) -> List[Measure
timestamp attribute, which (if timestamping was enabled in acquisition settings) contains the time at
which the acquisition was triggered.
"""
if (num_measurements % self._batch_size) != 0:
if (num_measurements % self.batch_size) != 0:
raise ValueError(
"Number of measurements in a finite FIFO acquisition must be a multiple of the "
" batch size configured using AbstractSpectrumDigitiser.configure_acquisition()."
)
self.execute_continuous_fifo_acquisition()
measurements = []
for _ in range(num_measurements // self._batch_size):
for _ in range(num_measurements // self.batch_size):
measurements += [
Measurement(waveforms=frame, timestamp=self.get_timestamp()) for frame in self.get_waveforms()
]
Expand Down
8 changes: 8 additions & 0 deletions src/spectrumdevice/devices/digitiser/digitiser_card.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def __init__(self, device_number: int = 0, ip_address: Optional[str] = None):
raise SpectrumCardIsNotADigitiser(self.type)
self._acquisition_mode = self.acquisition_mode
self._timestamper: Optional[Timestamper] = None
self._batch_size = 1

def _init_channels(self) -> Sequence[SpectrumDigitiserChannelInterface]:
num_modules = self.read_spectrum_device_register(SPC_MIINST_MODULES)
Expand Down Expand Up @@ -249,6 +250,13 @@ def set_acquisition_mode(self, mode: AcquisitionMode) -> None:
mode (`AcquisitionMode`): The desired acquisition mode."""
self.write_to_spectrum_device_register(SPC_CARDMODE, mode.value)

@property
def batch_size(self) -> int:
return self._batch_size

def set_batch_size(self, batch_size: int) -> None:
self._batch_size = batch_size

def define_transfer_buffer(self, buffer: Optional[Sequence[TransferBuffer]] = None) -> None:
"""Create or provide a `TransferBuffer` object for receiving acquired samples from the device.
Expand Down
9 changes: 9 additions & 0 deletions src/spectrumdevice/devices/digitiser/digitiser_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,12 @@ def acquisition_mode(self) -> AcquisitionMode:
@abstractmethod
def set_acquisition_mode(self, mode: AcquisitionMode) -> None:
raise NotImplementedError()

@property
@abstractmethod
def batch_size(self) -> int:
raise NotImplementedError()

@abstractmethod
def set_batch_size(self, batch_size: int) -> None:
raise NotImplementedError()
13 changes: 12 additions & 1 deletion src/spectrumdevice/devices/digitiser/digitiser_star_hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def _get_waveforms(digitiser_card: SpectrumDigitiserCard) -> None:
thread.join()

waveform_sets_all_cards_ordered = []
for n in range(self._batch_size):
for n in range(self.batch_size):
waveforms_in_this_batch = []
for card in self._child_cards:
waveforms_in_this_batch += card_ids_and_waveform_sets[str(card)][n]
Expand Down Expand Up @@ -178,3 +178,14 @@ def set_acquisition_mode(self, mode: AcquisitionMode) -> None:
mode (`AcquisitionMode`): The desired acquisition mode."""
for d in self._child_cards:
cast(SpectrumDigitiserCard, d).set_acquisition_mode(mode)

@property
def batch_size(self) -> int:
batch_sizes = []
for d in self._child_cards:
batch_sizes.append(cast(SpectrumDigitiserCard, d).batch_size)
return check_settings_constant_across_devices(batch_sizes, __name__)

def set_batch_size(self, batch_size: int) -> None:
for d in self._child_cards:
cast(SpectrumDigitiserCard, d).set_batch_size(batch_size)
2 changes: 1 addition & 1 deletion src/tests/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class SpectrumTestMode(Enum):

# 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.
TEST_DEVICE_IP = "169.254.45.181"
TEST_DEVICE_IP = "169.254.13.35"
# Set the device number to connect to for real hardware tests. If using a star hub (e.g. netbox), this should be the
# STAR_HUB_MASTER_CARD_INDEX. If you only have a single, local (PCIe) card, set to 0.
TEST_DEVICE_NUMBER = 1
Expand Down
12 changes: 7 additions & 5 deletions src/tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import pytest
from numpy import array, concatenate

from example_scripts.connect_to_star_hub import star_hub_example
from example_scripts.star_hub_example import connect_to_star_hub_example
from example_scripts.continuous_averaging_fifo_mode import continuous_averaging_multi_fifo_example
from example_scripts.continuous_multi_fifo_mode import continuous_multi_fifo_example
from example_scripts.finite_multi_fifo_mode import finite_multi_fifo_example
Expand Down Expand Up @@ -57,6 +57,7 @@ def test_finite_multi_fifo_mode(self) -> None:
measurements = finite_multi_fifo_example(
mock_mode=self._single_card_mock_mode,
num_measurements=5,
batch_size=5,
trigger_source=INTEGRATION_TEST_TRIGGER_SOURCE,
device_number=TEST_DEVICE_NUMBER,
ip_address=TEST_DEVICE_IP,
Expand All @@ -68,11 +69,12 @@ def test_finite_multi_fifo_mode(self) -> None:
def test_continuous_multi_fifo_mode(self) -> None:
measurements = continuous_multi_fifo_example(
mock_mode=self._single_card_mock_mode,
acquisition_duration_in_seconds=0.5,
time_to_keep_acquiring_for_in_seconds=0.5,
batch_size=1,
trigger_source=INTEGRATION_TEST_TRIGGER_SOURCE,
device_number=TEST_DEVICE_NUMBER,
ip_address=TEST_DEVICE_IP,
acquisition_length=ACQUISITION_LENGTH,
single_acquisition_length_in_samples=ACQUISITION_LENGTH,
)
self._asserts_for_fifo_mode(measurements)

Expand Down Expand Up @@ -108,11 +110,11 @@ def setUp(self) -> None:
self._star_hub_mock_mode = STAR_HUB_TEST_MODE == SpectrumTestMode.MOCK_HARDWARE

def test_star_hub(self) -> None:
hub = star_hub_example(
hub = connect_to_star_hub_example(
mock_mode=self._star_hub_mock_mode,
num_cards=NUM_CARDS_IN_STAR_HUB,
master_card_index=STAR_HUB_MASTER_CARD_INDEX,
ip_address="169.254.45.181",
ip_address=TEST_DEVICE_IP,
)
self.assertEqual(len(hub.channels), NUM_CHANNELS_PER_MODULE * NUM_MODULES_PER_CARD * NUM_CARDS_IN_STAR_HUB)
self.assertEqual(len(hub._child_cards), NUM_CARDS_IN_STAR_HUB)
Expand Down

0 comments on commit 61b2089

Please sign in to comment.