双水平呼吸机算法怎么写?(其实是记录自己写呼吸的心得)

双水平正压呼吸机是什么?

  • 市面上的双水平呼吸机,就是包含有双水平模式的呼吸机,其中一般也会包含单水平模式。
  • 其中正压的意思,就是抬高呼吸的压力基线,使吸气顺畅一些。

呼吸机硬件参考

不能给太详细,就给个名字,具体的自己设计。

压力传感器、压力差传感器、数字型电机驱动器、带霍尔的涡轮风机(和驱动器配合一起,最好找一家同时生产涡轮风机和驱动器的厂商)等(其他的额外的东西就不重要啦!)。

呼吸机模式有哪些

就拿鱼跃的YH-820呼吸机来说,其:

  • 单水平模式有CPAP
  • 双水平模式有S、T、ST、VGPS模式。

CPAP模式介绍(主要写的算法1)

CPAP诞生的历史是最早,沙利文博士搞的第一台呼吸机的就是这模式。

我的写法是按照《双水平呼吸机控制逻辑策略的设计与实现》这个论文的说法来写的,以下摘抄自论文双水平呼吸机控制逻辑策略的设计与实现

CPAP模式下,呼吸机在整个呼吸过程中,给患者的气道提供恒定的压力支持。患者进行呼吸切换时,呼吸机将动态调整内部涡轮风机的转速,抵抗患者呼吸动作造成的干扰,维持恒定的压力。由于呼气和吸气时,呼吸机提供相同的压力,患者在呼气时需要克服压力做功,舒适度一般。

虽然都叫CPAP,但是网上的CPAP各有各的说法,比如我的师兄,写的CPAP是固定气道压力的CPAP,还是有点不一样(笑)。

APAP模式介绍(主要写的算法2,加一条)

APAP叫 Auto CPAP,自动的CPAP,哪里自动了?原来是在人呼吸阻塞的时候,给气道加个压呀!

本来呼吸的好好的,突然压力没有变化了!为啥?原来是人不呼吸了,加压!必须马上加压!

然后等人正常呼吸后,再恢复原本的压力。

S模式介绍(主要写的算法3)

双水平模式来喽!双水平是飞利浦第一个搞的。牛!

其和单水平的区别在于呼气和吸气时压力不一致!上图!

如何做到呢?先知道如何识别呼吸吧(算法部分再讲)!

T模式简单介绍

就是用户自己设定一个呼吸周期,吸气占呼气比例多少,然后病人被动的跟着呼吸机呼吸。

ST模式简单介绍

就是把S模式和T模式结合起来了,根据病人的呼气周期、吸气占比,来动态的调整呼气和吸气的时间。

VGPS 不-介绍

算法涉及到哪些内容?

气道压力对应电机速度、延时升压、呼吸罩穿戴检测、呼吸阻塞检测、阻塞升压、呼吸切换检测、呼气吸气切换时间安排、pid动态调压等。

  • 气道压力对应电机速度:输入一个想要控制的气道压力值,输出电机速度,使气道达到该压力值。
  • 延时升压:这个时基于患者舒适度考虑的,设定一个初始压力,在初始压力的基础上,不断升压,在设定时间内升压到设定压力
  • pid动态调压:
    • 在单水平模式和双水平模式的非呼吸切换状态下,根据气道的压力,动态调节涡轮风机的转速,使气道压力动态稳定
    • 在双水平的呼吸切换状态下,快速切换呼气和吸气的气道压力
  • 呼吸切换检测:检测患者切换呼吸状态;
  • 呼吸阻塞检测:检测患者呼吸受阻;
  • 呼气吸气切换时间安排:在双水平模式下,切换两种气道压力时的切换时间,呼气到吸气为上升时间,吸气到呼吸为下降时间;
  • 阻塞升压:在APAP模式下,当患者呼吸受阻时,自动提升气道的压力,直到患者恢复正常呼吸;
  • 呼吸面罩的穿戴检测:检测人是否带上呼吸面罩。

算法实现

气道压力对应电机速度

我的控制电机是通过中间驱动器的,我对驱动器输入多少速度,电机就会自己达到那个速度,所以对于电机速度上,我不用管(你们要不要搞一个电机速度和电流的关系就不关我事了嘿嘿)。

如何做到电机速度对应压力呢?最简单的办法就是作拟合曲线。

上吧!我的 Excel !

测出带上面罩的压力数据以及对应的电机速度数据,对这两列建立散点图。

然后右键图像曲线,把这两列框上即可。


选择好后确认即可。

生成拟合曲线:

先添加趋势线,然后选择合适的趋势线选项,并且显示趋势线公式还有R^2^(R^2^越接近1说明拟合效果越好)

上面的公式是:

只要我想让气道输出一个固定的压力,比如4cmH2O,带入这个公式,算出的电机速度,直接发给驱动器就可以了。

验证一下:

是不是很相近了!

具体代码相关函数:

c 复制代码
/*********************************************************************************************************
* 函数名称:PressureToMotoSpeed
* 函数功能:输入气压参数控制电机转速
* 输入参数:cmH2O:4.0 - 20.0 cmH2O
* 输出参数:void
* 返 回 值:void
* 创建日期:2023年11月16日
* 注    意:根据公式1:y = 0.06573 x3 - 3.93066 x2 + 126.67006 x + 40.14498, R2 = 0.99997 ,这一条是电机对面罩输出气压
*********************************************************************************************************/
void PressureToMotoSpeed(double cmH2O)
{
	unsigned int realSpeed = 0;
	
	realSpeed = (unsigned int)(0.06573*cmH2O*cmH2O*cmH2O - 3.93066*cmH2O*cmH2O + 126.67*cmH2O + 40.14498);
	
	CtrlMotoSpeed(realSpeed);
}

这是一个函数,传入参数是厘米水柱,没有输出值。函数的作用是把厘米水柱的值,直接转换成电机速度,然后调用电机速度控制函数,直接控制电机。

延时升压

延时升压,经过一段时间,从初始压力逐渐上升到设定压力。

有几个参数需要注意:初始压力、设定压力、升压时间。

  • 初始压力:刚启动时的压力;
  • 设定压力:经过延时升压最终达到的压力;
  • 升压时间:升压需要的时间。

根据鱼跃的YH-820呼吸机来看,他的延时升压是以0.1分钟为单位的,也就是每过0.1分钟,就上升一次压力,也就是我们得根据这个0.1分钟来细分升压的压力,例子如下:

初始压力 == 5 cmH2O

设定压力 == 10 cmH2O

升压时间 == 5min

我们先把 5min 乘上 10 == 50,也就是需要进行50次升压。

用 设定压力 - 初始压力 = 10 - 5 = 5 cmH2O,也就是总共需要升高5cmH2O的压力。

用 5cmH2O / 50次 = 0.1 cmH2O,也就是说每过 0.1分钟,需要升高 0.1cmH2O。

具体代码片段:

c 复制代码
// 延时升压,当(s_boostPressureCnt2 > s_boostPressureCnt)时,延时升压结束。
if( s_boostPressureCnt2 <= s_boostPressureCnt )
{
	if( e_iTimCnt >= s_DelayBoostStartTime + 6000*s_boostPressureCnt2 )
	{
		s_boostPressureCnt2++;
		
		ctrlPressure += (Monitor_Set_Pressure-Monitor_Initial_Pressure) / (DelayedBoost*10);
		// 延时升压的最后一轮升压,直接变成设定的压力,防止浮点计算出现的误差。
		if( s_boostPressureCnt2 == s_boostPressureCnt )
		{
			ctrlPressure = Monitor_Set_Pressure;
		}
	}
}

以上参数解释:

  • s_boostPressureCnt:总升压次数,如上例中的50次;
  • s_boostPressureCnt2:当前升压的计数,每升一次压加1,直到大于总升压次数;
  • e_iTimCnt:系统计时时间,每过1ms加1;
  • s_DelayBoostStartTime:起始升压的时间,进入呼吸模式时记录的系统时间;
  • 其中在系统计时中,6000 == 0.1min;
  • ctrlPressure:当前压力;
  • Monitor_Set_Pressure:设定压力;
  • Monitor_Initial_Pressure:初始压力;
  • DelayedBoost:延时升压的时间,如上例中的5min。

算法解释:

当前升压计数 <= 总升压次数,且升压最小时间到达,则升压一次,当最后一轮升压时,直接赋值设定压力。

呼吸罩穿戴检测

如何检测呼吸面罩是否穿戴?有的人用硬件解决这个问题(专门搞个模块检测的),有的人用软件解决这个问题(用 压力 或 压力差 传感器来看),我属于后者。

压力 传感器怎么看

有了上面的带上面罩的压力速度曲线后,咱们再加一条没带上面罩的压力数据曲线。

再对两个压力作拟合曲线,这样就可以知道在没戴面罩时对应的压力是多少了。

例如:

我设定一个气道压力维持在4.48,此时是我带上面罩应该有的气道压力,但是我实际检测到气道压力小于等于1.55(这里可以加一个常数偏大一点,因为脱面罩不会老是在这个值位置,可以会偏一点),这个时候我就可以认定是没带面罩了。

具体代码片段:

c 复制代码
miniPressure = 0.0266*(double)ctrlPressure + 1.4685;
// 带着面罩
if( measurePressure > miniPressure )
{
	WearingMaskCnt2 = 0;
	if( WearingMaskCnt1++ > 10 )
	{
		WearingMaskCnt1 = 0;
		// 清除未戴面罩标志位
		WearingMaskFla = 0;
	}
}
else
{
	WearingMaskCnt1 = 0;
	if( WearingMaskCnt2++ > 10 )
	{
		WearingMaskCnt2 = 0;
		// 置位未戴面罩标志位
		WearingMaskFla = 1;
	}
}

参数解释:

  • measurePressure:这是实际测量的气道压力值。
  • ctrlPressure:这是实际应该要输出的戴面罩的压力值。
  • miniPressure:这是对应压力下未带面罩时应该有的压力值。

算法解释:

当实测压力值大于未戴面罩压力值,且持续一段时间,则清除 未带面罩标志位(此时就相当于戴上了面罩),否则进入else一段时间,则为置位 未带面罩标志位。

压力差 传感器怎么看

压力差传感器可以相当于流量传感器的作用,当流量大于一定阈值时,就是没戴上面罩,反之则戴上了。

因为带上面罩气流值基本很小了,没带上面罩时,就算电机转的很慢,气流也会很大。

呼吸切换检测

呼气吸气怎么检测?

哎呀直接上图:

这个是我实测的气道压力变化图。

我只要一呼气,气道压力迅速上升,而后缓慢下降;

我只要一吸气,气道压力迅速下降,然后缓慢上升;

其中有两个点很好捕捉的,就是迅速上升和迅速下降的两个点。

那就可以用 判断趋势 + 判断阈值 两重办法来弄。

代码片段如下:

c 复制代码
// 上升	+ 阈值 = 呼气
if( measurePressure > LastPressure )
{
	exhaleeCnt++;
	if( exhaleeCnt >= ExhalationTriggerS )
	{
		if( measurePressure > ExhalationThreshold )
		{
			// 呼气计数清零
			exhaleeCnt = 0;
			// 吸气计数清零
			inhaleCnt = 0;
			// 呼气
			printf("呼气\r\n");
		}
	}
}
else
{
	exhaleeCnt = 0;
}

以上只有呼气部分,是因为吸气部分和呼气的内容大差不差,就简略掉了。

参数解释:

  • measurePressure:当前气道压力;
  • LastPressure:上次检测气道压力;
  • exhaleeCnt:呼气上升计数;
  • ExhalationTriggerS:呼气触发敏感度;
  • ExhalationThreshold:呼气阈值;
  • inhaleCnt:吸气下降计数;

算法解释:

当连续上升一定次数时,并且当前的气道气压大于设置的阈值时,就判定为呼气;一旦在上升期间出现下降,则清空上升计数。

注意:

ExhalationTriggerS 和 ExhalationThreshold 参数都得自己耐心调试得到哦!

呼吸阻塞检测

呼吸阻塞检测简单呀,当一段时间不呼气也不吸气就是阻塞了,这个时候直接判定为阻塞。

代码如下:

c 复制代码
if( breathe == 0 )
{
	// 阻塞判断
	if( NotBreathingCnt++ > NotBreathingVal )
	{
		NotBreathingCnt = 0;
		// 陷入阻塞
		printf("阻塞\r\n");
	}
}
else
{
	NotBreathingCnt = 0;
}

参数解释:

breathe:不呼吸为0,呼吸为1;

NotBreathingCnt:不呼吸的持续计数值;

NotBreathingVal:不呼吸多久的认为设定参数值,需要自己调试得到。

算法解释:

当不呼吸且持续了一段时间,则陷入阻塞,否则清除不呼吸计数。

阻塞升压

在APAP模式中,陷入阻塞后逐渐上升压力。

c 复制代码
// 不阻塞
if( TrappedInBlockage == 0 )
{
	maintainCnt -= 10;
	if( maintainCnt < -60 )
	{
		maintainCnt = 0;
		if( ctrlPressure > SetPressure + (float)0.1 )
		{
			maintainPIDValCnt = 0;
			ctrlPressure -= (float)0.5;
		}
	}
}
// 陷入阻塞
else if( TrappedInBlockage == 1 )
{
	if( maintainCnt++ > 300 )
	{
		maintainCnt = 0;
		
		ctrlPressure += (float)0.5;
		if( ctrlPressure > (float)25.0 )
		{
			ctrlPressure = 25;
		}
		else if( ctrlPressure > SetPressureApap + AutopressureVal + (float)0.1 )
		{
			ctrlPressure = SetPressureApap + AutopressureVal;
		}
	}
}

参数解释:

  • TrappedInBlockage:陷入阻塞标志位;
  • maintainCnt:维持状态的计数值;
  • ctrlPressure:当前的控制的气道压力;
  • SetPressure:设置的气道压力;
  • 阻塞一定时间就上升一次0.5cmH2O;
  • 最大的气道压力限制在25cmH2O;
  • AutopressureVal:最大阻塞升压值,阻塞后最大能达到的压力就是(SetPressureApap + AutopressureVal)。

算法解释:

陷入阻塞一段时间后上升一定的压力,持续这个动作,直到压力上升达到极限。反之当不阻塞时,迅速减小压力,直到回归原本的压力。

呼气吸气切换时间安排

对于双水平中,有上升时间和下降时间的概念,意思就是说,当人呼吸切换时,气道压力切换需要的时间。

例如:呼气切换到吸气,气道压力需要上升到吸气需要的压力,这个时候,给个一定的逐步上升时间,可以给人一定的舒适感。

具体代码内容放到双水平S模式讲解。

pid动态调压

对于pid不了解的可以看看这个文章:PID超详细教程------PID原理+串级PID+C代码+在线仿真调参

对于pid动态调压,最难的点就是pid参数的设置,其他都很简单,但是我这里不讲pid参数怎么调节啦!大家自己想办法吧(hhh)!

代码如下:

c 复制代码
// 呼吸压力变化的情况下稳定压力。
pressureStabilityPID.target = ctrlPressure;
pid_calculate(&pressureStabilityPID, measurePressure);
if( pressureStabilityPID.output < 0 )
{
	PressureToMotoSpeed(0);
}
else if( pressureStabilityPID.output > 25 )
{
	PressureToMotoSpeed(25);
}
else
{
	PressureToMotoSpeed(pressureStabilityPID.output);
}

// pid 输出过高,一般是取下面罩导致的
if( (pressureStabilityPID.output - ctrlPressure) > 3 )
{
	// 进入稳定区域
}
// 气压过低,也是取下面罩导致的
if( measurePressure < miniPressure )
{
	// 进入稳定区域
}

参数解释:

  • pressureStabilityPID:pid结构体,包含pid的一些参数,如p、i、d参数、target目标值、output输出值等。
  • ctrlPressure:当前的控制的气道压力;
  • measurePressure:气压传感器读取的气道气压值。
  • pid_calculate(&pressureStabilityPID, measurePressure):对目标值和实际值之间做pid计算,计算出的值给到 pressureStabilityPID.output;
  • 不能输出负数的气压值,小于0就让他等于0;
  • 限制气压最大在25cmH2O以下;
  • pid的输出最大不要超过ctrlPressure一定值,自己设定一个合适值即可;
  • miniPressure:未戴面罩应该有的压力值。

算法解释:

对目标气压值和实际气压值之间做pid运算,输出的气压值做一个限制,在一个范围内。当压力过小时,或者pid输出过大时(相当于没戴面罩),减小电机转速进入未戴面罩的稳定区域。

具体呼吸机模式编写

不管是什么呼吸机模式,都可以给他拆分为多个状态,如常见的几种状态:正常运行模式,未带面罩时的低风速模式,过度到低风速模式的中间模式等

CPAP

CPAP可以分为:戴上面罩的正常运行模式、戴上面罩向没有戴面罩的风机转速过度模式、未戴上面罩的低风速模式、未戴面罩向戴上面罩的风机转速过度模式。

为什么要有过度模式,因为我的电机转速变化太快会停转,所以加了一个过度模式。

戴上面罩的正常运行模式(状态0,overvoltageStopFlag == 0)

要求:pid需要正常运行、实时控制电机转速、要检测未戴面罩;

代码如下:

c 复制代码
// 呼吸压力变化的情况下稳定压力。
pressureStabilityPID.target = ctrlPressure;
pid_calculate(&pressureStabilityPID, measurePressure);
if( pressureStabilityPID.output < 0 )
{
	PressureToMotoSpeed(0);
}
else if( pressureStabilityPID.output > 25 )
{
	PressureToMotoSpeed(25);
}
else
{
	PressureToMotoSpeed(pressureStabilityPID.output);
}

// pid 输出过高
if( (pressureStabilityPID.output - ctrlPressure) > 3 )
{
	overvoltageStopFlag = 2;
}
// 气压过低
if( measurePressure < miniPressure )
{
	overvoltageStopFlag = 2;
}

以上代码有没有和pid动态调压部分很像!其实就是一个东西hh。

戴上面罩向没有戴面罩的风机转速过度模式(状态2,overvoltageStopFlag == 2)

要求:要延时一段时间稳定电机转速、清除pid的缓存值;

c 复制代码
if( overvoltageStopCnt++ > 80 )
{
	overvoltageStopCnt = 0;
	overvoltageStopFlag = 3;
	pid_clear(&pressureStabilityPID);
}
// 输出风机转速
PressureToMotoSpeed(ctrlPressure/2);

控制电机转速降低一半,也可以逐步降低,看自己怎么写。

未戴上面罩的低风速模式(状态3,overvoltageStopFlag == 3)

要求:检测呼吸。

c 复制代码
// 检测到呼吸
if( ABS(LastBreathePressureVal - measurePressure ) > 0.06 )
{
	LastBreathePressureVal = measurePressure;
	
	BreathePressureCnt += 5;
	if( BreathePressureCnt > 10 )
	{
		BreathePressureCnt = 0;
		
		// 呼气启动
		overvoltageStopFlag = 1;
	}
}
else
{
	if( BreathePressureCnt > -10 )
	{
		BreathePressureCnt--;
	}
}

解释:

  • ABS是取绝对值。
  • 检测呼吸的判断就是,上次压力比这次压力差值大于一个自己调试出来的参数值(0.06),连续好几次就是呼吸了;

未戴面罩向戴上面罩的风机转速过度模式(状态1,overvoltageStopFlag == 1)

要求:提前稳定pid、电机转速进入过度速度。

c 复制代码
if( overvoltageStopCnt++ > 130 )
{
	overvoltageStopCnt = 0;
	overvoltageStopFlag = 0;
}
pressureStabilityPID.target = ctrlPressure;
pid_calculate(&pressureStabilityPID, measurePressure);
// 输出风机转速
PressureToMotoSpeed(ctrlPressure/2);

控制电机转速为实际输出的一半,也可以逐步上升,看自己怎么写。

过程中一直计算pid,使到达状态0。

APAP

APAP和CPAP差不多,只加入了阻塞升压的功能,具体内容直接翻看上面的阻塞升压部分,这部分只在状态0生效。

双水平S模式

双水平的状态就多喽,不过也没多到哪里去,也就9种状态,呼气3种,吸气3种,戴没戴面罩切换2种,没戴面罩低风速1种。

呼气3种状态(状态1,3,5,overvoltageStopFlag == 1或3或5)

呼气正常pid调节状态(pid正常运算,判断pid过大,判断没戴面罩,判断吸气)、吸气上升(逐步上升输出气道压力、pid运算)、等待pid达到气道压力(pid控制电机、pi的稳定判断、判断pid过大)

呼气正常pid调节状态(状态1,overvoltageStopFlag == 1)

pid正常运算,判断pid过大,判断没戴面罩,判断吸气

c 复制代码
// 呼吸压力变化的情况下稳定压力。
pressureStabilityPID.target = ctrlPressure;
pid_calculate(&pressureStabilityPID, measurePressure);
if( pressureStabilityPID.output < 0 )
{
	PressureToMotoSpeed(0);
}
else if( pressureStabilityPID.output > 24 )
{
	PressureToMotoSpeed(24);
}
else
{
	PressureToMotoSpeed(pressureStabilityPID.output);
}
// 下降	+ 阈值 = 吸气
if( LastPressure > measurePressure )
{
	inhaleCnt++;
	if( inhaleCnt >= InspiratoryTriggerS )
	{
		if( measurePressure < ctrlPressure )
		{
			inhaleCnt = 0;
			exhaleeCnt = 0;
			// 吸气
			printf("吸气\r\n");
			
			// 吸气上升
			overvoltageStopFlag = 3;
			
			// 设置新的pid参数
			pid_init(&pressureStabilityPID, PID_Position, P2, I2, D2);
		}
	}
}
else
{
	inhaleCnt = 0;
}
// pid 输出过高
if( (pressureStabilityPID.output - ctrlPressure) > 3 )
{
	overvoltageStopFlag = 6;
}
// 气压过低
if( measurePressure < miniPressure )
{
	overvoltageStopFlag = 6;
}

这些东西其实之前都介绍过了。

就是把他们杂糅起来而已。

其中这里设置了不同的pid参数:

c 复制代码
pid_init(&pressureStabilityPID, PID_Position, P2, I2, D2);

为什么这样设置?

我们的pid参数实际上分为两种,一个是稳定状态下的pid动态调压,一个是呼吸切换时的快速pid切换调压,这里就是切换到快速pid调压。

吸气上升(状态3,overvoltageStopFlag == 3)

逐步上升输出气道压力、pid运算。

c 复制代码
// pid计算
pressureStabilityPID.target = SuctionPressureS;
pid_calculate(&pressureStabilityPID, measurePressure);
// 逐渐上升
ctrlPressure += riseTimeMiniInterval;
// 输出风机转速
PressureToMotoSpeed(ctrlPressure);

if( overvoltageStopCnt++ >= 20*RiseTimeS )
{
	overvoltageStopCnt = 0;
	// 稳定吸气压力pid
	overvoltageStopFlag = 5;
	
	// 设置输出吸气压
	ctrlPressure = SuctionPressureS;
}

这一段是吸气上升吸气上升阶段,包含了电机逐步上升,pid跟随上升,吸气上升结束时切换到等待pid稳定状态。

等待pid达到气道压力

pid控制电机、pi的稳定判断、判断pid过大;

c 复制代码
// pid计算
pressureStabilityPID.target = ctrlPressure;
pid_calculate(&pressureStabilityPID, measurePressure);
if( pressureStabilityPID.output < 0 )
{
	PressureToMotoSpeed(0);
}
else if( pressureStabilityPID.output > 24 )
{
	PressureToMotoSpeed(24);
}
else
{
	PressureToMotoSpeed(pressureStabilityPID.output);
}

// pid稳定
if( ABS(ctrlPressure - pressureStabilityPID.output) < (float)0.1 )
{
	overvoltageStopFlag = 1;
	// 恢复pid参数
	pid_init(&pressureStabilityPID, PID_Position, P1, I1, D1);
}

// pid 输出过高
if( (pressureStabilityPID.output - ctrlPressure) > 6 )
{
	overvoltageStopFlag = 6;
}

恢复正常运行状态下的pid参数:

c 复制代码
pid_init(&pressureStabilityPID, PID_Position, P1, I1, D1);

这里的pid过高阈值设置的比较高,是因为这个参数的pid比较暴躁(应该是我没调好参数)。

吸气3种状态(状态0,2,4,overvoltageStopFlag == 0或2或4)

和呼气没太大区别,不写了!

戴面罩到没戴面罩过程中的2种状态(状态6,7,overvoltageStopFlag == 6或7)

电机稳定到设定气道压力的一半
c 复制代码
if( overvoltageStopCnt++ > 80 )
{
	overvoltageStopCnt = 0;
	overvoltageStopFlag = 7;
	pid_clear(&pressureStabilityPID);
	pressureStabilityPID.output = ctrlPressure*2;
}
// 输出风机转速
PressureToMotoSpeed(ctrlPressure/2);
电机稳定到一个较小值
c 复制代码
if( overvoltageStopCnt++ > 80 )
{
	overvoltageStopCnt = 0;
	overvoltageStopFlag = 8;
}
// 输出风机转速
PressureToMotoSpeed(miniPressure);

没戴面罩低风速1种(状态8,overvoltageStopFlag == 8)

c 复制代码
// 检测到呼吸

if( ABS(LastBreathePressureVal - measurePressure) > (float)0.06 )
{
	LastBreathePressureVal = measurePressure;
	
	BreathePressureCnt += 5;
	if( BreathePressureCnt > 10 )
	{
		BreathePressureCnt = 0;
		
		// 呼气启动
		overvoltageStopFlag = 1;
		ctrlPressure = ExpiratoryPressureS;
		// 恢复pid参数
		pid_init(&pressureStabilityPID, PID_Position, P1, I1, D1);
		exhaleeCnt = 0;
		inhaleCnt = 0;
		overvoltageStopCnt = 0;
	}
}
else
{
	if( BreathePressureCnt > -10 )
	{
		BreathePressureCnt--;
	}
}

总结

大概就这些啦,其中代码都是简略贴上来的,部分耦合思路还得自己去想啦,就提供个大概方向,尼玛写的真累!!

相关推荐
青い月の魔女9 分钟前
数据结构初阶---二叉树
c语言·数据结构·笔记·学习·算法
最后一个bug1 小时前
STM32MP1linux根文件系统目录作用
linux·c语言·arm开发·单片机·嵌入式硬件
林的快手1 小时前
209.长度最小的子数组
java·数据结构·数据库·python·算法·leetcode
千天夜1 小时前
多源多点路径规划:基于启发式动态生成树算法的实现
算法·机器学习·动态规划
从以前1 小时前
准备考试:解决大学入学考试问题
数据结构·python·算法
wenchm1 小时前
细说STM32F407单片机IIC总线基础知识
stm32·单片机·嵌入式硬件
.Vcoistnt1 小时前
Codeforces Round 994 (Div. 2)(A-D)
数据结构·c++·算法·贪心算法·动态规划
嵌入式lover2 小时前
STM32项目之环境空气质量检测系统软件设计
stm32·单片机·嵌入式硬件
ALISHENGYA2 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(实战训练三)
数据结构·c++·算法·图论
kenwblack3 小时前
STM32 SPI读取SD卡
stm32·单片机