Controller¶
Screenshot¶

The Controller consists of one main controller
object that receives sensor-data, and computes control parameters, to change valve settings. The controller receives ventilation control parameters (see set_control()
), and can provide the currently active set of controls (see???)
The Controller also feeds the Logger
SensorValues
objects so that it can store high-temporal resolution data.
The main polling loop of the Controller is PVP_Gui.update_gui()
which queries the Hardware for new variables, that are wired up in a new SensorValues
and distributes
them to all listening widgets (see method documentation for more details).
The Controller is configured by the values
module, in particular it creates
Display
widgets in the left “sensor monitor” box from allValue
s inDISPLAY_MONITOR
,
The Controller can be launched alone:
but was not intended to be launched alone.
add logging
Classes:
|
Representation of alarm status and parameters |
|
An enumeration. |
|
An enumeration. |
|
Physics simulator for inflating a balloon with an attached PEEP valve. |
|
Abstract controller class for simulation/hardware. |
|
Uses ControlModuleBase to control the hardware. |
|
Controlling Simulation. |
|
Message containing ventilation control parameters. |
|
Class to save control values, analogous to SensorValues. |
|
Class for logging numerical respiration data and control settings. Creates a hdf5 file with this general structure: / root |— waveforms (group) | |— time | pressure_data | flow_out | control_signal_in | control_signal_out | FiO2 | Cycle No. | |— controls (group) | |— (time, controllsignal) | |— derived_quantities (group) | |— (time, Cycle No, I_PHASE_DURATION, PIP_TIME, PEEP_time, PIP, PIP_PLATEAU, PEEP, VTE ) | |. |
|
Class to save derived values, analogous to SensorValues. |
|
Structured class for communicating sensor readings throughout PVP. |
|
Canonical names of all values used in PVP. |
|
count(start=0, step=1) –> count object |
|
deque([iterable[, maxlen]]) –> deque object |
Data:
|
The central part of internal API. |
Functions:
|
Generates control module. |
|
Initialize a logger for logging events. |
|
Defines a decorator for a 50ms timeout. |
-
class
pvp.controller.control_module.
ControlModuleBase
(save_logs: bool = False, flush_every: int = 10)[source]¶ Bases:
object
Abstract controller class for simulation/hardware.
1. General notes: All internal variables fall in three classes, denoted by the beginning of the variable:
COPY_varname: These are copies (for safe threading purposes) that are regularly sync’ed with internal variables.
__varname: These are variables only used in the ControlModuleBase-Class
_varname: These are variables used in derived classes.
2. Set and get values. Internal variables should only to be accessed though the set_ and get_ functions.
These functions act on COPIES of internal variables (__ and _), that are sync’d every few iterations. How often this is done is adjusted by the variable self._NUMBER_CONTROLL_LOOPS_UNTIL_UPDATE. To avoid multiple threads manipulating the same variables at the same time, every manipulation of COPY_ is surrounded by a thread lock.
- Public Methods:
get_sensors(): Returns a copy of the current sensor values.
get_alarms(): Returns a List of all alarms, active and logged
get_control(ControlSetting): Sets a controll-setting. Is updated at latest within self._NUMBER_CONTROLL_LOOPS_UNTIL_UPDATE
get_past_waveforms(): Returns a List of waveforms of pressure and volume during at the last N breath cycles, N<self. _RINGBUFFER_SIZE, AND clears this archive.
start(): Starts the main-loop of the controller
stop(): Stops the main-loop of the controller
set_control(): Set the control
interrupt(): Interrupt the controller, and re-spawns the thread. Used to restart a stuck controller
is_running(): Returns a bool whether the main-thread is running
get_heartbeat(): Returns a heartbeat, more specifically, the continuously increasing iteration-number of the main control loop.
Initializes the ControlModuleBase class.
- Parameters
save_logs (bool, optional) – Should sensor data and controls should be saved with the
DataLogger
? Defaults to False.flush_every (int, optional) – Flush and rotate logs every n breath cycles. Defaults to 10.
- Raises
alert – [description]
Methods:
_PID_update
(dt)This instantiates the PID control algorithms. During the breathing cycle, it goes through the four states: 1) Rise to PIP, speed is controlled by flow (variable: __SET_PIP_GAIN) 2) Sustain PIP pressure 3) Quick fall to PEEP 4) Sustaint PEEP pressure Once the cycle is complete, it checks the cycle for any alarms, and starts a new one. A record of pressure/volume waveforms is kept and saved.
__init__
([save_logs, flush_every])Initializes the ControlModuleBase class.
Resets the internal controller cycle to zero, i.e. restarts the breath cycle.
Produces the INSPIRATORY control-signal that has been calculated in __calculate_control_signal_in(dt)
Produces the EXPIRATORY control-signal for the different states, i.e. open/close.
Makes a copy of internal variables.
Prototype method to start main PID loop.
A method callable from the outside to get a copy of the alarms, that the controller checks: High airway pressure, and technical alarms.
get_control
(control_setting_name)A method callable from the outside to get current control settings.
Returns an independent heart-beat of the controller, i.e. the internal loop counter incremented in _start_mainloop.
Public method to return a list of past waveforms from __cycle_waveform_archive. Note: After calling this function, archive is emptied! The format is - Returns a list of [Nx3] waveforms, of [time, pressure, volume] - Most recent entry is waveform_list[-1].
A method callable from the outside to get a copy of sensorValues
If the controller seems stuck, this generates a new thread, and starts the main loop.
Public Method to assess whether the main loop thread is running.
set_breath_detection
(breath_detection)set_control
(control_setting)A method callable from the outside to set alarms.
start
()Method to start _start_mainloop as a thread.
stop
()Method to stop the main loop thread, and close the logfile.
-
__init__
(save_logs: bool = False, flush_every: int = 10)[source]¶ Initializes the ControlModuleBase class.
- Parameters
save_logs (bool, optional) – Should sensor data and controls should be saved with the
DataLogger
? Defaults to False.flush_every (int, optional) – Flush and rotate logs every n breath cycles. Defaults to 10.
- Raises
alert – [description]
-
_initialize_set_to_COPY
()[source]¶ Makes a copy of internal variables. This is used to facilitate threading
-
__analyze_last_waveform
()¶ - This goes through the last waveform, and updates the internal variables:
VTE, PEEP, PIP, PIP_TIME, I_PHASE, FIRST_PEEP and BPM.
-
get_sensors
() → pvp.common.message.SensorValues[source]¶ A method callable from the outside to get a copy of sensorValues
- Returns
A set of current sensorvalues, handeled by the controller.
- Return type
-
get_alarms
() → Union[None, Tuple[pvp.alarm.alarm.Alarm]][source]¶ A method callable from the outside to get a copy of the alarms, that the controller checks: High airway pressure, and technical alarms.
-
set_control
(control_setting: pvp.common.message.ControlSetting)[source]¶ A method callable from the outside to set alarms. This updates the entries of COPY with new control values.
- Parameters
control_setting (ControlSetting) – [description]
-
get_control
(control_setting_name: pvp.common.values.ValueName) → pvp.common.message.ControlSetting[source]¶ A method callable from the outside to get current control settings. This returns values of COPY to the outside world.
- Parameters
control_setting_name (ValueName) – The specific control asked for
- Returns
ControlSettings-Object that contains relevant data
- Return type
-
__get_PID_error
(ytarget, yis, dt, RC)¶ Calculates the three terms for PID control. Also takes a timestep “dt” on which the integral-term is smoothed.
-
__calculate_control_signal_in
(dt)¶ - Calculates the PID control signal by:
Combining the the three gain parameters.
And smoothing the control signal with a moving window of three frames (~10ms)
- Parameters
dt (float) – timestep
-
_get_control_signal_in
()[source]¶ Produces the INSPIRATORY control-signal that has been calculated in __calculate_control_signal_in(dt)
- Returns
the numerical control signal for the inspiratory prop valve
- Return type
-
_get_control_signal_out
()[source]¶ Produces the EXPIRATORY control-signal for the different states, i.e. open/close
- Returns
numerical control signal for expiratory side: open (1) close (0)
- Return type
-
_control_reset
()[source]¶ Resets the internal controller cycle to zero, i.e. restarts the breath cycle. Used for autonomous breath detection.
-
__test_for_alarms
()¶ - Implements tests that are to be executed in the main control loop:
Test for HAPA
Test for Technical Alert, making sure sensor values are plausible
Test for Technical Alert, make sure continuous in contact
Currently: Alarms are time.time() of first occurance.
-
__start_new_breathcycle
()¶ - Some housekeeping. This has to be executed when the next breath cycles starts:
starts new breathcycle
initializes newe __cycle_waveform
analyzes last breath waveform for PIP, PEEP etc. with __analyze_last_waveform()
flushes the logfile
-
_PID_update
(dt)[source]¶ This instantiates the PID control algorithms. During the breathing cycle, it goes through the four states:
Rise to PIP, speed is controlled by flow (variable: __SET_PIP_GAIN)
Sustain PIP pressure
Quick fall to PEEP
Sustaint PEEP pressure
Once the cycle is complete, it checks the cycle for any alarms, and starts a new one. A record of pressure/volume waveforms is kept and saved
- Parameters
dt (float) – timesstep since last update
-
__save_values
()¶ Helper function to reorganize key parameters in the main PID control loop, into a SensorValues object, that can be stored in the logfile, using a method from the DataLogger.
-
get_past_waveforms
()[source]¶ Public method to return a list of past waveforms from __cycle_waveform_archive. Note: After calling this function, archive is emptied! The format is
Returns a list of [Nx3] waveforms, of [time, pressure, volume]
Most recent entry is waveform_list[-1]
- Returns
[Nx3] waveforms, of [time, pressure, volume]
- Return type
-
_start_mainloop
()[source]¶ Prototype method to start main PID loop. Will depend on simulation or device, specified below.
-
interrupt
()[source]¶ If the controller seems stuck, this generates a new thread, and starts the main loop. No parameters have changed.
-
class
pvp.controller.control_module.
ControlModuleDevice
(save_logs=True, flush_every=10, config_file=None)[source]¶ Bases:
pvp.controller.control_module.ControlModuleBase
Uses ControlModuleBase to control the hardware.
Initializes the ControlModule for the physical system. Inherits methods from ControlModuleBase
- Parameters
save_logs (bool, optional) – Should logs be kept? Defaults to True.
flush_every (int, optional) – How often are log-files to be flushed, in units of main-loop-itertions? Defaults to 10.
config_file (str, optional) – Path to device config file, e.g. ‘pvp/io/config/dinky-devices.ini’. Defaults to None.
Methods:
__init__
([save_logs, flush_every, config_file])Initializes the ControlModule for the physical system.
_get_HAL
()Get sensor values from HAL, decorated with timeout.
Copies the current measurements to`COPY_sensor_values`, so that it can be queried from the outside.
_set_HAL
(valve_open_in, valve_open_out)Set Controls with HAL, decorated with a timeout.
This is the main loop.
This returns valves back to normal setting (in: closed, out: open)
-
__init__
(save_logs=True, flush_every=10, config_file=None)[source]¶ Initializes the ControlModule for the physical system. Inherits methods from ControlModuleBase
- Parameters
save_logs (bool, optional) – Should logs be kept? Defaults to True.
flush_every (int, optional) – How often are log-files to be flushed, in units of main-loop-itertions? Defaults to 10.
config_file (str, optional) – Path to device config file, e.g. ‘pvp/io/config/dinky-devices.ini’. Defaults to None.
-
_sensor_to_COPY
()[source]¶ Copies the current measurements to`COPY_sensor_values`, so that it can be queried from the outside.
-
_set_HAL
(valve_open_in, valve_open_out)[source]¶ Set Controls with HAL, decorated with a timeout.
As hardware communication is the speed bottleneck. this code is slightly optimized in so far as only changes are sent to hardware.
-
_get_HAL
()[source]¶ Get sensor values from HAL, decorated with timeout. As hardware communication is the speed bottleneck. this code is slightly optimized in so far as some sensors are queried only in certain phases of the breatch cycle. This is done to run the primary PID loop as fast as possible:
pressure is always queried
Flow is queried only outside of inspiration
In addition, oxygen is only read every 5 seconds.
-
class
pvp.controller.control_module.
Balloon_Simulator
(peep_valve)[source]¶ Bases:
object
Physics simulator for inflating a balloon with an attached PEEP valve. For math, see https://en.wikipedia.org/wiki/Two-balloon_experiment
Methods:
OUupdate
(variable, dt, mu, sigma, tau)This is a simple function to produce an OU process on variable.
_reset
()Resets Balloon to default settings.
set_flow_in
(Qin, dt)set_flow_out
(Qout, dt)update
(dt)
-
class
pvp.controller.control_module.
ControlModuleSimulator
(simulator_dt=None, peep_valve_setting=5)[source]¶ Bases:
pvp.controller.control_module.ControlModuleBase
Controlling Simulation.
Initializes the ControlModuleBase with the simple simulation (for testing/dev).
- Parameters
Methods:
__init__
([simulator_dt, peep_valve_setting])Initializes the ControlModuleBase with the simple simulation (for testing/dev).
Make the sensor value object from current (simulated) measurements
This is the main loop.
-
__init__
(simulator_dt=None, peep_valve_setting=5)[source]¶ Initializes the ControlModuleBase with the simple simulation (for testing/dev).
-
__SimulatedPropValve
(x)¶ This simulates the action of a proportional valve. Flow-current-curve eye-balled from generic prop vale with logistic activation.
-
__SimulatedSolenoid
(x)¶ This simulates the action of a two-state Solenoid valve.
-
pvp.controller.control_module.
get_control_module
(sim_mode=False, simulator_dt=None)[source]¶ Generates control module.
Control into a breathing cycle was accomplished with ahybrid system of state and PID control. During inspiration,we actively control pressure using a PID cycle to set theinspiratory valve. Expiration was then instantiated by closingthe inpiratory, and opening the expiratory valve to passivelyrelease PIP pressure as fast as possible. After reaching PEEP,we opened the inspiratory valve slightly to sustain PEEPusing the aforementioned manually operated PEEP-valveand to sustain a gentle flow of air through the system
The Raspberry pi allowed for the primary control loop torun at speeds exceeding≈320Hz, using≈40%of themaximum bandwidth of the analog-to-digital converterreading the sensors
In addition to pressure control, our software continuouslymonitors for autonomous breaths, high airway pressure,and general system status.Autonomous breathing wasdetected by transient pressure drops below PEEP. A detectedbreath triggered a new breath cycle. High airway pressureis defined as exceeding a certain pressure for a certain time(as to not be triggered by a cough). This triggered an alarm,and an immediate release of air to drop pressure to PEEP.The Controller also assesses whether numerical values arereasonable, and changing over time. If this is not the case,it raises an technical alarm. All alarms are collected andmaintained by an intelligent alarm manager, that provides theUI with the alarms to display in order of their importance.In addition to the alarm system, the controller monitorsfor autonomous breath events during peep. We define suchevents by a drop below the PEEP baseline exceeding somefixed threshold. If an autonomous drop was detected, thenext breath cycle is initiated