diff --git a/pulse_lib/keysight/M3202A_uploader.py b/pulse_lib/keysight/M3202A_uploader.py index af26465f97cb4956e87d5427430b4969d0597060..eed7020fbefba8b6f517a5abd3774d6eb4d9c3e0 100644 --- a/pulse_lib/keysight/M3202A_uploader.py +++ b/pulse_lib/keysight/M3202A_uploader.py @@ -78,10 +78,19 @@ class M3202A_Uploader: awg = list(self.AWGs.values())[0] return awg.convert_prescaler_to_sample_rate(awg.convert_sample_rate_to_prescaler(sample_rate)) - def get_num_samples(self, acquisition_channel, t_measure, sample_rate): + def actual_acquisition_points(self, acquisition_channel, t_measure, sample_rate): + ''' + Returns the actual number of points and interval of an acquisition. + ''' dig_ch = self.digitizer_channels[acquisition_channel] digitizer = self.digitizers[dig_ch.module_name] - return digitizer.get_samples_per_measurement(t_measure, sample_rate) + if hasattr(digitizer, 'actual_acquisition_points'): + n_samples, interval = digitizer.actual_acquisition_points(dig_ch, t_measure, sample_rate) + else: + # use old function and assume the digitizer is NOT in MODES.NORMAL + n_samples = digitizer.get_samples_per_measurement(t_measure, sample_rate) + interval = int(max(1, round(100e6 / sample_rate))) * 10 + return n_samples, interval def create_job(self, sequence, index, seq_id, n_rep, sample_rate, neutralize=True, alignment=None): # TODO @@@ implement alignment diff --git a/pulse_lib/keysight/qs_uploader.py b/pulse_lib/keysight/qs_uploader.py index e94c311699e2fce9459f3ae3a65895c358b33553..b0369d5ccf1b2095caea7ee5ca5f45604e6eb960 100644 --- a/pulse_lib/keysight/qs_uploader.py +++ b/pulse_lib/keysight/qs_uploader.py @@ -75,7 +75,7 @@ class QsUploader: awg = list(self.AWGs.values())[0] return awg.convert_prescaler_to_sample_rate(awg.convert_sample_rate_to_prescaler(sample_rate)) - def get_num_samples(self, acquisition_channel, t_measure, sample_rate): + def actual_acquisition_points(self, acquisition_channel, t_measure, sample_rate): raise NotImplementedError() def get_roundtrip_latency(self): diff --git a/pulse_lib/qblox/pulsar_uploader.py b/pulse_lib/qblox/pulsar_uploader.py index 503bfa6f61ec2eacc5acf268db18d13456b47539..63113d5004560fb2c328f5e138faf53f726691aa 100644 --- a/pulse_lib/qblox/pulsar_uploader.py +++ b/pulse_lib/qblox/pulsar_uploader.py @@ -151,13 +151,8 @@ class PulsarUploader: """ return 1e9 - def get_num_samples(self, acquisition_channel, t_measure, sample_rate): - # todo: remove code duplication with add_acquisition_channel - trigger_period = PulsarConfig.align(1e9/sample_rate) - n_samples = max(1, iround(t_measure / trigger_period)) - # @@@ n_repeat not taken into account - # @@@ always minimum 1 sample: UploadAggregator raises an exception for 0 cycles. - return n_samples + def actual_acquisition_points(self, acquisition_channel, t_measure, sample_rate): + return _actual_acquisition_points(t_measure, sample_rate) def create_job(self, sequence, index, seq_id, n_rep, sample_rate, neutralize=True, alignment=None): @@ -449,6 +444,13 @@ class SegmentRenderInfo: return self.t_start + self.npt +def _actual_acquisition_points(t_measure, sample_rate): + trigger_period = PulsarConfig.align(1e9/sample_rate) + t_measure = PulsarConfig.align(t_measure) + n_samples = t_measure // trigger_period + return n_samples, trigger_period + + class UploadAggregator: verbose = False @@ -750,11 +752,6 @@ class UploadAggregator: acq_conf = job.acquisition_conf - if acq_conf.sample_rate is not None: - trigger_period = PulsarConfig.align(1e9/acq_conf.sample_rate) - else: - trigger_period = None - if acq_conf.average_repetitions or not job.n_rep: n_rep = 1 else: @@ -790,8 +787,8 @@ class UploadAggregator: PulsarConfig.align(acquisition.interval)) if acq_conf.sample_rate is not None: logging.info(f'Acquisition sample_rate is ignored when n_repeat is set') - elif trigger_period: - n_cycles = iround(t_measure / trigger_period) + elif acq_conf.sample_rate is not None: + n_cycles, trigger_period = _actual_acquisition_points(t_measure, acq_conf.sample_rate) if n_cycles < 1: raise Exception(f'{channel_name} acquisition t_measure ({t_measure}) < 1/sample_rate ({trigger_period})') seq.repeated_acquire(t, trigger_period, n_cycles, trigger_period) diff --git a/pulse_lib/sequencer.py b/pulse_lib/sequencer.py index 5030d94b97507ca620f1afc4351b455a2e0f2694..a49ae532d31a4440d949396dacec3893da248961 100644 --- a/pulse_lib/sequencer.py +++ b/pulse_lib/sequencer.py @@ -177,7 +177,6 @@ class sequencer(): effective_rate = self.uploader.get_effective_sample_rate(seg_container.sample_rate) msg = f"effective sampling rate for {seg_container.name} is set to {si_format(effective_rate, precision=1)}Sa/s" logging.info(msg) - print("Info : " + msg) # update dimensionality of all sequence objects logging.debug('Enter pre-rendering') @@ -364,9 +363,15 @@ class sequencer(): t_measure = m.t_measure else: raise Exception(f't_measure must be number and not a {type(m.t_measure)} for time traces') - m.n_samples = self.uploader.get_num_samples( - m.acquisition_channel, t_measure, sample_rate) # @@@ implement QS, Tektronix - m.interval = round(1e9/sample_rate) + # @@@ implement QS, Tektronix + if hasattr(self.uploader, 'actual_acquisition_points'): + m.n_samples, m.interval = self.uploader.actual_acquisition_points(m.acquisition_channel, + t_measure, sample_rate) + else: + print(f'WARNING {type(self.uploader)} is missing method actual_acquisition_points(); using old computation') + m.n_samples = self.uploader.get_num_samples( + m.acquisition_channel, t_measure, sample_rate) + m.interval = round(1e9/sample_rate) else: m.n_samples = 1