已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也

基本已经实现 这大概是我目前做的最小巧的东西了 心跳和憋气测试有效果 (目前还没到考虑标定的那步)

1656061886800.jpg

从机器内通过串口导出的内部真实算出频谱结果如下 应该算具备足够的分辨能力了

pd-real.png

中间用采到的心跳数据 使用格兹尔算法也模拟了一遍 也有类似的效果

Goertzel.png

这个算法同样是非帧的 可以累进处理的 对内存要求也一样 但是多了cos查表和乘法 对运算误差有些敏感 而且还没有想到怎么进行收敛 (我现在开关鉴相算法中使用一阶低通来代替积分实现收敛)

这里把算法步骤放一下 运算相当简单 利用了整数的累加溢出后等效于取模的周期性

u16 idata g_pdi;   
u16 idata g_pdq;   
u16 idata g_pdf;   
i16 xdata g_hr_i[HR_MAX-HR_MIN+1]; // I信号数组 下标是心跳频率(从最小频率开始)
i16 xdata g_hr_q[HR_MAX-HR_MIN+1]; // I信号数组 下标是心跳频率(从最小频率开始)

// (65536*HR_MIN/60/SEN_RATE-6)=322, -6 is a fixed value for smallest error in whole heart beat rate scope 
#define PD_TADD  322
// (65536/(60*SEN_RATE))=11
#define PD_FADD  11

清零 g_hr_i[] g_hr_q[];
g_pdi=0;  // 0 degree
g_pdq=16384; // 90 degree

对每次采样结果(每秒100次):	{	
	pdi=g_pdi;
        pdq=g_pdq;
	依次对频率点(30-180/分): {
		if (pdi & 0x8000)
			g_hr_i[i]-=ac;
		else 
			g_hr_i[i]+=ac;

		if (pdq & 0x8000)
			g_hr_q[i]-=ac;
		else
			g_hr_q[i]+=ac;
              .....低通收敛一下....;
		pdi+=g_pdf; 
		pdq+=g_pdf;		
	}

	g_pdi+=PD_TADD;
	g_pdq+=PD_TADD;
	g_pdf+=PD_FADD;
}

我期间看了一下美信再mbed上的算法 其复杂性令人害怕 完全时域上的各种处理 找峰值 屏蔽干扰 鉴别等等等等.... 而我求心跳峰值的算法 借鉴了二极管检波求峰的原理和现有峰值自然衰退的方法

// max/min parameters decay
red_maxd -= (red_maxd - red32 +64)>>7;

// calculate new max/min
if (red32>red_maxd) {
	g_red_max += (red32 - g_red_max + 16) >> 5;
	red_maxd=red32;
} 		

 虽然极简 但是效果不错

max_maxd.png

目前程序离8k还差几百字节(已经包括了接近检测 光功率自动调整 串口输出和命令下载等所有的杂项功能) 还没有用任何浮点运算 (否则就只能把字库和查表放到eeprom里面省出足够空间) 可以算可用的初版了 下面等电池到货 设计一下外壳就差不多了 可能还想再优化一下鉴相算法 尤其是低通收敛这块 看看能不能让结果更平滑点

....................................

试了一下内建余弦表 使用余弦鉴相代替开关鉴相 得到心跳频谱图如下

hr_cos.png

有所改观但是区别不大 但是算力恰恰够 我的显示刷新是在空闲时候进行(并未打开中断而是轮询) 使用余弦鉴相后 刷新率下降到了2秒一次 而使用开关鉴相 刷新率基本符合0.6秒一次 代码仅仅改动如下 可以略微优化但是余量不大 现在数据采集率100Hz 如果降到50Hz可能会轻松点  但是衡量一下 还是保持采集率好处更大

i16 cos(u8 x)
{
	if (x<=64)  return COS_LUT[x];
	if (x<=128) return -COS_LUT[128-x];
	if (x<=192) return -COS_LUT[x-128];
	return COS_LUT[(u8)-(i8)x];
}

#ifdef USE_COS
		g_hr_i[i]+=(i16)(((i32)ac*(i32)cos((u8)(pdi>>8)))>>16);
#else		
		if (pdi & 0x8000)
			g_hr_i[i]-=ac;
		else 
			g_hr_i[i]+=ac;
#endif

..................................

还是优化了 减少了32位乘法 表中直接使用8位数减少位移 

i16 cos(i8 x)
{
	if (x<0) x=-x;
	if (x>64) return -COS_LUT[128-(u8)x];
  return COS_LUT[x];	
}
...............
.............
#ifdef USE_COS
		g_hr_q[i]+=(ac*(cos(*(i8*)&pdq)))>>7;
#else		

刷新率到了1秒1次 再三衡量 还是用这个罢

所以 题目虽然是开关鉴相 但是 最后还是做了余弦鉴相 .... 不过 也不妨碍开关鉴相好用可用

文号 / 905166

千古风流
名片发私信
学术分 1
总主题 52 帖总回复 897 楼拥有证书:进士 学者 机友
注册于 2020-01-22 18:44最后登录 2024-11-25 07:30
主体类型:个人
所属领域:无
认证方式:手机号
IP归属地:上海

个人简介

个人开源项目: m24h.github.io

文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

插入资源
全部
图片
视频
音频
附件
全部
未使用
已使用
正在上传
空空如也~
上传中..{{f.progress}}%
处理中..
上传失败,点击重试
等待中...
{{f.name}}
空空如也~
(视频){{r.oname}}
{{selectedResourcesId.indexOf(r.rid) + 1}}
处理中..
处理失败
插入表情
我的表情
共享表情
Emoji
上传
注意事项
最大尺寸100px,超过会被压缩。为保证效果,建议上传前自行处理。
建议上传自己DIY的表情,严禁上传侵权内容。
点击重试等待上传{{s.progress}}%处理中...已上传,正在处理中
空空如也~
处理中...
处理失败
加载中...
草稿箱
加载中...
此处只插入正文,如果要使用草稿中的其余内容,请点击继续创作。
{{fromNow(d.toc)}}
{{getDraftInfo(d)}}
标题:{{d.t}}
内容:{{d.c}}
继续创作
删除插入插入
插入公式
评论控制
加载中...
文号:{{pid}}
加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}
ID: {{user.uid}}