向小俊同志学习,心电图R波识别算法
warmonkey2010/07/23软件综合 IP:浙江
图片上的红线并不是心率-时间曲线,而是处理后的心电数据,用于识别心跳
Pan-Tompkins+maxsearch.jpg
识别率接近99.8%

BPF是9-11Hz带通滤波器
信号取自自己,睡觉时记录了10分钟,8位量化,没有进行数字滤波


程序代码:
%pan-tompkins算法与最大值搜索联用

%--------------------------需要配置的参数-----------------------------------

%最小阈值
thresh_min = 4;
%滑动平均窗口宽度
windowsize = 300;
%进一步搜索最大值的范围
findmax_l_edge=-400;
findmax_r_edge=-100;
%新阈值计算系数
%新阈值 = thresh_refresh_k*上一个峰值;
thresh_refresh_k = 0.4;

%--------------------------运行前要输入的数据-------------------------------

%原始心电数据  要校正到2uV/LSB
%ecg = ecg_readcsv('holter.csv',1);
%采样率
fs = 1024;
%需要处理的数据范围
x = XXXXXXlue(1:fs*200)*500;
%x = XXXXXXlue*500;
%滤波器对象及延时
%load XXXXXXt
%filter_delay = 200;
filter_delay = 0;

%---------------------------程序-------------------------------------------
disp('Stage 1 Filtering');

disp('    Step 1/5');
%x->原始数据,y->处理后数据
y = x;
disp('          OK');

disp('    Step 2/5');
%滤波
%x = filter(HPF,x);
%x = filter(LPF,x);
y = filter(BPF,y);
disp('          OK');

disp('    Step 3/5');
%微分
y = diff(y);
disp('          OK');

disp('    Step 4/5');
%平方每一项
for i=1:length(y)
    y(i) = y(i) * y(i);
   %if(y(i)<0)
   %    y(i)=-y(i);
   %end
end
disp('          OK');

disp('    Step 5/5');
%滑动平均
y = filter(ones(1,windowsize)/windowsize,1,y);
disp('          OK');

%------------------------Pan-Tompkins算法----------------------------------
peak_value=0;%峰值大小
peak_addr=0;%峰值位置

thresh = thresh_min;
thresh_updated = 0;

last_r_pos = 0;

clear rwave_stack;
rwave_stack = zeros(1,ceil(length(y)/(fs*60/300)));
rwave_stack_pos = 1;

disp('Stage 2 Pan-Tompkins');
last_percent = 0;
for i=1:length(y)
    %报告进度
    percent = i/length(y)*100;
    if( last_percent +1 == floor(percent))
         disp(strcat(num2str(percent),'%'));
         last_percent = floor(percent);
    end
    
    %当fs*2个样本内(心率最低30)有一个有效的峰值,就保存下来
    %查找峰值的范围
    if( last_r_pos == 0 )
        %之前没找到R波,从i处开始找峰值
        peak_search_l = i;
    else
        %之前找到了R波,在下一个峰值处寻找
        %心率最多300,间隔时间=去掉小数(fs*60/300)
        peak_search_l = peak_addr + floor(fs*60/300);
    end
   
    %搜索完毕
    if(peak_search_l > ( length(y) -40 ))
        break;
    end
   
    %15秒找不到峰值,复位所有参数
    peak_search_r = peak_search_l + 15*fs;
   
    if(peak_search_r > length(y) - 40)
        peak_search_r = length(y) - 40;
    end
   
    if(peak_search_r < peak_search_l)
        peak_search_r = peak_search_l;
    end
       
    for j = peak_search_l:peak_search_r
        %抓住一个极大值
        if( y(j)<y(j+10) && y(j+10)<y(j+20) && y(j+20)>y(j+30) && y(j+30)>y(j+40) )
            %精确定位极大值
            peak_value = max( y(j:j+40) );
            for k = j:j+40
                if(y(k)==peak_value)
                    peak_addr = k;
                end
            end
            %如果100ms后(R波宽度的一半)有更大的,则丢弃现在这个
            %先不写
           
            %有效峰值?
            if( peak_value >= thresh )
                %保存这个R波
                rwave_stack(rwave_stack_pos) = peak_addr - filter_delay ;
                rwave_stack_pos = rwave_stack_pos +1;    
                last_r_pos = peak_addr - filter_delay ;
                %刷新阈值
                thresh = thresh_refresh_k*peak_value;
                if(thresh < thresh_min )
                    thresh = thresh_min;
                end
                thresh_updated =1;
                break;
            else
                thresh_updated =0;
            end
        end
    end
   
    %没找到R波
    if(thresh_updated == 0 )
        %复位检测参数
        peak=0;
        peak_addr=0;
        thresh=thresh_min;
        thresh_updated=0;
    end
   
end

%作图
figure;
%plotyy(x,'b',y,'r');
plot(x,'b');

%----------------------在原始信号上搜索峰值,进一步定位R波-------------------
disp('Stage 3 Find peaks');
last_percent = 0;
for i=1:rwave_stack_pos-1
    %报告进度
    percent = i/(rwave_stack_pos-1)*100;
    if( percent == floor(percent))
         disp(strcat(num2str(percent),'%'));
         last_percent = floor(percent);
    end
    peak_value = max( x(rwave_stack(i)+findmax_l_edge:rwave_stack(i)+findmax_r_edge) );
    for j=rwave_stack(i)+findmax_l_edge:rwave_stack(i)+findmax_r_edge
        if( peak_value == x(j))
            rwave_stack(i) = j;
            break;
        end
    end
end

%-----------------------在图上标出R波位置-----------------------------------
disp('Marking Rwave');
for i=1:rwave_stack_pos-1
hold on;
plot(rwave_stack(i),x(rwave_stack(i)),'go');
end

%--------------------------统计数据----------------------------------------
rr_interval = diff(rwave_stack);
disp('Stage 4 Statistic');
bpm_average = 0;
for i=1:rwave_stack_pos-2
     bpm_average = bpm_average + rr_interval(i);
end
bpm_average = bpm_average/(rwave_stack_pos-2);
bpm_average = bpm_average * 60 /fs;
bpm_max = max(rr_interval(1:rwave_stack_pos-2)) * 60 /fs;
bpm_min = min(rr_interval(1:rwave_stack_pos-2)) * 60 /fs;

%心率-时间图
hold on;
plot( (1: length(x)/(rwave_stack_pos-2): length(x)), rr_interval(1:rwave_stack_pos-2)*60/fs, 'r');
disp('The red line is bpm vs time');

%-----------------------------报告数据-------------------------------------
disp(strcat('Max beats per second:',num2str(bpm_max)));
disp(strcat('Min beats per second:',num2str(bpm_min)));
disp(strcat('Average beats per second:',num2str(bpm_average)));




 
+500  科创币    phpskycn    2010/07/23
来自:计算机科学 / 软件综合
2
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
warmonkey 作者
14年6个月前 IP:未同步
239842
程序输出,同一段数据,
用的是上面的代码
(和绘图时用的代码不一样)


Stage 1 Filtering
    Step 1/5
          OK
    Step 2/5
          OK
    Step 3/5
          OK
    Step 4/5
          OK
    Step 5/5
          OK
Stage 2 Pan-Tompkins
(进度省略)
Stage 3 Find peaks
100%
Marking Rwave
Stage 4 Statistic
The red line is bpm vs time
Max beats per second:70.8398
Min beats per second:48.5156
Average beats per second:60.2187
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
上级专业
同级专业
warmonkey
学者 机友
文章
363
回复
7989
学术分
12
2008/10/11注册,1时28分前活动

Cubesat

主体类型:个人
所属领域:无
认证方式:手机号
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

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

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}