| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- import matplotlib.pyplot as plt
- import numpy as np
- from typing import List
- from ..utils.dataclass import TTLBlock
- from ..hardware.constraints import HardwareConstraints
- def plot_ttl_timeline(
- ttl_blocks: List[TTLBlock],
- original_blocks: List[dict],
- tick_duration: float = 20e-9
- ):
- """
- Визуализирует TTL timeline + оригинальные сигналы:
- RF и ADC отображаются как синусоиды, GRAD как трапеция.
- Оригинальные сигналы сдвигаются вправо с учётом начального TTL-блока.
- :param ttl_blocks: список TTLBlock объектов (результат Synchronizer)
- :param original_blocks: список исходных блоков {"type": [...], "duration": float}
- :param tick_duration: длительность одного тика (сек)
- """
- # === TTL timeline ===
- time = 0
- ttl_stream = {"RF": [], "SW": [], "ADC": [], "GR": []}
- time_stream = []
- for block in ttl_blocks:
- for _ in range(block.duration):
- time_stream.append(time)
- ttl_stream["RF"].append(block.RF)
- ttl_stream["SW"].append(block.SW)
- ttl_stream["ADC"].append(block.ADC)
- ttl_stream["GR"].append(block.GR)
- time += tick_duration
- # === Исходные сигналы (RF, ADC — синус; GRAD — трапеция) ===
- signal_plot = {"RF": [], "ADC": [], "GRAD": []}
- signal_time = []
- t = 0
- for block in original_blocks:
- duration = block["duration"]
- ticks = int(duration / tick_duration)
- t_block = np.linspace(t, t + duration, ticks)
- # RF синус
- if "RF" in block["type"]:
- signal_plot["RF"].extend(np.sin(2 * np.pi * 20e6 * t_block)) # 20 кГц
- else:
- signal_plot["RF"].extend([0] * ticks)
- # ADC синус, меньшей амплитудой
- if "ADC" in block["type"]:
- signal_plot["ADC"].extend(0.5 * np.sin(2 * np.pi * 10e6 * t_block))
- else:
- signal_plot["ADC"].extend([0] * ticks)
- # GRAD — трапеция
- if "GRAD" in block["type"]:
- ramp_len = ticks // 4
- plateau_len = ticks // 2
- trapezoid = list(np.linspace(0, 1, ramp_len)) + \
- [1] * plateau_len + \
- list(np.linspace(1, 0, ticks - ramp_len - plateau_len))
- signal_plot["GRAD"].extend(trapezoid)
- else:
- signal_plot["GRAD"].extend([0] * ticks)
- signal_time.extend(t_block)
- t += duration
- hw = HardwareConstraints()
- # === Сдвиг исходных сигналов на START_DELAY ===
- start_offset = tick_duration * (
- round(hw.START_DELAY / tick_duration) +
- max(
- round(hw.RF_DELAY / tick_duration),
- round(hw.TR_DELAY / tick_duration),
- round(hw.GRAD_DELAY / tick_duration)
- )
- )
- adjusted_signal_time = [t + start_offset for t in signal_time]
- # === Визуализация ===
- plt.figure(figsize=(14, 8))
- # TTL сигналы — логика
- for i, (label, values) in enumerate(ttl_stream.items()):
- plt.step(
- [t * 1e3 for t in time_stream],
- [v + i * 2 for v in values],
- where='post',
- label=f"TTL: {label}"
- )
- # Исходные сигналы (синус/трапеция)
- offset_map = {"RF": 8, "ADC": 10, "GRAD": 12}
- color_map = {"RF": "blue", "ADC": "purple", "GRAD": "orange"}
- for label in signal_plot:
- y = np.array(signal_plot[label]) + offset_map[label]
- plt.plot(
- [t * 1e3 for t in adjusted_signal_time],
- y,
- label=f"Signal: {label}",
- color=color_map[label]
- )
- # Финальные штрихи
- plt.title("TTL Timeline + Original Signal Shapes (с учётом задержек)")
- plt.xlabel("Time (mks)")
- yticks = [i * 2 for i in range(4)] + list(offset_map.values())
- ylabels = list(ttl_stream.keys()) + list(offset_map.keys())
- plt.yticks(yticks, ylabels)
- plt.grid(True)
- plt.legend(loc="upper right")
- plt.tight_layout()
- plt.show()
|