def get_metadata(self, name): metadata = {} self._pre_process() # TODO: add custom pulses j = 0 bb_d = {} for i in range(len(self._times) - 1): start = self._times[i] stop = self._times[i + 1] v_start = self._amplitudes[i] v_stop = self._amplitudes_end[i + 1] if stop == np.inf: stop = self._end_time if stop - start < 1 or (v_start == 0 and v_stop == 0): continue bb_d[f'p{j}'] = { 'start': start, 'stop': stop, 'v_start': v_start, 'v_stop': v_stop } j += 1 if bb_d: metadata[name + '_baseband'] = bb_d pulsedata = self.MW_pulse_data all_pulse = {} for (i, pulse) in enumerate(pulsedata): phase_shift = 0 for ps in self.phase_shifts: if ps.time <= pulse.start: phase_shift += ps.phase_shift pd = {} pd['start'] = pulse.start pd['stop'] = pulse.stop pd['amplitude'] = pulse.amplitude pd['frequency'] = pulse.frequency pd['start_phase'] = pulse.start_phase + phase_shift envelope = pulse.envelope if envelope is None: envelope = envelope_generator() pd['AM_envelope'] = repr(envelope.AM_envelope_function) pd['PM_envelope'] = repr(envelope.PM_envelope_function) all_pulse[('p%i' % i)] = pd if all_pulse: metadata[name + '_pulses'] = all_pulse return metadata
def add_chirp(self, t0, t1, f0, f1, amp): ''' Add chirp to the segment. Args: t0(float) : start time in ns t1(float) : stop tiume in ns f0(float) : start frequency f1 (float) : stop frequency amp (float) : amplitude of the pulse. ''' PM = make_chirp(f0, f1, t0, t1) MW_data = IQ_data_single(t0 + self.data_tmp.start_time, t1 + self.data_tmp.start_time, amp, f0, 0, envelope_generator(None, PM)) self.data_tmp.add_MW_data(MW_data) return self.data_tmp
def add_MW_pulse(self, t0, t1, amp, freq, phase=0, AM=None, PM=None): ''' Make a sine pulse (generic constructor) Args: t0(float) : start time in ns t1(float) : stop tiume in ns amp (float) : amplitude of the pulse. freq(float) : frequency phase (float) : phase of the microwave. AM ('str/tuple/function') : function describing an amplitude modulation (see examples in pulse_lib.segments.data_classes.data_IQ) PM ('str/tuple/function') : function describing an phase modulation (see examples in pulse_lib.segments.data_classes.data_IQ) ''' MW_data = IQ_data_single(t0 + self.data_tmp.start_time, t1 + self.data_tmp.start_time, amp, freq, phase + self.data_tmp.global_phase, envelope_generator(AM, PM)) self.data_tmp.add_MW_data(MW_data) return self.data_tmp
def render_MW_and_custom(self, sample_rate, ref_channel_states): ''' Render MW pulses and custom data in 'rendered_elements'. ''' elements = [] self._pre_process() # express in Gs/s sample_rate = sample_rate * 1e-9 # render MW pulses. # create list with phase shifts per ref_channel phase_shifts_channels = {} for ps in self.phase_shifts: ps_ch = phase_shifts_channels.setdefault(ps.channel_name, []) ps_ch.append(ps) for IQ_data_single_object in self.MW_pulse_data: # start stop time of MW pulse start_pulse = IQ_data_single_object.start stop_pulse = IQ_data_single_object.stop # max amp, freq and phase. amp = IQ_data_single_object.amplitude freq = IQ_data_single_object.frequency phase = IQ_data_single_object.start_phase if ref_channel_states and IQ_data_single_object.ref_channel in ref_channel_states.start_phase: ref_start_time = ref_channel_states.start_time ref_start_phase = ref_channel_states.start_phase[ IQ_data_single_object.ref_channel] phase_shift = 0 if IQ_data_single_object.ref_channel in phase_shifts_channels: for ps in phase_shifts_channels[ IQ_data_single_object.ref_channel]: if ps.time <= start_pulse: phase_shift += ps.phase_shift else: ref_start_time = 0 ref_start_phase = 0 phase_shift = 0 # envelope data of the pulse if IQ_data_single_object.envelope is None: IQ_data_single_object.envelope = envelope_generator() amp_envelope = IQ_data_single_object.envelope.get_AM_envelope( (stop_pulse - start_pulse), sample_rate) phase_envelope = IQ_data_single_object.envelope.get_PM_envelope( (stop_pulse - start_pulse), sample_rate) #self.baseband_pulse_data[-1,0] convert to point numbers n_pt = int((stop_pulse - start_pulse) * sample_rate) if isinstance( amp_envelope, float) else len(amp_envelope) start_pt = iround(start_pulse * sample_rate) stop_pt = start_pt + n_pt # add the sin pulse total_phase = phase_shift + phase + phase_envelope + ref_start_phase t = start_pt + ref_start_time / sample_rate + np.arange(n_pt) wvf = amp * amp_envelope * np.sin(2 * np.pi * freq / sample_rate * 1e-9 * t + total_phase) elements.append(rendered_element(start_pt, stop_pt, wvf)) for custom_pulse in self.custom_pulse_data: wvf = self._render_custom_pulse(custom_pulse, sample_rate * 1e9) start_pt = iround(custom_pulse.start * sample_rate) stop_pt = start_pt + len(wvf) elements.append(rendered_element(start_pt, stop_pt, wvf)) return self._merge_elements(elements)
def _render(self, sample_rate, ref_channel_states): ''' make a full rendering of the waveform at a predetermined sample rate. ''' self._pre_process() # express in Gs/s sample_rate = sample_rate * 1e-9 t_tot = self.total_time # get number of points that need to be rendered t_tot_pt = iround(t_tot * sample_rate) + 1 wvf = np.zeros([int(t_tot_pt)]) t_pt = iround(self._times * sample_rate) for i in range(len(t_pt) - 1): pt0 = t_pt[i] pt1 = t_pt[i + 1] if pt0 != pt1: if self._ramps[i] != 0: wvf[pt0:pt1] = np.linspace(self._amplitudes[i], self._amplitudes_end[i + 1], pt1 - pt0 + 1)[:-1] else: wvf[pt0:pt1] = self._amplitudes[i] # render MW pulses. # create list with phase shifts per ref_channel phase_shifts_channels = {} for ps in self.phase_shifts: ps_ch = phase_shifts_channels.setdefault(ps.channel_name, []) ps_ch.append(ps) for IQ_data_single_object in self.MW_pulse_data: # start stop time of MW pulse start_pulse = IQ_data_single_object.start stop_pulse = IQ_data_single_object.stop # max amp, freq and phase. amp = IQ_data_single_object.amplitude freq = IQ_data_single_object.frequency phase = IQ_data_single_object.start_phase if ref_channel_states and IQ_data_single_object.ref_channel in ref_channel_states.start_phase: ref_start_time = ref_channel_states.start_time ref_start_phase = ref_channel_states.start_phase[ IQ_data_single_object.ref_channel] if IQ_data_single_object.ref_channel in phase_shifts_channels: phase_shifts = [ ps.phase_shift for ps in phase_shifts_channels[ IQ_data_single_object.ref_channel] if ps.time <= start_pulse ] phase_shift = sum(phase_shifts) else: phase_shift = 0 else: ref_start_time = 0 ref_start_phase = 0 phase_shift = 0 # envelope data of the pulse if IQ_data_single_object.envelope is None: IQ_data_single_object.envelope = envelope_generator() amp_envelope = IQ_data_single_object.envelope.get_AM_envelope( (stop_pulse - start_pulse), sample_rate) phase_envelope = np.asarray( IQ_data_single_object.envelope.get_PM_envelope( (stop_pulse - start_pulse), sample_rate)) #self.baseband_pulse_data[-1,0] convert to point numbers n_pt = int((stop_pulse - start_pulse) * sample_rate) if isinstance( amp_envelope, float) else len(amp_envelope) start_pt = iround(start_pulse * sample_rate) stop_pt = start_pt + n_pt # add the sin pulse total_phase = phase_shift + phase + phase_envelope + ref_start_phase t = start_pt + ref_start_time / sample_rate + np.arange(n_pt) wvf[start_pt:stop_pt] += amp * amp_envelope * np.sin( 2 * np.pi * freq / sample_rate * 1e-9 * t + total_phase) for custom_pulse in self.custom_pulse_data: data = self._render_custom_pulse(custom_pulse, sample_rate * 1e9) start_pt = iround(custom_pulse.start * sample_rate) stop_pt = start_pt + len(data) wvf[start_pt:stop_pt] += data # remove last value. t_tot_pt = t_tot + 1. Last value is always 0. It is only needed in the loop on the pulses. return wvf[:-1]
frequency : float = 0 start_phase : float = 0 envelope : envelope_generator = None ref_channel : str = None if __name__ == '__main__': """ Example on how the envelope generator works. """ import matplotlib.pyplot as plt # empty envelope from pulse_lib.segments.data_classes.data_IQ import envelope_generator env = envelope_generator('blackman') env.get_AM_envelope(50) # example generation of envelopes with different timings. env = envelope_generator('blackman') data_1 = env.get_AM_envelope(50) data_2 = env.get_AM_envelope(50.2) data_3 = env.get_AM_envelope(50.4) data_4 = env.get_AM_envelope(50.6) # plt.figure("general windowing function") # plt.plot(data_1, label = "50.0 ns pulse") # plt.plot(data_2, label = "50.2 ns pulse") # plt.plot(data_3, label = "50.4 ns pulse") # plt.plot(data_4, label = "50.6 ns pulse")