mirror of
https://github.com/nqrduck/nqrduck-autotm.git
synced 2024-11-09 11:40:02 +00:00
Implemented LUT creation for mechanical probe coils.
This commit is contained in:
parent
3046b6c7d5
commit
bdfe4e3e9c
5 changed files with 86 additions and 34 deletions
|
@ -32,6 +32,7 @@ class AutoTMController(ModuleController):
|
||||||
self.module.model.serial_data_received.connect(self.print_info)
|
self.module.model.serial_data_received.connect(self.print_info)
|
||||||
self.module.model.serial_data_received.connect(self.read_position_data)
|
self.module.model.serial_data_received.connect(self.read_position_data)
|
||||||
self.module.model.serial_data_received.connect(self.process_reflection_data)
|
self.module.model.serial_data_received.connect(self.process_reflection_data)
|
||||||
|
self.module.model.serial_data_received.connect(self.process_position_sweep_result)
|
||||||
|
|
||||||
@pyqtSlot(str, object)
|
@pyqtSlot(str, object)
|
||||||
def process_signals(self, key: str, value: object) -> None:
|
def process_signals(self, key: str, value: object) -> None:
|
||||||
|
@ -216,7 +217,7 @@ class AutoTMController(ModuleController):
|
||||||
if text.startswith("v"):
|
if text.startswith("v"):
|
||||||
text = text[1:].split("t")
|
text = text[1:].split("t")
|
||||||
matching_voltage, tuning_voltage = map(float, text)
|
matching_voltage, tuning_voltage = map(float, text)
|
||||||
LUT = self.module.model.LUT
|
LUT = self.module.model.el_lut
|
||||||
logger.debug("Received voltage sweep result: %s %s", matching_voltage, tuning_voltage)
|
logger.debug("Received voltage sweep result: %s %s", matching_voltage, tuning_voltage)
|
||||||
LUT.add_voltages(matching_voltage, tuning_voltage)
|
LUT.add_voltages(matching_voltage, tuning_voltage)
|
||||||
self.continue_or_finish_voltage_sweep(LUT)
|
self.continue_or_finish_voltage_sweep(LUT)
|
||||||
|
@ -265,6 +266,7 @@ class AutoTMController(ModuleController):
|
||||||
LUT (LookupTable): The lookup table that is being generated."""
|
LUT (LookupTable): The lookup table that is being generated."""
|
||||||
logger.debug("Voltage sweep finished")
|
logger.debug("Voltage sweep finished")
|
||||||
self.module.view.el_LUT_spinner.hide()
|
self.module.view.el_LUT_spinner.hide()
|
||||||
|
self.module.model.LUT = LUT
|
||||||
self.module.model.voltage_sweep_stop = time.time()
|
self.module.model.voltage_sweep_stop = time.time()
|
||||||
duration = self.module.model.voltage_sweep_stop - self.module.model.voltage_sweep_start
|
duration = self.module.model.voltage_sweep_stop - self.module.model.voltage_sweep_start
|
||||||
self.module.view.add_info_text(f"Voltage sweep finished in {duration:.2f} seconds")
|
self.module.view.add_info_text(f"Voltage sweep finished in {duration:.2f} seconds")
|
||||||
|
@ -596,7 +598,7 @@ class AutoTMController(ModuleController):
|
||||||
confirmation = self.send_command(command)
|
confirmation = self.send_command(command)
|
||||||
# If the command was send successfully, we set the LUT
|
# If the command was send successfully, we set the LUT
|
||||||
if confirmation:
|
if confirmation:
|
||||||
self.module.model.LUT = LUT
|
self.module.model.el_lut = LUT
|
||||||
self.module.view.create_el_LUT_spinner_dialog()
|
self.module.view.create_el_LUT_spinner_dialog()
|
||||||
|
|
||||||
def switch_to_preamp(self) -> None:
|
def switch_to_preamp(self) -> None:
|
||||||
|
@ -674,6 +676,7 @@ class AutoTMController(ModuleController):
|
||||||
logger.debug("Homing")
|
logger.debug("Homing")
|
||||||
self.send_command("h")
|
self.send_command("h")
|
||||||
self.module.model.tuning_stepper.last_direction = 1
|
self.module.model.tuning_stepper.last_direction = 1
|
||||||
|
self.module.model.matching_stepper.last_direction = 1
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def on_stepper_changed(self, stepper: str) -> None:
|
def on_stepper_changed(self, stepper: str) -> None:
|
||||||
|
@ -711,18 +714,19 @@ class AutoTMController(ModuleController):
|
||||||
"""Send a command to the stepper motor based on the number of steps."""
|
"""Send a command to the stepper motor based on the number of steps."""
|
||||||
# Here we handle backlash of the tuner
|
# Here we handle backlash of the tuner
|
||||||
# Determine the direction of the current steps
|
# Determine the direction of the current steps
|
||||||
|
backlash = 0
|
||||||
current_direction = np.sign(steps) # This will be -1,or 1
|
current_direction = np.sign(steps) # This will be -1,or 1
|
||||||
if stepper.TYPE == "Tuning":
|
if stepper.TYPE == "Tuning":
|
||||||
logger.debug("Stepper last direction: %s", stepper.last_direction)
|
logger.debug("Stepper last direction: %s", stepper.last_direction)
|
||||||
logger.debug("Current direction: %s", current_direction)
|
logger.debug("Current direction: %s", current_direction)
|
||||||
if stepper.last_direction != current_direction:
|
if stepper.last_direction != current_direction:
|
||||||
steps = (abs(steps) + stepper.BACKLASH_STEPS) * current_direction
|
backlash = stepper.BACKLASH_STEPS * current_direction
|
||||||
|
|
||||||
stepper.last_direction = current_direction
|
stepper.last_direction = current_direction
|
||||||
logger.debug("Stepper last direction: %s", stepper.last_direction)
|
logger.debug("Stepper last direction: %s", stepper.last_direction)
|
||||||
|
|
||||||
motor_identifier = stepper.TYPE.lower()[0]
|
motor_identifier = stepper.TYPE.lower()[0]
|
||||||
command = f"m{motor_identifier}{steps}"
|
command = f"m{motor_identifier}{steps},{backlash}"
|
||||||
confirmation = self.send_command(command)
|
confirmation = self.send_command(command)
|
||||||
return confirmation
|
return confirmation
|
||||||
|
|
||||||
|
@ -893,6 +897,8 @@ class AutoTMController(ModuleController):
|
||||||
# Lock GUI
|
# Lock GUI
|
||||||
# self.module.view.create_mech_LUT_spinner_dialog()
|
# self.module.view.create_mech_LUT_spinner_dialog()
|
||||||
|
|
||||||
|
self.module.model.mech_lut = LUT
|
||||||
|
|
||||||
self.start_next_mechTM(LUT)
|
self.start_next_mechTM(LUT)
|
||||||
|
|
||||||
|
|
||||||
|
@ -903,41 +909,62 @@ class AutoTMController(ModuleController):
|
||||||
LUT.started_frequency = next_frequency
|
LUT.started_frequency = next_frequency
|
||||||
logger.debug("Starting next mechanical tuning and matching:")
|
logger.debug("Starting next mechanical tuning and matching:")
|
||||||
|
|
||||||
def get_magnitude(reflection):
|
|
||||||
CENTER_POINT_MAGNITUDE = 900 # mV
|
|
||||||
MAGNITUDE_SLOPE = 30 # dB/mV
|
|
||||||
return (reflection[0] - CENTER_POINT_MAGNITUDE) / MAGNITUDE_SLOPE
|
|
||||||
|
|
||||||
# Now we vary the tuning capacitor position and matching capacitor position
|
# Now we vary the tuning capacitor position and matching capacitor position
|
||||||
# Step size tuner:
|
# Step size tuner:
|
||||||
TUNER_STEP_SIZE = 20
|
TUNER_STEP_SIZE = 20
|
||||||
|
|
||||||
# Step size matcher:
|
# Step size matcher:
|
||||||
MATCHER_STEP_SIZE = 5
|
MATCHER_STEP_SIZE = 50
|
||||||
|
|
||||||
# We read the first reflection
|
TUNING_RANGE = 60
|
||||||
last_reflection = self.read_reflection(next_frequency)
|
MATCHING_RANGE = 500
|
||||||
last_magnitude = get_magnitude(last_reflection)
|
|
||||||
|
|
||||||
# Now we tune and match our probe coil for every frequency
|
tuning_backlash = 45
|
||||||
stepper = self.module.model.tuning_stepper
|
# I'm not sure about this value ...
|
||||||
new_magnitude = 1e6 # Big
|
matching_backlash = 0
|
||||||
|
|
||||||
# Probably also start a frequency sweep (?)
|
# Command for the position sweep: p<frequency in MHz>t<range>,<step size>,<backlash>,<last_direction>m<range>,<step size>,<backlash>,<last_direction>"
|
||||||
|
tuning_last_direction = self.module.model.tuning_stepper.last_direction
|
||||||
|
matching_last_direction = self.module.model.matching_stepper.last_direction
|
||||||
|
command = f"p{next_frequency}t{TUNING_RANGE},{TUNER_STEP_SIZE},{tuning_backlash},{tuning_last_direction}m{MATCHING_RANGE},{MATCHER_STEP_SIZE},{matching_backlash},{matching_last_direction}"
|
||||||
|
|
||||||
while new_magnitude > last_magnitude:
|
confirmation = self.send_command(command)
|
||||||
# We move the stepper
|
|
||||||
last_magnitude = new_magnitude
|
|
||||||
|
|
||||||
self.on_relative_move(TUNER_STEP_SIZE, stepper)
|
@pyqtSlot(str)
|
||||||
|
def process_position_sweep_result(self, text):
|
||||||
|
if text.startswith("z"):
|
||||||
|
text = text[1:]
|
||||||
|
# Format is z<tuning_position>,<tuning_last_direction>m<matching_position>,<matching_last_direction>
|
||||||
|
text = text.split("m")
|
||||||
|
tuning_position, tuning_last_direction = map(int, text[0].split(","))
|
||||||
|
matching_position, matching_last_direction = map(int, text[1].split(","))
|
||||||
|
|
||||||
# We read the reflection
|
# Keep backlash compensation consistent
|
||||||
new_magnitude = get_magnitude(self.read_reflection(next_frequency))
|
self.module.model.tuning_stepper.last_direction = tuning_last_direction
|
||||||
|
self.module.model.matching_stepper.last_direction = matching_last_direction
|
||||||
|
|
||||||
# We move the stepper back
|
logger.debug("Tuning position: %s, Matching position: %s", tuning_position, matching_position)
|
||||||
self.on_relative_move(-TUNER_STEP_SIZE, stepper)
|
|
||||||
logger.debug("Tuning capacitor position: %s", stepper.position)
|
|
||||||
|
|
||||||
|
LUT = self.module.model.mech_lut
|
||||||
|
logger.debug("Received position sweep result: %s %s", matching_position, tuning_position)
|
||||||
|
LUT.add_positions(tuning_position, matching_position)
|
||||||
|
self.continue_or_finish_position_sweep(LUT)
|
||||||
|
|
||||||
|
def continue_or_finish_position_sweep(self, LUT):
|
||||||
|
"""Continue or finish the position sweep."""
|
||||||
|
if LUT.is_incomplete():
|
||||||
|
self.start_next_mechTM(LUT)
|
||||||
|
else:
|
||||||
|
self.finish_position_sweep(LUT)
|
||||||
|
|
||||||
|
def finish_position_sweep(self, LUT):
|
||||||
|
"""Finish the position sweep."""
|
||||||
|
logger.debug("Finished position sweep")
|
||||||
|
self.module.model.mech_lut = LUT
|
||||||
|
self.module.model.LUT = LUT
|
||||||
|
# self.module.view.create_mech_LUT_spinner_dialog()
|
||||||
|
|
||||||
|
|
||||||
|
# This method isn't used anymore but it might be useful in the future so I'll keep it here
|
||||||
def read_reflection(self, frequency) -> tuple:
|
def read_reflection(self, frequency) -> tuple:
|
||||||
"""Starts a reflection measurement and reads the reflection at the specified frequency."""
|
"""Starts a reflection measurement and reads the reflection at the specified frequency."""
|
||||||
# We send the command to the atm system
|
# We send the command to the atm system
|
||||||
|
|
|
@ -224,6 +224,10 @@ class MatchingStepper(Stepper):
|
||||||
TYPE = "Matching"
|
TYPE = "Matching"
|
||||||
MAX_STEPS = 1e6
|
MAX_STEPS = 1e6
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.last_direction = None
|
||||||
|
|
||||||
class ElectricalLookupTable(LookupTable):
|
class ElectricalLookupTable(LookupTable):
|
||||||
TYPE = "Electrical"
|
TYPE = "Electrical"
|
||||||
|
|
||||||
|
@ -380,6 +384,8 @@ class AutoTMModel(ModuleModel):
|
||||||
|
|
||||||
self.el_lut = None
|
self.el_lut = None
|
||||||
self.mech_lut = None
|
self.mech_lut = None
|
||||||
|
self.LUT = None
|
||||||
|
|
||||||
self.last_reflection = None
|
self.last_reflection = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -236,7 +236,7 @@
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<number>50000</number>
|
<number>1000000</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="value">
|
<property name="value">
|
||||||
<number>500</number>
|
<number>500</number>
|
||||||
|
|
|
@ -85,6 +85,8 @@ class AutoTMView(ModuleView):
|
||||||
# On clicking of the viewLUTButton call the view_lut method
|
# On clicking of the viewLUTButton call the view_lut method
|
||||||
self._ui_form.viewelLUTButton.clicked.connect(self.view_el_lut)
|
self._ui_form.viewelLUTButton.clicked.connect(self.view_el_lut)
|
||||||
|
|
||||||
|
self._ui_form.viewmechLUTButton.clicked.connect(self.view_mech_lut)
|
||||||
|
|
||||||
# On clicking of the setvoltagesButton call the set_voltages method
|
# On clicking of the setvoltagesButton call the set_voltages method
|
||||||
self._ui_form.setvoltagesButton.clicked.connect(
|
self._ui_form.setvoltagesButton.clicked.connect(
|
||||||
lambda: self.module.controller.set_voltages(
|
lambda: self.module.controller.set_voltages(
|
||||||
|
@ -372,6 +374,16 @@ class AutoTMView(ModuleView):
|
||||||
self.lut_window = self.LutWindow(self.module)
|
self.lut_window = self.LutWindow(self.module)
|
||||||
self.lut_window.show()
|
self.lut_window.show()
|
||||||
|
|
||||||
|
def view_mech_lut(self) -> None:
|
||||||
|
"""Creates a new Dialog that shows the currently active mechanical LUT."""
|
||||||
|
logger.debug("View mechanical LUT")
|
||||||
|
if self.module.model.mech_lut is None:
|
||||||
|
logger.debug("No LUT available")
|
||||||
|
self.add_error_text("No LUT available")
|
||||||
|
return
|
||||||
|
self.lut_window = self.LutWindow(self.module)
|
||||||
|
self.lut_window.show()
|
||||||
|
|
||||||
class StepperSavedPositionsWindow(QDialog):
|
class StepperSavedPositionsWindow(QDialog):
|
||||||
def __init__(self, module, parent=None):
|
def __init__(self, module, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
@ -576,13 +588,20 @@ class AutoTMView(ModuleView):
|
||||||
# Add vertical main layout
|
# Add vertical main layout
|
||||||
main_layout = QVBoxLayout()
|
main_layout = QVBoxLayout()
|
||||||
|
|
||||||
|
LUT = self.module.model.LUT
|
||||||
|
|
||||||
# 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(
|
if LUT.TYPE == "Mechanical":
|
||||||
["Frequency (MHz)", "Matching Voltage", "Tuning Voltage"]
|
self.table_widget.setHorizontalHeaderLabels(
|
||||||
)
|
["Frequency (MHz)", "Tuning Position", "Matching Position"]
|
||||||
LUT = self.module.model.LUT
|
)
|
||||||
|
elif LUT.TYPE == "Electrical":
|
||||||
|
self.table_widget.setHorizontalHeaderLabels(
|
||||||
|
["Frequency (MHz)", "Matching Voltage", "Tuning Voltage"]
|
||||||
|
)
|
||||||
|
|
||||||
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)))
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# 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.1
|
# Created by: PyQt6 UI code generator 6.5.1
|
||||||
#
|
#
|
||||||
|
@ -130,7 +130,7 @@ class Ui_Form(object):
|
||||||
self.gridLayout_4.addWidget(self.label_20, 6, 0, 1, 1)
|
self.gridLayout_4.addWidget(self.label_20, 6, 0, 1, 1)
|
||||||
self.stepsizeBox = QtWidgets.QSpinBox(parent=self.mechTab)
|
self.stepsizeBox = QtWidgets.QSpinBox(parent=self.mechTab)
|
||||||
self.stepsizeBox.setMinimum(0)
|
self.stepsizeBox.setMinimum(0)
|
||||||
self.stepsizeBox.setMaximum(50000)
|
self.stepsizeBox.setMaximum(1000000)
|
||||||
self.stepsizeBox.setProperty("value", 500)
|
self.stepsizeBox.setProperty("value", 500)
|
||||||
self.stepsizeBox.setObjectName("stepsizeBox")
|
self.stepsizeBox.setObjectName("stepsizeBox")
|
||||||
self.gridLayout_4.addWidget(self.stepsizeBox, 3, 1, 1, 1)
|
self.gridLayout_4.addWidget(self.stepsizeBox, 3, 1, 1, 1)
|
||||||
|
|
Loading…
Reference in a new issue