From faab8049213a29b183287cc182ea8a4dca075f2f Mon Sep 17 00:00:00 2001
From: Li Li
Date: Tue, 25 Aug 2020 18:16:56 +1000
Subject: [PATCH 1/9] Add function
---
.../driven_controls/predefined.py | 118 ++++++++++++++++++
1 file changed, 118 insertions(+)
diff --git a/qctrlopencontrols/driven_controls/predefined.py b/qctrlopencontrols/driven_controls/predefined.py
index 59ae7b81..570ed858 100644
--- a/qctrlopencontrols/driven_controls/predefined.py
+++ b/qctrlopencontrols/driven_controls/predefined.py
@@ -38,6 +38,7 @@
WAMF1,
)
from ..exceptions import ArgumentsValueError
+from ..utils import check_arguments
from .driven_control import DrivenControl
@@ -812,3 +813,120 @@ def _new_walsh_amplitude_modulated_filter_1_control(
durations=durations,
**kwargs,
)
+
+
+def new_modulated_gaussian_control(
+ maximum_rabi_rate: float,
+ minimum_segment_duration: float,
+ duration: float,
+ modulation_frequency: float,
+) -> DrivenControl:
+ """
+ Generate a Gaussian driven control sequence modulated by a since signal.
+
+ The net effect of this control sequence is an identity gate.
+
+ Parameters
+ ----------
+ maximum_rabi_rate: float
+ Maximum Rabi rate of the system.
+
+ minimum_segment_duration : float
+ Minimum length of each segment in the control sequence.
+
+ duration : float
+ Total duration of the control sequence.
+
+ modulation_frequency: float
+ Frequency of the modulation sinusoidal signal.
+
+ Returns
+ -------
+ DrivenControl
+ A control sequence as an instance of DrivenControl.
+ """
+
+ check_arguments(
+ maximum_rabi_rate > 0.0,
+ "Maximum Rabi rate must be greater than zero.",
+ {"maximum_rabi_rate": maximum_rabi_rate},
+ )
+
+ check_arguments(
+ minimum_segment_duration > 0.0,
+ "Minimum segment duration must be greater than zero.",
+ {"minimum_segment_duration": minimum_segment_duration},
+ )
+
+ check_arguments(
+ duration > minimum_segment_duration,
+ "Total duration must be greater than minimum segment duration.",
+ {"duration": duration, "minimum_segment_duration": minimum_segment_duration,},
+ )
+
+ # Default spread of the gaussian shaped pulse as a fraction of its duration
+ _pulse_width = 0.1
+
+ # Default mean of the gaussian shaped pulse as a fraction of its duration
+ _pulse_mean = 0.5
+
+ segment_start_times = np.arange(0, duration, minimum_segment_duration)
+ segment_num = len(segment_start_times)
+ segment_midpoints = minimum_segment_duration / 2 + segment_start_times
+
+ # Prepare the modulation signals. We use sinusoids that are zero at the center of the pulse,
+ # which ensures the pulses are antisymmetric about the center of the pulse and thus effect a net
+ # zero rotation.
+ modulation_signals = np.sin(
+ 2.0 * np.pi * modulation_frequency * (segment_midpoints - duration / 2)
+ )
+
+ # Prepare a base gaussian shaped pulse
+ gaussian_mean = _pulse_mean * duration
+ gaussian_width = _pulse_width * duration
+ normalization_constant = np.sqrt(2 * np.pi) * gaussian_width
+ base_gaussian_segments = (1.0 / normalization_constant) * np.exp(
+ -0.5 * ((segment_midpoints - gaussian_mean) / gaussian_width) ** 2
+ )
+
+ # modulate the base gaussian
+ modulated_gaussian_segments = base_gaussian_segments * modulation_signals
+
+ # maximum segment value
+ pulse_segments_maximum = np.max(modulated_gaussian_segments)
+ # normalize to maximum Rabi rate
+ modulated_gaussian_segments = (
+ maximum_rabi_rate * modulated_gaussian_segments / pulse_segments_maximum
+ )
+
+ # For the zero-frequency pulse, we need to produce the largest possible full rotation (i.e.
+ # multiple of 2pi) while respecting the maximum Rabi rate. Note that if the maximum Rabi rate
+ # does not permit even a single rotation (which could happen to a small degree due to
+ # discretization issues) then we allow values to exceed the maximum Rabi rate.
+ normalized_gaussian_segments = base_gaussian_segments / np.max(
+ base_gaussian_segments
+ )
+ maximum_rotation_angle = (
+ minimum_segment_duration
+ * np.sum(normalized_gaussian_segments)
+ * maximum_rabi_rate
+ )
+ maximum_full_rotation_angle = max(
+ maximum_rotation_angle - maximum_rotation_angle % (2 * np.pi), 2 * np.pi
+ )
+
+ zero_frequency_gaussian_segments = (
+ normalized_gaussian_segments
+ * maximum_rabi_rate
+ * (maximum_full_rotation_angle / maximum_rotation_angle)
+ )
+
+ segment_values = np.concatenate(
+ [[zero_frequency_gaussian_segments], modulated_gaussian_segments]
+ )
+
+ return DrivenControl(
+ rabi_rates=segment_values,
+ azimuthal_angles=np.array([0] * segment_num),
+ durations=np.array([minimum_segment_duration] * segment_num),
+ )
From 3ac5bd66ace8cb898fd8b951688ad99b4d568df0 Mon Sep 17 00:00:00 2001
From: Li Li
Date: Tue, 25 Aug 2020 19:52:49 +1000
Subject: [PATCH 2/9] Fix
---
.../driven_controls/predefined.py | 79 +++++++++----------
1 file changed, 38 insertions(+), 41 deletions(-)
diff --git a/qctrlopencontrols/driven_controls/predefined.py b/qctrlopencontrols/driven_controls/predefined.py
index 570ed858..321ac76a 100644
--- a/qctrlopencontrols/driven_controls/predefined.py
+++ b/qctrlopencontrols/driven_controls/predefined.py
@@ -864,69 +864,66 @@ def new_modulated_gaussian_control(
{"duration": duration, "minimum_segment_duration": minimum_segment_duration,},
)
- # Default spread of the gaussian shaped pulse as a fraction of its duration
+ # default spread of the gaussian shaped pulse as a fraction of its duration
_pulse_width = 0.1
- # Default mean of the gaussian shaped pulse as a fraction of its duration
+ # default mean of the gaussian shaped pulse as a fraction of its duration
_pulse_mean = 0.5
segment_start_times = np.arange(0, duration, minimum_segment_duration)
segment_num = len(segment_start_times)
segment_midpoints = minimum_segment_duration / 2 + segment_start_times
- # Prepare the modulation signals. We use sinusoids that are zero at the center of the pulse,
+ # prepare the modulation signals. We use sinusoids that are zero at the center of the pulse,
# which ensures the pulses are antisymmetric about the center of the pulse and thus effect a net
# zero rotation.
modulation_signals = np.sin(
2.0 * np.pi * modulation_frequency * (segment_midpoints - duration / 2)
)
- # Prepare a base gaussian shaped pulse
+ # prepare a base gaussian shaped pulse
gaussian_mean = _pulse_mean * duration
gaussian_width = _pulse_width * duration
- normalization_constant = np.sqrt(2 * np.pi) * gaussian_width
- base_gaussian_segments = (1.0 / normalization_constant) * np.exp(
+ base_gaussian_segments = (1.0 / gaussian_width / np.sqrt(2 * np.pi)) * np.exp(
-0.5 * ((segment_midpoints - gaussian_mean) / gaussian_width) ** 2
)
- # modulate the base gaussian
- modulated_gaussian_segments = base_gaussian_segments * modulation_signals
+ if modulation_frequency != 0:
+ # modulate the base gaussian
+ modulated_gaussian_segments = base_gaussian_segments * modulation_signals
- # maximum segment value
- pulse_segments_maximum = np.max(modulated_gaussian_segments)
- # normalize to maximum Rabi rate
- modulated_gaussian_segments = (
- maximum_rabi_rate * modulated_gaussian_segments / pulse_segments_maximum
- )
-
- # For the zero-frequency pulse, we need to produce the largest possible full rotation (i.e.
- # multiple of 2pi) while respecting the maximum Rabi rate. Note that if the maximum Rabi rate
- # does not permit even a single rotation (which could happen to a small degree due to
- # discretization issues) then we allow values to exceed the maximum Rabi rate.
- normalized_gaussian_segments = base_gaussian_segments / np.max(
- base_gaussian_segments
- )
- maximum_rotation_angle = (
- minimum_segment_duration
- * np.sum(normalized_gaussian_segments)
- * maximum_rabi_rate
- )
- maximum_full_rotation_angle = max(
- maximum_rotation_angle - maximum_rotation_angle % (2 * np.pi), 2 * np.pi
- )
-
- zero_frequency_gaussian_segments = (
- normalized_gaussian_segments
- * maximum_rabi_rate
- * (maximum_full_rotation_angle / maximum_rotation_angle)
- )
+ # maximum segment value
+ pulse_segments_maximum = np.max(modulated_gaussian_segments)
+ # normalize to maximum Rabi rate
+ modulated_gaussian_segments = (
+ maximum_rabi_rate * modulated_gaussian_segments / pulse_segments_maximum
+ )
+ else:
+ # for the zero-frequency pulse, we need to produce the largest possible full rotation (i.e.
+ # multiple of 2pi) while respecting the maximum Rabi rate. Note that if the maximum Rabi
+ # rate does not permit even a single rotation (which could happen to a small degree due to
+ # discretization issues) then we allow values to exceed the maximum Rabi rate.
+ normalized_gaussian_segments = base_gaussian_segments / np.max(
+ base_gaussian_segments
+ )
+ maximum_rotation_angle = (
+ minimum_segment_duration
+ * np.sum(normalized_gaussian_segments)
+ * maximum_rabi_rate
+ )
+ maximum_full_rotation_angle = max(
+ maximum_rotation_angle - maximum_rotation_angle % (2 * np.pi), 2 * np.pi
+ )
+ modulated_gaussian_segments = (
+ normalized_gaussian_segments
+ * maximum_rabi_rate
+ * (maximum_full_rotation_angle / maximum_rotation_angle)
+ )
- segment_values = np.concatenate(
- [[zero_frequency_gaussian_segments], modulated_gaussian_segments]
- )
+ azimuthal_angles = [0 if v >= 0 else np.pi for v in modulated_gaussian_segments]
return DrivenControl(
- rabi_rates=segment_values,
- azimuthal_angles=np.array([0] * segment_num),
+ rabi_rates=np.abs(modulated_gaussian_segments),
+ azimuthal_angles=azimuthal_angles,
durations=np.array([minimum_segment_duration] * segment_num),
)
From 0e48d89195e3576871d3cc9cb295368eadb315b1 Mon Sep 17 00:00:00 2001
From: Li Li
Date: Tue, 25 Aug 2020 21:45:15 +1000
Subject: [PATCH 3/9] Add test
---
tests/test_predefined_driven_controls.py | 116 +++++++++++++++++++++++
1 file changed, 116 insertions(+)
diff --git a/tests/test_predefined_driven_controls.py b/tests/test_predefined_driven_controls.py
index 29b7f0ed..58e91130 100644
--- a/tests/test_predefined_driven_controls.py
+++ b/tests/test_predefined_driven_controls.py
@@ -28,9 +28,11 @@
CORPSE_IN_SK1,
PRIMITIVE,
SCROFULOUS,
+ SIGMA_X,
SK1,
WAMF1,
)
+from qctrlopencontrols.driven_controls.predefined import new_modulated_gaussian_control
from qctrlopencontrols.exceptions import ArgumentsValueError
@@ -592,3 +594,117 @@ def test_walsh_control():
)
assert np.allclose(pi_on_4_segments, _pi_on_4_segments)
+
+
+def test_modulated_gaussian_control():
+ """
+ Tests modulated Gaussian control at different modulate frequencies.
+ """
+ maximum_rabi_rate = 20 * 2 * np.pi
+ minimum_segment_duration = 0.01
+ maximum_duration = 0.2
+
+ # set modulation frequency to 0
+ pulses_zero = new_modulated_gaussian_control(
+ maximum_rabi_rate=maximum_rabi_rate,
+ minimum_segment_duration=minimum_segment_duration,
+ duration=maximum_duration,
+ modulation_frequency=0,
+ )
+ pulse_zero_segments = [
+ {"duration": d, "value": np.real(v)}
+ for d, v in zip(
+ pulses_zero.durations,
+ pulses_zero.rabi_rates * np.exp(1j * pulses_zero.azimuthal_angles),
+ )
+ ]
+
+ # set modulation frequency to 50/3
+ pulses_non_zero = new_modulated_gaussian_control(
+ maximum_rabi_rate=maximum_rabi_rate,
+ minimum_segment_duration=minimum_segment_duration,
+ duration=maximum_duration,
+ modulation_frequency=50 / 3,
+ )
+ pulse_non_zero_segments = [
+ {"duration": d, "value": np.real(v)}
+ for d, v in zip(
+ pulses_non_zero.durations,
+ pulses_non_zero.rabi_rates * np.exp(1j * pulses_non_zero.azimuthal_angles),
+ )
+ ]
+
+ # pulses should have 20 segments; 0.2/0.01 = 20
+ assert len(pulse_zero_segments) == 20
+ assert len(pulse_non_zero_segments) == 20
+
+ # determine the segment mid-points
+ segment_mid_points = 0.2 / 20 * (0.5 + np.arange(20))
+ base_gaussian_mean = maximum_duration * 0.5
+ base_gaussian_width = maximum_duration * 0.1
+ base_gaussian = np.exp(
+ -0.5 * ((segment_mid_points - base_gaussian_mean) / base_gaussian_width) ** 2.0
+ ) / (np.sqrt(2 * np.pi) * base_gaussian_width)
+
+ # for modulation at frequency = 0
+ segment_values = np.array([p["value"] for p in pulse_zero_segments])
+ segment_durations = np.array([p["duration"] for p in pulse_zero_segments])
+ # The base Gaussian creates a rotation of 1rad and has maximum value
+ # 1/(sqrt(2pi)*0.2*0.1)=~19.9. Therefore, with a maximum Rabi rate of 20*2pi, we can achieve
+ # only a single 2pi rotation, which corresponds to scaling up the Gaussian by 2pi.
+ expected_gaussian = 2 * np.pi * base_gaussian
+
+ assert np.allclose(segment_values, expected_gaussian)
+ assert np.allclose(segment_durations, 0.2 / 20)
+
+ # for modulation at frequency = 50/3
+ segment_values = np.array([segment["value"] for segment in pulse_non_zero_segments])
+ segment_durations = np.array(
+ [segment["duration"] for segment in pulse_non_zero_segments]
+ )
+ expected_base_segments = base_gaussian * np.sin(
+ 2 * np.pi * (50 / 3) * (segment_mid_points - 0.2 / 2)
+ )
+ expected_base_segments /= np.max(expected_base_segments)
+ expected_base_segments *= maximum_rabi_rate
+
+ assert np.allclose(segment_values, expected_base_segments)
+ assert np.allclose(segment_durations, 0.2 / 20)
+
+
+def test_modulated_gaussian_control_give_identity_gate():
+ """
+ Tests that the modulated Gaussian sequences produce identity gates when simulated.
+
+ Apply the modulated sequences to drive a noiseless qubit rotating along X, the net
+ effect should be an identity gate.
+ """
+
+ maximum_rabi_rate = 10 * 2 * np.pi
+ minimum_segment_duration = 0.02
+ maximum_duration = 0.2
+
+ pulses = [
+ new_modulated_gaussian_control(
+ maximum_rabi_rate=maximum_rabi_rate,
+ minimum_segment_duration=minimum_segment_duration,
+ duration=maximum_duration,
+ modulation_frequency=f,
+ )
+ for f in [0, 20]
+ ]
+
+ unitaries = [
+ np.linalg.multi_dot(
+ [
+ np.cos(d * v) * np.eye(2) + 1j * np.sin(d * v) * SIGMA_X
+ for d, v in zip(
+ p.durations, p.rabi_rates * np.exp(1j * p.azimuthal_angles),
+ )
+ ]
+ )
+ for p in pulses
+ ]
+
+ for _u in unitaries:
+ assert np.allclose(_u, np.eye(2))
From a536bcea55ad8f25c79a8bdf14dc979223917299 Mon Sep 17 00:00:00 2001
From: Li Li
Date: Tue, 25 Aug 2020 21:53:25 +1000
Subject: [PATCH 4/9] Add check
---
qctrlopencontrols/driven_controls/predefined.py | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/qctrlopencontrols/driven_controls/predefined.py b/qctrlopencontrols/driven_controls/predefined.py
index 321ac76a..4ad34a99 100644
--- a/qctrlopencontrols/driven_controls/predefined.py
+++ b/qctrlopencontrols/driven_controls/predefined.py
@@ -822,7 +822,8 @@ def new_modulated_gaussian_control(
modulation_frequency: float,
) -> DrivenControl:
"""
- Generate a Gaussian driven control sequence modulated by a since signal.
+ Generate a Gaussian driven control sequence modulated by a sinusoidal signal at a specific
+ frequency.
The net effect of this control sequence is an identity gate.
@@ -870,6 +871,17 @@ def new_modulated_gaussian_control(
# default mean of the gaussian shaped pulse as a fraction of its duration
_pulse_mean = 0.5
+ min_required_upper_bound = np.sqrt(2 * np.pi) / (_pulse_width * duration)
+ check_arguments(
+ maximum_rabi_rate >= min_required_upper_bound,
+ "Maximum Rabi rate must be large enough to permit a 2Pi rotation.",
+ {"maximum_rabi_rate": maximum_rabi_rate},
+ extras={
+ "minimum required value for upper_bound "
+ "(sqrt(2pi)/(0.1*maximum_duration))": min_required_upper_bound
+ },
+ )
+
segment_start_times = np.arange(0, duration, minimum_segment_duration)
segment_num = len(segment_start_times)
segment_midpoints = minimum_segment_duration / 2 + segment_start_times
From 60669e25db9f11677a689028f8ec4ceca665ade4 Mon Sep 17 00:00:00 2001
From: Li Li
Date: Tue, 25 Aug 2020 21:58:46 +1000
Subject: [PATCH 5/9] Fix test
---
tests/test_predefined_driven_controls.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/test_predefined_driven_controls.py b/tests/test_predefined_driven_controls.py
index 58e91130..02f8ad31 100644
--- a/tests/test_predefined_driven_controls.py
+++ b/tests/test_predefined_driven_controls.py
@@ -680,7 +680,7 @@ def test_modulated_gaussian_control_give_identity_gate():
effect should be an identity gate.
"""
- maximum_rabi_rate = 10 * 2 * np.pi
+ maximum_rabi_rate = 50 * 2 * np.pi
minimum_segment_duration = 0.02
maximum_duration = 0.2
From 26c7e5d40cfd6953f040176921964d422feb3c14 Mon Sep 17 00:00:00 2001
From: Li Li
Date: Tue, 25 Aug 2020 22:21:28 +1000
Subject: [PATCH 6/9] Tweak doc
---
tests/test_predefined_driven_controls.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/test_predefined_driven_controls.py b/tests/test_predefined_driven_controls.py
index 02f8ad31..49e129b9 100644
--- a/tests/test_predefined_driven_controls.py
+++ b/tests/test_predefined_driven_controls.py
@@ -674,9 +674,9 @@ def test_modulated_gaussian_control():
def test_modulated_gaussian_control_give_identity_gate():
"""
- Tests that the modulated Gaussian sequences produce identity gates when simulated.
+ Tests that the modulated Gaussian sequences produce identity gates.
- Apply the modulated sequences to drive a noiseless qubit rotating along X, the net
+ Apply the modulated sequences to drive a noiseless qubit rotating along X. The net
effect should be an identity gate.
"""
From a639a52b3a4003c131b87c9542efb611eb630dbf Mon Sep 17 00:00:00 2001
From: Li Li
Date: Wed, 26 Aug 2020 11:42:15 +1000
Subject: [PATCH 7/9] Use exact segment duration
---
.../driven_controls/predefined.py | 23 ++++++++++---------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/qctrlopencontrols/driven_controls/predefined.py b/qctrlopencontrols/driven_controls/predefined.py
index 4ad34a99..620edb7e 100644
--- a/qctrlopencontrols/driven_controls/predefined.py
+++ b/qctrlopencontrols/driven_controls/predefined.py
@@ -882,16 +882,11 @@ def new_modulated_gaussian_control(
},
)
- segment_start_times = np.arange(0, duration, minimum_segment_duration)
- segment_num = len(segment_start_times)
- segment_midpoints = minimum_segment_duration / 2 + segment_start_times
-
- # prepare the modulation signals. We use sinusoids that are zero at the center of the pulse,
- # which ensures the pulses are antisymmetric about the center of the pulse and thus effect a net
- # zero rotation.
- modulation_signals = np.sin(
- 2.0 * np.pi * modulation_frequency * (segment_midpoints - duration / 2)
- )
+ # work out exact segment duration
+ segment_num = int(np.ceil(duration / minimum_segment_duration))
+ segment_duration = duration / segment_num
+ segment_start_times = np.arange(segment_num) * segment_duration
+ segment_midpoints = segment_start_times + segment_duration / 2
# prepare a base gaussian shaped pulse
gaussian_mean = _pulse_mean * duration
@@ -901,6 +896,12 @@ def new_modulated_gaussian_control(
)
if modulation_frequency != 0:
+ # prepare the modulation signals. We use sinusoids that are zero at the center of the pulse,
+ # which ensures the pulses are antisymmetric about the center of the pulse and thus effect
+ # a net zero rotation.
+ modulation_signals = np.sin(
+ 2.0 * np.pi * modulation_frequency * (segment_midpoints - duration / 2)
+ )
# modulate the base gaussian
modulated_gaussian_segments = base_gaussian_segments * modulation_signals
@@ -937,5 +938,5 @@ def new_modulated_gaussian_control(
return DrivenControl(
rabi_rates=np.abs(modulated_gaussian_segments),
azimuthal_angles=azimuthal_angles,
- durations=np.array([minimum_segment_duration] * segment_num),
+ durations=np.array([segment_duration] * segment_num),
)
From a1547aa6f1afa3744473a9180f3db49e9ae4838f Mon Sep 17 00:00:00 2001
From: Li Li
Date: Wed, 26 Aug 2020 11:51:52 +1000
Subject: [PATCH 8/9] Fix
---
qctrlopencontrols/driven_controls/predefined.py | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/qctrlopencontrols/driven_controls/predefined.py b/qctrlopencontrols/driven_controls/predefined.py
index 620edb7e..1ff4606a 100644
--- a/qctrlopencontrols/driven_controls/predefined.py
+++ b/qctrlopencontrols/driven_controls/predefined.py
@@ -920,9 +920,7 @@ def new_modulated_gaussian_control(
base_gaussian_segments
)
maximum_rotation_angle = (
- minimum_segment_duration
- * np.sum(normalized_gaussian_segments)
- * maximum_rabi_rate
+ segment_duration * np.sum(normalized_gaussian_segments) * maximum_rabi_rate
)
maximum_full_rotation_angle = max(
maximum_rotation_angle - maximum_rotation_angle % (2 * np.pi), 2 * np.pi
From 6f3da61dd0b20ddc182a552b5aa2c9e1cdceb561 Mon Sep 17 00:00:00 2001
From: Li Li
Date: Wed, 26 Aug 2020 12:10:02 +1000
Subject: [PATCH 9/9] tweak
---
qctrlopencontrols/driven_controls/predefined.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/qctrlopencontrols/driven_controls/predefined.py b/qctrlopencontrols/driven_controls/predefined.py
index 1ff4606a..1a3a02da 100644
--- a/qctrlopencontrols/driven_controls/predefined.py
+++ b/qctrlopencontrols/driven_controls/predefined.py
@@ -883,15 +883,15 @@ def new_modulated_gaussian_control(
)
# work out exact segment duration
- segment_num = int(np.ceil(duration / minimum_segment_duration))
- segment_duration = duration / segment_num
- segment_start_times = np.arange(segment_num) * segment_duration
+ segment_count = int(np.ceil(duration / minimum_segment_duration))
+ segment_duration = duration / segment_count
+ segment_start_times = np.arange(segment_count) * segment_duration
segment_midpoints = segment_start_times + segment_duration / 2
# prepare a base gaussian shaped pulse
gaussian_mean = _pulse_mean * duration
gaussian_width = _pulse_width * duration
- base_gaussian_segments = (1.0 / gaussian_width / np.sqrt(2 * np.pi)) * np.exp(
+ base_gaussian_segments = np.exp(
-0.5 * ((segment_midpoints - gaussian_mean) / gaussian_width) ** 2
)
@@ -936,5 +936,5 @@ def new_modulated_gaussian_control(
return DrivenControl(
rabi_rates=np.abs(modulated_gaussian_segments),
azimuthal_angles=azimuthal_angles,
- durations=np.array([segment_duration] * segment_num),
+ durations=np.array([segment_duration] * segment_count),
)