Skip to content

Commit deca5d8

Browse files
committed
Changed the parameterization of AnalogQuantity.square_wave() inputs, then added square_wave_levels() method which uses the old parameterization.
This PR also inverts the previous meaning of duty cycle in the old parameterization. Now duty cycle is the fraction of the time spent outputing `level_0` rather than `level_1` in square_wave_levels().
1 parent 054e281 commit deca5d8

File tree

2 files changed

+96
-15
lines changed

2 files changed

+96
-15
lines changed

labscript/functions.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def piecewise_accel(duration,initial,final):
5151
def square_wave(duration, level_0, level_1, frequency, phase, duty_cycle):
5252
def square_wave_fixed_parameters(t):
5353
# Phase goes from 0 to 1 (NOT 2 pi) over one period.
54-
rising_edge_phase = 1 - duty_cycle
54+
edge_phase_0_to_1 = duty_cycle
5555
wrapped_phases = (frequency * t + phase) % 1.0
5656
# Ensure wrapped_phases is an array.
5757
wrapped_phases = np.array(wrapped_phases)
@@ -67,14 +67,14 @@ def square_wave_fixed_parameters(t):
6767
MIN_PHASE_STEP = frequency * LABSCRIPT_TIME_RESOLUTION
6868
PHASE_TOLERANCE = MIN_PHASE_STEP / 2.0
6969
# Round phases near level_0 -> level_1 transition at phase =
70-
# rising_edge_phase.
70+
# edge_phase_0_to_1.
7171
is_near_edge = np.isclose(
7272
wrapped_phases,
73-
rising_edge_phase,
73+
edge_phase_0_to_1,
7474
rtol=0,
7575
atol=PHASE_TOLERANCE,
7676
)
77-
wrapped_phases[is_near_edge] = rising_edge_phase
77+
wrapped_phases[is_near_edge] = edge_phase_0_to_1
7878
# Round phases near level_1 -> level_0 transition at phase = 1.
7979
is_near_edge = np.isclose(
8080
wrapped_phases,
@@ -90,7 +90,7 @@ def square_wave_fixed_parameters(t):
9090
# Use boolean indexing to set output to level_1 at the appropriate
9191
# times. For example level_0 for phases [0, 0.5) and level_1 for phases
9292
# [0.5, 1.0) when duty_cycle is 0.5.
93-
level_1_times = (wrapped_phases >= rising_edge_phase)
93+
level_1_times = (wrapped_phases >= edge_phase_0_to_1)
9494
outputs[level_1_times] = level_1
9595
return outputs
9696
return square_wave_fixed_parameters

labscript/labscript.py

Lines changed: 91 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,13 +1539,19 @@ def piecewise_accel_ramp(self, t, duration, initial, final, samplerate, units=No
15391539
'initial time': t, 'end time': t + truncation*duration, 'clock rate': samplerate, 'units': units})
15401540
return truncation*duration
15411541

1542-
def square_wave(self, t, duration, level_0, level_1, frequency, phase,
1542+
def square_wave(self, t, duration, amplitude, frequency, phase, offset,
15431543
duty_cycle, samplerate, units=None, truncation=1.):
15441544
"""A standard square wave.
15451545
1546-
This method generates a square wave which starts at `level_0` (when its
1547-
phase is zero) then transitions to/from `level_1` at the specified
1548-
`frequency`.
1546+
This method generates a square wave which starts HIGH (when its phase is
1547+
zero) then transitions to/from LOW at the specified `frequency` in Hz.
1548+
The `amplitude` parameter specifies the peak-to-peak amplitude of the
1549+
square wave which is centered around `offset`. For example, setting
1550+
`amplitude=1` and `offset=0` would give a square wave which transitions
1551+
between `0.5` and `-0.5`. Similarly, setting `amplitude=2` and
1552+
`offset=3` would give a square wave which transitions between `4` and
1553+
`2`. To instead specify the HIGH/LOW levels directly, use
1554+
`square_wave_levels()`.
15491555
15501556
Note that because the transitions of a square wave are sudden and
15511557
discontinuous, small changes in timings (e.g. due to numerical rounding
@@ -1563,22 +1569,97 @@ def square_wave(self, t, duration, level_0, level_1, frequency, phase,
15631569
Args:
15641570
t (float): The time at which to start the square wave.
15651571
duration (float): The duration for which to output a square wave
1566-
(assuming `truncation=1.0`).
1572+
when `truncation` is set to `1`. When `truncation` is set to a
1573+
value less than `1`, the actual duration will be shorter than
1574+
`duration` by that factor.
1575+
amplitude (float): The peak-to-peak amplitude of the square wave.
1576+
See above for an example of how to calculate the HIGH/LOW output
1577+
values given the `amplitude` and `offset` values.
1578+
frequency (float): The frequency of the square wave, in Hz.
1579+
phase (float): The initial phase of the square wave. Note that the
1580+
square wave is defined such that the phase goes from 0 to 1 (NOT
1581+
2 pi) over one cycle, so setting `phase=0.5` will start the
1582+
square wave advanced by 1/2 of a cycle. Setting `phase` equal to
1583+
`duty_cycle` will cause the waveform to start LOW rather than
1584+
HIGH.
1585+
offset (float): The offset of the square wave, which is the value
1586+
halfway between the LOW and HIGH output values. Note that this
1587+
is NOT the LOW output value; setting `offset` to `0` will cause
1588+
the HIGH/LOW values to be symmetrically split around `0`. See
1589+
above for an example of how to calculate the HIGH/LOW output
1590+
values given the `amplitude` and `offset` values.
1591+
duty_cycle (float): The fraction of the cycle for which the output
1592+
should be HIGH. This should be a number between zero and one
1593+
inclusively. For example, setting `duty_cycle=0.1` will
1594+
create a square wave which outputs HIGH over 10% of the
1595+
cycle and outputs LOW over 90% of the cycle.
1596+
samplerate (float): The requested rate at which to update the output
1597+
value. Note that the actual samplerate used may be different if,
1598+
for example, another output of the same device has a
1599+
simultaneous ramp with a different requested `samplerate`, or if
1600+
`1 / samplerate` isn't an integer multiple of the pseudoclock's
1601+
timing resolution.
1602+
units (str, optional): The units of the output values. If set to
1603+
`None` then the output's base units will be used. Defaults to
1604+
`None`.
1605+
truncation (float, optional): The actual duration of the square wave
1606+
will be `duration * truncation` and `truncation` must be set to
1607+
a value in the range [0, 1] (inclusively). Set to `1` to output
1608+
the full duration of the square wave. Setting it to `0` will
1609+
skip the square wave entirely. Defaults to `1.`.
1610+
1611+
Returns:
1612+
duration (float): The actual duration of the square wave, accounting
1613+
for `truncation`.
1614+
"""
1615+
# Convert to values used by square_wave_levels, then call that method.
1616+
level_0 = offset + 0.5 * amplitude
1617+
level_1 = offset - 0.5 * amplitude
1618+
return self.square_wave_levels(
1619+
t,
1620+
duration,
1621+
level_0,
1622+
level_1,
1623+
frequency,
1624+
phase,
1625+
duty_cycle,
1626+
samplerate,
1627+
units,
1628+
truncation,
1629+
)
1630+
1631+
def square_wave_levels(self, t, duration, level_0, level_1, frequency,
1632+
phase, duty_cycle, samplerate, units=None,
1633+
truncation=1.):
1634+
"""A standard square wave.
1635+
1636+
This method generates a square wave which starts at `level_0` (when its
1637+
phase is zero) then transitions to/from `level_1` at the specified
1638+
`frequency`. This is the same waveform output by `square_wave()`, but
1639+
parameterized differently. See that method's docstring for more
1640+
information.
1641+
1642+
Args:
1643+
t (float): The time at which to start the square wave.
1644+
duration (float): The duration for which to output a square wave
1645+
when `truncation` is set to `1`. When `truncation` is set to a
1646+
value less than `1`, the actual duration will be shorter than
1647+
`duration` by that factor.
15671648
level_0 (float): The initial level of the square wave, when the
15681649
phase is zero.
15691650
level_1 (float): The other level of the square wave.
15701651
frequency (float): The frequency of the square wave, in Hz.
15711652
phase (float): The initial phase of the square wave. Note that the
15721653
square wave is defined such that the phase goes from 0 to 1 (NOT
15731654
2 pi) over one cycle, so setting `phase=0.5` will start the
1574-
square wave advanced by 1/2 of a cycle. Setting `phase` to be
1575-
`1 - duty_cycle` will cause the waveform to start at `level_1`
1655+
square wave advanced by 1/2 of a cycle. Setting `phase` equal to
1656+
`duty_cycle` will cause the waveform to start at `level_1`
15761657
rather than `level_0`.
15771658
duty_cycle (float): The fraction of the cycle for which the output
1578-
should be set to `level_1`. This should be a number between zero
1659+
should be set to `level_0`. This should be a number between zero
15791660
and one inclusively. For example, setting `duty_cycle=0.1` will
1580-
create a square wave which outputs `level_0` over 90% of the
1581-
cycle and outputs `level_1` over 10% of the cycle.
1661+
create a square wave which outputs `level_0` over 10% of the
1662+
cycle and outputs `level_1` over 90% of the cycle.
15821663
samplerate (float): The requested rate at which to update the output
15831664
value. Note that the actual samplerate used may be different if,
15841665
for example, another output of the same device has a

0 commit comments

Comments
 (0)