Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DO NOT MERGE: additional ventilation modes #1270

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ repos:
rev: v2.5.0
hooks:
- id: check-yaml
exclude: ^software/.clang-format
- id: end-of-file-fixer
exclude: ^gui/app/third_party|^pcb/
- id: trailing-whitespace
Expand Down
4 changes: 4 additions & 0 deletions software/.clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,8 @@ StatementMacros:
TabWidth: 8
UseCRLF: false
UseTab: Never
---
Language: Proto
BasedOnStyle: Google
ColumnLimit: 100
...
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,16 @@ typedef enum _VentMode {
VentMode_OFF = 0,
VentMode_PRESSURE_CONTROL = 1,
VentMode_PRESSURE_ASSIST = 2,
VentMode_HIGH_FLOW_NASAL_CANNULA = 3
VentMode_HIGH_FLOW_NASAL_CANNULA = 3,
VentMode_VOLUME_CONTROL = 4,
VentMode_CPAP = 5,
VentMode_VOLUME_ASSIST = 6,
VentMode_PRESSURE_SUPPORT = 7,
VentMode_PC_SIMV = 8,
VentMode_VC_SIMV = 9,
VentMode_BIPAP = 10,
VentMode_PRESSURE_REG_VC = 11,
VentMode_SPONTANEOUS_BREATHS = 12,
} VentMode;

/* Struct definitions */
Expand All @@ -42,6 +51,10 @@ typedef struct _VentParams {
uint32_t inspiratory_trigger_cm_h2o;
uint32_t expiratory_trigger_ml_per_min;
float fio2;
float viv_ml;
float flow_l_per_min;
uint32_t psupp_cm_h2o;
uint32_t pstep_cm_h2o;
} VentParams;

typedef struct _ControllerStatus {
Expand All @@ -60,18 +73,18 @@ typedef struct _GuiStatus {

/* Helper constants for enums */
#define _VentMode_MIN VentMode_OFF
#define _VentMode_MAX VentMode_HIGH_FLOW_NASAL_CANNULA
#define _VentMode_ARRAYSIZE ((VentMode)(VentMode_HIGH_FLOW_NASAL_CANNULA+1))
#define _VentMode_MAX VentMode_SPONTANEOUS_BREATHS
#define _VentMode_ARRAYSIZE ((VentMode)(VentMode_SPONTANEOUS_BREATHS+1))


/* Initializer values for message structs */
#define GuiStatus_init_default {0, VentParams_init_default}
#define ControllerStatus_init_default {0, VentParams_init_default, SensorsProto_init_default, 0, 0}
#define VentParams_init_default {_VentMode_MIN, 0, 0, 0, 0, 0, 0, 0}
#define VentParams_init_default {_VentMode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define SensorsProto_init_default {0, 0, 0, 0, 0, 0, 0, 0}
#define GuiStatus_init_zero {0, VentParams_init_zero}
#define ControllerStatus_init_zero {0, VentParams_init_zero, SensorsProto_init_zero, 0, 0}
#define VentParams_init_zero {_VentMode_MIN, 0, 0, 0, 0, 0, 0, 0}
#define VentParams_init_zero {_VentMode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define SensorsProto_init_zero {0, 0, 0, 0, 0, 0, 0, 0}

/* Field tags (for use in manual encoding/decoding) */
Expand All @@ -91,6 +104,10 @@ typedef struct _GuiStatus {
#define VentParams_inspiratory_trigger_cm_h2o_tag 8
#define VentParams_expiratory_trigger_ml_per_min_tag 9
#define VentParams_fio2_tag 10
#define VentParams_viv_ml_tag 11
#define VentParams_flow_l_per_min_tag 12
#define VentParams_psupp_cm_h2o_tag 13
#define VentParams_pstep_cm_h2o_tag 14
#define ControllerStatus_uptime_ms_tag 1
#define ControllerStatus_active_params_tag 2
#define ControllerStatus_sensor_readings_tag 3
Expand Down Expand Up @@ -126,7 +143,11 @@ X(a, STATIC, REQUIRED, UINT32, pip_cm_h2o, 5) \
X(a, STATIC, REQUIRED, FLOAT, inspiratory_expiratory_ratio, 6) \
X(a, STATIC, REQUIRED, UINT32, inspiratory_trigger_cm_h2o, 8) \
X(a, STATIC, REQUIRED, UINT32, expiratory_trigger_ml_per_min, 9) \
X(a, STATIC, REQUIRED, FLOAT, fio2, 10)
X(a, STATIC, REQUIRED, FLOAT, fio2, 10) \
X(a, STATIC, REQUIRED, FLOAT, viv_ml, 11) \
X(a, STATIC, REQUIRED, FLOAT, flow_l_per_min, 12) \
X(a, STATIC, REQUIRED, UINT32, psupp_cm_h2o, 13) \
X(a, STATIC, REQUIRED, UINT32, pstep_cm_h2o, 14)
#define VentParams_CALLBACK NULL
#define VentParams_DEFAULT NULL

Expand Down Expand Up @@ -154,9 +175,9 @@ extern const pb_msgdesc_t SensorsProto_msg;
#define SensorsProto_fields &SensorsProto_msg

/* Maximum encoded size of messages (where known) */
#define GuiStatus_size 55
#define ControllerStatus_size 108
#define VentParams_size 42
#define GuiStatus_size 71
#define ControllerStatus_size 124
#define VentParams_size 58
#define SensorsProto_size 45

#ifdef __cplusplus
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ message GuiStatus {
// params.
required VentParams desired_params = 2;

// TODO: Include some sort of code version, e.g. git sha that the gui was
// built from?
// TODO: Include some sort of code version, e.g. git sha that the gui was built from?
}

// Periodically sent from the controller to the GUI.
Expand All @@ -110,8 +109,7 @@ message ControllerStatus {
// Value in range [0, 1] indicating how fast we're spinning the fan.
required float fan_power = 6;

// TODO: Include some sort of code version, e.g. git sha that the controller
// was built from?
// TODO: Include some sort of code version, e.g. git sha that the controller built from?
}

// Values set by the ventilator operator.
Expand All @@ -121,18 +119,21 @@ message VentParams {
// For more info on these terms, see
// https://github.com/RespiraWorks/Ventilator/wiki/Ventilator-Glossary

required uint32 peep_cm_h2o = 3; // PEEP - positive end-expiratory pressure
required uint32 breaths_per_min = 4; // RR - respiratory rate
required uint32 pip_cm_h2o = 5; // PIP - peak inspiratory pressure
required float inspiratory_expiratory_ratio = 6; // I:E

required uint32 inspiratory_trigger_cm_h2o = 8; // P-trigger
required uint32 peep_cm_h2o = 3; // PEEP - positive end-expiratory pressure
required uint32 breaths_per_min = 4; // RR - respiratory rate
required uint32 pip_cm_h2o = 5; // PIP - peak inspiratory pressure
required float inspiratory_expiratory_ratio = 6; // I:E
required uint32 inspiratory_trigger_cm_h2o = 8; // P-trigger

// TODO(jlebar): Is ml/min the correct unit for this?
required uint32 expiratory_trigger_ml_per_min = 9; // V-trigger
required uint32 expiratory_trigger_ml_per_min = 9; // V-trigger

// A value between 0..1. Technically only values in [0.21, 1] are allowed.
required float fio2 = 10;
required float viv_ml = 11;
required float flow_l_per_min = 12;
required uint32 psupp_cm_h2o = 13;
required uint32 pstep_cm_h2o = 14;
}

// See
Expand Down Expand Up @@ -164,8 +165,17 @@ enum VentMode {
// P-trigger - inspiratory_trigger_cm_h2o
PRESSURE_ASSIST = 2;

// TODO: Implement me!
// TODO: Document these!
HIGH_FLOW_NASAL_CANNULA = 3;
VOLUME_CONTROL = 4;
CPAP = 5;
VOLUME_ASSIST = 6;
PRESSURE_SUPPORT = 7;
PC_SIMV = 8;
VC_SIMV = 9;
BIPAP = 10;
PRESSURE_REG_VC = 11;
SPONTANEOUS_BREATHS = 12;
}

// Sensor readings.
Expand Down
41 changes: 30 additions & 11 deletions software/controller/lib/core/breath_detection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,23 @@ limitations under the License.

#include "breath_detection.h"

/// \TODO: this is only here for loop period for default trigger values. Get rid of this
#include <algorithm>

#include "controller.h"

using DebugFloat = Debug::Variable::Float;

// Note tat since BreathDetection is instantiated for each breath, these debugvars are static and
// Note that since BreathDetection is instantiated for each breath, these debugvars are static and
// apply to any and all breath detection instances, to make them permanent and therefore traceable.
// This is fine because there can only ever be a single breath detection instance at any given time.

/// \TODO This should be configurable from the GUI.
static DebugFloat dbg_flow_trigger{"bd_flow_trigger", Debug::Variable::Access::ReadWrite, 200,
"mL/s", "Breath detection flow trigger"};
static DebugFloat inhale_trigger{"bd_inhale_trigger", Debug::Variable::Access::ReadWrite, 200,
"mL/s", "Breath detection inhale trigger"};

static DebugFloat exhale_trigger("bd_exhale_trigger", Debug::Variable::Access::ReadWrite, 300,
"mL/s", "Breath detection exhale trigger");

// fast_alpha_ and slow_alpha_ were tuned for a control loop that runs at a particular frequency.
// In theory if the control loop gets slower, the alpha terms should get bigger, placing more weight
Expand All @@ -48,13 +52,8 @@ BreathDetection::BreathDetection() {
dbg_slow_flow_avg.set(0);
};

bool BreathDetection::PatientInspiring(const BreathDetectionInputs &inputs, bool at_dwell) {
if (inputs.net_flow < ml_per_sec(0)) {
return false;
}

// Once flow is non-negative, start calculating two
// exponentially-weighted averages of net flow: slow_flow_avg_ and fast_flow_avg_.
void BreathDetection::update_averages(const BreathDetectionInputs &inputs) {
// Calculate two exponentially-weighted averages of net flow: slow_flow_avg_ and fast_flow_avg_.
//
// The slow one has a smaller alpha term, so updates slower than the fast one.
// You can think of the slow average as estimating "flow at dwell" and
Expand All @@ -69,6 +68,26 @@ bool BreathDetection::PatientInspiring(const BreathDetectionInputs &inputs, bool

dbg_slow_flow_avg.set(slow_flow_avg_.ml_per_sec());
dbg_fast_flow_avg.set(fast_flow_avg_.ml_per_sec());
}

bool BreathDetection::PatientInhaling(const BreathDetectionInputs &inputs, bool at_dwell) {
// Calculate averages only once flow is non-negative
if (inputs.net_flow < ml_per_sec(0)) {
return false;
}

update_averages(inputs);

return at_dwell && fast_flow_avg_ - slow_flow_avg_ > ml_per_sec(inhale_trigger.get());
}

bool BreathDetection::PatientExhaling(const BreathDetectionInputs &inputs, bool at_dwell) {
// Calculate averages only once flow is non-negative
if (inputs.net_flow < ml_per_sec(0)) {
return false;
}

update_averages(inputs);

return at_dwell && fast_flow_avg_ - slow_flow_avg_ > ml_per_sec(dbg_flow_trigger.get());
return slow_flow_avg_ > fast_flow_avg_ + ml_per_sec(exhale_trigger.get());
}
6 changes: 5 additions & 1 deletion software/controller/lib/core/breath_detection.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ class BreathDetection {
// - net_flow, to allow inspire detection
// - at_dwell, telling BreathDetection that the dwell plateau has been reached
// TODO: automatically detect dwell plateau from flow
bool PatientInspiring(const BreathDetectionInputs &inputs, bool at_dwell);
bool PatientInhaling(const BreathDetectionInputs &inputs, bool at_dwell);
bool PatientExhaling(const BreathDetectionInputs &inputs, bool at_dwell);

protected:
void update_averages(const BreathDetectionInputs &inputs);

private:
// During breath we maintain two exponentially-weighted averages of flow, one
Expand Down
Loading