Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d4a5af40a | ||
|
|
0526157bfc | ||
|
|
09e8ade74c | ||
|
|
8d8b409807 | ||
|
|
8f342eebd7 |
+133
-19
@@ -2,6 +2,7 @@
|
||||
|
||||
import sys
|
||||
import math
|
||||
import json
|
||||
import socket
|
||||
import platform
|
||||
|
||||
@@ -14,6 +15,19 @@ from PyQt6.QtCore import Qt
|
||||
import pyqtgraph as pg
|
||||
from PyQt6.QtWidgets import QApplication, QMainWindow
|
||||
|
||||
SETTINGS_LIST = [
|
||||
"dac_dw",
|
||||
"adc_dw",
|
||||
"nmax",
|
||||
"window_size",
|
||||
"packet_size",
|
||||
"adc_clk",
|
||||
"dac_clk",
|
||||
"accum_width",
|
||||
"recv_port",
|
||||
"send_port",
|
||||
]
|
||||
|
||||
|
||||
@dataclass
|
||||
class ReflectometerConfig:
|
||||
@@ -31,7 +45,9 @@ class ReflectometerConfig:
|
||||
pulse_height: int
|
||||
pulse_num: int
|
||||
|
||||
adc_dac_ratio: float = 0.52
|
||||
# adc_dac_ratio: float = 0.52
|
||||
adc_clk: float = 65
|
||||
dac_clk: float = 125
|
||||
socket_timeout_sec: float = 2.0
|
||||
|
||||
|
||||
@@ -46,6 +62,7 @@ class ReflectometerWorker(QObject):
|
||||
self.config = config
|
||||
self._stop_requested = False
|
||||
self._sock = None
|
||||
self.measure_timeout = 1.0
|
||||
|
||||
def stop(self):
|
||||
self._stop_requested = True
|
||||
@@ -64,7 +81,7 @@ class ReflectometerWorker(QObject):
|
||||
|
||||
self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self._sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self._sock.settimeout(self.config.socket_timeout_sec)
|
||||
self._sock.settimeout(self.measure_timeout)
|
||||
self._sock.bind(("0.0.0.0", self.config.recv_port))
|
||||
|
||||
dest = (self.config.ip, self.config.send_port)
|
||||
@@ -108,7 +125,8 @@ class ReflectometerWorker(QObject):
|
||||
output += 0b10001000.to_bytes(1, "little")
|
||||
|
||||
pulse_period_adc = (
|
||||
int(self.config.pulse_period * self.config.adc_dac_ratio)
|
||||
int(self.config.pulse_period *
|
||||
(self.config.adc_clk / self.config.dac_clk))
|
||||
// self.config.window_size
|
||||
) * self.config.window_size
|
||||
|
||||
@@ -126,7 +144,7 @@ class ReflectometerWorker(QObject):
|
||||
def _recv_data(self) -> list[int]:
|
||||
packet_count = math.ceil(
|
||||
(
|
||||
self.config.adc_dac_ratio
|
||||
(self.config.adc_clk / self.config.dac_clk)
|
||||
* self.config.pulse_period
|
||||
/ self.config.window_size
|
||||
* self.config.data_width
|
||||
@@ -135,7 +153,7 @@ class ReflectometerWorker(QObject):
|
||||
)
|
||||
|
||||
expected_length = math.ceil(
|
||||
self.config.adc_dac_ratio
|
||||
(self.config.adc_clk / self.config.dac_clk)
|
||||
* self.config.pulse_period
|
||||
/ self.config.window_size
|
||||
)
|
||||
@@ -227,7 +245,6 @@ class MainWindow(QMainWindow):
|
||||
self.nmax = 4096
|
||||
self.packet_size = 1024
|
||||
self.window_size = 65
|
||||
self.adc_dac_ration = 0.52
|
||||
self.accum_width = 32
|
||||
|
||||
# setup
|
||||
@@ -239,8 +256,6 @@ class MainWindow(QMainWindow):
|
||||
|
||||
self.data = []
|
||||
|
||||
self.adc_dac_ratio = 0.52
|
||||
|
||||
self.measurement_thread = None
|
||||
self.measurement_worker = None
|
||||
|
||||
@@ -250,8 +265,58 @@ class MainWindow(QMainWindow):
|
||||
self.button_start.clicked.connect(self.run_measurement)
|
||||
self.button_graph_autoscale.clicked.connect(self.reset_graph_autoscale)
|
||||
|
||||
# ping utils
|
||||
self.button_save.clicked.connect(self.save_config)
|
||||
self.button_load.clicked.connect(self.load_config)
|
||||
|
||||
# timeout progress bar
|
||||
self.measure_progress_timer = QTimer(self)
|
||||
self.measure_progress_timer.setInterval(50)
|
||||
self.measure_progress_timer.timeout.connect(
|
||||
self.update_measure_progress)
|
||||
|
||||
self.measure_progress_elapsed_ms = 0
|
||||
self.measure_progress_total_ms = 1
|
||||
|
||||
self.progress_measure.setRange(0, 100)
|
||||
self.progress_measure.setValue(0)
|
||||
|
||||
def update_measure_progress(self):
|
||||
self.measure_progress_elapsed_ms += self.measure_progress_timer.interval()
|
||||
|
||||
progress = int(
|
||||
self.measure_progress_elapsed_ms
|
||||
/ self.measure_progress_total_ms
|
||||
* 100
|
||||
)
|
||||
|
||||
self.progress_measure.setValue(min(progress, 100))
|
||||
|
||||
if progress >= 100:
|
||||
self.measure_progress_timer.stop()
|
||||
|
||||
# load/save
|
||||
|
||||
def save_config(self):
|
||||
|
||||
conf = {}
|
||||
for setting in SETTINGS_LIST:
|
||||
conf[setting] = self.__getattribute__(setting)
|
||||
with open(".settings.json", "w") as f:
|
||||
f.write(json.dumps(conf))
|
||||
self.label_save_status.setText("Настройки сохранены")
|
||||
|
||||
def load_config(self):
|
||||
try:
|
||||
with open(".settings.json", 'r') as f:
|
||||
conf = json.loads(f.read())
|
||||
except FileNotFoundError:
|
||||
self.label_save_status.setText("Нет сохранненого .setting.json")
|
||||
return
|
||||
for setting in conf:
|
||||
self.__getattribute__(f"box_{setting}").setValue(conf[setting])
|
||||
self.label_save_status.setText("Настройки загружены")
|
||||
|
||||
# ping utils
|
||||
def check_ping(self):
|
||||
ip = self.line_ip.text().strip()
|
||||
|
||||
@@ -280,14 +345,14 @@ class MainWindow(QMainWindow):
|
||||
|
||||
if system_name == "windows":
|
||||
program = "ping"
|
||||
arguments = ["-n", "1", "-w", "2000", ip]
|
||||
arguments = ["-n", "1", "-w", "1000", ip]
|
||||
else:
|
||||
program = "ping"
|
||||
arguments = ["-c", "1", "-W", "2", ip]
|
||||
arguments = ["-c", "1", "-W", "1", ip]
|
||||
|
||||
self.ping_process.start(program, arguments)
|
||||
# fallback
|
||||
self.ping_timeout_timer.start(2000)
|
||||
self.ping_timeout_timer.start(1000)
|
||||
|
||||
def on_ping_finished(self, exit_code, exit_status):
|
||||
self.ping_timeout_timer.stop()
|
||||
@@ -371,6 +436,7 @@ class MainWindow(QMainWindow):
|
||||
box.setValue(new_value)
|
||||
|
||||
setattr(self, name, new_value)
|
||||
self.recalculate_times()
|
||||
|
||||
slider.valueChanged.connect(update_value)
|
||||
box.valueChanged.connect(update_value)
|
||||
@@ -426,6 +492,22 @@ class MainWindow(QMainWindow):
|
||||
)
|
||||
self.pulse_num = self.box_pulse_num.value()
|
||||
|
||||
def recalculate_times(self):
|
||||
# пересчет показываемых метрик
|
||||
LS = 200000 # ~km/s
|
||||
period_us = (self.pulse_period / self.dac_clk)
|
||||
self.label_meas_time.setText(
|
||||
f"{round(period_us, 1)}мкс / {round(LS * period_us / 10e6, 1)}км")
|
||||
|
||||
self.label_duty.setText(
|
||||
f"{round(self.pulse_width / self.pulse_period * 100, 4)}%")
|
||||
|
||||
self.label_voltage.setText(
|
||||
f"{round((self.pulse_height - 8192) * 10 / 16384, 3)}V")
|
||||
|
||||
self.label_meas_total.setText(
|
||||
f"{round(period_us * self.pulse_num / 10e6, 3)}с")
|
||||
|
||||
# settings
|
||||
|
||||
def setup_global_settings(self):
|
||||
@@ -456,8 +538,13 @@ class MainWindow(QMainWindow):
|
||||
)
|
||||
|
||||
self._bind_spinbox_setting(
|
||||
name="adc_dac_ratio",
|
||||
box=self.box_adc_dac_ratio,
|
||||
name="adc_clk",
|
||||
box=self.box_adc_clk,
|
||||
)
|
||||
|
||||
self._bind_spinbox_setting(
|
||||
name="dac_clk",
|
||||
box=self.box_dac_clk,
|
||||
)
|
||||
|
||||
self._bind_spinbox_setting(
|
||||
@@ -554,7 +641,7 @@ class MainWindow(QMainWindow):
|
||||
def setup_graph(self):
|
||||
self.graph_widget = pg.PlotWidget()
|
||||
self.graph_widget.setLabel("left", "ADC value")
|
||||
self.graph_widget.setLabel("bottom", "Sample")
|
||||
self.graph_widget.setLabel("bottom", "Distance", units="km")
|
||||
self.graph_widget.showGrid(x=True, y=True)
|
||||
|
||||
self.graph_curve = self.graph_widget.plot(
|
||||
@@ -596,10 +683,21 @@ class MainWindow(QMainWindow):
|
||||
config = self.build_reflectometer_config()
|
||||
|
||||
self.data = []
|
||||
self.graph_curve.setData([])
|
||||
|
||||
# self.graph_curve.setData([])
|
||||
|
||||
self.measurement_thread = QThread(self)
|
||||
self.measurement_worker = ReflectometerWorker(config)
|
||||
period_us = (self.pulse_period / self.dac_clk)
|
||||
self.measurement_worker.measure_timeout = period_us * self.pulse_num / 10e6 + 0.2
|
||||
|
||||
self.measure_progress_total_ms = int(
|
||||
self.measurement_worker.measure_timeout * 1000 - 199
|
||||
)
|
||||
self.measure_progress_elapsed_ms = 0
|
||||
|
||||
self.progress_measure.setValue(0)
|
||||
self.measure_progress_timer.start()
|
||||
|
||||
self.measurement_worker.moveToThread(self.measurement_thread)
|
||||
|
||||
@@ -642,7 +740,8 @@ class MainWindow(QMainWindow):
|
||||
pulse_height=self.pulse_height,
|
||||
pulse_num=self.pulse_num,
|
||||
|
||||
adc_dac_ratio=self.adc_dac_ratio,
|
||||
adc_clk=self.adc_clk,
|
||||
dac_clk=self.dac_clk
|
||||
)
|
||||
|
||||
def on_data_received(self, data: list[int]):
|
||||
@@ -664,10 +763,14 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def on_measurement_error(self, message: str):
|
||||
self.set_measurement_status(f"Ошибка: {message}")
|
||||
if self.checkbox_autorestart.isChecked():
|
||||
self.run_measurement()
|
||||
|
||||
def on_measurement_finished(self):
|
||||
self.measurement_worker = None
|
||||
self.measurement_thread = None
|
||||
if self.checkbox_autorestart.isChecked():
|
||||
self.run_measurement()
|
||||
|
||||
def stop_measurement(self):
|
||||
if self.measurement_worker is not None:
|
||||
@@ -681,7 +784,18 @@ class MainWindow(QMainWindow):
|
||||
self.graph_curve.setData([])
|
||||
return
|
||||
|
||||
x = list(range(len(self.data)))
|
||||
LS = 200000 # km/s
|
||||
|
||||
period_us = self.pulse_period / self.dac_clk
|
||||
max_distance_km = LS * period_us / 10e6
|
||||
|
||||
sample_count = len(self.data)
|
||||
|
||||
x = [
|
||||
i * max_distance_km / sample_count
|
||||
for i in range(sample_count)
|
||||
]
|
||||
|
||||
self.graph_curve.setData(x, self.data)
|
||||
|
||||
def update_reference_graph(self):
|
||||
@@ -711,7 +825,7 @@ class MainWindow(QMainWindow):
|
||||
reference = [0] * length
|
||||
|
||||
actual_pulse_width = round(
|
||||
(self.pulse_width * self.adc_dac_ratio) / self.window_size)
|
||||
(self.pulse_width * self.adc_clk / self.dac_clk) / self.window_size)
|
||||
|
||||
reference[0:actual_pulse_width] = [
|
||||
(self.pulse_height / 2 ** (self.dac_dw - self.adc_dw)) - 2 ** (self.adc_dw - 1), ] * (actual_pulse_width - 1)
|
||||
|
||||
+158
-12
@@ -7,11 +7,11 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1023</width>
|
||||
<height>708</height>
|
||||
<height>844</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Reflectometer PREMIUM</string>
|
||||
<string>Reflectometer PRO MAX</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="4,2">
|
||||
@@ -39,9 +39,9 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<y>-32</y>
|
||||
<width>294</width>
|
||||
<height>621</height>
|
||||
<height>762</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
@@ -118,21 +118,37 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="box_adc_dac_ratio">
|
||||
<widget class="QSpinBox" name="box_adc_clk">
|
||||
<property name="suffix">
|
||||
<string> MHz</string>
|
||||
</property>
|
||||
<property name="prefix">
|
||||
<string>ADC:DAC clk ratio: </string>
|
||||
<string>ADC CLK: </string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.200000000000000</double>
|
||||
<number>25</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>3.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
<number>350</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.520000000000000</double>
|
||||
<number>65</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="box_dac_clk">
|
||||
<property name="suffix">
|
||||
<string> MHz</string>
|
||||
</property>
|
||||
<property name="prefix">
|
||||
<string>DAC CLK: </string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>25</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>350</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -292,6 +308,50 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Конфигурация</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_save_status">
|
||||
<property name="text">
|
||||
<string>Можно сохранить или загрузить</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<widget class="QPushButton" name="button_save">
|
||||
<property name="text">
|
||||
<string>Сохранить</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="button_load">
|
||||
<property name="text">
|
||||
<string>Загрузить</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
@@ -353,6 +413,24 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Время измерения:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_meas_time">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="1,1,2">
|
||||
<item>
|
||||
@@ -374,6 +452,24 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_11">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>Скважность:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_duty">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4" stretch="1,1,2">
|
||||
<item>
|
||||
@@ -395,6 +491,24 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>Напряжение:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_voltage">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5" stretch="1,1,2">
|
||||
<item>
|
||||
@@ -423,6 +537,24 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_13">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Суммарное время:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_meas_total">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="button_start">
|
||||
<property name="text">
|
||||
@@ -453,6 +585,20 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progress_measure">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkbox_autorestart">
|
||||
<property name="text">
|
||||
<string>Авто-рестарт</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkbox_draw_reference">
|
||||
<property name="text">
|
||||
|
||||
Reference in New Issue
Block a user