251 def __init__(self, port: int = DEFAULT_PORT, bind_address: str =
"0.0.0.0"):
253 self.setWindowTitle(
"LC Calibration - Live Plots")
254 self.resize(1400, 800)
263 central = QtWidgets.QWidget()
264 self.setCentralWidget(central)
265 root = QtWidgets.QVBoxLayout(central)
268 top = QtWidgets.QHBoxLayout()
270 self.
status_label.setStyleSheet(
"font-weight: bold; padding: 5px;")
274 btn_settings = QtWidgets.QPushButton(
"Settings")
276 top.addWidget(btn_settings)
278 btn_export = QtWidgets.QPushButton(
"Export CSV")
280 top.addWidget(btn_export)
290 main = QtWidgets.QHBoxLayout()
291 root.addLayout(main, 1)
295 self.
plot.setLabel(
"bottom",
"Time", units=
"s")
296 self.
plot.setLabel(
"left",
"Voltage", units=
"V")
297 self.
plot.showGrid(x=
True, y=
True, alpha=0.3)
298 self.
plot.setTitle(
"LC Calibration - All Connectors")
299 self.
plot.setClipToView(
True)
300 self.
plot.setDownsampling(mode=
"peak")
301 self.
plot.setMouseEnabled(x=
True, y=
True)
303 main.addWidget(self.
plot, 1)
306 right = QtWidgets.QVBoxLayout()
307 main.addLayout(right)
310 right.addWidget(QtWidgets.QLabel(
"Show connectors:"))
313 for conn
in range(1, NUM_LC_CONNECTORS + 1):
314 cb = QtWidgets.QCheckBox(f
"LC {conn}")
316 cb.setChecked(conn
in SENSOR_TO_CONNECTOR)
317 cb.setEnabled(conn
in SENSOR_TO_CONNECTOR)
321 color = LC_COLORS[conn - 1]
322 pen = pg.mkPen(color=color, width=2)
323 self.
curves[conn] = self.
plot.
plot([], [], name=f
"LC {conn}", pen=pen)
326 box = QtWidgets.QGroupBox(
"Statistics")
327 form = QtWidgets.QVBoxLayout(box)
329 self.
lbl_sps = QtWidgets.QLabel(
"Packets/sec: n/a")
332 form.addWidget(self.
_hline())
333 form.addWidget(QtWidgets.QLabel(
"Current voltage:"))
336 for conn
in SENSOR_TO_CONNECTOR:
337 lbl = QtWidgets.QLabel(f
"LC {conn}: n/a")
343 status_box = QtWidgets.QGroupBox(
"Status")
344 status_layout = QtWidgets.QVBoxLayout(status_box)
348 right.addWidget(status_box)
353 self.
t = {conn: deque(maxlen=MAX_POINTS)
for conn
in SENSOR_TO_CONNECTOR}
354 self.
v = {conn: deque(maxlen=MAX_POINTS)
for conn
in SENSOR_TO_CONNECTOR}
406 has_data = any(len(self.
t.get(conn, [])) > 0
for conn
in SENSOR_TO_CONNECTOR)
413 for conn
in SENSOR_TO_CONNECTOR:
414 cb = self.
chk.get(conn)
415 if cb
and cb.isChecked():
416 t_data = self.
t.get(conn, [])
417 v_data = self.
v.get(conn, [])
418 if t_data
and v_data:
419 self.
curves[conn].setData(list(t_data), list(v_data))
421 self.
curves[conn].setData([], [])
423 self.
curves[conn].setData([], [])
427 for conn
in SENSOR_TO_CONNECTOR:
428 if self.
chk[conn].isChecked()
and self.
t.get(conn):
429 latest =
max(latest, self.
t[conn][-1]
if self.
t[conn]
else 0.0)
431 if has_data
and latest > 0:
433 self.
plot.setXRange(xmin,
max(xmin + 1e-3, latest), padding=0)
438 for conn
in SENSOR_TO_CONNECTOR:
439 if self.
chk[conn].isChecked():
440 v_data = self.
v.get(conn, [])
442 values.extend(v_data)
444 vmin, vmax =
min(values),
max(values)
446 pad = 0.1
if vmax == 0
else abs(vmax) * 0.1
447 self.
plot.setYRange(vmin - pad, vmax + pad, padding=0)
451 vmin - 0.1 * rng, vmax + 0.1 * rng, padding=0
456 for conn
in SENSOR_TO_CONNECTOR:
457 v_data = self.
v.get(conn, [])
459 current_v = v_data[-1]
460 self.
per_lc[conn].setText(f
"LC {conn}: {current_v:.6f} V")
462 self.
per_lc[conn].setText(f
"LC {conn}: n/a")
464 for conn
in SENSOR_TO_CONNECTOR:
465 self.
per_lc[conn].setText(f
"LC {conn}: n/a")
485 """Export current data to CSV file"""
486 total_points = sum(len(self.
t[conn])
for conn
in SENSOR_TO_CONNECTOR)
487 if total_points == 0:
488 QtWidgets.QMessageBox.warning(
489 self,
"No Data",
"No data available to export."
496 timestamp = datetime.now().strftime(
"%Y%m%d_%H%M%S")
497 default_filename = f
"lc_calibration_{timestamp}.csv"
499 filename, _ = QtWidgets.QFileDialog.getSaveFileName(
500 self,
"Save CSV File", default_filename,
"CSV Files (*.csv);;All Files (*)"
507 with open(filename,
"w", newline=
"", encoding=
"utf-8")
as csvfile:
508 writer = csv.writer(csvfile)
511 header = [
"Time (s)"]
512 for conn
in SENSOR_TO_CONNECTOR:
513 header.append(f
"LC {conn} (V)")
514 writer.writerow(header)
517 max_points =
max(len(self.
t[conn])
for conn
in SENSOR_TO_CONNECTOR)
520 for i
in range(max_points):
524 if i < len(self.
t[SENSOR_TO_CONNECTOR[0]]):
525 row.append(f
"{self.t[SENSOR_TO_CONNECTOR[0]][i]:.6f}")
530 for conn
in SENSOR_TO_CONNECTOR:
531 if i < len(self.
v[conn]):
532 row.append(f
"{self.v[conn][i]:.6f}")
538 points_per_connector = [len(self.
t[conn])
for conn
in SENSOR_TO_CONNECTOR]
539 QtWidgets.QMessageBox.information(
542 f
"Data exported successfully to:\n{filename}\n\n"
543 f
"Points per connector: {points_per_connector}",
545 except Exception
as e:
546 QtWidgets.QMessageBox.critical(
547 self,
"Export Failed", f
"Failed to export data:\n{str(e)}"