Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/pymodaq_plugins_slmsuite/hardware/slm_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,5 +127,19 @@ def get_phase(self) -> np.ndarray:
phase = self.slm.phase
return np.asarray(phase.get() if hasattr(phase, 'get') else phase)

def set_wavelength(self, wav_um: float):
"""Change the working wavelength of the open SLM (microns)

slmsuite reads ``wav_um`` each time it converts a phase into grey levels. The design wavelength follows it if
it was the same (default of slmsuite), keeping ``phase_scaling`` at 1. The Holoeye SDK also has to know it.
"""
old = self.slm.wav_um
if self.slm.wav_design_um == old:
self.slm.wav_design_um = float(wav_um)
self.slm.wav_um = float(wav_um)
slm_lib = getattr(self.slm, 'slm_lib', None)
if self.slm_type == 'Holoeye' and slm_lib is not None:
self.slm._handle_error(slm_lib.setWavelength(wav_um * 1000))

def close(self):
self.slm.close()
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ class DAQ_Move_SlmsuiteBase(DAQ_Move_base):
]},
{'title': 'Wavelength (nm):', 'name': 'wavelength_nm', 'type': 'float',
'value': config('slm', 'wavelength_nm'), 'min': 1.,
'tip': 'Working wavelength, used by slmsuite to convert phases into grey levels. Needs a re-initialization.'},
'tip': 'Working wavelength, used by slmsuite to convert phases into grey levels. Imposed by the BeamShaping '
'extension (setup preference) when it is loaded. A change is applied directly to the open SLM.'},
{'title': 'Apply phase correction:', 'name': 'phase_correct', 'type': 'bool', 'value': True,
'tip': 'Add the wavefront correction loaded in slmsuite (if any) to the displayed phases'},
{'title': 'Input as grey levels:', 'name': 'input_as_grey_levels', 'type': 'bool', 'value': False,
Expand Down Expand Up @@ -89,7 +90,8 @@ def close(self):
self.controller.close()

def commit_settings(self, param: Parameter):
pass
if param.name() == 'wavelength_nm' and self.controller is not None and self.is_master:
self.controller.set_wavelength(param.value() / 1000)

def get_actuator_value(self) -> DataActuator:
"""The phase (radians) that the SLM displays"""
Expand Down
30 changes: 30 additions & 0 deletions tests/test_slmsuite_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,3 +255,33 @@ def test_holoeye_preview_can_be_enabled(monkeypatch):
def test_holoeye_sdk_without_preview_option(monkeypatch):
_open_holoeye(monkeypatch, FakeHEDSWithoutOption)
assert FakeHEDSWithoutOption.SLM.calls == [('index:0',)]


class TestWavelengthUpdate:
def test_changed_after_the_init(self, slm):
param = slm.settings.child('wavelength_nm')
param.setValue(800.)
slm.commit_settings(param) # called by the DAQ_Move when a setting changes
slm_object = slm.controller.slm
assert slm_object.wav_um == pytest.approx(0.8)
assert slm_object.phase_scaling == 1 # design wavelength follows the working one

# the phase is converted with the new wavelength, without re-initialization
slm.controller.show_phase(np.full((HEIGHT, WIDTH), 1.))
assert slm.initialized

def test_design_wavelength_chosen_by_the_user_is_kept(self):
controller = SlmController('SimulatedSLM', resolution=(WIDTH, HEIGHT), wav_um=0.5, wav_design_um=1.)
controller.set_wavelength(0.8)
assert (controller.slm.wav_um, controller.slm.wav_design_um) == (0.8, 1.)
controller.close()

def test_holoeye_sdk_is_told(self):
calls = []
slm_object = SimpleNamespace(wav_um=0.5, wav_design_um=0.5, _handle_error=calls.append,
slm_lib=SimpleNamespace(setWavelength=lambda nm: calls.append(nm) or 0))
controller = SlmController.__new__(SlmController)
controller.slm_type, controller.slm = 'Holoeye', slm_object
controller.set_wavelength(0.8)
assert calls == [800., 0]
assert slm_object.wav_um == 0.8
Loading