Fork PyRPL on GitHub

Source code for pyrpl.software_modules.lockbox.gainoptimizer

from qtpy import QtCore
from pyrpl.software_modules.lockbox import *
from pyrpl.async_utils import sleep


[docs]class GainOptimizerLoop(LockboxPlotLoop): amplitude = FloatProperty(default=0.1, doc='Amplitude of gain modulation for the estimation of the dependency ' 'of lock rms') unity_gain_frequency = FloatProperty(default = 0.01, doc="Unity gain frequency for the gain integrator.") current_gain_factor = FloatProperty(default=1.0, doc="Current gain factor of the gain correction mechanism.") measurement_time = FloatProperty(default=0.05, doc="Current gain factor of the gain correction mechanism.") #phase = PhaseProperty(default=0, doc="current phase of the gain modulation") @property def phase(self): return (self.n%2)*np.pi @phase.setter def phase(self, v): pass _phase_step = np.pi max_length = 10 @property def rms(self): input = self.lockbox.inputs[self.lockbox.final_stage.input] input.stats(self.parent.measurement_time) return input.relative_rms @property def pdh(self): return self._lastrms[-1] * np.cos(self.phase-self._phase_step) + self.rms * np.cos(self.phase)
[docs] def setup_loop(self): """ put your initialization routine here""" if not self.lockbox.is_locked_and_final(loglevel=0): self._clear() self._lastrms = [self.rms] self._lastpdh = [0] self._lasttime = [self.time] self.phase = 0 self.current_gain_factor = self.lockbox.final_stage.gain_factor
[docs] def loop(self, a): if not self.lockbox.is_locked_and_final(loglevel=0): setattr(self.parent, self.name, None) self._clear() # get the rms of the current error signal and store it rms, pdh, time = self.rms, self.pdh, self.time dt = time - self._lasttime[-1] self._lastrms.append(rms) self._lastpdh.append(pdh) self._lasttime.append(time) while len(self._lastrms) > self.max_length: self._lastrms.pop(0) self._lastpdh.pop(0) self._lasttime.pop(0) # compute integral self.current_gain_factor += pdh * self.parent.unity_gain_frequency * dt * 2.0 * np.pi self.phase = self.phase + self._phase_step self.lockbox.final_stage.gain_factor = self.current_gain_factor * (1.0 + self.parent.amplitude*np.cos(self.phase)) self.plotappend(b=rms, g=pdh, r=self.current_gain_factor, y=self.lockbox.final_stage.gain_factor)
[docs] def teardown_loop(self): """ put your destruction routine here""" self.lockbox.final_stage.gain_factor = self.current_gain_factor
[docs]class GainOptimizer(LockboxModule): """ a module that is used to optimize the lockbox gain by setting the gain_factor of the lockbox to the integral of an error signal derived from the slope of the error signal rms value vs gain_factor """ _setup_attributes = ["interval", "amplitude", "unity_gain_frequency", "plot", "measurement_time"] _gui_attributes = _setup_attributes + ["start", "stop"] interval = FloatProperty(default=1.0, min=0) amplitude = FloatProperty(default=0.05, min=0) unity_gain_frequency = FloatProperty(default=0.1) plot = BoolProperty(default=True) measurement_time = FloatProperty(default=0.05, doc="Current gain factor of the gain correction mechanism.")
[docs] def start(self): self.stop() if self.lockbox.is_locked_and_final(loglevel=0): self.loop = GainOptimizerLoop(parent=self, name="gainoptimizerloop", interval=self.interval, unity_gain_frequency=self.unity_gain_frequency, amplitude=self.amplitude, plot=self.plot ) else: self._logger.error('The lockbox must be "locked" in order to start gain optimization.')
def _start_when_locked(self): for i in range(100): # 100s timeout sleep(1.0) if self.lockbox.is_locked_and_final(loglevel=0): return self.start()
[docs] def start_delayed(self): QtCore.QTimer.singleShot(100, self._start_when_locked)
[docs] def stop(self): if hasattr(self, 'loop') and self.loop is not None: self.loop._clear() self.loop = None