Commit 8408494e authored by Matias Guijarro's avatar Matias Guijarro

Merge branch '1332-regulation-tests' into 'master'

Resolve "regulation tests"

Closes #1332

See merge request !1993
parents e6880641 210bc876
Pipeline #21100 failed with stages
in 50 minutes and 21 seconds
This diff is collapsed.
......@@ -28,19 +28,20 @@ class MyDevice:
def __init__(self, name="FakeDevice", config=None):
self.name = name
self.current_temp = 10. # deg
self.current_temp = 1. # deg
# live temp simulator attributes
self.cooling_rate = 1. # deg per sec
self.heating_rate = 0. # deg per sec
self._cool_down_tasks = None
self._stop_cool_down_events = None
self._cool_down_task = None
self._stop_cool_down_event = gevent.event.Event()
self._cool_down_task_frequency = 20.0
def __close__(self):
self._stop_cool_down_events.set()
with gevent.Timeout(2.0):
self._cool_down_tasks.join()
def __del__(self):
self.close()
def close(self):
self._stop_cooling()
def get_current_temp(self):
""" read the current temperature (like a sensor) """
......@@ -55,19 +56,19 @@ class MyDevice:
self.heating_rate = heating_rate
def _start_cooling(self):
if self._stop_cool_down_events is None:
self._stop_cool_down_events = gevent.event.Event()
if not self._cool_down_task:
self._stop_cool_down_event.clear()
self._cool_down_task = gevent.spawn(self._cooling_task)
if not self._cool_down_tasks:
self._cool_down_tasks = gevent.spawn(self._cooling_task)
def _stop_cooling(self):
if self._cool_down_task is not None:
self._stop_cool_down_event.set()
with gevent.Timeout(2.0):
self._cool_down_task.join()
def _cooling_task(self):
self._stop_cool_down_events.clear()
last_time = time.time()
while not self._stop_cool_down_events.is_set():
while not self._stop_cool_down_event.is_set():
gevent.sleep(1. / self._cool_down_task_frequency)
......@@ -184,12 +185,22 @@ class Mockup(Controller):
self.pids = {}
def __del__(self):
self.close()
def close(self):
for spe in self._stop_pid_events.values():
spe.set()
for sde in self._stop_cool_down_events.values():
sde.set()
with gevent.Timeout(2.0):
gevent.joinall(self._pid_tasks.values())
with gevent.Timeout(2.0):
gevent.joinall(self._cool_down_tasks.values())
def initialize_controller(self):
# host becomes mandatory
log_debug(self, "mockup: initialize ")
......@@ -365,16 +376,13 @@ class Mockup(Controller):
"""
log_debug(self, "Controller:start_regulation: %s" % (tloop))
if self._stop_cool_down_events.get(tloop.name) is None:
self._stop_cool_down_events[tloop.name] = gevent.event.Event()
if not self._cool_down_tasks.get(tloop.name):
self._cool_down_tasks[tloop.name] = gevent.spawn(self._cooling_task, tloop)
self._start_cooling(tloop)
if self._stop_pid_events.get(tloop.name) is None:
self._stop_pid_events[tloop.name] = gevent.event.Event()
if not self._pid_tasks.get(tloop.name):
self._stop_pid_events[tloop.name].clear()
self._pid_tasks[tloop.name] = gevent.spawn(self._pid_task, tloop)
def stop_regulation(self, tloop):
......@@ -388,7 +396,10 @@ class Mockup(Controller):
"""
log_debug(self, "Controller:stop_regulation: %s" % (tloop))
self._stop_pid_events[tloop.name].set()
if self._pid_tasks.get(tloop.name) is not None:
self._stop_pid_events[tloop.name].set()
with gevent.Timeout(2.0):
self._pid_tasks[tloop.name].join()
def read_input(self, tinput):
"""Reading on a Input object"""
......@@ -435,9 +446,21 @@ class Mockup(Controller):
return self.pids[tloop.name].setpoint
def _cooling_task(self, tloop):
def _start_cooling(self, tloop):
if self._stop_cool_down_events.get(tloop.name) is None:
self._stop_cool_down_events[tloop.name] = gevent.event.Event()
self._stop_cool_down_events[tloop.name].clear()
if not self._cool_down_tasks.get(tloop.name):
self._stop_cool_down_events[tloop.name].clear()
self._cool_down_tasks[tloop.name] = gevent.spawn(self._cooling_task, tloop)
def _stop_cooling(self, tloop):
if self._cool_down_tasks.get(tloop.name) is not None:
self._stop_cool_down_events[tloop.name].set()
with gevent.Timeout(2.0):
self._cool_down_tasks[tloop.name].join()
def _cooling_task(self, tloop):
tloop.input._attr_dict["last_cool_time"] = time.time()
......@@ -471,8 +494,6 @@ class Mockup(Controller):
# simulate the PID processes handled by the controller hardware
self._stop_pid_events[tloop.name].clear()
while not self._stop_pid_events[tloop.name].is_set():
input_value = tloop.input.read()
......
# -*- coding: utf-8 -*-
#
# This file is part of the bliss project
#
# Copyright (c) 2015-2019 Beamline Control Unit, ESRF
# Distributed under the GNU LGPLv3. See LICENSE for more info.
import pytest
@pytest.fixture
def temp_tloop(beacon):
l = beacon.get("sample_regulation_new")
yield l
l.close()
l.controller.close()
@pytest.fixture
def temp_soft_tloop(beacon):
l = beacon.get("soft_regul")
yield l
l.close()
l.input.device.close()
@pytest.fixture
def temp_soft_tloop_2(beacon):
l = beacon.get("soft_regul2")
yield l
l.close()
l.input.device.close()
import pytest
import gevent
from bliss.common.regulation import SoftLoop
from bliss.common.scans import ascan
def mockup_regulation(loop):
x = loop
info = x.__info__()
info_i = x.input.__info__()
info_o = x.output.__info__()
kp = x.kp
x.kp = kp + 0.1
assert x.kp == kp + 0.1
x.kp = kp
ki = x.ki
x.ki = ki + 0.1
assert x.ki == ki + 0.1
x.ki = ki
kd = x.kd
x.kd = kd + 0.1
assert x.kd == kd + 0.1
x.kd = kd
rr = x.ramprate
x.ramprate = rr + 0.1
assert x.ramprate == rr + 0.1
x.ramprate = rr
# --- Soft loop params ------
if isinstance(x, SoftLoop):
spf = x.sampling_frequency
x.sampling_frequency = spf + 1
assert x.sampling_frequency == spf + 1
x.sampling_frequency = spf
assert x.sampling_frequency == spf
pr = x.pid_range
x.pid_range = (0, 1)
assert x.pid_range == (0, 1)
x.pid_range = pr
assert x.pid_range == pr
# ---- start/stop --------
# -- no ramping (rate = 0)
x.ramprate = 0
sp = x.input.read() + 1.0
x.setpoint = sp
assert x.is_ramping() == False
gevent.sleep(0.1)
assert x.is_ramping() == False
assert x.setpoint == sp
# -- with ramping (rate != 0)
x.ramprate = 1.0
sp = x.input.read() + 1.0
x.setpoint = sp
assert x.is_ramping() == True
gevent.sleep(0.1)
assert x.is_ramping() == True
with gevent.Timeout(2.0):
while x.is_ramping():
gevent.sleep(0.01)
assert x.setpoint == sp
# -- interupt the ramping ----
sp = x.input.read() + 1.0
x.setpoint = sp
gevent.sleep(0.1)
assert x.is_ramping() == True
x.stop()
assert x.is_ramping() == False
# ---- scanning ----------
db = x.deadband
x.deadband = db + 0.01
assert x.deadband == db + 0.01
x.deadband = db
dif = x.deadband_idle_factor
x.deadband_idle_factor = dif + 1
assert x.deadband_idle_factor == dif + 1
x.deadband_idle_factor = dif
x.ramprate = 10.0
x.deadband_time = 2.0
x.wait_mode = "DEADBAND"
sp = x.input.read() + 0.1
x.axis_move(sp)
with gevent.Timeout(5.0):
while x.axis_state() != "READY":
gevent.sleep(0.01)
assert x.setpoint == sp
def test_sampling_counter_input(default_session):
din = default_session.config.get("diode_input")
din.read()
def test_sample_regulation(temp_tloop):
mockup_regulation(temp_tloop)
def test_soft_regulation(temp_soft_tloop):
mockup_regulation(temp_soft_tloop)
def test_soft_regulation_2(temp_soft_tloop_2):
mockup_regulation(temp_soft_tloop_2)
def test_regulation_plot(temp_tloop, flint_session):
x = temp_tloop
x.setpoint = 0
x.history_size = 150
x.clear_history_data()
plt = x.plot()
plt.stop()
gevent.sleep(1.0)
plt.start()
x.ramprate = 1.0
sp = x.input.read() + 0.1
# x.deadband_time = 2.0
x.wait_mode = "RAMP"
ascan(x.axis, sp, sp + 1, 10, 0.1, x)
import sys
import time
from bliss.controllers.temperature.linkam import LinkamDsc
config = {
"serial_url": "rfc2217://ld262:28068", # serial line name
"serial_baudrate": 19200,
"max_temp": 910,
"min_temp": -40,
}
dev = LinkamDsc("T95", config)
# for i in range(20):
# time.sleep(1)
# print dev.getTemperature()
# print dev.pumpSpeed
# dev.pumpSpeed = 0
# dev.rampRate = 10
# dev.rampLimit=25
# dev.rampHoldTime=5000
# dev.getTemperature()
# dev.stop()
# print dev.status()
# dev.start()
# print dev._profile_task
# dev.setTemperature(25)
# dev.cool()
dev.profile([(10, 35, 0)])
# dev.profile([(5,30,60),(5,35,30),(1,25,0)])
with open("rampData", "w") as f:
while 1:
time.sleep(0.1)
temp, dsc = dev.getDscData()
print("temp ", temp, " dsc ", dsc)
# print "rampNb",dev.rampNumber," rampLimit",dev.rampLimit," rampRate",dev.rampRate,"rampHold",dev.rampHoldTime
f.write("%f %f\n" % (ts, temp))
print(dev.status())
running = dev.isProfileRunning()
print("Profile running ", running)
if running == False:
break
# with open('temperatureData', 'w') as f:
# while (1):
# f.write("{0}\n".format(dev.getTemperature()))
# time.sleep(5)
......@@ -13,7 +13,7 @@
plugin: bliss
name: custom_input
device: $my_device # <== any kind of object reference (pointing to an object declared somewhere else in a YML config file)
unit: eV
unit: deg
-
......@@ -34,7 +34,7 @@
plugin: bliss
name: custom_output
device: $my_device # <== any kind of object reference (pointing to an object declared somewhere else in a YML config file)
unit: eV
unit: W
low_limit: 0.0 # <== minimum device value [unit]
high_limit: 100.0 # <== maximum device value [unit]
ramprate: 0.0 # <== ramprate to reach the output value [unit/s].
......@@ -44,7 +44,7 @@
class: ExternalInput # <== declare an 'ExternalInput' object
name: diode_input
device: $diode # <== a SamplingCounter object reference (pointing to a counter declared somewhere else in a YML config file)
unit: mm
unit: N/A
-
......@@ -63,16 +63,16 @@
name: soft_regul
input: $custom_input
output: $custom_output
P: 0.01
I: 0.01
P: 0.05
I: 0.1
D: 0.0
low_limit: -1.0 # <== low limit of the PID output value. Usaually equal to 0 or -1.
low_limit: 0.0 # <== low limit of the PID output value. Usaually equal to 0 or -1.
high_limit: 1.0 # <== high limit of the PID output value. Usaually equal to 1.
frequency: 10.0
deadband: 0.1
deadband_time: 1.5
deadband_time: 3.0
ramprate: 1.0
wait_mode: ramp
wait_mode: deadband
-
class: SoftLoop # <== declare a 'SoftLoop' object
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment