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 serial
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
logger = logging.getLogger(__name__)
@ -21,12 +22,33 @@ class AutoTMController(ModuleController):
"""Connect to the specified device. """
logger.debug("Connecting to device %s", device)
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)
except serial.SerialException as e:
logger.error("Failed to connect to device %s", device)
logger.error(e)
except Exception as e:
logger.error("Could not connect to device %s: %s", device, e)
def start_frequency_sweep(self, start_frequency : float, stop_frequency : float) -> None:
""" 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
from PyQt6.QtCore import pyqtSignal
from PyQt6.QtSerialPort import QSerialPort
from nqrduck.module.module_model import ModuleModel
class AutoTMModel(ModuleModel):
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
def available_devices(self):
@ -23,3 +30,13 @@ class AutoTMModel(ModuleModel):
def serial(self, value):
self._serial = 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>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<widget class="QPushButton" name="startButton">
<property name="text">
<string>Start Sweep</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Calibrate</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_3">
<property name="text">
@ -193,7 +200,7 @@
<x>0</x>
<y>0</y>
<width>273</width>
<height>229</height>
<height>189</height>
</rect>
</property>
</widget>

View file

@ -1,8 +1,8 @@
import logging
import serial
from datetime import datetime
from PyQt6.QtWidgets import QWidget, QLabel, QVBoxLayout
from PyQt6.QtCore import pyqtSlot, Qt
from PyQt6.QtSerialPort import QSerialPort
from PyQt6.QtWidgets import QWidget, QLabel, QVBoxLayout, QApplication
from PyQt6.QtCore import pyqtSlot, Qt
from nqrduck.module.module_view import ModuleView
from .widget import Ui_Form
@ -33,6 +33,15 @@ class AutoTMView(ModuleView):
# On clicking of the connect button call the connect method
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
self._ui_form.scrollAreaWidgetContents.setLayout(QVBoxLayout())
self._ui_form.scrollAreaWidgetContents.layout().setAlignment(Qt.AlignmentFlag.AlignTop)
@ -81,20 +90,43 @@ class AutoTMView(ModuleView):
selected_device = self._ui_form.portBox.currentText()
self.module.controller.connect(selected_device)
@pyqtSlot(serial.Serial)
def on_serial_changed(self, serial : serial.Serial) -> None:
@pyqtSlot(QSerialPort)
def on_serial_changed(self, serial : QSerialPort) -> None:
"""Update the serial 'connectionLabel' according to the current serial connection.
Args:
serial (serial.Serial): The current serial connection."""
logger.debug("Updating serial connection label")
if serial.is_open:
self._ui_form.connectionLabel.setText(serial.port)
self.add_info_text("Connected to device %s" % serial.port)
if serial.isOpen():
self._ui_form.connectionLabel.setText(serial.portName())
self.add_info_text("Connected to device %s" % serial.portName())
else:
self._ui_form.connectionLabel.setText("Disconnected")
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:
""" 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'
#
# 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
# 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.gridLayout.addWidget(self.label_5, 0, 0, 1, 1)
self.verticalLayout_2.addLayout(self.gridLayout)
self.pushButton_2 = QtWidgets.QPushButton(parent=Form)
self.pushButton_2.setObjectName("pushButton_2")
self.verticalLayout_2.addWidget(self.pushButton_2)
self.startButton = QtWidgets.QPushButton(parent=Form)
self.startButton.setObjectName("startButton")
self.verticalLayout_2.addWidget(self.startButton)
self.pushButton_3 = QtWidgets.QPushButton(parent=Form)
self.pushButton_3.setObjectName("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_7.setText(_translate("Form", "Stop 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.titleinfoLabel.setText(_translate("Form", "Info Box:"))
from nqrduck.contrib.mplwidget import MplWidget