@@ -1006,6 +1006,7 @@ def new_gaussian_control(
10061006 See Also
10071007 --------
10081008 new_modulated_gaussian_control
1009+ new_drag_control
10091010
10101011 Notes
10111012 -----
@@ -1206,3 +1207,132 @@ def new_modulated_gaussian_control(
12061207 detunings = np .zeros (segment_count ),
12071208 durations = np .array ([segment_duration ] * segment_count ),
12081209 )
1210+
1211+
1212+ def new_drag_control (
1213+ rabi_rotation : float ,
1214+ segment_count : int ,
1215+ duration : float ,
1216+ width : float ,
1217+ beta : float ,
1218+ azimuthal_angle : float = 0.0 ,
1219+ name : Optional [str ] = None ,
1220+ ) -> DrivenControl :
1221+ r"""
1222+ Generates a Gaussian driven control sequence with a first-order DRAG
1223+ (Derivative Removal by Adiabatic Gate) correction applied.
1224+
1225+ The addition of DRAG further reduces leakage out of the qubit subspace via an additional
1226+ off-quadrature corrective driving term proportional to the derivative of the Gaussian pulse.
1227+
1228+ Parameters
1229+ ----------
1230+ rabi_rotation : float
1231+ Total Rabi rotation :math:`\theta` to be performed by the driven control.
1232+ segment_count : int
1233+ Number of segments in the control sequence.
1234+ duration : float
1235+ Total duration :math:`t_g` of the control sequence.
1236+ width : float
1237+ Width (standard deviation) :math:`\sigma` of the ideal Gaussian pulse.
1238+ beta : float
1239+ Amplitude scaling :math:`\beta` of the Gaussian derivative.
1240+ azimuthal_angle : float, optional
1241+ The azimuthal angle :math:`\phi` for the rotation. Defaults to 0.
1242+ name : str, optional
1243+ An optional string to name the control. Defaults to ``None``.
1244+
1245+ Returns
1246+ -------
1247+ DrivenControl
1248+ A control sequence as an instance of DrivenControl.
1249+
1250+ See Also
1251+ --------
1252+ new_gaussian_control
1253+
1254+ Notes
1255+ -----
1256+ A DRAG-corrected Gaussian driven control [#]_
1257+ applies a Hamiltonian consisting of a piecewise constant approximation to an ideal
1258+ Gaussian pulse controlling :math:`\sigma_x` while its derivative controls the
1259+ application of the :math:`\sigma_y` operator:
1260+
1261+ .. math::
1262+ H(t) = \frac{1}{2}(\Omega_G(t) \sigma_x + \beta \dot{\Omega}_G(t) \sigma_y)
1263+
1264+ where :math:`\Omega_G(t)` is simply given by :doc:`new_gaussian_control`. Optimally,
1265+ :math:`\beta = -\frac{\lambda_1^2}{4\Delta_2}` where :math:`\Delta_2` is the
1266+ anharmonicity of the system and :math:`\lambda_1` is the relative strength required
1267+ to drive a transition :math:`\lvert 1 \rangle \rightarrow \lvert 2 \rangle` vs.
1268+ :math:`\lvert 0 \rangle \rightarrow \lvert 1 \rangle`. Note
1269+ that this choice of :math:`\beta`, sometimes called "simple drag" or "half derivative",
1270+ is a first-order version of DRAG, and it excludes an additional detuning corrective term.
1271+
1272+ References
1273+ ----------
1274+ .. [#] `Motzoi, F. et al. Physical Review Letters 103, 110501 (2009).
1275+ <https://doi.org/10.1103/PhysRevLett.103.110501>`_
1276+ .. [#] `J. M. Gambetta, F. Motzoi, S. T. Merkel, and F. K. Wilhelm,
1277+ Physical Review A 83, 012308 (2011).
1278+ <https://doi.org/10.1103/PhysRevA.83.012308>`_
1279+ """
1280+
1281+ check_arguments (
1282+ duration > 0.0 ,
1283+ "Pulse duration must be greater than zero." ,
1284+ {"duration" : duration },
1285+ )
1286+
1287+ check_arguments (
1288+ segment_count > 0 ,
1289+ "Segment count must be greater than zero." ,
1290+ {"segment_count" : segment_count },
1291+ )
1292+
1293+ check_arguments (
1294+ width > 0.0 ,
1295+ "Width of ideal Gaussian pulse must be greater than zero." ,
1296+ {"width" : width },
1297+ )
1298+
1299+ # compute sampling parameters
1300+ segment_duration = duration / segment_count
1301+ segment_start_times = np .arange (segment_count ) * segment_duration
1302+ segment_midpoints = segment_start_times + segment_duration / 2
1303+
1304+ # prepare a base (un-normalized) gaussian shaped pulse
1305+ gaussian_mean = duration / 2
1306+ base_gaussian_segments = np .exp (
1307+ - 0.5 * ((segment_midpoints - gaussian_mean ) / width ) ** 2
1308+ )
1309+
1310+ # translate pulse by B/A (from Motzoi '09 paper) to ensure output is 0 at t=0
1311+ y_translation = - np .exp (- 0.5 * ((0 - gaussian_mean ) / width ) ** 2 )
1312+ base_gaussian_segments += y_translation
1313+
1314+ # compute A (from Motzoi '09 paper)
1315+ base_gaussian_total_rotation = np .sum (base_gaussian_segments ) * segment_duration
1316+ normalization_factor = rabi_rotation / base_gaussian_total_rotation
1317+
1318+ x_quadrature_segments = base_gaussian_segments * normalization_factor
1319+ y_quadrature_segments = (
1320+ beta
1321+ * (gaussian_mean - segment_midpoints )
1322+ / width ** 2
1323+ * (
1324+ x_quadrature_segments
1325+ - y_translation * normalization_factor # = B (from Motzoi '09 paper)
1326+ )
1327+ )
1328+
1329+ rabi_rates = np .sqrt (x_quadrature_segments ** 2 + y_quadrature_segments ** 2 )
1330+ azimuthal_angles = np .arcsin (y_quadrature_segments / rabi_rates ) + azimuthal_angle
1331+
1332+ return DrivenControl (
1333+ rabi_rates = rabi_rates ,
1334+ azimuthal_angles = azimuthal_angles ,
1335+ detunings = np .zeros (segment_count ),
1336+ durations = np .array ([segment_duration ] * segment_count ),
1337+ name = name ,
1338+ )
0 commit comments