vizualizator.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import matplotlib.pyplot as plt
  2. import numpy as np
  3. from typing import List
  4. from ..utils.dataclass import TTLBlock
  5. from ..hardware.constraints import HardwareConstraints
  6. def plot_ttl_timeline(
  7. ttl_blocks: List[TTLBlock],
  8. original_blocks: List[dict],
  9. tick_duration: float = 20e-9
  10. ):
  11. """
  12. Визуализирует TTL timeline + оригинальные сигналы:
  13. RF и ADC отображаются как синусоиды, GRAD как трапеция.
  14. Оригинальные сигналы сдвигаются вправо с учётом начального TTL-блока.
  15. :param ttl_blocks: список TTLBlock объектов (результат Synchronizer)
  16. :param original_blocks: список исходных блоков {"type": [...], "duration": float}
  17. :param tick_duration: длительность одного тика (сек)
  18. """
  19. # === TTL timeline ===
  20. time = 0
  21. ttl_stream = {"RF": [], "SW": [], "ADC": [], "GR": []}
  22. time_stream = []
  23. for block in ttl_blocks:
  24. for _ in range(block.duration):
  25. time_stream.append(time)
  26. ttl_stream["RF"].append(block.RF)
  27. ttl_stream["SW"].append(block.SW)
  28. ttl_stream["ADC"].append(block.ADC)
  29. ttl_stream["GR"].append(block.GR)
  30. time += tick_duration
  31. # === Исходные сигналы (RF, ADC — синус; GRAD — трапеция) ===
  32. signal_plot = {"RF": [], "ADC": [], "GRAD": []}
  33. signal_time = []
  34. t = 0
  35. for block in original_blocks:
  36. duration = block["duration"]
  37. ticks = int(duration / tick_duration)
  38. t_block = np.linspace(t, t + duration, ticks)
  39. # RF синус
  40. if "RF" in block["type"]:
  41. signal_plot["RF"].extend(np.sin(2 * np.pi * 20e6 * t_block)) # 20 кГц
  42. else:
  43. signal_plot["RF"].extend([0] * ticks)
  44. # ADC синус, меньшей амплитудой
  45. if "ADC" in block["type"]:
  46. signal_plot["ADC"].extend(0.5 * np.sin(2 * np.pi * 10e6 * t_block))
  47. else:
  48. signal_plot["ADC"].extend([0] * ticks)
  49. # GRAD — трапеция
  50. if "GRAD" in block["type"]:
  51. ramp_len = ticks // 4
  52. plateau_len = ticks // 2
  53. trapezoid = list(np.linspace(0, 1, ramp_len)) + \
  54. [1] * plateau_len + \
  55. list(np.linspace(1, 0, ticks - ramp_len - plateau_len))
  56. signal_plot["GRAD"].extend(trapezoid)
  57. else:
  58. signal_plot["GRAD"].extend([0] * ticks)
  59. signal_time.extend(t_block)
  60. t += duration
  61. hw = HardwareConstraints()
  62. # === Сдвиг исходных сигналов на START_DELAY ===
  63. start_offset = tick_duration * (
  64. round(hw.START_DELAY / tick_duration) +
  65. max(
  66. round(hw.RF_DELAY / tick_duration),
  67. round(hw.TR_DELAY / tick_duration),
  68. round(hw.GRAD_DELAY / tick_duration)
  69. )
  70. )
  71. adjusted_signal_time = [t + start_offset for t in signal_time]
  72. # === Визуализация ===
  73. plt.figure(figsize=(14, 8))
  74. # TTL сигналы — логика
  75. for i, (label, values) in enumerate(ttl_stream.items()):
  76. plt.step(
  77. [t * 1e3 for t in time_stream],
  78. [v + i * 2 for v in values],
  79. where='post',
  80. label=f"TTL: {label}"
  81. )
  82. # Исходные сигналы (синус/трапеция)
  83. offset_map = {"RF": 8, "ADC": 10, "GRAD": 12}
  84. color_map = {"RF": "blue", "ADC": "purple", "GRAD": "orange"}
  85. for label in signal_plot:
  86. y = np.array(signal_plot[label]) + offset_map[label]
  87. plt.plot(
  88. [t * 1e3 for t in adjusted_signal_time],
  89. y,
  90. label=f"Signal: {label}",
  91. color=color_map[label]
  92. )
  93. # Финальные штрихи
  94. plt.title("TTL Timeline + Original Signal Shapes (с учётом задержек)")
  95. plt.xlabel("Time (mks)")
  96. yticks = [i * 2 for i in range(4)] + list(offset_map.values())
  97. ylabels = list(ttl_stream.keys()) + list(offset_map.keys())
  98. plt.yticks(yticks, ylabels)
  99. plt.grid(True)
  100. plt.legend(loc="upper right")
  101. plt.tight_layout()
  102. plt.show()