mirror of
https://github.com/nqrduck/nqrduck-autotm.git
synced 2024-11-09 11:40:02 +00:00
Implemented basic measurement of RL.
This commit is contained in:
parent
2cf6219f84
commit
4859763b3c
6 changed files with 105 additions and 22 deletions
|
@ -0,0 +1,5 @@
|
||||||
|
# nqrduck-autotm
|
||||||
|
A module for the [nqrduck](https://github.com/nqrduck/nqrduck) project. This module is used to automatically tune and match mechanical and electrical probes.
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
- The active user needs to be in the correct group to use serial ports. For example 'uucp' in Arch Linux and 'dialout' in Ubuntu.
|
|
@ -1,6 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
import serial
|
|
||||||
from serial.tools.list_ports import comports
|
from serial.tools.list_ports import comports
|
||||||
|
from PyQt6 import QtSerialPort
|
||||||
|
from PyQt5.QtCore import QThread, pyqtSignal, pyqtSlot
|
||||||
from nqrduck.module.module_controller import ModuleController
|
from nqrduck.module.module_controller import ModuleController
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -21,12 +22,33 @@ class AutoTMController(ModuleController):
|
||||||
"""Connect to the specified device. """
|
"""Connect to the specified device. """
|
||||||
logger.debug("Connecting to device %s", device)
|
logger.debug("Connecting to device %s", device)
|
||||||
try:
|
try:
|
||||||
self.module.model.serial = serial.Serial(device, self.BAUDRATE, timeout=0.1)
|
self.module.model.serial = QtSerialPort.QSerialPort(device, baudRate=self.BAUDRATE, readyRead=self.on_ready_read)
|
||||||
|
self.module.model.serial.open(QtSerialPort.QSerialPort.OpenModeFlag.ReadWrite)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
logger.debug("Connected to device %s", device)
|
logger.debug("Connected to device %s", device)
|
||||||
except serial.SerialException as e:
|
except Exception as e:
|
||||||
logger.error("Failed to connect to device %s", device)
|
logger.error("Could not connect to device %s: %s", device, e)
|
||||||
logger.error(e)
|
|
||||||
|
|
||||||
def start_frequency_sweep(self, start_frequency : float, stop_frequency : float) -> None:
|
def start_frequency_sweep(self, start_frequency : float, stop_frequency : float) -> None:
|
||||||
""" This starts a frequency sweep on the device in the specified range."""
|
""" This starts a frequency sweep on the device in the specified range."""
|
||||||
pass
|
logger.debug("Starting frequency sweep from %s to %s", start_frequency, stop_frequency)
|
||||||
|
# Print the command 'f <start> <stop>' to the serial connection
|
||||||
|
command = "f %s %s" % (start_frequency, stop_frequency)
|
||||||
|
self.module.model.serial.write(command.encode('utf-8'))
|
||||||
|
|
||||||
|
def on_ready_read(self) -> None:
|
||||||
|
"""This method is called when data is received from the serial connection. """
|
||||||
|
serial = self.module.model.serial
|
||||||
|
while serial.canReadLine():
|
||||||
|
text = serial.readLine().data().decode()
|
||||||
|
text = text.rstrip('\r\n')
|
||||||
|
logger.debug("Received data: %s", text)
|
||||||
|
if text.startswith("f"):
|
||||||
|
text = text[1:].split("r")
|
||||||
|
frequency = float(text[0])
|
||||||
|
return_loss = float(text[1])
|
||||||
|
self.module.model.add_data_point(frequency, return_loss)
|
||||||
|
else:
|
||||||
|
self.module.view.add_info_text(text)
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
import serial
|
import serial
|
||||||
from PyQt6.QtCore import pyqtSignal
|
from PyQt6.QtCore import pyqtSignal
|
||||||
|
from PyQt6.QtSerialPort import QSerialPort
|
||||||
from nqrduck.module.module_model import ModuleModel
|
from nqrduck.module.module_model import ModuleModel
|
||||||
|
|
||||||
class AutoTMModel(ModuleModel):
|
class AutoTMModel(ModuleModel):
|
||||||
available_devices_changed = pyqtSignal(list)
|
available_devices_changed = pyqtSignal(list)
|
||||||
serial_changed = pyqtSignal(serial.Serial)
|
serial_changed = pyqtSignal(QSerialPort)
|
||||||
|
data_points_changed = pyqtSignal(list)
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, module) -> None:
|
||||||
|
super().__init__(module)
|
||||||
|
self.data_points = []
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available_devices(self):
|
def available_devices(self):
|
||||||
|
@ -23,3 +30,13 @@ class AutoTMModel(ModuleModel):
|
||||||
def serial(self, value):
|
def serial(self, value):
|
||||||
self._serial = value
|
self._serial = value
|
||||||
self.serial_changed.emit(value)
|
self.serial_changed.emit(value)
|
||||||
|
|
||||||
|
def add_data_point(self, frequency : float, return_loss : float) -> None:
|
||||||
|
"""Add a data point to the model. """
|
||||||
|
self.data_points.append((frequency, return_loss))
|
||||||
|
self.data_points_changed.emit(self.data_points)
|
||||||
|
|
||||||
|
def clear_data_points(self) -> None:
|
||||||
|
"""Clear all data points from the model. """
|
||||||
|
self.data_points.clear()
|
||||||
|
self.data_points_changed.emit(self.data_points)
|
||||||
|
|
|
@ -156,12 +156,19 @@
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pushButton_2">
|
<widget class="QPushButton" name="startButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Start Sweep</string>
|
<string>Start Sweep</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Calibrate</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pushButton_3">
|
<widget class="QPushButton" name="pushButton_3">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -193,7 +200,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>273</width>
|
<width>273</width>
|
||||||
<height>229</height>
|
<height>189</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import logging
|
import logging
|
||||||
import serial
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from PyQt6.QtWidgets import QWidget, QLabel, QVBoxLayout
|
from PyQt6.QtSerialPort import QSerialPort
|
||||||
from PyQt6.QtCore import pyqtSlot, Qt
|
from PyQt6.QtWidgets import QWidget, QLabel, QVBoxLayout, QApplication
|
||||||
|
from PyQt6.QtCore import pyqtSlot, Qt
|
||||||
from nqrduck.module.module_view import ModuleView
|
from nqrduck.module.module_view import ModuleView
|
||||||
from .widget import Ui_Form
|
from .widget import Ui_Form
|
||||||
|
|
||||||
|
@ -33,6 +33,15 @@ class AutoTMView(ModuleView):
|
||||||
# On clicking of the connect button call the connect method
|
# On clicking of the connect button call the connect method
|
||||||
self._ui_form.connectButton.clicked.connect(self.on_connect_button_clicked)
|
self._ui_form.connectButton.clicked.connect(self.on_connect_button_clicked)
|
||||||
|
|
||||||
|
# On clicking of the start button call the start_frequency_sweep method
|
||||||
|
self._ui_form.startButton.clicked.connect(lambda: self.module.controller.start_frequency_sweep(
|
||||||
|
float(self._ui_form.startEdit.text()),
|
||||||
|
float(self._ui_form.stopEdit.text())
|
||||||
|
))
|
||||||
|
|
||||||
|
# Connect the data points changed signal to the on_data_points_changed slot
|
||||||
|
self.module.model.data_points_changed.connect(self.on_data_points_changed)
|
||||||
|
|
||||||
# Add a vertical layout to the info box
|
# Add a vertical layout to the info box
|
||||||
self._ui_form.scrollAreaWidgetContents.setLayout(QVBoxLayout())
|
self._ui_form.scrollAreaWidgetContents.setLayout(QVBoxLayout())
|
||||||
self._ui_form.scrollAreaWidgetContents.layout().setAlignment(Qt.AlignmentFlag.AlignTop)
|
self._ui_form.scrollAreaWidgetContents.layout().setAlignment(Qt.AlignmentFlag.AlignTop)
|
||||||
|
@ -81,20 +90,43 @@ class AutoTMView(ModuleView):
|
||||||
selected_device = self._ui_form.portBox.currentText()
|
selected_device = self._ui_form.portBox.currentText()
|
||||||
self.module.controller.connect(selected_device)
|
self.module.controller.connect(selected_device)
|
||||||
|
|
||||||
@pyqtSlot(serial.Serial)
|
@pyqtSlot(QSerialPort)
|
||||||
def on_serial_changed(self, serial : serial.Serial) -> None:
|
def on_serial_changed(self, serial : QSerialPort) -> None:
|
||||||
"""Update the serial 'connectionLabel' according to the current serial connection.
|
"""Update the serial 'connectionLabel' according to the current serial connection.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serial (serial.Serial): The current serial connection."""
|
serial (serial.Serial): The current serial connection."""
|
||||||
logger.debug("Updating serial connection label")
|
logger.debug("Updating serial connection label")
|
||||||
if serial.is_open:
|
if serial.isOpen():
|
||||||
self._ui_form.connectionLabel.setText(serial.port)
|
self._ui_form.connectionLabel.setText(serial.portName())
|
||||||
self.add_info_text("Connected to device %s" % serial.port)
|
self.add_info_text("Connected to device %s" % serial.portName())
|
||||||
else:
|
else:
|
||||||
self._ui_form.connectionLabel.setText("Disconnected")
|
self._ui_form.connectionLabel.setText("Disconnected")
|
||||||
logger.debug("Updated serial connection label")
|
logger.debug("Updated serial connection label")
|
||||||
|
|
||||||
|
@pyqtSlot(list)
|
||||||
|
def on_data_points_changed(self, data_points : list) -> None:
|
||||||
|
"""Update the S11 plot with the current data points.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data_points (list): List of data points to plot.
|
||||||
|
"""
|
||||||
|
x = [data_point[0] for data_point in data_points]
|
||||||
|
y = [data_point[1] for data_point in data_points]
|
||||||
|
ax = self._ui_form.S11Plot.canvas.ax
|
||||||
|
ax.clear()
|
||||||
|
ax.set_xlabel("Frequency (MHz)")
|
||||||
|
ax.set_ylabel("S11 (dB)")
|
||||||
|
ax.set_title("S11")
|
||||||
|
ax.grid(True)
|
||||||
|
ax.plot(x, y)
|
||||||
|
# make the y axis go down instead of up
|
||||||
|
ax.invert_yaxis()
|
||||||
|
self._ui_form.S11Plot.canvas.draw()
|
||||||
|
self._ui_form.S11Plot.canvas.flush_events()
|
||||||
|
# Wait for the signals to be processed before adding the info text
|
||||||
|
QApplication.processEvents()
|
||||||
|
|
||||||
def add_info_text(self, text : str) -> None:
|
def add_info_text(self, text : str) -> None:
|
||||||
""" Adds text to the info text box.
|
""" Adds text to the info text box.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Form implementation generated from reading ui file '../Modules/nqrduck-autotm/src/nqrduck_autotm/resources/autotm_widget.ui'
|
# Form implementation generated from reading ui file '../Modules/nqrduck-autotm/src/nqrduck_autotm/resources/autotm_widget.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.5.2
|
# Created by: PyQt6 UI code generator 6.5.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
@ -91,9 +91,9 @@ class Ui_Form(object):
|
||||||
self.label_5.setObjectName("label_5")
|
self.label_5.setObjectName("label_5")
|
||||||
self.gridLayout.addWidget(self.label_5, 0, 0, 1, 1)
|
self.gridLayout.addWidget(self.label_5, 0, 0, 1, 1)
|
||||||
self.verticalLayout_2.addLayout(self.gridLayout)
|
self.verticalLayout_2.addLayout(self.gridLayout)
|
||||||
self.pushButton_2 = QtWidgets.QPushButton(parent=Form)
|
self.startButton = QtWidgets.QPushButton(parent=Form)
|
||||||
self.pushButton_2.setObjectName("pushButton_2")
|
self.startButton.setObjectName("startButton")
|
||||||
self.verticalLayout_2.addWidget(self.pushButton_2)
|
self.verticalLayout_2.addWidget(self.startButton)
|
||||||
self.pushButton_3 = QtWidgets.QPushButton(parent=Form)
|
self.pushButton_3 = QtWidgets.QPushButton(parent=Form)
|
||||||
self.pushButton_3.setObjectName("pushButton_3")
|
self.pushButton_3.setObjectName("pushButton_3")
|
||||||
self.verticalLayout_2.addWidget(self.pushButton_3)
|
self.verticalLayout_2.addWidget(self.pushButton_3)
|
||||||
|
@ -145,7 +145,7 @@ class Ui_Form(object):
|
||||||
self.label_6.setText(_translate("Form", "MHz"))
|
self.label_6.setText(_translate("Form", "MHz"))
|
||||||
self.label_7.setText(_translate("Form", "Stop Frequency:"))
|
self.label_7.setText(_translate("Form", "Stop Frequency:"))
|
||||||
self.label_5.setText(_translate("Form", "Start Frequency:"))
|
self.label_5.setText(_translate("Form", "Start Frequency:"))
|
||||||
self.pushButton_2.setText(_translate("Form", "Start Sweep"))
|
self.startButton.setText(_translate("Form", "Start Sweep"))
|
||||||
self.pushButton_3.setText(_translate("Form", "T&M Settings"))
|
self.pushButton_3.setText(_translate("Form", "T&M Settings"))
|
||||||
self.titleinfoLabel.setText(_translate("Form", "Info Box:"))
|
self.titleinfoLabel.setText(_translate("Form", "Info Box:"))
|
||||||
from nqrduck.contrib.mplwidget import MplWidget
|
from nqrduck.contrib.mplwidget import MplWidget
|
||||||
|
|
Loading…
Reference in a new issue