From 720cbb44905b8f23179dc41b6bbdc5c839a38ade Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Wed, 7 Feb 2024 16:44:53 +0800 Subject: [PATCH] comm_analyzer, waveform add ndecimals --- artiq/coredevice/comm_analyzer.py | 44 +++++++++++++++++++---------- artiq/dashboard/waveform.py | 47 ++++++++++++++++++------------- 2 files changed, 56 insertions(+), 35 deletions(-) diff --git a/artiq/coredevice/comm_analyzer.py b/artiq/coredevice/comm_analyzer.py index 61c13348a..be6993bdd 100644 --- a/artiq/coredevice/comm_analyzer.py +++ b/artiq/coredevice/comm_analyzer.py @@ -8,11 +8,15 @@ from enum import Enum import struct import logging import socket +import math logger = logging.getLogger(__name__) +DEFAULT_REF_PERIOD = 1e-9 + + class MessageType(Enum): output = 0b00 input = 0b01 @@ -228,7 +232,7 @@ class VCDManager: def set_timescale_ps(self, timescale): self.out.write("$timescale {}ps $end\n".format(round(timescale))) - def get_channel(self, name, width, ty): + def get_channel(self, name, width, ty, ndecimals=0): code = next(self.codes) self.out.write("$var wire {width} {code} {name} $end\n" .format(name=name, code=code, width=width)) @@ -265,9 +269,9 @@ class WaveformManager: def set_timescale_ps(self, timescale): self.trace["timescale"] = int(timescale) - def get_channel(self, name, width, ty): + def get_channel(self, name, width, ty, ndecimals=0): if ty == WaveformType.LOG: - self.trace["logs"][self.current_scope + name] = (width, ty) + self.trace["logs"][self.current_scope + name] = (width, ty, ndecimals) data = self.trace["data"][self.current_scope + name] = list() channel = WaveformChannel(data, self.current_time) self.channels.append(channel) @@ -318,8 +322,8 @@ class ChannelSignatureManager: self.current_scope = "" self.channels = dict() - def get_channel(self, name, width, ty): - self.channels[self.current_scope + name] = (width, ty) + def get_channel(self, name, width, ty, ndecimals=0): + self.channels[self.current_scope + name] = (width, ty, ndecimals) return None @contextmanager @@ -361,8 +365,9 @@ class TTLClockGenHandler: def __init__(self, manager, name, ref_period): self.name = name self.ref_period = ref_period + ndecimals = max(0, math.ceil(math.log10(2**24 * ref_period))) self.channel_frequency = manager.get_channel( - "ttl_clkgen/" + name, 64, ty=WaveformType.ANALOG) + "ttl_clkgen/" + name, 64, ty=WaveformType.ANALOG, ndecimals=ndecimals) def process_message(self, message): if isinstance(message, OutputMessage): @@ -383,11 +388,17 @@ class DDSHandler: def add_dds_channel(self, name, dds_channel_nr): dds_channel = dict() + frequency_decimals = max(0, math.ceil(math.log10(2**32 / self.sysclk))) + phase_decimals = max(0, math.ceil(math.log10(2**16))) with self.manager.scope("dds", name): dds_channel["vcd_frequency"] = \ - self.manager.get_channel(name + "/frequency", 64, ty=WaveformType.ANALOG) + self.manager.get_channel(name + "/frequency", 64, + ty=WaveformType.ANALOG, + ndecimals=frequency_decimals) dds_channel["vcd_phase"] = \ - self.manager.get_channel(name + "/phase", 64, ty=WaveformType.ANALOG) + self.manager.get_channel(name + "/phase", 64, + ty=WaveformType.ANALOG, + ndecimals=phase_decimals) dds_channel["ftw"] = [None, None] dds_channel["pow"] = None self.dds_channels[dds_channel_nr] = dds_channel @@ -662,8 +673,12 @@ def get_channel_list(devices): manager = ChannelSignatureManager() create_channel_handlers(manager, devices, 1e-9, 3e9, False) manager.get_channel("timestamp", 64, ty=WaveformType.VECTOR) - manager.get_channel("interval", 64, ty=WaveformType.ANALOG) - manager.get_channel("rtio_slack", 64, ty=WaveformType.ANALOG) + ref_period = get_ref_period(devices) + if ref_period is None: + ref_period = DEFAULT_REF_PERIOD + ndecimals = max(0, math.ceil(math.log10(1 / ref_period))) + manager.get_channel("interval", 64, ty=WaveformType.ANALOG, ndecimals=ndecimals) + manager.get_channel("rtio_slack", 64, ty=WaveformType.ANALOG, ndecimals=ndecimals) return manager.channels @@ -685,12 +700,11 @@ def decoded_dump_to_waveform_data(devices, dump, uniform_interval=False): def decoded_dump_to_target(manager, devices, dump, uniform_interval): ref_period = get_ref_period(devices) - if ref_period is not None: - if not uniform_interval: - manager.set_timescale_ps(ref_period*1e12) - else: + if ref_period is None: logger.warning("unable to determine core device ref_period") - ref_period = 1e-9 # guess + ref_period = DEFAULT_REF_PERIOD + if not uniform_interval: + manager.set_timescale_ps(ref_period*1e12) dds_sysclk = get_dds_sysclk(devices) if dds_sysclk is None: logger.warning("unable to determine DDS sysclk") diff --git a/artiq/dashboard/waveform.py b/artiq/dashboard/waveform.py index 831efbac6..a20d65a32 100644 --- a/artiq/dashboard/waveform.py +++ b/artiq/dashboard/waveform.py @@ -122,7 +122,8 @@ class _BackgroundItem(pg.GraphicsWidgetAnchor, pg.GraphicsWidget): class _BaseWaveform(pg.PlotWidget): cursorMove = QtCore.pyqtSignal(float) - def __init__(self, name, width, parent=None, pen="r", stepMode="right", connect="finite"): + def __init__(self, name, width, ndecimals, + parent=None, pen="r", stepMode="right", connect="finite"): pg.PlotWidget.__init__(self, parent=parent, x=None, @@ -138,6 +139,8 @@ class _BaseWaveform(pg.PlotWidget): self.name = name self.width = width + self.ndecimals = ndecimals + self.x_data = [] self.y_data = [] @@ -223,8 +226,8 @@ class _BaseWaveform(pg.PlotWidget): class BitWaveform(_BaseWaveform): - def __init__(self, name, width, parent=None): - _BaseWaveform.__init__(self, name, width, parent) + def __init__(self, name, width, ndecimals, parent=None): + _BaseWaveform.__init__(self, name, width, ndecimals, parent) self._arrows = [] def onDataChange(self, data): @@ -266,8 +269,9 @@ class BitWaveform(_BaseWaveform): class AnalogWaveform(_BaseWaveform): - def __init__(self, name, width, parent=None): - _BaseWaveform.__init__(self, name, width, parent) + def __init__(self, name, width, ndecimals, parent=None): + _BaseWaveform.__init__(self, name, width, ndecimals, parent) + self._format_string = "{:." + str(ndecimals) + "f}" def onDataChange(self, data): _BaseWaveform.onDataChange(self, data) @@ -283,12 +287,15 @@ class AnalogWaveform(_BaseWaveform): def onCursorMove(self, x): _BaseWaveform.onCursorMove(self, x) - self.cursor_label.setText(self.cursor_y) + t = None + if self.cursor_y is not None: + t = self._format_string.format(self.cursor_y) + self.cursor_label.setText(t) class BitVectorWaveform(_BaseWaveform): - def __init__(self, name, width, parent=None): - _BaseWaveform.__init__(self, name, width, parent) + def __init__(self, name, width, ndecimals, parent=None): + _BaseWaveform.__init__(self, name, width, ndecimals, parent) self._labels = [] self._format_string = "{:0=" + str(math.ceil(width / 4)) + "X}" self.view_box.sigTransformChanged.connect(self._update_labels) @@ -345,8 +352,8 @@ class BitVectorWaveform(_BaseWaveform): class LogWaveform(_BaseWaveform): - def __init__(self, name, width, parent=None): - _BaseWaveform.__init__(self, name, width, parent) + def __init__(self, name, width, ndecimals, parent=None): + _BaseWaveform.__init__(self, name, width, ndecimals, parent) self.plot_data_item.opts['pen'] = None self.plot_data_item.opts['symbol'] = 'x' self._labels = [] @@ -454,8 +461,9 @@ class _WaveformView(QtWidgets.QWidget): def onDataChange(self, top, bottom, roles): first = top.row() last = bottom.row() + data_row = self._model.headers.index("data") for i in range(first, last + 1): - data = self._model.data(self._model.index(i, 3)) + data = self._model.data(self._model.index(i, data_row)) self._splitter.widget(i).onDataChange(data) def onInsert(self, parent, first, last): @@ -481,16 +489,15 @@ class _WaveformView(QtWidgets.QWidget): self._splitter.widget(i).onCursorMove(x) def _create_waveform(self, row): - name = self._model.data(self._model.index(row, 0)) - ty = self._model.data(self._model.index(row, 1)) - width = self._model.data(self._model.index(row, 2)) + name, ty, width, ndecimals = ( + self._model.data(self._model.index(row, i)) for i in range(4)) waveform_cls = { WaveformType.BIT: BitWaveform, WaveformType.VECTOR: BitVectorWaveform, WaveformType.ANALOG: AnalogWaveform, WaveformType.LOG: LogWaveform }[ty] - w = waveform_cls(name, width, parent=self._splitter) + w = waveform_cls(name, width, ndecimals, parent=self._splitter) w.setXLink(self._ref_vb) w.setStoppedX(self._stopped_x) w.setTimescale(self._timescale) @@ -516,7 +523,7 @@ class _WaveformView(QtWidgets.QWidget): class _WaveformModel(QtCore.QAbstractTableModel): def __init__(self): self.backing_struct = [] - self.headers = ["name", "type", "width", "data"] + self.headers = ["name", "type", "width", "ndecimals", "data"] QtCore.QAbstractTableModel.__init__(self) def rowCount(self, parent=QtCore.QModelIndex()): @@ -557,11 +564,11 @@ class _WaveformModel(QtCore.QAbstractTableModel): self.endRemoveRows() def export_list(self): - return [[row[0], row[1].value, row[2]] for row in self.backing_struct] + return [[row[0], row[1].value, row[2], row[3]] for row in self.backing_struct] def import_list(self, channel_list): self.clear() - data = [[row[0], WaveformType(row[1]), row[2], []] for row in channel_list] + data = [[row[0], WaveformType(row[1]), row[2], row[3], []] for row in channel_list] self.extend(data) def update_data(self, waveform_data, top, bottom): @@ -669,8 +676,8 @@ class _AddChannelDialog(QtWidgets.QDialog): for select in selection: key = self._model.index_to_key(select) if key is not None: - width, ty = self._model[key].ref - channels.append([key, ty, width, []]) + width, ty, ndecimals = self._model[key].ref + channels.append([key, ty, width, ndecimals, []]) self.accepted.emit(channels) self.close()