Skip to content

Commit

Permalink
Merge pull request #4 from hoodlabpurdue/add-powermeter
Browse files Browse the repository at this point in the history
Add powermeter
  • Loading branch information
bcerjan authored Apr 4, 2025
2 parents 4d4ea1f + 3ad1f91 commit a885dd5
Show file tree
Hide file tree
Showing 8 changed files with 382 additions and 147 deletions.
18 changes: 17 additions & 1 deletion cfg/terascan.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
global:
# list of modules to load when starting
startup_modules: [photon_counts_time_average_gui, terascan_gui]
startup_modules: [photon_counts_time_average_gui, powermeter_gui, terascan_gui]

# Module server configuration for accessing qudi GUI/logic/hardware modules from remote clients
remote_modules_server:
Expand Down Expand Up @@ -44,6 +44,11 @@ gui:
swabian_timetagger: 'swabian_timetagger'
options:
ring_buffer_length_s: 5

powermeter_gui:
module.Class: 'powermeter.powermeter_gui.PowermeterGui'
connect:
powermeter_logic: powermeter_logic

logic:
terascan_logic:
Expand All @@ -59,6 +64,11 @@ logic:
mode_hop_overlap_med: 0.001 # in nm, from the SolsTiS control panel. This is how far back we go to discard data every time a mode hop occurs
mode_hop_overlap_fine: 0.00025 # ""

powermeter_logic:
module.Class: 'powermeter.powermeter_logic.PowermeterLogic'
connect:
powermeter: powermeter_thorlabs

# daq_reader_logic:
# module.Class: 'common.daq_reader_logic.DAQReaderLogic'
# connect:
Expand Down Expand Up @@ -117,6 +127,12 @@ hardware:
host_ip_addr: '192.168.1.225' # IP address of control computer
laser_ip_addr: '192.168.1.222' # IP address of laser
laser_port: 39900 # Port number to connect on

powermeter_thorlabs:
module.Class: 'powermeter.thorlabs_power_meter.ThorlabsPowerMeter'
options:
average_count: 5
update_period: 100 # in ms, hardware will emit data ~10 times/second

# Dummy Hardware:
# daq_reader_dummy:
Expand Down
53 changes: 53 additions & 0 deletions src/qudi/gui/powermeter/powermeter_gui.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from PySide2 import QtCore
from qudi.core.module import GuiBase
from qudi.core.connector import Connector
from qudi.core.statusvariable import StatusVar

from .powermeter_main_window import PowermeterMainWindow

class PowermeterGui(GuiBase):
"""
GUI module to display power meter readings with a multiplication factor.
Example config:
powermeter_gui:
module.Class: 'powermeter.powermeter_gui.PowermeterGui'
connect:
powermeter_logic: powermeter_logic
"""
# Connector to the logic module (which emits power readings)
_powermeter_logic = Connector(name='powermeter_logic', interface='PowermeterLogic')
# StatusVar to store the multiplication factor between sessions
_multiplication_factor = StatusVar(name='multiplication_factor', default=1.0)

def on_activate(self):
self._mw = PowermeterMainWindow()
# Initialize the main window's multiplication factor from the status variable.
self._mw.set_multiplication_factor(self._multiplication_factor)
# Set the spinbox value accordingly.
self._mw.mult_factor_spinbox.setValue(self._multiplication_factor)
# Connect spinbox changes to our handler.
self._mw.mult_factor_spinbox.valueChanged.connect(self._on_mult_factor_changed)
# Connect logic's power update signal to the main window update slot.
self._powermeter_logic().sigPowerUpdated.connect(
self._mw.update_power, QtCore.Qt.QueuedConnection
)
self.show()

def on_deactivate(self):
self._powermeter_logic().sigPowerUpdated.disconnect(self._mw.update_power)
self._mw.mult_factor_spinbox.valueChanged.disconnect(self._on_mult_factor_changed)
self._mw.close()

def show(self):
self._mw.show()
self._mw.raise_()

@QtCore.Slot(float)
def _on_mult_factor_changed(self, factor: float):
"""
Slot called when the multiplication factor is changed via the spinbox.
Updates the StatusVar and informs the main window.
"""
self._multiplication_factor = factor
self._mw.set_multiplication_factor(factor)
102 changes: 102 additions & 0 deletions src/qudi/gui/powermeter/powermeter_main_window.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
from PySide2 import QtWidgets, QtCore, QtGui

class PowermeterMainWindow(QtWidgets.QMainWindow):
"""
Main window for displaying the Thorlabs Power Meter reading.
Features:
- Automatic unit conversion.
- A multiplication factor control (for correcting losses) in the lower right,
where the user types in the value (no increment arrows).
- Dynamic font scaling: as the window is resized, the power reading text scales.
"""
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle('Thorlabs Power Meter')
self.resize(400, 180)

# Initialize multiplication factor (default 1.0)
self._mult_factor = 1.0

# Set up central widget and main layout
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
main_layout = QtWidgets.QVBoxLayout(central_widget)
main_layout.setContentsMargins(10, 10, 10, 10)
main_layout.setSpacing(5)

# Create power reading label with initial font
self.power_label = QtWidgets.QLabel("--", self)
self.power_label.setAlignment(QtCore.Qt.AlignCenter)
initial_font = QtGui.QFont("Arial", 24)
self.power_label.setFont(initial_font)
main_layout.addWidget(self.power_label)

# Add a stretch to push the following controls to the bottom
main_layout.addStretch()

# Create a horizontal layout for the multiplication factor controls
h_layout = QtWidgets.QHBoxLayout()
h_layout.addStretch() # Pushes items to the right side

self.mult_factor_label = QtWidgets.QLabel("Multiplication Factor:", self)
self.mult_factor_spinbox = QtWidgets.QDoubleSpinBox(self)
self.mult_factor_spinbox.setDecimals(4)
self.mult_factor_spinbox.setRange(0.0, 1000.0)
self.mult_factor_spinbox.setSingleStep(0.1)
# Remove the up/down arrows so the user types the value
self.mult_factor_spinbox.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
self.mult_factor_spinbox.setValue(self._mult_factor)

h_layout.addWidget(self.mult_factor_label)
h_layout.addWidget(self.mult_factor_spinbox)
main_layout.addLayout(h_layout)

@QtCore.Slot(float)
def update_power(self, power: float):
"""
Update the label text with the new power reading.
The raw power (in Watts) is multiplied by the multiplication factor, then
converted into a suitable unit (pW, nW, µW, mW, or W).
"""
corrected_power = power * self._mult_factor
abs_pwr = abs(corrected_power)

if abs_pwr < 1e-12:
display_val = corrected_power
display_unit = "W"
elif abs_pwr < 1e-9:
display_val = corrected_power * 1e12
display_unit = "pW"
elif abs_pwr < 1e-6:
display_val = corrected_power * 1e9
display_unit = "nW"
elif abs_pwr < 1e-3:
display_val = corrected_power * 1e6
display_unit = "µW"
elif abs_pwr < 1:
display_val = corrected_power * 1e3
display_unit = "mW"
else:
display_val = corrected_power
display_unit = "W"

self.power_label.setText(f"{display_val:.4f} {display_unit}")

def set_multiplication_factor(self, factor: float):
"""
Update the multiplication factor.
"""
self._mult_factor = factor

def resizeEvent(self, event):
"""
Dynamically scale the font size of the power reading label based on the
available width of the central widget.
Adjust the divisor (here, 10) to fine-tune scaling.
"""
available_width = self.centralWidget().width()
new_font_size = max(12, int(available_width / 8))
font = self.power_label.font()
font.setPointSize(new_font_size)
self.power_label.setFont(font)
super().resizeEvent(event)
Loading

0 comments on commit a885dd5

Please sign in to comment.