forked from M-Labs/artiq
sawg: kernel support (wip)
This commit is contained in:
parent
74e5013fe5
commit
9221a275cb
|
@ -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)))
|
|
||||||
|
|
|
@ -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}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue