Updated view

This commit is contained in:
jupfi 2023-08-28 08:59:39 +02:00
commit 9777ba3570
5 changed files with 566 additions and 111 deletions

View file

@ -1,6 +1,7 @@
import logging import logging
import numpy as np import numpy as np
import json import json
import time
from serial.tools.list_ports import comports from serial.tools.list_ports import comports
from PyQt6.QtTest import QTest from PyQt6.QtTest import QTest
from PyQt6 import QtSerialPort from PyQt6 import QtSerialPort
@ -24,17 +25,41 @@ class AutoTMController(ModuleController):
for device in self.module.model.available_devices: for device in self.module.model.available_devices:
logger.debug("Found device: %s", device) logger.debug("Found device: %s", device)
def connect(self, device: str) -> None: def handle_connection(self, device: str) -> None:
"""Connect to the specified device. """Connect or disconnect to the specified device based on if there already is a connection.
Args: Args:
device (str): The device port to connect to.""" device (str): The device port to connect to.
@TODO: If the user actually want to connect to another device while already connected to one,
this would have to be handled differently. But this doesn't really make sense in the current implementation.
"""
logger.debug("Connecting to device %s", device) logger.debug("Connecting to device %s", device)
# If the user has already connected to a device, close the previous connection
if self.module.model.serial is not None:
if self.module.model.serial.isOpen():
logger.debug("Closing previous connection")
serial = self.module.model.serial
serial.close()
self.module.model.serial = serial
else:
self.open_connection(device)
# This is just for the first time the user connects to the device
else:
self.open_connection(device)
def open_connection(self, device: str) -> None:
"""Open a connection to the specified device.
Args:
device (str): The device port to connect to.
"""
try: try:
self.module.model.serial = QtSerialPort.QSerialPort( serial = QtSerialPort.QSerialPort(
device, baudRate=self.BAUDRATE, readyRead=self.on_ready_read device, baudRate=self.BAUDRATE, readyRead=self.on_ready_read
) )
self.module.model.serial.open(QtSerialPort.QSerialPort.OpenModeFlag.ReadWrite) serial.open(QtSerialPort.QSerialPort.OpenModeFlag.ReadWrite)
self.module.model.serial = serial
logger.debug("Connected to device %s", device) logger.debug("Connected to device %s", device)
except Exception as e: except Exception as e:
@ -77,9 +102,12 @@ class AutoTMController(ModuleController):
return return
if start_frequency < MIN_FREQUENCY or stop_frequency > MAX_FREQUENCY: if start_frequency < MIN_FREQUENCY or stop_frequency > MAX_FREQUENCY:
error = "Could not start frequency sweep. Start and stop frequency must be between %s and %s MHz" % ( error = (
MIN_FREQUENCY / 1e6, "Could not start frequency sweep. Start and stop frequency must be between %s and %s MHz"
MAX_FREQUENCY / 1e6, % (
MIN_FREQUENCY / 1e6,
MAX_FREQUENCY / 1e6,
)
) )
logger.error(error) logger.error(error)
self.module.view.add_info_text(error) self.module.view.add_info_text(error)
@ -92,12 +120,15 @@ class AutoTMController(ModuleController):
stop_frequency, stop_frequency,
frequency_step, frequency_step,
) )
# We create the frequency sweep spinner dialog
self.module.model.clear_data_points()
self.module.view.create_frequency_sweep_spinner_dialog()
# Print the command 'f<start>f<stop>f<step>' to the serial connection # Print the command 'f<start>f<stop>f<step>' to the serial connection
command = "f%sf%sf%s" % (start_frequency, stop_frequency, frequency_step) command = "f%sf%sf%s" % (start_frequency, stop_frequency, frequency_step)
self.send_command(command) self.module.model.frequency_sweep_start = time.time()
confirmation = self.send_command(command)
if confirmation:
# We create the frequency sweep spinner dialog
self.module.model.clear_data_points()
self.module.view.create_frequency_sweep_spinner_dialog()
def on_ready_read(self) -> None: def on_ready_read(self) -> None:
"""This method is called when data is received from the serial connection.""" """This method is called when data is received from the serial connection."""
@ -108,7 +139,10 @@ class AutoTMController(ModuleController):
# logger.debug("Received data: %s", text) # logger.debug("Received data: %s", text)
# If the text starts with 'f' and the frequency sweep spinner is visible we know that the data is a data point # If the text starts with 'f' and the frequency sweep spinner is visible we know that the data is a data point
# then we have the data for the return loss and the phase at a certain frequency # then we have the data for the return loss and the phase at a certain frequency
if text.startswith("f") and self.module.view.frequency_sweep_spinner.isVisible(): if (
text.startswith("f")
and self.module.view.frequency_sweep_spinner.isVisible()
):
text = text[1:].split("r") text = text[1:].split("r")
frequency = float(text[0]) frequency = float(text[0])
return_loss, phase = map(float, text[1].split("p")) return_loss, phase = map(float, text[1].split("p"))
@ -116,24 +150,46 @@ class AutoTMController(ModuleController):
# If the text starts with 'r' and no calibration is active we know that the data is a measurement # If the text starts with 'r' and no calibration is active we know that the data is a measurement
elif text.startswith("r") and self.module.model.active_calibration == None: elif text.startswith("r") and self.module.model.active_calibration == None:
logger.debug("Measurement finished") logger.debug("Measurement finished")
self.module.model.measurement = S11Data(self.module.model.data_points.copy()) self.module.model.measurement = S11Data(
self.module.model.data_points.copy()
)
self.module.view.frequency_sweep_spinner.hide() self.module.view.frequency_sweep_spinner.hide()
self.module.model.frequency_sweep_stop = time.time()
self.module.view.add_info_text(
"Frequency sweep finished in %.2f seconds"
% (
self.module.model.frequency_sweep_stop
- self.module.model.frequency_sweep_start
)
)
# If the text starts with 'r' and a short calibration is active we know that the data is a short calibration # If the text starts with 'r' and a short calibration is active we know that the data is a short calibration
elif text.startswith("r") and self.module.model.active_calibration == "short": elif (
text.startswith("r") and self.module.model.active_calibration == "short"
):
logger.debug("Short calibration finished") logger.debug("Short calibration finished")
self.module.model.short_calibration = S11Data(self.module.model.data_points.copy()) self.module.model.short_calibration = S11Data(
self.module.model.data_points.copy()
)
self.module.model.active_calibration = None self.module.model.active_calibration = None
self.module.view.frequency_sweep_spinner.hide() self.module.view.frequency_sweep_spinner.hide()
# If the text starts with 'r' and an open calibration is active we know that the data is an open calibration # If the text starts with 'r' and an open calibration is active we know that the data is an open calibration
elif text.startswith("r") and self.module.model.active_calibration == "open": elif (
text.startswith("r") and self.module.model.active_calibration == "open"
):
logger.debug("Open calibration finished") logger.debug("Open calibration finished")
self.module.model.open_calibration = S11Data(self.module.model.data_points.copy()) self.module.model.open_calibration = S11Data(
self.module.model.data_points.copy()
)
self.module.model.active_calibration = None self.module.model.active_calibration = None
self.module.view.frequency_sweep_spinner.hide() self.module.view.frequency_sweep_spinner.hide()
# If the text starts with 'r' and a load calibration is active we know that the data is a load calibration # If the text starts with 'r' and a load calibration is active we know that the data is a load calibration
elif text.startswith("r") and self.module.model.active_calibration == "load": elif (
text.startswith("r") and self.module.model.active_calibration == "load"
):
logger.debug("Load calibration finished") logger.debug("Load calibration finished")
self.module.model.load_calibration = S11Data(self.module.model.data_points.copy()) self.module.model.load_calibration = S11Data(
self.module.model.data_points.copy()
)
self.module.model.active_calibration = None self.module.model.active_calibration = None
self.module.view.frequency_sweep_spinner.hide() self.module.view.frequency_sweep_spinner.hide()
# If the text starts with 'i' we know that the data is an info message # If the text starts with 'i' we know that the data is an info message
@ -167,7 +223,9 @@ class AutoTMController(ModuleController):
logger.debug("Starting next voltage sweep: %s", command) logger.debug("Starting next voltage sweep: %s", command)
self.send_command(command) self.send_command(command)
def on_short_calibration(self, start_frequency: float, stop_frequency: float) -> None: def on_short_calibration(
self, start_frequency: float, stop_frequency: float
) -> None:
"""This method is called when the short calibration button is pressed. """This method is called when the short calibration button is pressed.
It starts a frequency sweep in the specified range and then starts a short calibration. It starts a frequency sweep in the specified range and then starts a short calibration.
""" """
@ -175,7 +233,9 @@ class AutoTMController(ModuleController):
self.module.model.init_short_calibration() self.module.model.init_short_calibration()
self.start_frequency_sweep(start_frequency, stop_frequency) self.start_frequency_sweep(start_frequency, stop_frequency)
def on_open_calibration(self, start_frequency: float, stop_frequency: float) -> None: def on_open_calibration(
self, start_frequency: float, stop_frequency: float
) -> None:
"""This method is called when the open calibration button is pressed. """This method is called when the open calibration button is pressed.
It starts a frequency sweep in the specified range and then starts an open calibration. It starts a frequency sweep in the specified range and then starts an open calibration.
""" """
@ -183,7 +243,9 @@ class AutoTMController(ModuleController):
self.module.model.init_open_calibration() self.module.model.init_open_calibration()
self.start_frequency_sweep(start_frequency, stop_frequency) self.start_frequency_sweep(start_frequency, stop_frequency)
def on_load_calibration(self, start_frequency: float, stop_frequency: float) -> None: def on_load_calibration(
self, start_frequency: float, stop_frequency: float
) -> None:
"""This method is called when the load calibration button is pressed. """This method is called when the load calibration button is pressed.
It starts a frequency sweep in the specified range and then loads a calibration. It starts a frequency sweep in the specified range and then loads a calibration.
""" """
@ -205,13 +267,19 @@ class AutoTMController(ModuleController):
logger.debug("Calculating calibration") logger.debug("Calculating calibration")
# First we check if the short and open calibration data points are available # First we check if the short and open calibration data points are available
if self.module.model.short_calibration == None: if self.module.model.short_calibration == None:
logger.error("Could not calculate calibration. No short calibration data points available.") logger.error(
"Could not calculate calibration. No short calibration data points available."
)
return return
if self.module.model.open_calibration == None: if self.module.model.open_calibration == None:
logger.error("Could not calculate calibration. No open calibration data points available.") logger.error(
"Could not calculate calibration. No open calibration data points available."
)
return return
if self.module.model.load_calibration == None: if self.module.model.load_calibration == None:
logger.error("Could not calculate calibration. No load calibration data points available.") logger.error(
"Could not calculate calibration. No load calibration data points available."
)
return return
# Then we calculate the calibration # Then we calculate the calibration
@ -226,7 +294,9 @@ class AutoTMController(ModuleController):
e_00s = [] e_00s = []
e_11s = [] e_11s = []
delta_es = [] delta_es = []
for gamma_s, gamma_o, gamma_l in zip(measured_gamma_short, measured_gamma_open, measured_gamma_load): for gamma_s, gamma_o, gamma_l in zip(
measured_gamma_short, measured_gamma_open, measured_gamma_load
):
# This is the solution from # This is the solution from
A = np.array( A = np.array(
[ [
@ -257,15 +327,21 @@ class AutoTMController(ModuleController):
logger.debug("Exporting calibration") logger.debug("Exporting calibration")
# First we check if the short and open calibration data points are available # First we check if the short and open calibration data points are available
if self.module.model.short_calibration == None: if self.module.model.short_calibration == None:
logger.error("Could not export calibration. No short calibration data points available.") logger.error(
"Could not export calibration. No short calibration data points available."
)
return return
if self.module.model.open_calibration == None: if self.module.model.open_calibration == None:
logger.error("Could not export calibration. No open calibration data points available.") logger.error(
"Could not export calibration. No open calibration data points available."
)
return return
if self.module.model.load_calibration == None: if self.module.model.load_calibration == None:
logger.error("Could not export calibration. No load calibration data points available.") logger.error(
"Could not export calibration. No load calibration data points available."
)
return return
# Then we export the different calibrations as a json file # Then we export the different calibrations as a json file
@ -316,7 +392,9 @@ class AutoTMController(ModuleController):
return return
if tuning_voltage < 0 or matching_voltage < 0: if tuning_voltage < 0 or matching_voltage < 0:
error = "Could not set voltages. Tuning and matching voltage must be positive" error = (
"Could not set voltages. Tuning and matching voltage must be positive"
)
logger.error(error) logger.error(error)
self.module.view.add_info_text(error) self.module.view.add_info_text(error)
return return
@ -332,7 +410,7 @@ class AutoTMController(ModuleController):
tuning_voltage, tuning_voltage,
matching_voltage, matching_voltage,
) )
command = "v%sv%s" % (matching_voltage, tuning_voltage) command = "v%sv%s" % (matching_voltage, tuning_voltage)
self.send_command(command) self.send_command(command)
@ -368,7 +446,12 @@ class AutoTMController(ModuleController):
self.module.view.add_info_text(error) self.module.view.add_info_text(error)
return return
if start_frequency < 0 or stop_frequency < 0 or frequency_step < 0 or voltage_resolution < 0: if (
start_frequency < 0
or stop_frequency < 0
or frequency_step < 0
or voltage_resolution < 0
):
error = "Could not generate LUT. Start frequency, stop frequency, frequency step and voltage resolution must be positive" error = "Could not generate LUT. Start frequency, stop frequency, frequency step and voltage resolution must be positive"
logger.error(error) logger.error(error)
self.module.view.add_info_text(error) self.module.view.add_info_text(error)
@ -395,52 +478,88 @@ class AutoTMController(ModuleController):
) )
# We create the lookup table # We create the lookup table
LUT = LookupTable(start_frequency, stop_frequency, frequency_step, voltage_resolution) LUT = LookupTable(
start_frequency, stop_frequency, frequency_step, voltage_resolution
)
LUT.started_frequency = start_frequency LUT.started_frequency = start_frequency
self.module.model.LUT = LUT self.module.model.LUT = LUT
# We write the first command to the serial connection # We write the first command to the serial connection
command = "s%s" % (start_frequency) command = "s%s" % (start_frequency)
self.send_command(command) confirmation = self.send_command(command)
if not confirmation:
return
def switch_to_preamp(self) -> None: def switch_to_preamp(self) -> None:
""" This method is used to send the command 'cp' to the atm system. This switches the signal pathway of the atm system to 'RX' to 'Preamp'. """This method is used to send the command 'cp' to the atm system. This switches the signal pathway of the atm system to 'RX' to 'Preamp'.
This is the mode for either NQR or NMR measurements or if on wants to check the tuning of the probe coil on a network analyzer. This is the mode for either NQR or NMR measurements or if on wants to check the tuning of the probe coil on a network analyzer.
""" """
logger.debug("Switching to preamp") logger.debug("Switching to preamp")
self.send_command("cp") self.send_command("cp")
def switch_to_atm(self) -> None: def switch_to_atm(self) -> None:
""" This method is used to send the command 'ca' to the atm system. This switches the signal pathway of the atm system to 'RX' to 'ATM. """This method is used to send the command 'ca' to the atm system. This switches the signal pathway of the atm system to 'RX' to 'ATM.
In this state the atm system can be used to measure the reflection coefficient of the probecoils. In this state the atm system can be used to measure the reflection coefficient of the probecoils.
""" """
logger.debug("Switching to atm") logger.debug("Switching to atm")
self.send_command("ca") self.send_command("ca")
def send_command(self, command : str) -> None: def send_command(self, command: str) -> bool:
""" This method is used to send a command to the active serial connection. """This method is used to send a command to the active serial connection.
Args: Args:
command (str): The command that should be send to the atm system. command (str): The command that should be send to the atm system.
Returns:
bool: True if the command was send successfully, False otherwise.
""" """
logger.debug("Sending command %s", command) logger.debug("Sending command %s", command)
timeout = 10000 # ms
if self.module.model.serial is None:
logger.error("Could not send command. No serial connection")
self.module.view.add_error_text(
"Could not send command. No serial connection"
)
return False
if self.module.model.serial.isOpen() == False:
logger.error("Could not send command. Serial connection is not open")
self.module.view.add_error_text(
"Could not send command. Serial connection is not open"
)
return False
try: try:
self.module.model.serial.write(command.encode("utf-8")) self.module.model.serial.write(command.encode("utf-8"))
# Wait for 0.5 seconds # Wait for the confirmation of the command ('c') to be read with a timeout of 1 second
QTest.qWait(500)
# Make sure that the command is being send if not self.module.model.serial.waitForReadyRead(timeout):
QApplication.processEvents() logger.error("Could not send command. Timeout")
except AttributeError: self.module.view.add_error_text("Could not send command. Timeout")
logger.error("Could not send command. No device connected.") return False
self.module.view.add_error_text("Could not send command. No device connected.")
confirmation = self.module.model.serial.readLine().data().decode("utf-8")
logger.debug("Confirmation: %s", confirmation)
if confirmation == "c":
logger.debug("Command send successfully")
return True
else:
logger.error("Could not send command. No confirmation received")
self.module.view.add_error_text(
"Could not send command. No confirmation received"
)
return False
except Exception as e:
logger.error("Could not send command. %s", e)
self.module.view.add_error_text("Could not send command. %s" % e)
def homing(self) -> None: def homing(self) -> None:
""" This method is used to send the command 'h' to the atm system. """This method is used to send the command 'h' to the atm system.
This command is used to home the stepper motors of the atm system. This command is used to home the stepper motors of the atm system.
""" """
logger.debug("Homing") logger.debug("Homing")
self.send_command("h") self.send_command("h")

View file

@ -1,6 +1,7 @@
import cmath import cmath
import numpy as np import numpy as np
import logging import logging
from scipy.signal import find_peaks
from PyQt6.QtCore import pyqtSignal from PyQt6.QtCore import pyqtSignal
from PyQt6.QtSerialPort import QSerialPort from PyQt6.QtSerialPort import QSerialPort
from nqrduck.module.module_model import ModuleModel from nqrduck.module.module_model import ModuleModel
@ -12,7 +13,7 @@ class S11Data:
# Conversion factors - the data is generally sent and received in mV # Conversion factors - the data is generally sent and received in mV
# These values are used to convert the data to dB and degrees # These values are used to convert the data to dB and degrees
CENTER_POINT_MAGNITUDE = 900 # mV CENTER_POINT_MAGNITUDE = 900 # mV
CENTER_POINT_PHASE = 900 # mV CENTER_POINT_PHASE = 0 # mV
MAGNITUDE_SLOPE = 30 # dB/mV MAGNITUDE_SLOPE = 30 # dB/mV
PHASE_SLOPE = 10 # deg/mV PHASE_SLOPE = 10 # deg/mV
@ -32,9 +33,18 @@ class S11Data:
) / self.MAGNITUDE_SLOPE ) / self.MAGNITUDE_SLOPE
@property @property
def phase_deg(self): def phase_deg(self, phase_correction=True):
"""Returns the absolute value of the phase in degrees""" """Returns the absolute value of the phase in degrees
return (self.phase_mv - self.CENTER_POINT_PHASE) / self.PHASE_SLOPE
Keyword Arguments:
phase_correction {bool} -- If True, the phase correction is applied. (default: {False})
"""
phase_deg = (self.phase_mv - self.CENTER_POINT_PHASE) / self.PHASE_SLOPE
if phase_correction:
phase_deg = self.phase_correction(self.frequency, phase_deg)
return phase_deg
@property @property
def phase_rad(self): def phase_rad(self):
@ -51,6 +61,86 @@ class S11Data:
for loss_db, phase_rad in zip(self.return_loss_db, self.phase_rad) for loss_db, phase_rad in zip(self.return_loss_db, self.phase_rad)
] ]
def phase_correction(
self, frequency_data: np.array, phase_data: np.array
) -> np.array:
"""This method fixes the phase sign of the phase data.
The AD8302 can only measure the absolute value of the phase.
Therefore we need to correct the phase sign. This can be done via the slope of the phase.
If the slope is negative, the phase is positive and vice versa.
Args:
frequency_data (np.array): The frequency data.
phase_data (np.array): The phase data.
Returns:
np.array: The corrected phase data.
"""
# First we apply a moving average filter to the phase data
WINDOW_SIZE = 5
phase_data_filtered = (
np.convolve(phase_data, np.ones(WINDOW_SIZE), "same") / WINDOW_SIZE
)
# Fix transient response
phase_data_filtered[: WINDOW_SIZE // 2] = phase_data[: WINDOW_SIZE // 2]
phase_data_filtered[-WINDOW_SIZE // 2 :] = phase_data[-WINDOW_SIZE // 2 :]
# Now we find the peaks and valleys of the data
HEIGHT = 100
distance = len(phase_data_filtered) / 10
peaks, _ = find_peaks(phase_data_filtered, distance=distance, height=HEIGHT)
valleys, _ = find_peaks(
180 - phase_data_filtered, distance=distance, height=HEIGHT
)
# Determine if the first point is a peak or a valley
if phase_data_filtered[0] > phase_data_filtered[1]:
peaks = np.insert(peaks, 0, 0)
else:
valleys = np.insert(valleys, 0, 0)
# Determine if the last point is a peak or a valley
if phase_data_filtered[-1] > phase_data_filtered[-2]:
peaks = np.append(peaks, len(phase_data_filtered) - 1)
else:
valleys = np.append(valleys, len(phase_data_filtered) - 1)
frequency_peaks = frequency_data[peaks]
frequency_valleys = frequency_data[valleys]
# Combine the peaks and valleys
frequency_peaks_valleys = np.sort(
np.concatenate((frequency_peaks, frequency_valleys))
)
peaks_valleys = np.sort(np.concatenate((peaks, valleys)))
# Now we can determine the slope of the phase
# For this we compare the phase of our peaks_valleys array to the next point
# If the phase is increasing, the slope is positive, if it is decreasing, the slope is negative
phase_slope = np.zeros(len(peaks_valleys) - 1)
for i in range(len(peaks_valleys) - 1):
phase_slope[i] = (
phase_data_filtered[peaks_valleys[i + 1]]
- phase_data_filtered[peaks_valleys[i]]
)
# Now we can determine the sign of the phase
# If the slope is negative, the phase is positive and vice versa
phase_sign = np.sign(phase_slope) * -1
# Now we can correct the phase for the different sections
phase_data_corrected = np.zeros(len(phase_data))
for i in range(len(peaks_valleys) - 1):
phase_data_corrected[peaks_valleys[i] : peaks_valleys[i + 1]] = (
phase_data_filtered[peaks_valleys[i] : peaks_valleys[i + 1]]
* phase_sign[i]
)
return phase_data_corrected
def to_json(self): def to_json(self):
return { return {
"frequency": self.frequency.tolist(), "frequency": self.frequency.tolist(),
@ -148,6 +238,7 @@ class AutoTMModel(ModuleModel):
self.data_points = [] self.data_points = []
self.active_calibration = None self.active_calibration = None
self.calibration = None self.calibration = None
self.serial = None
@property @property
def available_devices(self): def available_devices(self):
@ -265,3 +356,21 @@ class AutoTMModel(ModuleModel):
@LUT.setter @LUT.setter
def LUT(self, value): def LUT(self, value):
self._LUT = value self._LUT = value
@property
def frequency_sweep_start(self):
"""The timestamp for when the frequency sweep has been started. This is used for timing of the frequency sweep."""
return self._frequency_sweep_start
@frequency_sweep_start.setter
def frequency_sweep_start(self, value):
self._frequency_sweep_start = value
@property
def frequency_sweep_end(self):
"""The timestamp for when the frequency sweep has been ended. This is used for timing of the frequency sweep."""
return self._frequency_sweep_end
@frequency_sweep_end.setter
def frequency_sweep_end(self, value):
self._frequency_sweep_end = value

View file

@ -97,14 +97,114 @@
<attribute name="title"> <attribute name="title">
<string>Mechanical</string> <string>Mechanical</string>
</attribute> </attribute>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0"> <layout class="QVBoxLayout" name="verticalLayout" stretch="0,1,0">
<item> <item>
<widget class="QPushButton" name="homingButton"> <layout class="QGridLayout" name="gridLayout_4" rowstretch="0,0,0,0,0,0">
<item row="5" column="1">
<widget class="QPushButton" name="homematcherButton">
<property name="text">
<string>Home</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Step Size:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="stepsizeBox">
<property name="minimum">
<number>-1000</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>500</number>
</property>
</widget>
</item>
<item row="2" column="0" colspan="3">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Tuning Stepper:</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="decreasetunerButton">
<property name="text">
<string>-</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="increasetunerButton">
<property name="text">
<string>+</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="3">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Matching Stepper:</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QPushButton" name="decreasematcherButton">
<property name="text">
<string>-</string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QPushButton" name="increasematcherButton">
<property name="text">
<string>+</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="hometunerButton">
<property name="text">
<string>Home</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Stepper Control:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="starpositionButton">
<property name="text"> <property name="text">
<string>Homing</string> <string>Start Position</string>
</property> </property>
</widget> </widget>
</item> </item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="elecTab"> <widget class="QWidget" name="elecTab">
@ -257,7 +357,11 @@
<item> <item>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="1"> <item row="0" column="1">
<widget class="QLineEdit" name="startEdit"/> <widget class="QLineEdit" name="startEdit">
<property name="text">
<string>80</string>
</property>
</widget>
</item> </item>
<item row="1" column="2"> <item row="1" column="2">
<widget class="QLabel" name="label_8"> <widget class="QLabel" name="label_8">
@ -267,7 +371,11 @@
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QLineEdit" name="stopEdit"/> <widget class="QLineEdit" name="stopEdit">
<property name="text">
<string>100</string>
</property>
</widget>
</item> </item>
<item row="0" column="2"> <item row="0" column="2">
<widget class="QLabel" name="label_6"> <widget class="QLabel" name="label_6">

View file

@ -18,6 +18,10 @@ from PyQt6.QtWidgets import (
from PyQt6.QtCore import pyqtSlot, Qt from PyQt6.QtCore import pyqtSlot, Qt
from nqrduck.module.module_view import ModuleView from nqrduck.module.module_view import ModuleView
from nqrduck.contrib.mplwidget import MplWidget from nqrduck.contrib.mplwidget import MplWidget
<<<<<<< HEAD
=======
from nqrduck.assets.icons import Logos
>>>>>>> c21dc155fa5b50d6dce64605a6d86007ea8086c7
from nqrduck.assets.animations import DuckAnimations from nqrduck.assets.animations import DuckAnimations
from .widget import Ui_Form from .widget import Ui_Form
@ -32,8 +36,8 @@ class AutoTMView(ModuleView):
self._ui_form = Ui_Form() self._ui_form = Ui_Form()
self._ui_form.setupUi(self) self._ui_form.setupUi(self)
self.widget = widget self.widget = widget
self.frequency_sweep_spinner = self.FrequencySweepSpinner() self.frequency_sweep_spinner = self.FrequencySweepSpinner(self)
self.frequency_sweep_spinner.hide() self.frequency_sweep_spinner.hide()
# Disable the connectButton while no devices are selected # Disable the connectButton while no devices are selected
@ -43,7 +47,9 @@ class AutoTMView(ModuleView):
self._ui_form.refreshButton.clicked.connect(self.module.controller.find_devices) self._ui_form.refreshButton.clicked.connect(self.module.controller.find_devices)
# Connect the available devices changed signal to the on_available_devices_changed slot # Connect the available devices changed signal to the on_available_devices_changed slot
self.module.model.available_devices_changed.connect(self.on_available_devices_changed) self.module.model.available_devices_changed.connect(
self.on_available_devices_changed
)
# Connect the serial changed signal to the on_serial_changed slot # Connect the serial changed signal to the on_serial_changed slot
self.module.model.serial_changed.connect(self.on_serial_changed) self.module.model.serial_changed.connect(self.on_serial_changed)
@ -79,23 +85,35 @@ class AutoTMView(ModuleView):
) )
# On clicking of the calibration button call the on_calibration_button_clicked method # On clicking of the calibration button call the on_calibration_button_clicked method
self._ui_form.calibrationButton.clicked.connect(self.on_calibration_button_clicked) self._ui_form.calibrationButton.clicked.connect(
self.on_calibration_button_clicked
)
# On clicking of the switchpreampButton call the switch_preamp method # On clicking of the switchpreampButton call the switch_preamp method
self._ui_form.switchpreampButton.clicked.connect(self.module.controller.switch_to_preamp) self._ui_form.switchpreampButton.clicked.connect(
self.module.controller.switch_to_preamp
)
# On clicking of the switchATMButton call the switch_atm method # On clicking of the switchATMButton call the switch_atm method
self._ui_form.switchATMButton.clicked.connect(self.module.controller.switch_to_atm) self._ui_form.switchATMButton.clicked.connect(
self.module.controller.switch_to_atm
)
# On clicking of the homingButton call the homing method # On clicking of the homingButton call the homing method
self._ui_form.homingButton.clicked.connect(self.module.controller.homing) self._ui_form.starpositionButton.clicked.connect(self.module.controller.homing)
# Connect the measurement finished signal to the plot_measurement slot # Connect the measurement finished signal to the plot_measurement slot
self.module.model.measurement_finished.connect(self.plot_measurement) self.module.model.measurement_finished.connect(self.plot_measurement)
# 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
)
# Add button Icons
self._ui_form.startButton.setIcon(Logos.Play_16x16())
self._ui_form.startButton.setIconSize(self._ui_form.startButton.size())
self.init_plot() self.init_plot()
self.init_labels() self.init_labels()
@ -117,7 +135,7 @@ class AutoTMView(ModuleView):
ax.set_xlim(0, 100) ax.set_xlim(0, 100)
ax.set_ylim(-100, 0) ax.set_ylim(-100, 0)
self._ui_form.S11Plot.canvas.draw() self._ui_form.S11Plot.canvas.draw()
self.phase_ax = self._ui_form.S11Plot.canvas.ax.twinx() self.phase_ax = self._ui_form.S11Plot.canvas.ax.twinx()
def on_calibration_button_clicked(self) -> None: def on_calibration_button_clicked(self) -> None:
@ -125,7 +143,7 @@ class AutoTMView(ModuleView):
It opens the calibration window. It opens the calibration window.
""" """
logger.debug("Calibration button clicked") logger.debug("Calibration button clicked")
self.calibration_window = self.CalibrationWindow(self.module) self.calibration_window = self.CalibrationWindow(self.module, self)
self.calibration_window.show() self.calibration_window.show()
@pyqtSlot(list) @pyqtSlot(list)
@ -148,7 +166,7 @@ class AutoTMView(ModuleView):
""" """
logger.debug("Connect button clicked") logger.debug("Connect button clicked")
selected_device = self._ui_form.portBox.currentText() selected_device = self._ui_form.portBox.currentText()
self.module.controller.connect(selected_device) self.module.controller.handle_connection(selected_device)
@pyqtSlot(QSerialPort) @pyqtSlot(QSerialPort)
def on_serial_changed(self, serial: QSerialPort) -> None: def on_serial_changed(self, serial: QSerialPort) -> None:
@ -157,11 +175,16 @@ class AutoTMView(ModuleView):
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: if serial.isOpen():
self._ui_form.connectionLabel.setText(serial.portName()) self._ui_form.connectionLabel.setText(serial.portName())
self.add_info_text("Connected to device %s" % serial.portName()) self.add_info_text("Connected to device %s" % serial.portName())
# Change the connectButton to a disconnectButton
self._ui_form.connectButton.setText("Disconnect")
else: else:
self._ui_form.connectionLabel.setText("Disconnected") self._ui_form.connectionLabel.setText("Disconnected")
self.add_info_text("Disconnected from device")
self._ui_form.connectButton.setText("Connect")
logger.debug("Updated serial connection label") logger.debug("Updated serial connection label")
def plot_measurement(self, data: "S11Data") -> None: def plot_measurement(self, data: "S11Data") -> None:
@ -179,7 +202,7 @@ class AutoTMView(ModuleView):
gamma = data.gamma gamma = data.gamma
self._ui_form.S11Plot.canvas.ax.clear() self._ui_form.S11Plot.canvas.ax.clear()
magnitude_ax = self._ui_form.S11Plot.canvas.ax magnitude_ax = self._ui_form.S11Plot.canvas.ax
magnitude_ax.clear() magnitude_ax.clear()
@ -188,26 +211,27 @@ class AutoTMView(ModuleView):
# Calibration for visualization happens here. # Calibration for visualization happens here.
if self.module.model.calibration is not None: if self.module.model.calibration is not None:
calibration = self.module.model.calibration calibration = self.module.model.calibration
e_00 = calibration[0] e_00 = calibration[0]
e11 = calibration[1] e11 = calibration[1]
delta_e = calibration[2] delta_e = calibration[2]
gamma_corr = [ gamma_corr = [
(data_point - e_00[i]) / (data_point * e11[i] - delta_e[i]) for i, data_point in enumerate(gamma) (data_point - e_00[i]) / (data_point * e11[i] - delta_e[i])
for i, data_point in enumerate(gamma)
]
return_loss_db_corr = [
-20 * cmath.log10(abs(g + 1e-12)) for g in gamma_corr
] ]
return_loss_db_corr = [-20 * cmath.log10(abs(g + 1e-12)) for g in gamma_corr]
magnitude_ax.plot(frequency, return_loss_db_corr, color="red") magnitude_ax.plot(frequency, return_loss_db_corr, color="red")
else: else:
magnitude_ax.plot(frequency, return_loss_db, color="blue") magnitude_ax.plot(frequency, return_loss_db, color="blue")
self.phase_ax.set_ylabel("|Phase (deg)|") self.phase_ax.set_ylabel("|Phase (deg)|")
self.phase_ax.plot(frequency, phase, color="orange", linestyle="--") self.phase_ax.plot(frequency, phase, color="orange", linestyle="--")
self.phase_ax.set_ylim(-180, 180) # self.phase_ax.invert_yaxis()
self.phase_ax.invert_yaxis()
magnitude_ax.set_xlabel("Frequency (MHz)") magnitude_ax.set_xlabel("Frequency (MHz)")
magnitude_ax.set_ylabel("S11 (dB)") magnitude_ax.set_ylabel("S11 (dB)")
@ -234,7 +258,9 @@ class AutoTMView(ModuleView):
text_label = QLabel(text) text_label = QLabel(text)
text_label.setStyleSheet("font-size: 25px;") text_label.setStyleSheet("font-size: 25px;")
self._ui_form.scrollAreaWidgetContents.layout().addWidget(text_label) self._ui_form.scrollAreaWidgetContents.layout().addWidget(text_label)
self._ui_form.scrollArea.verticalScrollBar().setValue(self._ui_form.scrollArea.verticalScrollBar().maximum()) self._ui_form.scrollArea.verticalScrollBar().setValue(
self._ui_form.scrollArea.verticalScrollBar().maximum()
)
def add_error_text(self, text: str) -> None: def add_error_text(self, text: str) -> None:
"""Adds text to the error text box. """Adds text to the error text box.
@ -242,17 +268,30 @@ class AutoTMView(ModuleView):
Args: Args:
text (str): Text to add to the error text box. text (str): Text to add to the error text box.
""" """
message_widget = QWidget()
message_widget.setLayout(QHBoxLayout())
error_icon = QLabel()
error_icon.setPixmap(
Logos.Error_16x16().pixmap(Logos.Error_16x16().availableSizes()[0])
)
# Add a timestamp to the text # Add a timestamp to the text
timestamp = datetime.now().strftime("%H:%M:%S") timestamp = datetime.now().strftime("%H:%M:%S")
text = "[%s] %s ERROR:" % (timestamp, text) text = "[%s] %s" % (timestamp, text)
text_label = QLabel(text) text_label = QLabel(text)
text_label.setStyleSheet("font-size: 25px; color: red;") text_label.setStyleSheet("font-size: 25px; color: red;")
self._ui_form.scrollAreaWidgetContents.layout().addWidget(text_label)
self._ui_form.scrollArea.verticalScrollBar().setValue(self._ui_form.scrollArea.verticalScrollBar().maximum()) message_widget.layout().addWidget(error_icon)
message_widget.layout().addWidget(text_label)
self._ui_form.scrollAreaWidgetContents.layout().addWidget(message_widget)
self._ui_form.scrollArea.verticalScrollBar().setValue(
self._ui_form.scrollArea.verticalScrollBar().maximum()
)
def create_frequency_sweep_spinner_dialog(self) -> None: def create_frequency_sweep_spinner_dialog(self) -> None:
"""Creates a frequency sweep spinner dialog.""" """Creates a frequency sweep spinner dialog."""
self.frequency_sweep_spinner = self.FrequencySweepSpinner() self.frequency_sweep_spinner = self.FrequencySweepSpinner(self)
self.frequency_sweep_spinner.show() self.frequency_sweep_spinner.show()
def view_lut(self) -> None: def view_lut(self) -> None:
@ -264,19 +303,24 @@ class AutoTMView(ModuleView):
class FrequencySweepSpinner(QDialog): class FrequencySweepSpinner(QDialog):
"""This class implements a spinner dialog that is shown during a frequency sweep.""" """This class implements a spinner dialog that is shown during a frequency sweep."""
def __init__(self): def __init__(self, parent=None):
super().__init__() super().__init__(parent)
self.setWindowTitle("Frequency sweep") self.setWindowTitle("Frequency sweep")
self.setModal(True) self.setModal(True)
self.setWindowFlag(Qt.WindowType.FramelessWindowHint) self.setWindowFlag(Qt.WindowType.FramelessWindowHint)
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
<<<<<<< HEAD
self.spinner_movie = DuckAnimations.DuckKick128x128() self.spinner_movie = DuckAnimations.DuckKick128x128()
=======
self.spinner_movie = DuckAnimations.DuckSleep128x128()
>>>>>>> c21dc155fa5b50d6dce64605a6d86007ea8086c7
self.spinner_label = QLabel(self) self.spinner_label = QLabel(self)
self.spinner_label.setMovie(self.spinner_movie) self.spinner_label.setMovie(self.spinner_movie)
self.layout = QVBoxLayout(self) self.layout = QVBoxLayout(self)
self.layout.addWidget(QLabel("Performing frequency sweep..."))
self.layout.addWidget(self.spinner_label) self.layout.addWidget(self.spinner_label)
self.spinner_movie.start() self.spinner_movie.start()
@ -294,13 +338,19 @@ class AutoTMView(ModuleView):
# Create table widget # Create table widget
self.table_widget = QTableWidget() self.table_widget = QTableWidget()
self.table_widget.setColumnCount(3) self.table_widget.setColumnCount(3)
self.table_widget.setHorizontalHeaderLabels(["Frequency (MHz)", "Matching Voltage", "Tuning Voltage"]) self.table_widget.setHorizontalHeaderLabels(
["Frequency (MHz)", "Matching Voltage", "Tuning Voltage"]
)
LUT = self.module.model.LUT LUT = self.module.model.LUT
for row, frequency in enumerate(LUT.data.keys()): for row, frequency in enumerate(LUT.data.keys()):
self.table_widget.insertRow(row) self.table_widget.insertRow(row)
self.table_widget.setItem(row, 0, QTableWidgetItem(str(frequency))) self.table_widget.setItem(row, 0, QTableWidgetItem(str(frequency)))
self.table_widget.setItem(row, 1, QTableWidgetItem(str(LUT.data[frequency][0]))) self.table_widget.setItem(
self.table_widget.setItem(row, 2, QTableWidgetItem(str(LUT.data[frequency][1]))) row, 1, QTableWidgetItem(str(LUT.data[frequency][0]))
)
self.table_widget.setItem(
row, 2, QTableWidgetItem(str(LUT.data[frequency][1]))
)
# Add table widget to main layout # Add table widget to main layout
main_layout.addWidget(self.table_widget) main_layout.addWidget(self.table_widget)
@ -321,11 +371,11 @@ class AutoTMView(ModuleView):
matching_voltage = str(self.module.model.LUT.data[frequency][0]) matching_voltage = str(self.module.model.LUT.data[frequency][0])
self.module.controller.set_voltages(tuning_voltage, matching_voltage) self.module.controller.set_voltages(tuning_voltage, matching_voltage)
class CalibrationWindow(QWidget): class CalibrationWindow(QDialog):
def __init__(self, module, parent=None): def __init__(self, module, parent=None):
super().__init__() super().__init__(parent)
self.module = module
self.setParent(parent) self.setParent(parent)
self.module = module
self.setWindowTitle("Calibration") self.setWindowTitle("Calibration")
# Add vertical main layout # Add vertical main layout
@ -344,6 +394,7 @@ class AutoTMView(ModuleView):
frequency_layout.addWidget(stop_edit) frequency_layout.addWidget(stop_edit)
unit_label = QLabel("MHz") unit_label = QLabel("MHz")
frequency_layout.addWidget(unit_label) frequency_layout.addWidget(unit_label)
frequency_layout.addStretch()
# Add horizontal layout for the calibration type # Add horizontal layout for the calibration type
type_layout = QHBoxLayout() type_layout = QHBoxLayout()
@ -353,7 +404,9 @@ class AutoTMView(ModuleView):
short_layout = QVBoxLayout() short_layout = QVBoxLayout()
short_button = QPushButton("Short") short_button = QPushButton("Short")
short_button.clicked.connect( short_button.clicked.connect(
lambda: self.module.controller.on_short_calibration(start_edit.text(), stop_edit.text()) lambda: self.module.controller.on_short_calibration(
start_edit.text(), stop_edit.text()
)
) )
# Short plot widget # Short plot widget
self.short_plot = MplWidget() self.short_plot = MplWidget()
@ -365,7 +418,9 @@ class AutoTMView(ModuleView):
open_layout = QVBoxLayout() open_layout = QVBoxLayout()
open_button = QPushButton("Open") open_button = QPushButton("Open")
open_button.clicked.connect( open_button.clicked.connect(
lambda: self.module.controller.on_open_calibration(start_edit.text(), stop_edit.text()) lambda: self.module.controller.on_open_calibration(
start_edit.text(), stop_edit.text()
)
) )
# Open plot widget # Open plot widget
self.open_plot = MplWidget() self.open_plot = MplWidget()
@ -377,7 +432,9 @@ class AutoTMView(ModuleView):
load_layout = QVBoxLayout() load_layout = QVBoxLayout()
load_button = QPushButton("Load") load_button = QPushButton("Load")
load_button.clicked.connect( load_button.clicked.connect(
lambda: self.module.controller.on_load_calibration(start_edit.text(), stop_edit.text()) lambda: self.module.controller.on_load_calibration(
start_edit.text(), stop_edit.text()
)
) )
# Load plot widget # Load plot widget
self.load_plot = MplWidget() self.load_plot = MplWidget()
@ -405,9 +462,15 @@ class AutoTMView(ModuleView):
self.setLayout(main_layout) self.setLayout(main_layout)
# Connect the calibration finished signals to the on_calibration_finished slot # Connect the calibration finished signals to the on_calibration_finished slot
self.module.model.short_calibration_finished.connect(self.on_short_calibration_finished) self.module.model.short_calibration_finished.connect(
self.module.model.open_calibration_finished.connect(self.on_open_calibration_finished) self.on_short_calibration_finished
self.module.model.load_calibration_finished.connect(self.on_load_calibration_finished) )
self.module.model.open_calibration_finished.connect(
self.on_open_calibration_finished
)
self.module.model.load_calibration_finished.connect(
self.on_load_calibration_finished
)
def on_short_calibration_finished(self, short_calibration: "S11Data") -> None: def on_short_calibration_finished(self, short_calibration: "S11Data") -> None:
self.on_calibration_finished("short", self.short_plot, short_calibration) self.on_calibration_finished("short", self.short_plot, short_calibration)
@ -418,7 +481,9 @@ class AutoTMView(ModuleView):
def on_load_calibration_finished(self, load_calibration: "S11Data") -> None: def on_load_calibration_finished(self, load_calibration: "S11Data") -> None:
self.on_calibration_finished("load", self.load_plot, load_calibration) self.on_calibration_finished("load", self.load_plot, load_calibration)
def on_calibration_finished(self, type: str, widget: MplWidget, data: "S11Data") -> None: def on_calibration_finished(
self, type: str, widget: MplWidget, data: "S11Data"
) -> None:
"""This method is called when a calibration has finished. """This method is called when a calibration has finished.
It plots the calibration data on the given widget. It plots the calibration data on the given widget.
""" """

View file

@ -62,9 +62,51 @@ class Ui_Form(object):
self.mechTab.setObjectName("mechTab") self.mechTab.setObjectName("mechTab")
self.verticalLayout = QtWidgets.QVBoxLayout(self.mechTab) self.verticalLayout = QtWidgets.QVBoxLayout(self.mechTab)
self.verticalLayout.setObjectName("verticalLayout") self.verticalLayout.setObjectName("verticalLayout")
self.homingButton = QtWidgets.QPushButton(parent=self.mechTab) self.gridLayout_4 = QtWidgets.QGridLayout()
self.homingButton.setObjectName("homingButton") self.gridLayout_4.setObjectName("gridLayout_4")
self.verticalLayout.addWidget(self.homingButton) self.homematcherButton = QtWidgets.QPushButton(parent=self.mechTab)
self.homematcherButton.setObjectName("homematcherButton")
self.gridLayout_4.addWidget(self.homematcherButton, 5, 1, 1, 1)
self.label_17 = QtWidgets.QLabel(parent=self.mechTab)
self.label_17.setObjectName("label_17")
self.gridLayout_4.addWidget(self.label_17, 1, 0, 1, 1)
self.stepsizeBox = QtWidgets.QSpinBox(parent=self.mechTab)
self.stepsizeBox.setMinimum(-1000)
self.stepsizeBox.setMaximum(1000)
self.stepsizeBox.setProperty("value", 500)
self.stepsizeBox.setObjectName("stepsizeBox")
self.gridLayout_4.addWidget(self.stepsizeBox, 1, 1, 1, 1)
self.label_18 = QtWidgets.QLabel(parent=self.mechTab)
self.label_18.setObjectName("label_18")
self.gridLayout_4.addWidget(self.label_18, 2, 0, 1, 3)
self.decreasetunerButton = QtWidgets.QPushButton(parent=self.mechTab)
self.decreasetunerButton.setObjectName("decreasetunerButton")
self.gridLayout_4.addWidget(self.decreasetunerButton, 3, 0, 1, 1)
self.increasetunerButton = QtWidgets.QPushButton(parent=self.mechTab)
self.increasetunerButton.setObjectName("increasetunerButton")
self.gridLayout_4.addWidget(self.increasetunerButton, 3, 2, 1, 1)
self.label_19 = QtWidgets.QLabel(parent=self.mechTab)
self.label_19.setObjectName("label_19")
self.gridLayout_4.addWidget(self.label_19, 4, 0, 1, 3)
self.decreasematcherButton = QtWidgets.QPushButton(parent=self.mechTab)
self.decreasematcherButton.setObjectName("decreasematcherButton")
self.gridLayout_4.addWidget(self.decreasematcherButton, 5, 0, 1, 1)
self.increasematcherButton = QtWidgets.QPushButton(parent=self.mechTab)
self.increasematcherButton.setObjectName("increasematcherButton")
self.gridLayout_4.addWidget(self.increasematcherButton, 5, 2, 1, 1)
self.hometunerButton = QtWidgets.QPushButton(parent=self.mechTab)
self.hometunerButton.setObjectName("hometunerButton")
self.gridLayout_4.addWidget(self.hometunerButton, 3, 1, 1, 1)
self.label_16 = QtWidgets.QLabel(parent=self.mechTab)
self.label_16.setObjectName("label_16")
self.gridLayout_4.addWidget(self.label_16, 0, 0, 1, 3)
self.verticalLayout.addLayout(self.gridLayout_4)
self.starpositionButton = QtWidgets.QPushButton(parent=self.mechTab)
self.starpositionButton.setObjectName("starpositionButton")
self.verticalLayout.addWidget(self.starpositionButton)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.verticalLayout.setStretch(1, 1)
self.typeTab.addTab(self.mechTab, "") self.typeTab.addTab(self.mechTab, "")
self.elecTab = QtWidgets.QWidget() self.elecTab = QtWidgets.QWidget()
self.elecTab.setObjectName("elecTab") self.elecTab.setObjectName("elecTab")
@ -215,7 +257,17 @@ class Ui_Form(object):
self.label_10.setText(_translate("Form", "Connected to:")) self.label_10.setText(_translate("Form", "Connected to:"))
self.connectButton.setText(_translate("Form", "Connect")) self.connectButton.setText(_translate("Form", "Connect"))
self.titletypeLabel.setText(_translate("Form", "T&M Type:")) self.titletypeLabel.setText(_translate("Form", "T&M Type:"))
self.homingButton.setText(_translate("Form", "Homing")) self.homematcherButton.setText(_translate("Form", "Home"))
self.label_17.setText(_translate("Form", "Step Size:"))
self.label_18.setText(_translate("Form", "Tuning Stepper:"))
self.decreasetunerButton.setText(_translate("Form", "-"))
self.increasetunerButton.setText(_translate("Form", "+"))
self.label_19.setText(_translate("Form", "Matching Stepper:"))
self.decreasematcherButton.setText(_translate("Form", "-"))
self.increasematcherButton.setText(_translate("Form", "+"))
self.hometunerButton.setText(_translate("Form", "Home"))
self.label_16.setText(_translate("Form", "Stepper Control:"))
self.starpositionButton.setText(_translate("Form", "Start Position"))
self.typeTab.setTabText(self.typeTab.indexOf(self.mechTab), _translate("Form", "Mechanical")) self.typeTab.setTabText(self.typeTab.indexOf(self.mechTab), _translate("Form", "Mechanical"))
self.label_4.setText(_translate("Form", "Voltage Resolution")) self.label_4.setText(_translate("Form", "Voltage Resolution"))
self.label_2.setText(_translate("Form", "Voltage Tuning")) self.label_2.setText(_translate("Form", "Voltage Tuning"))
@ -233,7 +285,9 @@ class Ui_Form(object):
self.switchATMButton.setText(_translate("Form", "ATM")) self.switchATMButton.setText(_translate("Form", "ATM"))
self.typeTab.setTabText(self.typeTab.indexOf(self.elecTab), _translate("Form", "Electrical")) self.typeTab.setTabText(self.typeTab.indexOf(self.elecTab), _translate("Form", "Electrical"))
self.titlefrequencyLabel.setText(_translate("Form", "Frequency Sweep:")) self.titlefrequencyLabel.setText(_translate("Form", "Frequency Sweep:"))
self.startEdit.setText(_translate("Form", "80"))
self.label_8.setText(_translate("Form", "MHz")) self.label_8.setText(_translate("Form", "MHz"))
self.stopEdit.setText(_translate("Form", "100"))
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:"))