def _sensor_to_COPY(self): # And the sensor measurements self._lock.acquire() self.COPY_sensor_values = SensorValues( pip=self._DATA_PIP, peep=self._DATA_PEEP, fio2=self.Balloon.fio2, temp=self.Balloon.temperature, humidity=self.Balloon.humidity, pressure=self.Balloon.current_pressure, vte=self._DATA_VTE, breaths_per_minute=self._DATA_BPM, inspiration_time_sec=self._DATA_I_PHASE, timestamp=time.time(), loop_counter=self._loop_counter) self._lock.release()
def _fake_sensor(arg=None): # make an empty SensorValues vals = {k:0 for k in ValueName} vals.update({k:0 for k in SensorValues.additional_values}) # since 0 is out of range for fio2, manually set it # FIXME: find values that by definition don't raise any of the default rules vals[ValueName.FIO2] = 80 # update with any in kwargs if arg: for k, v in arg.items(): vals[k] = v sensors = SensorValues(vals=vals) return sensors
def _sensor_to_COPY(self): # And the sensor measurements self._lock.acquire() self.COPY_sensor_values = SensorValues( vals={ ValueName.PIP: self._DATA_PIP, ValueName.PEEP: self._DATA_PEEP, ValueName.FIO2: 70, ValueName.PRESSURE: self.HAL.pressure, ValueName.VTE: self._DATA_VTE, ValueName.BREATHS_PER_MINUTE: self._DATA_BPM, ValueName.INSPIRATION_TIME_SEC: self._DATA_I_PHASE, 'timestamp': time.time(), 'loop_counter': self._loop_counter, 'breath_count': self._DATA_BREATH_COUNT }) self._lock.release()
def get_sensors_values(self): # returns SensorValues and a time stamp self.update_alarms() # Make sure we are up to date self.sensor_values = SensorValues( pip=self.Controller.PIP, peep=self.PEEP, fio2=self.Balloon.fio2, temp=self.Balloon.temperature, humidity=self.Balloon.humidity, pressure=self.Balloon.current_pressure, vte=self.vte, breaths_per_minute=self.bpm, inspiration_time_sec=self.I_phase, timestamp=time.time()) return self.sensor_values
def _sensor_to_COPY(self): # And the sensor measurements self._lock.acquire() self.COPY_sensor_values = SensorValues( vals={ ValueName.PIP.name: self._DATA_PIP, ValueName.PEEP.name: self._DATA_PEEP, ValueName.FIO2.name: self.Balloon.fio2, ValueName.TEMP.name: self.Balloon.temperature, ValueName.HUMIDITY.name: self.Balloon.humidity, ValueName.PRESSURE.name: self.Balloon.current_pressure, ValueName.VTE.name: self._DATA_VTE, ValueName.BREATHS_PER_MINUTE.name: self._DATA_BPM, ValueName.INSPIRATION_TIME_SEC.name: self._DATA_I_PHASE, 'timestamp': time.time(), 'loop_counter': self._loop_counter, 'breath_count': self._DATA_BREATH_COUNT }) self._lock.release()
def get_sensors(self): self._running.wait() return SensorValues(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
def __init__(self): ##################### Algorithm/Program parameters ################## # Hyper-Parameters self._LOOP_UPDATE_TIME = 0.01 # Run the main control loop every 0.01 sec self._NUMBER_CONTROLL_LOOPS_UNTIL_UPDATE = 10 # After every 10 main control loop iterations, update COPYs. self._RINGBUFFER_SIZE = 100 # Maximum number of breath cycles kept in memory ######################### Control management ######################### # This is what the machine has controll over: self.__control_signal_in = 0 # State of a valve on the inspiratory side - could be a proportional valve. self.__control_signal_out = 0 # State of a valve on the exspiratory side - this is open/close self._pid_control_flag = True # Default is: use PID control # Internal Control variables. "SET" indicates that this is set. self.__SET_PIP = CONTROL[ValueName.PIP].default # Target PIP pressure self.__SET_PIP_TIME = CONTROL[ ValueName.PIP_TIME].default # Target time to reach PIP in seconds self.__SET_PEEP = CONTROL[ ValueName.PEEP].default # Target PEEP pressure self.__SET_PEEP_TIME = CONTROL[ ValueName. PEEP_TIME].default # Target time to reach PEEP from PIP plateau self.__SET_BPM = CONTROL[ ValueName.BREATHS_PER_MINUTE].default # Target breaths per minute self.__SET_I_PHASE = CONTROL[ ValueName. INSPIRATION_TIME_SEC].default # Target duration of inspiratory phase # Derived internal control variables - fully defined by numbers above self.__SET_CYCLE_DURATION = 60 / self.__SET_BPM self.__SET_E_PHASE = self.__SET_CYCLE_DURATION - self.__SET_I_PHASE self.__SET_T_PLATEAU = self.__SET_I_PHASE - self.__SET_PIP_TIME self.__SET_T_PEEP = self.__SET_E_PHASE - self.__SET_PEEP_TIME ######################### Data management ######################### # These are measurements from the last breath cycle. self._DATA_PIP = None # Measured value of PIP self._DATA_PIP_TIME = None # Measured time of reaching PIP plateau self._DATA_PEEP = None # Measured valued of PEEP self._DATA_I_PHASE = None # Measured duration of inspiratory phase self.__DATA_LAST_PEEP = None # Last time of PEEP - by definition end of breath cycle self._DATA_BPM = None # Measured breathing rate, by definition 60sec / length_of_breath_cycle self._DATA_VTE = None # Maximum air displacement in last breath cycle self._DATA_P = 0 # Last measurements of the proportional term for PID-control self._DATA_I = 0 # Last measurements of the integral term for PID-control self._DATA_D = 0 # Last measurements of the differential term for PID-control # Parameters to keep track of breath-cycle self.__cycle_start = time.time() self.__cycle_waveform = np.array( [[0, 0, 0]]) # To build up the current cycle's waveform self.__cycle_waveform_archive = deque( maxlen=self._RINGBUFFER_SIZE) # An archive of past waveforms. # These are measurements that change from timepoint to timepoint self._DATA_PRESSURE = 0 self.__DATA_VOLUME = 0 self._DATA_Qin = 0 # Measurement of the airflow in self._DATA_Qout = 0 # Measurement of the airflow out self._DATA_dpdt = 0 # Current sample of the rate of change of pressure dP/dt in cmH2O/sec self._last_update = time.time() ######################### Alarm management ######################### self.__active_alarms = {} # Dictionary of active alarms self.__logged_alarms = deque( maxlen=self._RINGBUFFER_SIZE) # List of all resolved alarms # Variable limits to raise alarms, initialized as small deviation of what the controller initializes self.__PIP_min = CONTROL[ValueName.PIP].safe_range[0] self.__PIP_max = CONTROL[ValueName.PIP].safe_range[1] self.__PIP_lastset = time.time() self.__PIP_time_min = CONTROL[ValueName.PIP_TIME].safe_range[0] self.__PIP_time_max = CONTROL[ValueName.PIP_TIME].safe_range[1] self.__PIP_time_lastset = time.time() self.__PEEP_min = CONTROL[ValueName.PEEP].safe_range[0] self.__PEEP_max = CONTROL[ValueName.PEEP].safe_range[1] self.__PEEP_lastset = time.time() self.__bpm_min = CONTROL[ValueName.BREATHS_PER_MINUTE].safe_range[0] self.__bpm_max = CONTROL[ValueName.BREATHS_PER_MINUTE].safe_range[1] self.__bpm_lastset = time.time() self.__I_phase_min = CONTROL[ ValueName.INSPIRATION_TIME_SEC].safe_range[0] self.__I_phase_max = CONTROL[ ValueName.INSPIRATION_TIME_SEC].safe_range[1] self.__I_phase_lastset = time.time() ############### Initialize COPY variables for threads ############## # COPY variables that later updated on a regular basis self.COPY_active_alarms = {} self.COPY_logged_alarms = list(self.__logged_alarms) self.COPY_sensor_values = SensorValues() ########################### Threading init ######################### # Run the start() method as a thread self._loop_counter = 0 self._running = False self._lock = threading.Lock() self._alarm_to_COPY() #These require the lock self._initialize_set_to_COPY() self.__thread = threading.Thread(target=self._start_mainloop, daemon=True) self.__thread.start()