Example #1
0
File: sawg.py Project: JQIamo/artiq
 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.)
Example #2
0
 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.)
Example #3
0
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)
Example #4
0
File: sawg.py Project: JQIamo/artiq
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)