diff --git a/src/qibolab/pulses.py b/src/qibolab/pulses.py index 100bf498b..9e0ab82ad 100644 --- a/src/qibolab/pulses.py +++ b/src/qibolab/pulses.py @@ -468,19 +468,20 @@ class SNZ(PulseShape): """ Sudden variant Net Zero. https://arxiv.org/abs/2008.07411 + (Supplementary materials: FIG. S1.) """ - def __init__(self, t_half_flux_pulse=None, b_amplitude=1): + def __init__(self, t_idling, b_amplitude=None): self.name = "SNZ" self.pulse: Pulse = None - self.t_half_flux_pulse: float = t_half_flux_pulse - self.b_amplitude: float = b_amplitude + self.t_idling: float = t_idling + self.b_amplitude = b_amplitude def __eq__(self, item) -> bool: """Overloads == operator""" if super().__eq__(item): - return self.t_half_flux_pulse == item.t_half_flux_pulse and self.b_amplitude == item.b_amplitude + return self.t_idling == item.t_idling and self.b_amplitude == item.b_amplitude return False @property @@ -488,21 +489,22 @@ def envelope_waveform_i(self) -> Waveform: """The envelope waveform of the i component of the pulse.""" if self.pulse: - if not self.t_half_flux_pulse: - self.t_half_flux_pulse = self.pulse.duration / 2 - elif 2 * self.t_half_flux_pulse > self.pulse.duration: - raise ValueError("Pulse shape parameter error: pulse.t_half_flux_pulse <= pulse.duration") + if self.t_idling > self.pulse.duration: + raise ValueError(f"Cannot put idling time {self.t_idling} higher than duration {self.pulse.duration}.") + if self.b_amplitude is None: + self.b_amplitude = self.pulse.amplitude / 2 num_samples = int(np.rint(self.pulse.duration / 1e9 * PulseShape.SAMPLING_RATE)) - half_flux_pulse_samples = int(np.rint(num_samples * self.t_half_flux_pulse / self.pulse.duration)) - iding_samples = num_samples - 2 * half_flux_pulse_samples + half_pulse_duration = (self.pulse.duration - self.t_idling) / 2 + half_flux_pulse_samples = int(np.rint(num_samples * half_pulse_duration / self.pulse.duration)) + idling_samples = num_samples - 2 * half_flux_pulse_samples waveform = Waveform( np.concatenate( ( self.pulse.amplitude * np.ones(half_flux_pulse_samples - 1), - np.array([self.pulse.amplitude * self.b_amplitude]), - np.zeros(iding_samples), - -1 * np.array([self.pulse.amplitude * self.b_amplitude]), - -1 * self.pulse.amplitude * np.ones(half_flux_pulse_samples - 1), + np.array([self.b_amplitude]), + np.zeros(idling_samples), + -np.array([self.b_amplitude]), + -self.pulse.amplitude * np.ones(half_flux_pulse_samples - 1), ) ) ) @@ -522,7 +524,7 @@ def envelope_waveform_q(self) -> Waveform: raise ShapeInitError def __repr__(self): - return f"{self.name}({self.t_half_flux_pulse}, {self.b_amplitude})" + return f"{self.name}({self.t_idling})" class eCap(PulseShape): diff --git a/tests/test_instruments_zhinst.py b/tests/test_instruments_zhinst.py index d32f1b54f..f9962b7e5 100644 --- a/tests/test_instruments_zhinst.py +++ b/tests/test_instruments_zhinst.py @@ -31,7 +31,7 @@ def test_zhpulse(shape): if shape == "Drag": pulse = Pulse(0, 40, 0.05, int(3e9), 0.0, Drag(5, 0.4), "ch0", qubit=0) if shape == "SNZ": - pulse = Pulse(0, 40, 0.05, int(3e9), 0.0, SNZ(10, 0.4), "ch0", qubit=0) + pulse = Pulse(0, 40, 0.05, int(3e9), 0.0, SNZ(10, 0.01), "ch0", qubit=0) if shape == "IIR": pulse = Pulse(0, 40, 0.05, int(3e9), 0.0, IIR([10, 1], [0.4, 1], target=Gaussian(5)), "ch0", qubit=0) diff --git a/tests/test_pulses.py b/tests/test_pulses.py index b4970f39f..4c274e809 100644 --- a/tests/test_pulses.py +++ b/tests/test_pulses.py @@ -34,7 +34,7 @@ def test_pulses_plot_functions(): p1 = Pulse(0, 40, 0.9, 50e6, 0, Gaussian(5), 0, PulseType.DRIVE, 2) p2 = Pulse(0, 40, 0.9, 50e6, 0, Drag(5, 2), 0, PulseType.DRIVE, 200) p3 = FluxPulse(0, 40, 0.9, IIR([-0.5, 2], [1], Rectangular()), 0, 200) - p4 = FluxPulse(0, 40, 0.9, SNZ(t_half_flux_pulse=17, b_amplitude=0.8), 0, 200) + p4 = FluxPulse(0, 40, 0.9, SNZ(t_idling=10), 0, 200) p5 = Pulse(0, 40, 0.9, 400e6, 0, eCap(alpha=2), 0, PulseType.DRIVE) p6 = SplitPulse(p5, window_start=10, window_finish=30) ps = p0 + p1 + p2 + p3 + p4 + p5 + p6 @@ -155,7 +155,7 @@ def test_pulses_pulse_init(): p8 = Pulse(0, 40, 0.9, 50e6, 0, Gaussian(5), 0, PulseType.DRIVE, 2) p9 = Pulse(0, 40, 0.9, 50e6, 0, Drag(5, 2), 0, PulseType.DRIVE, 200) p10 = FluxPulse(0, 40, 0.9, IIR([-1, 1], [-0.1, 0.1001], Rectangular()), 0, 200) - p11 = FluxPulse(0, 40, 0.9, SNZ(t_half_flux_pulse=17, b_amplitude=0.8), 0, 200) + p11 = FluxPulse(0, 40, 0.9, SNZ(t_idling=10, b_amplitude=0.5), 0, 200) p11 = Pulse(0, 40, 0.9, 400e6, 0, eCap(alpha=2), 0, PulseType.DRIVE) # initialisation with float duration and start @@ -364,7 +364,7 @@ def test_raise_shapeiniterror(): with pytest.raises(ShapeInitError): shape.envelope_waveform_q - shape = SNZ(0, 0) + shape = SNZ(0) with pytest.raises(ShapeInitError): shape.envelope_waveform_i with pytest.raises(ShapeInitError): @@ -924,11 +924,11 @@ def test_pulses_pulseshape_eq(): assert not shape1 == shape5 assert not shape1 == shape6 - shape1 = SNZ(17, 0.8) - shape2 = SNZ(17, 0.8) - shape3 = SNZ(18, 0.8) - shape4 = SNZ(17, 0.9) - shape5 = SNZ(18, 0.9) + shape1 = SNZ(5) + shape2 = SNZ(5) + shape3 = SNZ(2) + shape4 = SNZ(2, 0.1) + shape5 = SNZ(2, 0.1) assert shape1 == shape2 assert not shape1 == shape3 assert not shape1 == shape4