def test_event(self): # ported from C++ test-event sequence = stadls.DigitalInit() builder, _ = sequence.generate() num_spikes = 1000 spike_pack_types = [ [1, halco.SpikePack1ToChipOnDLS, haldls.SpikePack1ToChip], [2, halco.SpikePack2ToChipOnDLS, haldls.SpikePack2ToChip], [3, halco.SpikePack3ToChipOnDLS, haldls.SpikePack3ToChip] ] to_fpga_spike_labels = [] # TODO: introspection would be nicer than hard-coding the types for spike_type_count, spike_type_coord, spike_type in spike_pack_types: for i in range(num_spikes): # TODO: random numbers would be nicer here labels = [haldls.SpikeLabel(i)] * spike_type_count spike = spike_type(labels) builder.write(spike_type_coord(), spike) builder.write(halco.TimerOnDLS(), haldls.Timer()) builder.block_until(halco.TimerOnDLS(), haldls.Timer.Value(10)) to_fpga_spike_labels.extend(labels) builder.write(halco.TimerOnDLS(), haldls.Timer()) builder.block_until(halco.TimerOnDLS(), haldls.Timer.Value(1000)) program = builder.done() with hxcomm.ManagedConnection() as conn: stadls.run(conn, program) spikes = program.spikes # assert 98 % of sent spikes are received again total_spikes_sent = sum(numpy.array(spike_pack_types)[:, 0]) \ * num_spikes self.assertGreater(len(spikes), total_spikes_sent * 0.98) spikes = program.spikes.to_numpy() self.assertGreater(spikes.shape[0], total_spikes_sent * 0.98) # count incorrectly received spikes (unknown label) incorrect_spikes = numpy.sum([ haldls.SpikeLabel(spike["label"]) not in to_fpga_spike_labels for spike in spikes ]) self.assertLess(incorrect_spikes, 100, "Too many random spikes were received.") self.assertEqual(spikes.ndim, 1, "Expected numpy-wrapped spikes to be 1D") dtype_tmp = numpy.dtype([('label', numpy.uint16), ('fpga_time', numpy.uint64), ('chip_time', numpy.uint64)]) self.assertEqual(spikes.dtype, dtype_tmp, "Expect spikes.dtype to be {}".format(str(dtype_tmp))) self.assertGreater( spikes.size, total_spikes_sent * 0.98, "Expected at least {} received spikes".format(total_spikes_sent * 0.98))
def test_board_led_chain(cls): all_leds = list(iter_all(halco.LEDOnBoard)) builder = stadls.PlaybackProgramBuilder() # reset chip builder.write(halco.ResetChipOnDLS(), haldls.ResetChip(True)) builder.write(halco.TimerOnDLS(), haldls.Timer()) builder.block_until(halco.TimerOnDLS(), 10) builder.write(halco.ResetChipOnDLS(), haldls.ResetChip(False)) # write shiftreg container shiftreg = haldls.ShiftRegister() builder.write(halco.ShiftRegisterOnBoard(), shiftreg) for led in all_leds + list(reversed(all_leds)): builder.write(halco.TimerOnDLS(), haldls.Timer()) shiftreg.set_enable_led(led, True) builder.write(halco.ShiftRegisterOnBoard(), shiftreg) builder.block_until(halco.TimerOnDLS(), int(fisch.fpga_clock_cycles_per_us * 1e6 / 8)) shiftreg.set_enable_led(led, False) builder.write(halco.ShiftRegisterOnBoard(), shiftreg) # pop playback program program = builder.done() # execute playback program with hxcomm.ManagedConnection() as conn: stadls.run(conn, program)
def test_pb_program_builder_dumper(self): builder = stadls.PlaybackProgramBuilderDumper() # reset chip builder.write(halco.ResetChipOnDLS(), haldls.ResetChip(True)) builder.write(halco.TimerOnDLS(), haldls.Timer()) builder.block_until(halco.TimerOnDLS(), 10) tmp = (halco.ResetChipOnDLS(), haldls.ResetChip(False)) builder.write(*tmp) # write shiftreg container shiftreg = haldls.ShiftRegister() builder.write(halco.ShiftRegisterOnBoard(), shiftreg) all_leds = list(iter_all(halco.LEDOnBoard)) for led in all_leds + list(reversed(all_leds)): builder.write(halco.TimerOnDLS(), haldls.Timer()) shiftreg.set_enable_led(led, True) builder.write(halco.ShiftRegisterOnBoard(), shiftreg) builder.block_until(halco.TimerOnDLS(), int(fisch.fpga_clock_cycles_per_us * 1e6 / 8)) shiftreg.set_enable_led(led, False) builder.write(halco.ShiftRegisterOnBoard(), shiftreg) builder.block_until(halco.BarrierOnFPGA(), haldls.Barrier.omnibus) # pop playback program builder_copy = stadls.PlaybackProgramBuilderDumper() builder_copy.copy_back(builder) program = builder.done() self.assertEqual(len(program), 5 + len(all_leds) * 2 * 3 + 2, "Wrong number of coordinate/container pairs") self.assertNotEqual(program.tolist()[0], tmp) self.assertNotEqual(program.tolist()[1], tmp) self.assertNotEqual(program.tolist()[2], tmp) self.assertEqual(program.tolist()[3], tmp) self.assertNotEqual(program.tolist()[4], tmp) dump = pickle.dumps(program.tolist()) restored_cocos = pickle.loads(dump) self.assertEqual(program.tolist(), restored_cocos) builder = stadls.PlaybackProgramBuilder() for cor, con in restored_cocos: if isinstance(cor, (halco.TimerOnDLS, halco.BarrierOnFPGA)) and \ isinstance(con, (haldls.Timer.Value, haldls.Barrier)): builder.block_until(cor, con) else: builder.write(cor, con) real_program = builder.done() self.assertEqual(real_program, stadls.convert_to_builder(program).done()) self.assertEqual(real_program, stadls.convert_to_builder(builder_copy).done())
def test_reinit_stack_entry(self): builder, _ = stadls.DigitalInit().generate() builder.block_until(halco.TimerOnDLS(), haldls.Timer.Value(100)) init = builder.done() builder = stadls.PlaybackProgramBuilder() builder.block_until(halco.TimerOnDLS(), haldls.Timer.Value(400)) program = builder.done() with hxcomm.ManagedConnection() as conn: reinit = stadls.ReinitStackEntry(conn) reinit.set(init, enforce=True) stadls.run(conn, program)
def test_madc_sample_rate(self): """ Observe the MADC sampling rate in dependency of the MADC configuration, then compare it to a calculated sample rate based on the configuration. """ # define (arbitrary) test values for the MADC config # defaults are tested via Nones madc_clock_scale_values = [None, 10, 50, 100, 200, 4095] sample_duration_adjusts = [0, None, 7] enable_madc_clock_scalings = [True, False] # sweep over configuration space and sample dumpy data for madc_clock_scale_value in madc_clock_scale_values: for sample_duration_adjust in sample_duration_adjusts: for enable_madc_clock_scaling in enable_madc_clock_scalings: builder, _ = stadls.DigitalInit().generate() # configure MADC madc_config = haldls.MADCConfig() madc_config.number_of_samples = 20000 madc_config.enable_dummy_data = True madc_config.enable_madc_clock_scaling = \ enable_madc_clock_scaling if sample_duration_adjust is not None: madc_config.sample_duration_adjust = \ sample_duration_adjust if madc_clock_scale_value is not None: madc_config.madc_clock_scale_value = \ madc_clock_scale_value builder.write(halco.MADCConfigOnDLS(), madc_config) # calculate expected sample rate from MADC config (Hz) adpll = haldls.ADPLL() output = adpll.Output(adpll.Output.dco) # dco madc_base_frequ = adpll.calculate_output_frequency(output) calc_rate = madc_config.calculate_sample_rate( madc_base_frequ) / 1e6 # MHz # wake up MADC madc_control = haldls.MADCControl() madc_control.enable_power_down_after_sampling = False madc_control.start_recording = False madc_control.wake_up = True builder.write(halco.MADCControlOnDLS(), madc_control) # initial wait, systime sync initial_wait = 100 # us builder.write(halco.TimerOnDLS(), haldls.Timer()) builder.write(halco.SystimeSyncOnFPGA(), haldls.SystimeSync()) builder.block_until( halco.TimerOnDLS(), haldls.Timer.Value( initial_wait * int(haldls.Timer.Value.fpga_clock_cycles_per_us))) # trigger MADC sampling, power MADC down once done madc_control.wake_up = False madc_control.start_recording = True madc_control.enable_power_down_after_sampling = True builder.write(halco.MADCControlOnDLS(), madc_control) # wait for samples and additional 3 ms sampling_time = float(madc_config.number_of_samples) / \ calc_rate + 3000 # us builder.block_until( halco.TimerOnDLS(), haldls.Timer.Value( (initial_wait + int(sampling_time)) * int(haldls.Timer.Value.fpga_clock_cycles_per_us))) # run program program = builder.done() with hxcomm.ManagedConnection() as conn: stadls.run(conn, program) # inspect MADC samples samples = program.madc_samples.to_numpy() # drop incorrectly received samples (value 0, issue 3545) # then sort by chip time samples = samples[samples["value"] != 0] samples = numpy.sort(samples, order=["chip_time", "fpga_time"]) # convert to SI units (us) sample_times = samples["chip_time"] / \ (float(haldls.Timer.Value.fpga_clock_cycles_per_us)) # get time between two samples time_between_samples = numpy.diff(sample_times) # calculate average sample rate from measured samples (MHz) average_rate = 1 / numpy.mean(time_between_samples) # compare measurement with prediction and check that the # error is less than 1% self.assertAlmostEqual( average_rate, calc_rate, delta=calc_rate * 0.01, msg="Recorded rate deviates by more than 1% from " "the calculated one.")
def test_madc_samples(self): """ Observe an MADC test pattern and assert it is accessible through the madc_samples.to_numpy() interface. Samples are recorded continuously, in order to test more samples than configurable in the MADC config. """ builder, _ = stadls.DigitalInit().generate() madc_config = haldls.MADCConfig() madc_config.enable_dummy_data = True builder.write(halco.MADCConfigOnDLS(), madc_config) # wake up MADC madc_control = haldls.MADCControl() madc_control.enable_power_down_after_sampling = False madc_control.start_recording = False madc_control.wake_up = True builder.write(halco.MADCControlOnDLS(), madc_control) # initial wait, systime sync initial_wait = 100 # us builder.write(halco.TimerOnDLS(), haldls.Timer()) builder.write(halco.SystimeSyncOnFPGA(), haldls.SystimeSync()) builder.block_until( halco.TimerOnDLS(), haldls.Timer.Value( initial_wait * int(haldls.Timer.Value.fpga_clock_cycles_per_us))) # trigger MADC sampling, power MADC down once done madc_control.wake_up = False madc_control.start_recording = True madc_control.enable_power_down_after_sampling = False madc_control.enable_continuous_sampling = True builder.write(halco.MADCControlOnDLS(), madc_control) # wait for samples sampling_time = 40000 # us builder.block_until( halco.TimerOnDLS(), haldls.Timer.Value( (initial_wait + sampling_time) * int(haldls.Timer.Value.fpga_clock_cycles_per_us))) # turn off MADC madc_control.start_recording = False madc_control.stop_recording = True madc_control.enable_power_down_after_sampling = True builder.write(halco.MADCControlOnDLS(), madc_control) # run program program = builder.done() with hxcomm.ManagedConnection() as conn: stadls.run(conn, program) # inspect MADC samples samples = program.madc_samples.to_numpy() # drop incorrectly received samples (value 0, issue 3545) # then sort by chip time samples = samples[samples["value"] != 0] samples = numpy.sort(samples, order=["chip_time", "fpga_time"]) # assert number of received samples is as expected, # assuming a sampling rate of 30 MHz sampling_rate = 30 # MHz expected_number_of_samples = \ sampling_time * sampling_rate # us * MHz cancels self.assertEqual(samples.ndim, 1) self.assertGreater(len(samples), int(expected_number_of_samples * 0.95), "Too few MADC samples recorded.") expected_dtype = numpy.dtype([('value', numpy.uint64), ('fpga_time', numpy.uint64), ('chip_time', numpy.uint64)]) self.assertEqual( samples.dtype, expected_dtype, "Expected samples.dtype to be {}".format(str(expected_dtype))) # assert sawtooth test pattern is visible in samples diff = numpy.diff(samples["value"].astype(int)) self.assertAlmostEqual(numpy.mean(diff[diff > 0]), 1, places=1, msg="MADC sample values don't increase by 1" + "on average in sawtooth pattern.") self.assertLess( numpy.mean(diff[diff < 0]), -1000, "MADC samples don't show proper falling edge in sawtooth pattern.")