diff --git a/addons/medical_engine/script_macros_medical.hpp b/addons/medical_engine/script_macros_medical.hpp index f2d4fb9a094..0016bf2c5b6 100644 --- a/addons/medical_engine/script_macros_medical.hpp +++ b/addons/medical_engine/script_macros_medical.hpp @@ -43,6 +43,7 @@ #define DEFAULT_HEART_RATE 80 #define DEFAULT_PERIPH_RES 100 +#define DEFAULT_STROKE_VOLUME 95e-3 // --- blood // 0.077 l/kg * 80kg = 6.16l @@ -54,6 +55,11 @@ #define BLOOD_VOLUME_CLASS_4_HEMORRHAGE 3.600 // lost more than 40% blood, Class IV Hemorrhage #define BLOOD_VOLUME_FATAL 3.0 // Lost more than 50% blood, Unrecoverable +#define DEFAULT_BP_MEAN 107 +#define DEFAULT_BP_HIGH 120 +#define DEFAULT_BP_LOW 80 +#define DEFAULT_BLOOD_PRESSURE [DEFAULT_BP_LOW,DEFAULT_BP_HIGH,DEFAULT_BP_MEAN] // at default heart rate + // IV Change per second calculation: // 250 ml should take 60 seconds to fill. 250 ml / 60 s ~ 4.1667 ml/s. #define IV_CHANGE_PER_SECOND 4.1667 // in milliliters per second diff --git a/addons/medical_status/XEH_PREP.hpp b/addons/medical_status/XEH_PREP.hpp index 811c49c1031..2e24691ff01 100644 --- a/addons/medical_status/XEH_PREP.hpp +++ b/addons/medical_status/XEH_PREP.hpp @@ -5,6 +5,7 @@ PREP(getBloodPressure); PREP(getBloodVolumeChange); PREP(getCardiacOutput); PREP(getMedicationCount); +PREP(getStrokeVolume); PREP(handleKilled); PREP(handleKilledMission); PREP(hasStableVitals); diff --git a/addons/medical_status/functions/fnc_getBloodPressure.sqf b/addons/medical_status/functions/fnc_getBloodPressure.sqf index bbb0e5b65ef..ec24137538d 100644 --- a/addons/medical_status/functions/fnc_getBloodPressure.sqf +++ b/addons/medical_status/functions/fnc_getBloodPressure.sqf @@ -9,6 +9,7 @@ * Return Value: * 0: BloodPressure Low * 1: BloodPressure High + * 2: Mean Arterial Pressure * * Example: * [player] call ace_medical_status_fnc_getBloodPressure @@ -16,16 +17,22 @@ * Public: No */ -// Value is taken because with cardic output and resistance at default values, it will put blood pressure High at 120. -#define MODIFIER_BP_HIGH 9.4736842 - -// Value is taken because with cardic output and resistance at default values, it will put blood pressure Low at 80. -#define MODIFIER_BP_LOW 6.3157894 +// Value that gives MAP=107 at default values +#define MODIFIER_BP 8.2168 params ["_unit"]; private _cardiacOutput = [_unit] call FUNC(getCardiacOutput); private _resistance = _unit getVariable [VAR_PERIPH_RES, DEFAULT_PERIPH_RES]; -private _bloodPressure = _cardiacOutput * _resistance; +private _meanPressure = _cardiacOutput * _resistance * MODIFIER_BP; + +private _heartRate = GET_HEART_RATE(_unit); + +//https://www.researchgate.net/publication/14609651_Calculation_of_Mean_Arterial_Pressure_During_Exercise_as_a_Function_of_Heart_Rate +private _stFraction = 0 max (0.01*exp(4.14-40.74/_heartRate)) min 0.5; + +private _strokeVol = [_unit] call FUNC(getStrokeVolume); +private _pulsePressure = (DEFAULT_BP_HIGH - DEFAULT_BP_LOW) * (_strokeVol / DEFAULT_STROKE_VOLUME) * (_resistance / DEFAULT_PERIPH_RES); -[round(_bloodPressure * MODIFIER_BP_LOW), round(_bloodPressure * MODIFIER_BP_HIGH)] +private _bpLow = _meanPressure - _pulsePressure*_stFraction; +[round _bpLow, round (_bpLow + _pulsePressure), round _meanPressure]; diff --git a/addons/medical_status/functions/fnc_getCardiacOutput.sqf b/addons/medical_status/functions/fnc_getCardiacOutput.sqf index cf405b52bc6..fa128cf2133 100644 --- a/addons/medical_status/functions/fnc_getCardiacOutput.sqf +++ b/addons/medical_status/functions/fnc_getCardiacOutput.sqf @@ -26,12 +26,17 @@ params ["_unit"]; -private _bloodVolumeRatio = GET_BLOOD_VOLUME(_unit) / DEFAULT_BLOOD_VOLUME; private _heartRate = GET_HEART_RATE(_unit); +if (_heartRate <= 1) exitwith {0}; + +private _strokeVol = [_unit] call FUNC(getStrokeVolume); + +/* // Blood volume ratio dictates how much is entering the ventricle (this is an approximation) private _entering = linearConversion [0.5, 1, _bloodVolumeRatio, 0, 1, true]; +*/ -private _cardiacOutput = (_entering * VENTRICLE_STROKE_VOL) * _heartRate / 60; +private _cardiacOutput = _strokeVol * _heartRate / 60; 0 max _cardiacOutput diff --git a/addons/medical_status/functions/fnc_getStrokeVolume.sqf b/addons/medical_status/functions/fnc_getStrokeVolume.sqf new file mode 100644 index 00000000000..b9526031e4f --- /dev/null +++ b/addons/medical_status/functions/fnc_getStrokeVolume.sqf @@ -0,0 +1,51 @@ +#include "script_component.hpp" +/* + * Author: Pterolatypus + * Calculate the stroke volume. + * + * Arguments: + * 0: The Unit + * + * Return Value: + * stroke volume (ml) + * + * Example: + * [player] call ace_medical_status_fnc_getStrokeVolume + * + * Public: No + */ + +// Value taken from https://doi.org/10.1093%2Feurheartj%2Fehl336 +// as 94/95 ml ± 15 ml +#define VENTRICLE_STROKE_VOL 95e-3 + +params ["_unit"]; + +private _heartRate = GET_HEART_RATE(_unit); +private _bloodVolumeRatio = GET_BLOOD_VOLUME(_unit) / DEFAULT_BLOOD_VOLUME; +_unit getVariable [VAR_BLOOD_PRESS, DEFAULT_BLOOD_PRESSURE] params ["_bpLow", "_bpHigh", "_bpMean"]; + +// Blood is pushed into the heart by Central Venous Pressure +// Approximated here using blood volume and (arterial) blood pressure +private _fillPressure = 0.7*_bloodVolumeRatio + 0.3*_bpMean/DEFAULT_BP_MEAN; +// Afterload (the force the heart must overcome to pump blood) depends primarily on systolic bp +private _afterload = _bpHigh/DEFAULT_BP_HIGH; +// TODO: Force of the heart contraction is influenced by medication. +private _contractility = 1; + +// End diastolic volume (volume the heart fills to) based on filling pressure and time available to fill +private _fillTime = DEFAULT_HEART_RATE/_heartRate; +private _fillPortion = 1 - exp (-3*_fillTime); +private _edv = _fillPortion * _fillPressure * 1.053 * 1.5 * VENTRICLE_STROKE_VOL; + +// End systolic volume (volume the heart contracts to) is based on afterload and contractility +private _esv = _afterload/_contractility * 0.5*VENTRICLE_STROKE_VOL; + +private _strokeVol = (_edv - _esv) max 0; + +#ifdef DEBUG_MODE_FULL +if (_unit getVariable [QGVAR(trace_strokevol), false]) then { + TRACE_10("Stroke volume trace",_bpHigh,_bpMean,_heartRate,_fillPressure,_fillTime,_fillPortion,_afterload,_edv,_esv,_strokeVol); +} +#endif +_strokeVol \ No newline at end of file diff --git a/addons/medical_status/script_component.hpp b/addons/medical_status/script_component.hpp index 324fb88078b..817ec494907 100644 --- a/addons/medical_status/script_component.hpp +++ b/addons/medical_status/script_component.hpp @@ -2,7 +2,7 @@ #define COMPONENT_BEAUTIFIED Medical Status #include "\z\ace\addons\main\script_mod.hpp" -// #define DEBUG_MODE_FULL +#define DEBUG_MODE_FULL // #define DISABLE_COMPILE_CACHE // #define ENABLE_PERFORMANCE_COUNTERS diff --git a/addons/medical_vitals/functions/fnc_updateHeartRate.sqf b/addons/medical_vitals/functions/fnc_updateHeartRate.sqf index 4da8519077f..d7989556609 100644 --- a/addons/medical_vitals/functions/fnc_updateHeartRate.sqf +++ b/addons/medical_vitals/functions/fnc_updateHeartRate.sqf @@ -35,17 +35,17 @@ if IN_CRDC_ARRST(_unit) then { private _targetHR = 0; private _bloodVolume = GET_BLOOD_VOLUME(_unit); if (_bloodVolume > BLOOD_VOLUME_CLASS_4_HEMORRHAGE) then { - GET_BLOOD_PRESSURE(_unit) params ["_bloodPressureL", "_bloodPressureH"]; - private _meanBP = (2/3) * _bloodPressureH + (1/3) * _bloodPressureL; + GET_BLOOD_PRESSURE(_unit) params ["_bloodPressureL", "_bloodPressureH", "_meanBP"]; + //private _meanBP = (2/3) * _bloodPressureH + (1/3) * _bloodPressureL; private _painLevel = GET_PAIN_PERCEIVED(_unit); private _targetBP = 107; if (_bloodVolume < BLOOD_VOLUME_CLASS_2_HEMORRHAGE) then { - _targetBP = _targetBP * (_bloodVolume / DEFAULT_BLOOD_VOLUME); + //_targetBP = _targetBP * (_bloodVolume / DEFAULT_BLOOD_VOLUME); }; _targetHR = DEFAULT_HEART_RATE; - if (_bloodVolume < BLOOD_VOLUME_CLASS_3_HEMORRHAGE) then { + if (_bloodVolume < 6) then { _targetHR = _heartRate * (_targetBP / (45 max _meanBP)); }; if (_painLevel > 0.2) then {