artiq/artiq/wavesynth/compute_samples.py

133 lines
3.6 KiB
Python
Raw Normal View History

2015-03-15 23:30:07 +08:00
from copy import copy
from math import cos, pi
class Spline:
def __init__(self):
self.c = [0.0]
2015-03-15 23:30:07 +08:00
def set_coefficients(self, c):
self.c = copy(c)
def next(self):
r = self.c[0]
for i in range(len(self.c) - 1):
self.c[i] += self.c[i + 1]
2015-03-15 23:30:07 +08:00
return r
class SplinePhase:
def __init__(self):
2015-03-15 23:30:07 +08:00
self.c = [0.0]
self.c0 = 0.0
2015-03-15 23:30:07 +08:00
def set_coefficients(self, c):
self.c = self.c[0:1] + c[1:]
2015-03-16 01:05:03 +08:00
self.c0 = c[0]
2015-03-15 23:30:07 +08:00
def clear(self):
self.c[0] = 0.0
2015-03-15 23:30:07 +08:00
def next(self):
r = self.c[0] + self.c0
for i in range(len(self.c) - 1):
self.c[i] = (self.c[i] + self.c[i + 1]) % 1.0
2015-03-15 23:30:07 +08:00
return r
class DDS:
def __init__(self):
self.amplitude = Spline()
self.phase = SplinePhase()
2015-03-15 23:30:07 +08:00
def next(self):
return self.amplitude.next()*cos(2*pi*self.phase.next())
class Wave:
def __init__(self):
self.bias = Spline()
self.dds = DDS()
self.last = 0.
self.silence = False
2015-03-15 23:30:07 +08:00
def next(self):
v = self.bias.next() + self.dds.next()
if not self.silence:
self.last = v
return self.last
2015-03-15 23:30:07 +08:00
2015-03-16 01:05:03 +08:00
class TriggerError(Exception):
pass
class Synthesizer:
def __init__(self, nchannels, program):
self.channels = [Wave() for _ in range(nchannels)]
self.program = program
2015-03-16 01:05:03 +08:00
# line_iter is None: "wait for segment selection" state
# otherwise: iterator on the current position in the segment
self.line_iter = None
def trigger(self, selection=None):
if selection is None:
if self.line_iter is None:
raise TriggerError
else:
if self.line_iter is not None:
raise TriggerError
self.line_iter = iter(self.program[selection])
r = [[] for _ in self.channels]
while True:
line = next(self.line_iter)
if line.get("dac_divider", 1) != 1:
2015-03-16 01:05:03 +08:00
raise NotImplementedError
for channel, channel_data in zip(self.channels,
line["channel_data"]):
if "bias" in channel_data:
channel.bias.set_coefficients(channel_data["bias"]["amplitude"])
2015-03-16 01:05:03 +08:00
if "dds" in channel_data:
channel.dds.amplitude.set_coefficients(
channel_data["dds"]["amplitude"])
if "phase" in channel_data["dds"]:
channel.dds.phase.set_coefficients(
channel_data["dds"]["phase"])
if channel_data["dds"].get("clear", False):
2015-03-16 01:05:03 +08:00
channel.dds.phase.clear()
channel.silence = channel_data.get("silence", False)
2015-03-16 01:05:03 +08:00
for channel, rc in zip(self.channels, r):
for i in range(line["duration"]):
rc.append(channel.next())
if line.get("wait_trigger", False):
2015-03-16 01:05:03 +08:00
return r
if line.get("jump", False):
if not line.get("wait_trigger", False):
raise ValueError("Jumps should be with wait_trigger")
try:
next(self.line_iter)
raise ValueError("Jump in the middle of a frame")
except StopIteration:
pass
2015-03-16 01:05:03 +08:00
self.line_iter = None
return r
2015-03-16 01:05:03 +08:00
def main():
2015-04-05 13:40:27 +08:00
from artiq.test.wavesynth import TestSynthesizer
import cairoplot
t = TestSynthesizer()
t.setUp()
x, y = t.drive()
2015-03-15 23:30:07 +08:00
cairoplot.scatter_plot("plot.png", [x, y])
2015-03-16 01:05:03 +08:00
2015-03-16 01:05:03 +08:00
if __name__ == "__main__":
main()