Skip to content

Commit

Permalink
Merge pull request #811 from lnls-sirius/add-fcs
Browse files Browse the repository at this point in the history
Add fast corrector controls
  • Loading branch information
anacso17 authored May 13, 2022
2 parents 40d7835 + 961be2a commit a0f2d7d
Show file tree
Hide file tree
Showing 11 changed files with 713 additions and 40 deletions.
2 changes: 1 addition & 1 deletion siriuspy/siriuspy/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.46.0
2.47.0
199 changes: 199 additions & 0 deletions siriuspy/siriuspy/clientconfigdb/types/si_fofb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
"""SI fast orbit feedback system configuration."""
from copy import deepcopy as _dcopy


def get_dict():
"""Return configuration type dictionary."""
module_name = __name__.split('.')[-1]
_dict = {
'config_type_name': module_name,
'value': _dcopy(_template_dict),
'check': False,
}
return _dict


# When using this type of configuration to set the machine,
# the list of PVs should be processed in the same order they are stored
# in the configuration. The second numeric parameter in the pair is the
# delay [s] the client should wait before setting the next PV.

_corrs = [
'SI-01M1:PS-FCH',
'SI-01M1:PS-FCV',
'SI-01M2:PS-FCH',
'SI-01M2:PS-FCV',
'SI-01C2:PS-FCH',
'SI-01C2:PS-FCV',
'SI-01C3:PS-FCH',
'SI-01C3:PS-FCV',
'SI-02M1:PS-FCH',
'SI-02M1:PS-FCV',
'SI-02M2:PS-FCH',
'SI-02M2:PS-FCV',
'SI-02C2:PS-FCH',
'SI-02C2:PS-FCV',
'SI-02C3:PS-FCH',
'SI-02C3:PS-FCV',
'SI-03M1:PS-FCH',
'SI-03M1:PS-FCV',
'SI-03M2:PS-FCH',
'SI-03M2:PS-FCV',
'SI-03C2:PS-FCH',
'SI-03C2:PS-FCV',
'SI-03C3:PS-FCH',
'SI-03C3:PS-FCV',
'SI-04M1:PS-FCH',
'SI-04M1:PS-FCV',
'SI-04M2:PS-FCH',
'SI-04M2:PS-FCV',
'SI-04C2:PS-FCH',
'SI-04C2:PS-FCV',
'SI-04C3:PS-FCH',
'SI-04C3:PS-FCV',
'SI-05M1:PS-FCH',
'SI-05M1:PS-FCV',
'SI-05M2:PS-FCH',
'SI-05M2:PS-FCV',
'SI-05C2:PS-FCH',
'SI-05C2:PS-FCV',
'SI-05C3:PS-FCH',
'SI-05C3:PS-FCV',
'SI-06M1:PS-FCH',
'SI-06M1:PS-FCV',
'SI-06M2:PS-FCH',
'SI-06M2:PS-FCV',
'SI-06C2:PS-FCH',
'SI-06C2:PS-FCV',
'SI-06C3:PS-FCH',
'SI-06C3:PS-FCV',
'SI-07M1:PS-FCH',
'SI-07M1:PS-FCV',
'SI-07M2:PS-FCH',
'SI-07M2:PS-FCV',
'SI-07C2:PS-FCH',
'SI-07C2:PS-FCV',
'SI-07C3:PS-FCH',
'SI-07C3:PS-FCV',
'SI-08M1:PS-FCH',
'SI-08M1:PS-FCV',
'SI-08M2:PS-FCH',
'SI-08M2:PS-FCV',
'SI-08C2:PS-FCH',
'SI-08C2:PS-FCV',
'SI-08C3:PS-FCH',
'SI-08C3:PS-FCV',
'SI-09M1:PS-FCH',
'SI-09M1:PS-FCV',
'SI-09M2:PS-FCH',
'SI-09M2:PS-FCV',
'SI-09C2:PS-FCH',
'SI-09C2:PS-FCV',
'SI-09C3:PS-FCH',
'SI-09C3:PS-FCV',
'SI-10M1:PS-FCH',
'SI-10M1:PS-FCV',
'SI-10M2:PS-FCH',
'SI-10M2:PS-FCV',
'SI-10C2:PS-FCH',
'SI-10C2:PS-FCV',
'SI-10C3:PS-FCH',
'SI-10C3:PS-FCV',
'SI-11M1:PS-FCH',
'SI-11M1:PS-FCV',
'SI-11M2:PS-FCH',
'SI-11M2:PS-FCV',
'SI-11C2:PS-FCH',
'SI-11C2:PS-FCV',
'SI-11C3:PS-FCH',
'SI-11C3:PS-FCV',
'SI-12M1:PS-FCH',
'SI-12M1:PS-FCV',
'SI-12M2:PS-FCH',
'SI-12M2:PS-FCV',
'SI-12C2:PS-FCH',
'SI-12C2:PS-FCV',
'SI-12C3:PS-FCH',
'SI-12C3:PS-FCV',
'SI-13M1:PS-FCH',
'SI-13M1:PS-FCV',
'SI-13M2:PS-FCH',
'SI-13M2:PS-FCV',
'SI-13C2:PS-FCH',
'SI-13C2:PS-FCV',
'SI-13C3:PS-FCH',
'SI-13C3:PS-FCV',
'SI-14M1:PS-FCH',
'SI-14M1:PS-FCV',
'SI-14M2:PS-FCH',
'SI-14M2:PS-FCV',
'SI-14C2:PS-FCH',
'SI-14C2:PS-FCV',
'SI-14C3:PS-FCH',
'SI-14C3:PS-FCV',
'SI-15M1:PS-FCH',
'SI-15M1:PS-FCV',
'SI-15M2:PS-FCH',
'SI-15M2:PS-FCV',
'SI-15C2:PS-FCH',
'SI-15C2:PS-FCV',
'SI-15C3:PS-FCH',
'SI-15C3:PS-FCV',
'SI-16M1:PS-FCH',
'SI-16M1:PS-FCV',
'SI-16M2:PS-FCH',
'SI-16M2:PS-FCV',
'SI-16C2:PS-FCH',
'SI-16C2:PS-FCV',
'SI-16C3:PS-FCH',
'SI-16C3:PS-FCV',
'SI-17M1:PS-FCH',
'SI-17M1:PS-FCV',
'SI-17M2:PS-FCH',
'SI-17M2:PS-FCV',
'SI-17C2:PS-FCH',
'SI-17C2:PS-FCV',
'SI-17C3:PS-FCH',
'SI-17C3:PS-FCV',
'SI-18M1:PS-FCH',
'SI-18M1:PS-FCV',
'SI-18M2:PS-FCH',
'SI-18M2:PS-FCV',
'SI-18C2:PS-FCH',
'SI-18C2:PS-FCV',
'SI-18C3:PS-FCH',
'SI-18C3:PS-FCV',
'SI-19M1:PS-FCH',
'SI-19M1:PS-FCV',
'SI-19M2:PS-FCH',
'SI-19M2:PS-FCV',
'SI-19C2:PS-FCH',
'SI-19C2:PS-FCV',
'SI-19C3:PS-FCH',
'SI-19C3:PS-FCV',
'SI-20M1:PS-FCH',
'SI-20M1:PS-FCV',
'SI-20M2:PS-FCH',
'SI-20M2:PS-FCV',
'SI-20C2:PS-FCH',
'SI-20C2:PS-FCV',
'SI-20C3:PS-FCH',
'SI-20C3:PS-FCV',
]
_corr_propts = [
[':CtrlLoopKp-SP', 5000000, 0.0], # PI Kp parameter
[':CtrlLoopTi-SP', 300, 0.0], # PI Ti parameter
[':CurrGain-SP', 6.25e-5, 0.0], # current gain
[':CurrOffset-SP', 0, 0.0], # current offset
[':VoltGain-SP', 1.12916762036e-4, 0.0], # voltage gain
[':VoltOffset-SP', 0, 0.0], # voltage offset
]
_pvs_corrs = list()
for dev in _corrs:
for ppt, val, dly in _corr_propts:
_pvs_corrs.append([dev+ppt, val, dly])

_template_dict = {
'pvs':
_pvs_corrs
}
3 changes: 2 additions & 1 deletion siriuspy/siriuspy/cycle/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from .main import CycleController
from .conn import Timing, PSCycler, LinacPSCycler, PSCyclerFBP
from .conn import Timing, PSCycler, LinacPSCycler, PSCyclerFBP, FOFBPSCycler
from .util import get_psnames, get_sections, get_trigger_by_psname, \
TRIGGER_NAMES
from .bo_cycle_data import \
DEFAULT_RAMP_AMPLITUDE, DEFAULT_RAMP_DURATION, DEFAULT_RAMP_NRCYCLES,\
DEFAULT_RAMP_TOTDURATION, BASE_RAMP_CURVE_ORIG, \
bo_get_default_waveform, bo_generate_base_waveform
from .li_cycle_data import li_get_default_waveform
from .fc_cycle_data import fc_get_default_waveform
151 changes: 147 additions & 4 deletions siriuspy/siriuspy/cycle/conn.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from .bo_cycle_data import DEFAULT_RAMP_NRCYCLES, DEFAULT_RAMP_TOTDURATION, \
bo_get_default_waveform as _bo_get_default_waveform
from .li_cycle_data import li_get_default_waveform as _li_get_default_waveform
from .fc_cycle_data import fc_get_default_waveform as _fc_get_default_waveform


TIMEOUT_SLEEP = 0.1
Expand Down Expand Up @@ -444,8 +445,7 @@ def check_on(self):

def set_current_zero(self):
"""Set PS current to zero ."""
status = _pv_conn_put(self['Current-SP'], 0)
return status
return _pv_conn_put(self['Current-SP'], 0)

def check_current_zero(self, wait=5):
"""Return whether power supply PS current is zero."""
Expand Down Expand Up @@ -725,8 +725,7 @@ def prepare(self, _):

def is_prepared(self, mode, wait=5):
"""Return whether power supply is ready."""
status = self.check_current_zero(wait)
return status
return self.check_current_zero(wait)

def cycle(self):
"""Cycle. This function may run in a thread."""
Expand All @@ -753,3 +752,147 @@ def _get_duration_and_waveform(self):
def __getitem__(self, prop):
"""Return item."""
return self._pvs[prop]


class FOFBPSCycler:
"""Handle FOFB power supply properties to cycle."""

# NOTE: this could be a class derived from one of the Device classes.

properties = [
'Current-SP', 'Current-RB', 'PwrState-Sts',
'PSAmpOverCurrFlagL-Sts', 'PSAmpOverTempFlagL-Sts',
'PSAmpOverCurrFlagR-Sts', 'PSAmpOverTempFlagR-Sts',
'TestOpenLoopTriang-Sel', 'TestOpenLoopTriang-Sts',
'TestOpenLoopSquare-Sel', 'TestOpenLoopSquare-Sts',
'TestClosedLoopSquare-Sel', 'TestClosedLoopSquare-Sts',
]

def __init__(self, psname):
"""Constructor."""
self._psname = _PVName(psname)
self._waveform = None
self._cycle_duration = None
self._times = None
self._pvs = dict()
for prop in FOFBPSCycler.properties:
if prop not in self._pvs.keys():
self._pvs[prop] = _PV(
self._psname.substitute(prefix=VACA_PREFIX, propty=prop),
connection_timeout=TIMEOUT_CONNECTION)

@property
def psname(self):
"""Power supply name."""
return self._psname

@property
def connected(self):
"""Return connected state."""
for prop in FOFBPSCycler.properties:
if not self[prop].connected:
return False
return True

def wait_for_connection(self, timeout=0.5):
"""Wait for connection."""
for pvobj in self._pvs.values():
if not pvobj.wait_for_connection(timeout):
return False
return True

@property
def waveform(self):
"""Return waveform."""
if self._waveform is None:
self._get_duration_and_waveform()
return self._waveform

def cycle_duration(self, _):
"""Return the duration of the cycling in seconds."""
if self._cycle_duration is None:
self._get_duration_and_waveform()
return self._cycle_duration

def check_intlks(self, wait=2):
"""Check interlocks."""
if not self.connected:
return False
status = (self._pvs['PSAmpOverCurrFlagL-Sts'].value == 1)
status &= (self._pvs['PSAmpOverTempFlagL-Sts'].value == 1)
status &= (self._pvs['PSAmpOverCurrFlagR-Sts'].value == 1)
status &= (self._pvs['PSAmpOverTempFlagR-Sts'].value == 1)
return status

def check_on(self):
"""Return whether power supply PS is on."""
return _pv_timed_get(self['PwrState-Sts'], 1)

def set_current_zero(self):
"""Set PS current to zero ."""
return _pv_conn_put(self['Current-SP'], 0)

def check_current_zero(self, wait=5):
"""Return whether power supply PS current is zero."""
return _pv_timed_get(self['Current-RB'], 0, abs_tol=0.01, wait=wait)

def prepare(self, _):
"""Config power supply to cycling mode."""
status = True
if not self.check_current_zero(wait=0.5):
status &= self.set_current_zero()
return status

def is_prepared(self, _, wait=5):
"""Return whether power supply is ready."""
return self.check_current_zero(wait)

def set_opmode_slowref(self):
"""Set OpMode to SlowRef, if needed."""
if self.check_opmode_slowref(wait=1):
return True
sts = _pv_conn_put(
self['TestOpenLoopTriang-Sel'], _PSConst.DsblEnbl.Dsbl)
sts &= _pv_conn_put(
self['TestOpenLoopSquare-Sel'], _PSConst.DsblEnbl.Dsbl)
sts &= _pv_conn_put(
self['TestClosedLoopSquare-Sel'], _PSConst.DsblEnbl.Dsbl)
_time.sleep(TIMEOUT_SLEEP)
return sts

def check_opmode_slowref(self, wait=10):
"""Check if OpMode is SlowRef."""
_wt = wait/3
sts = _pv_timed_get(
self['TestOpenLoopTriang-Sts'], _PSConst.DsblEnbl.Dsbl, wait=_wt)
sts &= _pv_timed_get(
self['TestOpenLoopSquare-Sts'], _PSConst.DsblEnbl.Dsbl, wait=_wt)
sts &= _pv_timed_get(
self['TestClosedLoopSquare-Sts'], _PSConst.DsblEnbl.Dsbl, wait=_wt)
return sts

def cycle(self):
"""Cycle. This function may run in a thread."""
for i in range(len(self._waveform)-1):
self['Current-SP'].value = self._waveform[i]
_time.sleep(self._times[i+1] - self._times[i])
self['Current-SP'].value = self._waveform[-1]

def check_final_state(self, _):
"""Check state after Cycle."""
status = self.check_on()
status &= self.check_intlks()
if not status:
return _Const.CycleEndStatus.Interlock
return _Const.CycleEndStatus.Ok

def _get_duration_and_waveform(self):
"""Get duration and waveform."""
time, wfm = _fc_get_default_waveform(psname=self.psname)
self._times = time
self._cycle_duration = max(time)
self._waveform = wfm

def __getitem__(self, prop):
"""Return item."""
return self._pvs[prop]
Loading

0 comments on commit a0f2d7d

Please sign in to comment.