pulse modulation added

This commit is contained in:
Ayzen
2026-09-01 18:09:03 +03:00
parent 4c6292d6aa
commit 62e0430668
9 changed files with 123 additions and 16 deletions
+20
View File
@@ -28,6 +28,7 @@ from laser_control.constants import (
AD9102_PAT_PERIOD_MIN,
AD9102_SAW_STEP_MAX,
AD9102_SAW_STEP_MIN,
AD9102_WAVE_PERIOD_US_MAX,
AD9102_SRAM_AMPLITUDE_MAX,
AD9102_SRAM_AMPLITUDE_MIN,
AD9102_SRAM_HOLD_MAX,
@@ -526,6 +527,25 @@ def _build_wave_tab(owner) -> QWidget:
owner._wave_samples_box.textChanged.connect(owner._on_wave_text_changed)
layout.addWidget(owner._wave_samples_box)
period_row = QWidget()
period_layout = QHBoxLayout(period_row)
period_layout.setContentsMargins(0, 0, 0, 0)
period_layout.setSpacing(8)
period_label = QLabel("Период повторения")
owner._wave_period_us = _int_spinbox(0, AD9102_WAVE_PERIOD_US_MAX, 0, suffix=" мкс")
owner._wave_period_us.setToolTip(
"Период запуска формы. Между повторами выход держит последний отсчёт формы.\n"
"0 - повтор вплотную (как раньше). Для импульса 1 мкс с частотой 1 кГц:\n"
"форма = 150 отсчётов вершины + несколько отсчётов базы, период = 1000 мкс."
)
owner._wave_period_us.valueChanged.connect(owner._on_wave_period_changed)
owner._wave_period_info = QLabel("0 = повтор вплотную, без паузы")
owner._wave_period_info.setObjectName("captionLabel")
period_layout.addWidget(period_label)
period_layout.addWidget(owner._wave_period_us)
period_layout.addWidget(owner._wave_period_info, stretch=1)
layout.addWidget(period_row)
buttons = QWidget()
buttons_layout = QHBoxLayout(buttons)
buttons_layout.setContentsMargins(0, 0, 0, 0)
+26 -3
View File
@@ -22,6 +22,7 @@ from PyQt6.QtWidgets import (
import pyqtgraph as pg
from laser_control.constants import (
AD9102_CLOCK_HZ,
AD9833_MCLK_HZ,
DEFAULT_AD9102_AMPLITUDE,
DEFAULT_AD9102_HOLD_CYCLES,
@@ -67,7 +68,7 @@ class MainWindow(QMainWindow):
request_pulse_ds1809 = pyqtSignal(bool, int, int)
request_set_stm32_dac = pyqtSignal(bool, int)
request_apply_tec_modulation = pyqtSignal(bool, int, int, int)
request_upload_wave = pyqtSignal(object)
request_upload_wave = pyqtSignal(object, int)
request_cancel_wave = pyqtSignal()
request_save_profile = pyqtSignal(object)
request_poll = pyqtSignal()
@@ -359,7 +360,15 @@ class MainWindow(QMainWindow):
except Exception as exc: # noqa: BLE001
self._append_log("ERROR", str(exc))
return
self._dispatch_command(lambda: self.request_upload_wave.emit(samples))
pat_period_us = self._wave_period_us.value()
pattern_us = len(samples) * 1e6 / AD9102_CLOCK_HZ
if pat_period_us and pat_period_us <= pattern_us:
self._append_log(
"WARN",
f"Период {pat_period_us} мкс короче самой формы ({pattern_us:.2f} мкс) - "
"форма будет проигрываться вплотную",
)
self._dispatch_command(lambda: self.request_upload_wave.emit(samples, pat_period_us))
def _on_cancel_waveform(self) -> None:
self._dispatch_command(self.request_cancel_wave.emit)
@@ -387,10 +396,23 @@ class MainWindow(QMainWindow):
return
try:
count = len(self._parse_wave_samples(text))
self._wave_info_label.setText(f"Отсчётов: {count}")
duration_us = count * 1e6 / AD9102_CLOCK_HZ
self._wave_info_label.setText(
f"Отсчётов: {count} (длительность формы {duration_us:.2f} мкс "
f"при клоке {AD9102_CLOCK_HZ / 1e6:.0f} МГц)"
)
except Exception:
self._wave_info_label.setText("Отсчётов: ошибка формата")
def _on_wave_period_changed(self) -> None:
period_us = self._wave_period_us.value()
if period_us == 0:
self._wave_period_info.setText("0 = повтор вплотную, без паузы")
return
self._wave_period_info.setText(
f"= {1e6 / period_us:.1f} Гц частота повторения"
)
def _on_reconnect(self) -> None:
self._append_log("INFO", "Reconnect requested from UI")
self._emit_connect_request()
@@ -728,6 +750,7 @@ class MainWindow(QMainWindow):
f"waveform_saw_step={self._ad9102_saw_step.value()}",
f"waveform_pat_base={self._ad9102_pat_base.value()}",
f"waveform_pat_period={self._ad9102_pat_period.value()}",
f"waveform_custom_period_us={self._wave_period_us.value() if custom_wave_samples else 0}",
f"waveform_sample_count={waveform_sample_count}",
f"waveform_hold_cycles={waveform_hold_cycles}",
f"waveform_amplitude={self._ad9102_amplitude.value()}",
+10 -6
View File
@@ -127,13 +127,13 @@ class ControllerWorker(QObject):
)
)
@pyqtSlot(object)
def upload_ad9102_waveform(self, samples: object) -> None:
@pyqtSlot(object, int)
def upload_ad9102_waveform(self, samples: object, pat_period_us: int) -> None:
"""Upload a custom waveform to AD9102 SRAM."""
self._run_command(
lambda: (
self._ensure_connected(),
self._upload_ad9102_waveform_impl(samples),
self._upload_ad9102_waveform_impl(samples, pat_period_us),
)
)
@@ -298,10 +298,14 @@ class ControllerWorker(QObject):
self.log_message.emit("INFO", f"Profile saved to SD: {profile_name}")
self._emit_status()
def _upload_ad9102_waveform_impl(self, samples: object) -> None:
def _upload_ad9102_waveform_impl(self, samples: object, pat_period_us: int) -> None:
sample_list = list(samples)
self._controller.upload_ad9102_waveform(sample_list)
self.log_message.emit("INFO", f"AD9102 waveform uploaded ({len(sample_list)} samples)")
self._controller.upload_ad9102_waveform(sample_list, pat_period_us)
period_note = f", период {pat_period_us} мкс" if pat_period_us else ""
self.log_message.emit(
"INFO",
f"AD9102 waveform uploaded ({len(sample_list)} samples{period_note})",
)
self._emit_status()
def _cancel_ad9102_waveform_upload_impl(self) -> None: