sawg: kernel support (wip)

This commit is contained in:
Robert Jördens 2016-11-20 16:39:53 +01:00
parent 74e5013fe5
commit 9221a275cb
2 changed files with 131 additions and 65 deletions

View File

@ -1,73 +1,139 @@
from artiq.language.core import kernel, now_mu from artiq.language.core import kernel, now_mu, portable
from artiq.coredevice.rtio import rtio_output from artiq.coredevice.rtio import rtio_output, rtio_output_list
from artiq.language.types import TInt32, TFloat from artiq.language.types import TInt32, TInt64, TFloat, TList
class Spline:
kernel_invariants = {"channel", "core", "scale", "width",
"time_width", "time_scale"}
def __init__(self, width, time_width, channel, core_device, scale=1.):
self.core = core_device
self.channel = channel
self.width = width
self.scale = (1 << width) / scale
self.time_width = time_width
self.time_scale = (1 << time_width) / core_device.coarse_ref_period
@portable(flags=["fast-math"])
def to_mu(self, value: TFloat) -> TInt32:
return int(round(value*self.scale))
@portable(flags=["fast-math"])
def from_mu(self, value: TInt32) -> TFloat:
return value/self.scale
@portable(flags=["fast-math"])
def to_mu64(self, value: TFloat) -> TList(TInt32):
v = int(round(value*self.scale), width=64)
return [int(v >> 32, width=32), int(v, width=32)]
@kernel
def set_mu(self, value: TInt32):
"""Set spline value (machine units).
:param value: Spline value in integer machine units.
"""
rtio_output(now_mu(), self.channel, 0, value)
@kernel
def set(self, value: TFloat):
"""Set spline value.
:param value: Spline value relative to full-scale.
"""
rtio_output(now_mu(), self.channel, 0, self.to_mu(value))
@kernel
def set64(self, value: TFloat):
"""Set spline value.
:param value: Spline value relative to full-scale.
"""
rtio_output_list(now_mu(), self.channel, 0, self.to_mu64(value))
@kernel
def set_list_mu(self, value: TList(TInt32)):
"""Set spline raw values.
:param value: Spline packed raw values.
"""
rtio_output_list(now_mu(), self.channel, 0, value)
@portable(flags=["fast-math"])
def coeff_to_mu(self, value: TList(TFloat)) -> TList(TInt32):
l = len(value)
w = l*self.width + (l - 1)*l//2*self.time_width
v = [0] * ((w + 31)//32)
j = 0
for i, vi in enumerate(value):
w = self.width + i*self.time_width
vi = int(round(vi*(self.scale*self.time_scale**i)), width=64)
for k in range(0, w, 16):
wi = (vi >> k) & 0xffff
v[j//2] += wi << (16 * ((j + 1)//2 - j//2))
j += 1
v.append(vi)
return v
@kernel
def set_list(self, value: TList(TFloat)):
"""Set spline coefficients.
:param value: List of floating point spline knot coefficients,
lowest order (constant) coefficient first.
"""
self.set_list_mu(self.coeff_to_mu(value))
class SAWG: class SAWG:
"""Smart arbitrary waveform generator channel. """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))
Where:
* offset, amplitude1, amplitude1: in units of full scale
* phase0, phase1, phase2: in units of turns
* frequency0, frequency1, frequency2: in units of Hz
:param channel_base: RTIO channel number of the first channel (amplitude). :param channel_base: RTIO channel number of the first channel (amplitude).
Frequency and Phase are then assumed to be successive channels. Frequency and Phase are then assumed to be successive channels.
""" """
kernel_invariants = {"amplitude_scale", "frequency_scale", "phase_scale", kernel_invariants = {"channel_base", "core",
"channel_base", "core"} "amplitude1", "frequency1", "phase1",
"amplitude2", "frequency2", "phase2"
"frequency0", "phase0", "offset"}
def __init__(self, dmgr, channel_base, parallelism=4, core_device="core"): def __init__(self, dmgr, channel_base, parallelism, core_device="core"):
self.core = dmgr.get(core_device) self.core = dmgr.get(core_device)
self.channel_base = channel_base self.channel_base = channel_base
width = 16
time_width = 16
cordic_gain = 1.646760258057163 # Cordic(width=16, guard=None).gain cordic_gain = 1.646760258057163 # Cordic(width=16, guard=None).gain
a_width = 16 # cfg: channel_base
f_width = 32 self.offset = Spline(width, time_width, channel_base + 1,
p_width = 16 self.core, 2)
self.amplitude_scale = (1 << a_width) / 2 / cordic_gain self.amplitude1 = Spline(width, time_width, channel_base + 2,
self.phase_scale = 1 << p_width self.core, 2*cordic_gain**2)
self.frequency_scale = ((1 << f_width) * self.core.coarse_ref_period / self.frequency1 = Spline(3*width, time_width, channel_base + 3,
parallelism) self.core, self.core.coarse_ref_period)
self.phase1 = Spline(width, time_width, channel_base + 4,
@kernel self.core, 1.)
def set_amplitude_mu(self, amplitude: TInt32): self.amplitude2 = Spline(width, time_width, channel_base + 5,
"""Set DDS amplitude (machine units). self.core, 2*cordic_gain**2)
self.frequency2 = Spline(3*width, time_width, channel_base + 6,
:param amplitude: DDS amplitude in machine units. self.core, self.core.coarse_ref_period)
""" self.phase2 = Spline(width, time_width, channel_base + 7,
rtio_output(now_mu(), self.channel_base, 0, amplitude) self.core, 1.)
self.frequency0 = Spline(2*width, time_width, channel_base + 8,
@kernel(flags=["fast-math"]) self.core,
def set_amplitude(self, amplitude: TFloat): parallelism/self.core.coarse_ref_period)
"""Set DDS amplitude. self.phase0 = Spline(width, time_width, channel_base + 9,
self.core, 1.)
:param amplitude: DDS amplitude relative to full-scale.
"""
self.set_amplitude_mu(int(round(amplitude*self.amplitude_scale)))
@kernel
def set_frequency_mu(self, frequency: TInt32):
"""Set DDS frequency (machine units).
:param frequency: DDS frequency in machine units.
"""
rtio_output(now_mu(), self.channel_base + 1, 0, frequency)
@kernel(flags=["fast-math"])
def set_frequency(self, frequency: TFloat):
"""Set DDS frequency.
:param frequency: DDS frequency in Hz.
"""
self.set_frequency_mu(int(round(frequency*self.frequency_scale)))
@kernel
def set_phase_mu(self, phase: TInt32):
"""Set DDS phase (machine units).
:param phase: DDS phase in machine units.
"""
rtio_output(now_mu(), self.channel_base + 2, 0, phase)
@kernel(flags=["fast-math"])
def set_phase(self, phase: TFloat):
"""Set DDS phase.
:param phase: DDS phase relative in turns.
"""
self.set_phase_mu(int(round(phase*self.phase_scale)))

View File

@ -12,7 +12,7 @@
"module": "artiq.coredevice.core", "module": "artiq.coredevice.core",
"class": "Core", "class": "Core",
"arguments": { "arguments": {
"ref_period": 5/6, "ref_period": 5e-9/6,
"external_clock": True "external_clock": True
} }
}, },
@ -60,18 +60,18 @@
"type": "local", "type": "local",
"module": "artiq.coredevice.sawg", "module": "artiq.coredevice.sawg",
"class": "SAWG", "class": "SAWG",
"arguments": {"channel_base": 7, "parallelism": 2} "arguments": {"channel_base": 14, "parallelism": 2}
}, },
"sawg2": { "sawg2": {
"type": "local", "type": "local",
"module": "artiq.coredevice.sawg", "module": "artiq.coredevice.sawg",
"class": "SAWG", "class": "SAWG",
"arguments": {"channel_base": 10, "parallelism": 2} "arguments": {"channel_base": 24, "parallelism": 2}
}, },
"sawg3": { "sawg3": {
"type": "local", "type": "local",
"module": "artiq.coredevice.sawg", "module": "artiq.coredevice.sawg",
"class": "SAWG", "class": "SAWG",
"arguments": {"channel_base": 13, "parallelism": 2} "arguments": {"channel_base": 34, "parallelism": 2}
} }
} }