diff --git a/pulse_lib/base_pulse.py b/pulse_lib/base_pulse.py index 633309a72046bea5f5d57075f501b3758bdef5b7..47c2e1e0d84469c2e15c8f903857548fa9b3d68e 100644 --- a/pulse_lib/base_pulse.py +++ b/pulse_lib/base_pulse.py @@ -461,7 +461,7 @@ class pulselib: else: raise Exception(f'Unknown backend: {self._backend}') - def mk_segment(self, name=None, sample_rate=None): + def mk_segment(self, name=None, sample_rate=None, hres=False): ''' generate a new segment. Returns: @@ -470,7 +470,7 @@ class pulselib: return segment_container(self.awg_channels.keys(), self.marker_channels.keys(), self._virtual_matrices, self.IQ_channels.values(), self.digitizer_channels.values(), - name=name, sample_rate=sample_rate) + name=name, sample_rate=sample_rate, hres=hres) def mk_sequence(self,seq): ''' diff --git a/pulse_lib/segments/data_classes/data_pulse.py b/pulse_lib/segments/data_classes/data_pulse.py index a177fcf44b7ac5da954ba0d53acd213b09192337..5ca7b83b01a3853fb28d314a0ad5b4ce98dc91da 100644 --- a/pulse_lib/segments/data_classes/data_pulse.py +++ b/pulse_lib/segments/data_classes/data_pulse.py @@ -160,7 +160,7 @@ class pulse_data(parent_data): """ class defining base (utility) operations for baseband and microwave pulses. """ - def __init__(self): + def __init__(self, hres=False): super().__init__() self.pulse_deltas = list() self.MW_pulse_data = list() @@ -169,8 +169,10 @@ class pulse_data(parent_data): self.start_time = 0 self._end_time = 0 + self._hres = hres self._consolidated = False self._preprocessed = False + self._preprocessed_sample_rate = None self._phase_shifts_consolidated = False def add_delta(self, delta): @@ -331,7 +333,8 @@ class pulse_data(parent_data): operators for the data object. ''' def __copy__(self): - # NOTE: copy is called in pulse_data_all, before adding virtual channels. + # NOTE: Copy is called in pulse_data_all, before adding virtual channels. + # It is also called when a dimension is added in looping. self._consolidate() my_copy = pulse_data() my_copy.pulse_deltas = copy.deepcopy(self.pulse_deltas) @@ -340,6 +343,7 @@ class pulse_data(parent_data): my_copy.custom_pulse_data = copy.deepcopy(self.custom_pulse_data) my_copy.start_time = copy.copy(self.start_time) my_copy._end_time = self._end_time + my_copy._hres = self._hres my_copy._consolidated = self._consolidated my_copy._phase_shifts_consolidated = self._phase_shifts_consolidated @@ -351,6 +355,7 @@ class pulse_data(parent_data): ''' new_data = pulse_data() new_data.start_time = copy.copy(self.start_time) + new_data._hres = self._hres if isinstance(other, pulse_data): new_data.pulse_deltas = self.pulse_deltas + other.pulse_deltas @@ -424,6 +429,7 @@ class pulse_data(parent_data): new_data.phase_shifts = copy.copy(self.phase_shifts) new_data._end_time = self._end_time new_data.start_time = self.start_time + new_data._hres = self._hres new_data._consolidated = self._consolidated new_data._phase_shifts_consolidated = self._phase_shifts_consolidated else: @@ -458,9 +464,9 @@ class pulse_data(parent_data): self._consolidated = True self._preprocessed = False - def _pre_process(self): + def _pre_process(self, sample_rate=None): self._consolidate() - if not self._preprocessed: + if not self._preprocessed or self._preprocessed_sample_rate != sample_rate: n = len(self.pulse_deltas) if n == 0: times = np.zeros(0) @@ -468,6 +474,7 @@ class pulse_data(parent_data): amplitudes = np.zeros(0) amplitudes_end = np.zeros(0) ramps = np.zeros(0) + samples = np.zeros(0) else: times = np.zeros(n) intervals = np.zeros(n) @@ -475,10 +482,25 @@ class pulse_data(parent_data): ramps = np.zeros(n) amplitudes = np.zeros(n) amplitudes_end = np.zeros(n) - for i,delta in enumerate(self.pulse_deltas): - times[i] = delta.time - steps[i] = delta.step - ramps[i] = delta.ramp + samples = np.zeros(n) + if self._hres and sample_rate is not None: + t_sample = 1e9/sample_rate + for i,delta in enumerate(self.pulse_deltas): + if delta.time != np.inf: + t = int(delta.time/t_sample)*t_sample + dt = (delta.time - t) + else: + t = np.inf + dt = 0.0 + times[i] = t + ramps[i] = delta.ramp + steps[i] = delta.step - dt*delta.ramp + samples[i] = -dt*delta.step + dt*delta.ramp # - dt*(t_sample-dt)*delta.ramp + else: + for i,delta in enumerate(self.pulse_deltas): + times[i] = delta.time + steps[i] = delta.step + ramps[i] = delta.ramp if times[-1] == np.inf: times[-1] = self._end_time intervals[:-1] = times[1:] - times[:-1] @@ -491,8 +513,10 @@ class pulse_data(parent_data): self._intervals = intervals self._amplitudes = amplitudes self._amplitudes_end = amplitudes_end + self._samples = samples self._ramps = ramps self._preprocessed = True + self._preprocessed_sample_rate = sample_rate def integrate_waveform(self, sample_rate): ''' @@ -502,7 +526,7 @@ class pulse_data(parent_data): Returns: integrate (double) : the integrated value of the waveform (unit is mV/sec). ''' - self._pre_process() + self._pre_process(sample_rate) integrated_value = 0 @@ -556,7 +580,7 @@ class pulse_data(parent_data): ''' make a full rendering of the waveform at a predetermined sample rate. ''' - self._pre_process() + self._pre_process(sample_rate) # express in Gs/s sample_rate = sample_rate*1e-9 @@ -579,6 +603,10 @@ class pulse_data(parent_data): else: wvf[pt0:pt1] = self._amplitudes[i] + for i in range(len(t_pt)): + pt0 = t_pt[i] + wvf[pt0] += self._samples[i] + # render MW pulses. # create list with phase shifts per ref_channel phase_shifts_channels = {} diff --git a/pulse_lib/segments/segment_container.py b/pulse_lib/segments/segment_container.py index b2d3302571be961d318dc13f6491bfb81e7e3717..56ba7a06e9e5f8fb10eff966fcda97efc652ca50 100644 --- a/pulse_lib/segments/segment_container.py +++ b/pulse_lib/segments/segment_container.py @@ -30,7 +30,7 @@ class segment_container(): ''' def __init__(self, channel_names, markers=[], virtual_gate_matrices=None, IQ_channels_objs=[], digitizer_channels = [], - name=None, sample_rate=None): + name=None, sample_rate=None, hres=False): """ initialize a container for segments. Args: @@ -58,7 +58,7 @@ class segment_container(): # define real channels (+ markers) for name in channel_names: - segment = segment_pulse(name, self._software_markers) + segment = segment_pulse(name, self._software_markers, hres=hres) setattr(self, name, segment) self.channels[name] = segment for name in markers: diff --git a/pulse_lib/segments/segment_pulse.py b/pulse_lib/segments/segment_pulse.py index 117db0a795ae50fb6919fdf5abac1104d6837f66..49e2fdab55f16d46c2053013b3f31bca32483a0d 100644 --- a/pulse_lib/segments/segment_pulse.py +++ b/pulse_lib/segments/segment_pulse.py @@ -23,14 +23,15 @@ class segment_pulse(segment_base): ''' Class defining single segments for one sequence. ''' - def __init__(self, name, HVI_variable_data = None,segment_type = 'render'): + def __init__(self, name, HVI_variable_data=None, + segment_type='render', hres=False): ''' Args: name (str): name of the segment usually the channel name HVI_variable_data (segment_HVI_variables) : segment used to keep variables that can be used in HVI. segment_type (str) : type of the segment (e.g. 'render' --> to be rendered, 'virtual'--> no not render.) ''' - super().__init__(name, pulse_data(), HVI_variable_data,segment_type) + super().__init__(name, pulse_data(hres=hres), HVI_variable_data, segment_type) @loop_controller def add_block(self,start,stop, amplitude): diff --git a/pulse_lib/tests/acquire/__init__.py b/pulse_lib/tests/acquire/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/pulse_lib/tests/baseband/__init__.py b/pulse_lib/tests/baseband/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/pulse_lib/tests/baseband/test_hres.py b/pulse_lib/tests/baseband/test_hres.py new file mode 100644 index 0000000000000000000000000000000000000000..0d492dd37732753619b7a32529d81b3fe5e7ccab --- /dev/null +++ b/pulse_lib/tests/baseband/test_hres.py @@ -0,0 +1,103 @@ + +from pulse_lib.tests.configurations.test_configuration import context +import pulse_lib.segments.utility.looping as lp + +#%% +def test1(): + pulse = context.init_pulselib(n_gates=2) + + dt = lp.linspace(0.25, 0.75, 3, name='dt', axis=0) + + s = pulse.mk_segment(hres=True) + + for t in dt: + s.wait(15) + s.P1.add_ramp_ss(4, 8, 0, 80) + s.P1.add_block(8, 10, 80) + s.P1.add_ramp_ss(10, 14, 80, 0) + s.P2.add_ramp_ss(4-t, 8-t, 0, 80) + s.P2.add_block(8-t, 10+t, 80) + s.P2.add_ramp_ss(10+t, 14+t, 80, 0) + s.reset_time() + + sequence = pulse.mk_sequence([s]) + sequence.n_rep = None + context.add_hw_schedule(sequence) + + context.plot_awgs(sequence, ylim=(-0.0,0.100), xlim=(0, 50)) + +# return context.run('hres1', sequence) + +def test2(): + pulse = context.init_pulselib(n_gates=2) + + dt = lp.linspace(0.25, 0.75, 3, name='dt', axis=0) + + s = pulse.mk_segment(hres=True) + t_ramp = 3 + + for t in dt: + s.P1.wait(4) + s.P1.reset_time() + s.P1.add_ramp_ss(0, t_ramp, 0, 80) + s.P1.reset_time() + s.P1.add_block(0, 8, 80) + s.P1.reset_time() + s.P1.add_ramp_ss(0, t_ramp, 80, 0) + s.P1.wait(4) + + s.P2.wait(4+t) + s.P2.reset_time() + s.P2.add_ramp_ss(0, t_ramp, 0, 80) + s.P2.reset_time() + s.P2.add_block(0, 8, 80) + s.P2.reset_time() + s.P2.add_ramp_ss(0, t_ramp, 80, 0) + + s.reset_time() + + sequence = pulse.mk_sequence([s]) + sequence.n_rep = None + context.add_hw_schedule(sequence) + + context.plot_awgs(sequence, ylim=(-0.0,0.100), xlim=(0, 70)) + +# return context.run('hres1', sequence) + +def test3(): + pulse = context.init_pulselib(n_gates=3) + + dt = lp.linspace(0, 1.0, 6, name='dt', axis=0) + + s = pulse.mk_segment(hres=True) + + s.wait(10) + s.P1.add_block(4, 8, 80) + s.P2.add_block(4+dt, 8+dt, 80) + s.P3.add_block(4-dt, 8-dt, 80) + s.reset_time() + s.wait(15) + s.P1.add_ramp_ss(4, 8, 0, 80) + s.P1.add_block(8, 10, 80) + s.P1.add_ramp_ss(10, 14, 80, 0) + s.P2.add_ramp_ss(4-dt, 8-dt, 0, 80) + s.P2.add_block(8-dt, 10+dt, 80) + s.P2.add_ramp_ss(10+dt, 14+dt, 80, 0) + + sequence = pulse.mk_sequence([s]) + sequence.n_rep = None + context.add_hw_schedule(sequence) + +# sequence.dt(0.2) +# context.plot_awgs(sequence, ylim=(-0.100,0.100), xlim=(0, 26)) + for t in sequence.dt.values: + sequence.dt(t) + context.plot_awgs(sequence, ylim=(-0.100,0.100)) + +# return context.run('hres2', sequence) + +#%% +if __name__ == '__main__': + ds1 = test1() + ds2 = test2() + ds3 = test3() diff --git a/pulse_lib/tests/configurations/configurations.yaml b/pulse_lib/tests/configurations/configurations.yaml index 71552a3650441692f7438704a1049382f8529756..a1edb5f329f249ea6a9849e2d46888b953178849 100644 --- a/pulse_lib/tests/configurations/configurations.yaml +++ b/pulse_lib/tests/configurations/configurations.yaml @@ -1,4 +1,4 @@ -default: QbloxMocked +default: KeysightMocked KeysightMocked: station: keysight_mocked.yaml