Implemented basic measurement of RL.

This commit is contained in:
jupfi 2023-08-07 14:34:41 +02:00
parent 2cf6219f84
commit 4859763b3c
6 changed files with 105 additions and 22 deletions

View file

@ -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.

View file

@ -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)

View file

@ -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)

View file

@ -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>

View file

@ -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.

View file

@ -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