def __init__(self, dmgr, channel_base, parallelism, core_device="core"): self.core = dmgr.get(core_device) self.channel_base = channel_base self.parallelism = parallelism width = 16 time_width = 16 cordic_gain = 1.646760258057163 # Cordic(width=16, guard=None).gain head_room = 1.001 self.config = Config(channel_base, self.core, cordic_gain) self.offset = Spline(width, time_width, channel_base + 1, self.core, 2.*head_room) self.amplitude1 = Spline(width, time_width, channel_base + 2, self.core, 2*head_room*cordic_gain**2) self.frequency1 = Spline(3*width, time_width, channel_base + 3, self.core, 1/self.core.coarse_ref_period) self.phase1 = Spline(width, time_width, channel_base + 4, self.core, 1.) self.amplitude2 = Spline(width, time_width, channel_base + 5, self.core, 2*head_room*cordic_gain**2) self.frequency2 = Spline(3*width, time_width, channel_base + 6, self.core, 1/self.core.coarse_ref_period) self.phase2 = Spline(width, time_width, channel_base + 7, self.core, 1.) self.frequency0 = Spline(2*width, time_width, channel_base + 8, self.core, parallelism/self.core.coarse_ref_period) self.phase0 = Spline(width, time_width, channel_base + 9, self.core, 1.)
def __init__(self, dmgr, channel_base, parallelism, core_device="core"): self.core = dmgr.get(core_device) self.channel_base = channel_base width = 16 time_width = 16 cordic_gain = 1.646760258057163 # Cordic(width=16, guard=None).gain # cfg: channel_base self.offset = Spline(width, time_width, channel_base + 1, self.core, 2.) self.amplitude1 = Spline(width, time_width, channel_base + 2, self.core, 2 * cordic_gain**2) self.frequency1 = Spline(3 * width, time_width, channel_base + 3, self.core, 1 / self.core.coarse_ref_period) self.phase1 = Spline(width, time_width, channel_base + 4, self.core, 1.) self.amplitude2 = Spline(width, time_width, channel_base + 5, self.core, 2 * cordic_gain**2) self.frequency2 = Spline(3 * width, time_width, channel_base + 6, self.core, 1 / self.core.coarse_ref_period) self.phase2 = Spline(width, time_width, channel_base + 7, self.core, 1.) self.frequency0 = Spline(2 * width, time_width, channel_base + 8, self.core, parallelism / self.core.coarse_ref_period) self.phase0 = Spline(width, time_width, channel_base + 9, self.core, 1.)
class SAWG: """Smart arbitrary waveform generator channel. The channel is parametrized as: :: oscillators = exp(2j*pi*(frequency0*t + phase0))*( amplitude1*exp(2j*pi*(frequency1*t + phase1)) + amplitude2*exp(2j*pi*(frequency2*t + phase2))) output = (offset + i_enable*Re(oscillators) + q_enable*Im(buddy_oscillators)) This parametrization can be viewed as two complex (quadrature) oscillators (``frequency1``/``phase1`` and ``frequency2``/``phase2``) that are executing and sampling at the coarse RTIO frequency. They can represent frequencies within the first Nyquist zone from ``-f_rtio_coarse/2`` to ``f_rtio_coarse/2``. .. note:: The coarse RTIO frequency ``f_rtio_coarse`` is the inverse of ``ref_period*multiplier``. Both are arguments of the ``Core`` device, specified in the device database ``device_db.py``. The sum of their outputs is then interpolated by a factor of :attr:`parallelism` (2, 4, 8 depending on the bitstream) using a finite-impulse-response (FIR) anti-aliasing filter (more accurately a half-band filter). The filter is followed by a configurable saturating limiter. After the limiter, the data is shifted in frequency using a complex digital up-converter (DUC, ``frequency0``/``phase0``) running at :attr:`parallelism` times the coarse RTIO frequency. The first Nyquist zone of the DUC extends from ``-f_rtio_coarse*parallelism/2`` to ``f_rtio_coarse*parallelism/2``. Other Nyquist zones are usable depending on the interpolation/modulation options configured in the DAC. The real/in-phase data after digital up-conversion can be offset using another spline interpolator ``offset``. The ``i_enable``/``q_enable`` switches enable emission of quadrature signals for later analog quadrature mixing distinguishing upper and lower sidebands and thus doubling the bandwidth. They can also be used to emit four-tone signals. .. note:: Quadrature data from the buddy channel is currently ignored in the SAWG gateware and not added to the DAC output. This is equivalent to the ``q_enable`` switch always being ``0``. The configuration channel and the nine :class:`artiq.coredevice.spline.Spline` interpolators are accessible as attributes: * :attr:`config`: :class:`Config` * :attr:`offset`, :attr:`amplitude1`, :attr:`amplitude2`: in units of full scale * :attr:`phase0`, :attr:`phase1`, :attr:`phase2`: in units of turns * :attr:`frequency0`, :attr:`frequency1`, :attr:`frequency2`: in units of Hz .. note:: The latencies (pipeline depths) of the nine data channels (i.e. all except :attr:`config`) are matched. Equivalent channels (e.g. :attr:`phase1` and :attr:`phase2`) are exactly matched. Channels of different type or functionality (e.g. :attr:`offset` vs :attr:`amplitude1`, DDS vs DUC, :attr:`phase0` vs :attr:`phase1`) are only matched to within one coarse RTIO cycle. :param channel_base: RTIO channel number of the first channel (amplitude). The configuration channel and frequency/phase/amplitude channels are then assumed to be successive channels. :param parallelism: Number of output samples per coarse RTIO clock cycle. :param core_device: Name of the core device that this SAWG is on. """ kernel_invariants = { "channel_base", "core", "parallelism", "amplitude1", "frequency1", "phase1", "amplitude2", "frequency2", "phase2", "frequency0", "phase0", "offset" } def __init__(self, dmgr, channel_base, parallelism, core_device="core"): self.core = dmgr.get(core_device) self.channel_base = channel_base self.parallelism = parallelism width = 16 time_width = 16 cordic_gain = 1.646760258057163 # Cordic(width=16, guard=None).gain head_room = 1.001 self.config = Config(channel_base, self.core, cordic_gain) self.offset = Spline(width, time_width, channel_base + 1, self.core, 2. * head_room) self.amplitude1 = Spline(width, time_width, channel_base + 2, self.core, 2 * head_room * cordic_gain**2) self.frequency1 = Spline(3 * width, time_width, channel_base + 3, self.core, 1 / self.core.coarse_ref_period) self.phase1 = Spline(width, time_width, channel_base + 4, self.core, 1.) self.amplitude2 = Spline(width, time_width, channel_base + 5, self.core, 2 * head_room * cordic_gain**2) self.frequency2 = Spline(3 * width, time_width, channel_base + 6, self.core, 1 / self.core.coarse_ref_period) self.phase2 = Spline(width, time_width, channel_base + 7, self.core, 1.) self.frequency0 = Spline(2 * width, time_width, channel_base + 8, self.core, parallelism / self.core.coarse_ref_period) self.phase0 = Spline(width, time_width, channel_base + 9, self.core, 1.) @kernel def reset(self): """Re-establish initial conditions. This clears all spline interpolators, accumulators and configuration settings. This method advances the timeline by the time required to perform all 7 writes to the configuration channel, plus 9 coarse RTIO cycles. """ self.config.set_div(0, 0) self.config.set_clr(1, 1, 1) self.config.set_iq_en(1, 0) self.config.set_duc_min(-1.) self.config.set_duc_max(1.) self.config.set_out_min(-1.) self.config.set_out_max(1.) self.frequency0.set_mu(0) coarse_cycle = int64(self.core.ref_multiplier) delay_mu(coarse_cycle) self.frequency1.set_mu(0) delay_mu(coarse_cycle) self.frequency2.set_mu(0) delay_mu(coarse_cycle) self.phase0.set_mu(0) delay_mu(coarse_cycle) self.phase1.set_mu(0) delay_mu(coarse_cycle) self.phase2.set_mu(0) delay_mu(coarse_cycle) self.amplitude1.set_mu(0) delay_mu(coarse_cycle) self.amplitude2.set_mu(0) delay_mu(coarse_cycle) self.offset.set_mu(0) delay_mu(coarse_cycle)
class SAWG: """Smart arbitrary waveform generator channel. The channel is parametrized as: :: oscillators = exp(2j*pi*(frequency0*t + phase0))*( amplitude1*exp(2j*pi*(frequency1*t + phase1)) + amplitude2*exp(2j*pi*(frequency2*t + phase2))) output = (offset + i_enable*Re(oscillators) + q_enable*Im(buddy_oscillators)) This parametrization can be viewed as two complex (quadrature) oscillators (``frequency1``/``phase1`` and ``frequency2``/``phase2``) that are executing and sampling at the coarse RTIO frequency. They can represent frequencies within the first Nyquist zone from ``-f_rtio_coarse/2`` to ``f_rtio_coarse/2``. .. note:: The coarse RTIO frequency ``f_rtio_coarse`` is the inverse of ``ref_period*multiplier``. Both are arguments of the ``Core`` device, specified in the device database ``device_db.py``. The sum of their outputs is then interpolated by a factor of :attr:`parallelism` (2, 4, 8 depending on the bitstream) using a finite-impulse-response (FIR) anti-aliasing filter (more accurately a half-band filter). The filter is followed by a configurable saturating limiter. After the limiter, the data is shifted in frequency using a complex digital up-converter (DUC, ``frequency0``/``phase0``) running at :attr:`parallelism` times the coarse RTIO frequency. The first Nyquist zone of the DUC extends from ``-f_rtio_coarse*parallelism/2`` to ``f_rtio_coarse*parallelism/2``. Other Nyquist zones are usable depending on the interpolation/modulation options configured in the DAC. The real/in-phase data after digital up-conversion can be offset using another spline interpolator ``offset``. The ``i_enable``/``q_enable`` switches enable emission of quadrature signals for later analog quadrature mixing distinguishing upper and lower sidebands and thus doubling the bandwidth. They can also be used to emit four-tone signals. .. note:: Quadrature data from the buddy channel is currently ignored in the SAWG gateware and not added to the DAC output. This is equivalent to the ``q_enable`` switch always being ``0``. The configuration channel and the nine :class:`artiq.coredevice.spline.Spline` interpolators are accessible as attributes: * :attr:`config`: :class:`Config` * :attr:`offset`, :attr:`amplitude1`, :attr:`amplitude2`: in units of full scale * :attr:`phase0`, :attr:`phase1`, :attr:`phase2`: in units of turns * :attr:`frequency0`, :attr:`frequency1`, :attr:`frequency2`: in units of Hz .. note:: The latencies (pipeline depths) of the nine data channels (i.e. all except :attr:`config`) are matched. Equivalent channels (e.g. :attr:`phase1` and :attr:`phase2`) are exactly matched. Channels of different type or functionality (e.g. :attr:`offset` vs :attr:`amplitude1`, DDS vs DUC, :attr:`phase0` vs :attr:`phase1`) are only matched to within one coarse RTIO cycle. :param channel_base: RTIO channel number of the first channel (amplitude). The configuration channel and frequency/phase/amplitude channels are then assumed to be successive channels. :param parallelism: Number of output samples per coarse RTIO clock cycle. :param core_device: Name of the core device that this SAWG is on. """ kernel_invariants = {"channel_base", "core", "parallelism", "amplitude1", "frequency1", "phase1", "amplitude2", "frequency2", "phase2", "frequency0", "phase0", "offset"} def __init__(self, dmgr, channel_base, parallelism, core_device="core"): self.core = dmgr.get(core_device) self.channel_base = channel_base self.parallelism = parallelism width = 16 time_width = 16 cordic_gain = 1.646760258057163 # Cordic(width=16, guard=None).gain head_room = 1.001 self.config = Config(channel_base, self.core, cordic_gain) self.offset = Spline(width, time_width, channel_base + 1, self.core, 2.*head_room) self.amplitude1 = Spline(width, time_width, channel_base + 2, self.core, 2*head_room*cordic_gain**2) self.frequency1 = Spline(3*width, time_width, channel_base + 3, self.core, 1/self.core.coarse_ref_period) self.phase1 = Spline(width, time_width, channel_base + 4, self.core, 1.) self.amplitude2 = Spline(width, time_width, channel_base + 5, self.core, 2*head_room*cordic_gain**2) self.frequency2 = Spline(3*width, time_width, channel_base + 6, self.core, 1/self.core.coarse_ref_period) self.phase2 = Spline(width, time_width, channel_base + 7, self.core, 1.) self.frequency0 = Spline(2*width, time_width, channel_base + 8, self.core, parallelism/self.core.coarse_ref_period) self.phase0 = Spline(width, time_width, channel_base + 9, self.core, 1.) @kernel def reset(self): """Re-establish initial conditions. This clears all spline interpolators, accumulators and configuration settings. This method advances the timeline by the time required to perform all seven writes to the configuration channel. """ self.config.set_div(0, 0) self.config.set_clr(1, 1, 1) self.config.set_iq_en(1, 0) self.config.set_duc_min(-1.) self.config.set_duc_max(1.) self.config.set_out_min(-1.) self.config.set_out_max(1.) self.frequency0.set_mu(0) self.frequency1.set_mu(0) self.frequency2.set_mu(0) self.phase0.set_mu(0) self.phase1.set_mu(0) self.phase2.set_mu(0) self.amplitude1.set_mu(0) self.amplitude2.set_mu(0) self.offset.set_mu(0)