TI毫米波雷达人体生命体征(呼吸、心跳)信号提取算法(IWR6843ISK+DCA1000EVM)

目录

一、引言

二、毫米波雷达检测呼吸、心跳基本原理

1.TI官方开发资料:

2.博主“调皮连续波”开源资料以及原理讲解:

三、 毫米波雷达提取呼吸、心跳信号Matlab算法处理

1.硬件平台: IWR6843ISKEVM+DCA1000EVM

2.mmavestudio参数设置: 

配置说明:

算法流程简介:

(1) 预处理:

(2)粗略的人体定位:距离维FFT

(3)消除静态干扰算法【因为后面用了滑动平均去噪,故这里不做静态干扰算法处理】

 (4)经典算法提取相位:相位反正切

(5)相位解缠绕

(6)相位差分

(7)脉冲噪声去除:滑动平均滤波

(8)带通滤波器输出呼吸信号:

带通滤波器的设计可以参考上一篇内容:MATLAB设计滤波器之新版filterDesigner使用_CoCo哥的博客-CSDN博客

(9)带通滤波器输出心跳信号:

(10)提取心跳波的包络线,归一化心跳波

 四、参考资料

已上代码资料到csdn的资源区:

五 、总结

一、引言

        非雷达科班出身,“入坑”毫米波雷达一年多,现在把入门毫米波雷达检测呼吸、心跳的传统与改进算法进行开源并归纳整理了相关的资料。欢迎交流以及专业人士的指正。

二、毫米波雷达检测呼吸、心跳基本原理

1.TI官方开发资料:

Vital Signs 68xx Users Guide (ti.com)

2.博主“调皮连续波”开源资料以及原理讲解:

干货 | IWR1642EVM呼吸心跳原始数据采集与仿真分析(含MATLAB代码和数据) (qq.com)

(1)线性调频连续波雷达基本原理(第1讲): 干货-线性调频连续波雷达基本原理(第1讲)

(2)线性调频连续波雷达基本原理(第2讲): 干货-线性调频连续波雷达基本原理(第2讲)

(3)线性调频连续波雷达基本原理(第3讲): 干货-线性调频连续波雷达基本原理(第3讲)

3. 驾驶员生命体征检测原理视频说明(1642EVM,77GHZ)中文讲解:

毫米波雷达的应用无处不在- 1.4 对驾驶员心跳呼吸检测的应用-模拟与混合信号在线培训- 德州仪器(TI)官方视频课程培训

三、 毫米波雷达提取呼吸、心跳信号Matlab算法处理

        以下matlab代码基于“调皮连续波”的77GHz IWR1642EVM的算法处理代码进行改进,同时参考了期刊论文文献: 《基于毫米波雷达的生命体征检测》(张兰春,顾海潮)重新设计了带通滤波器分离呼吸心跳信号,并且还参考了另一篇论文:《mmHRV_Contactless_Heart_Rate_Variability_Monitoring_Using_Millimeter-Wave_Radio》对提取的心跳信号进行估计包络的归一化处理。

1.硬件平台: IWR6843ISKEVM+DCA1000EVM

2.mmavestudio参数设置: 

配置说明:

雷达配置:一帧2个chirp,一帧50ms,ADC采样点为200个,采样率为4Msps,数据处理时仅采用每帧的第一个chirp。
毫米波雷达发射起始频率:f0=60.25GHz      调频斜率:S=64.985MHz/us(~65e17)    

有效带宽B=ts*S=3.24925GHz≈3.25GHZ     距离分辨率:ΔR=0.04615m

3.信号处理算法(matlab)

算法流程简介:

(1) 预处理:
%复采样
    numChirps = fileSize/2/numADCSamples/numRX;     %含有实部虚部,除以2
    %共2048个chirps(1024帧*2个chirp)
    LVDS = zeros(1, fileSize/2);
    %combine real and imaginary part into complex data将实部虚部结合成复数
    %read in file: 2I is followed by 2Q     adcData数据组成:两个实部,接着是两个虚部
    counter = 1;
    for i=1:4:fileSize-1        %1T4R
        LVDS(1,counter) = adcData(i) + sqrt(-1)*adcData(i+2);       %复数形式
        LVDS(1,counter+1) = adcData(i+1)+sqrt(-1)*adcData(i+3); 
        counter = counter + 2;
    end
    % create column for each chirp:每一列为chirp
    LVDS = reshape(LVDS, numADCSamples*numRX, numChirps);
    %each row is data from one chirp:每一行为chirp
    LVDS = LVDS.';
end

%% 重组数据(4条接收天线的复数数据)
adcData = zeros(numRX,numChirps*numADCSamples);
for row = 1:numRX
    for i = 1: numChirps
        adcData(row, (i-1)*numADCSamples+1:i*numADCSamples) = LVDS(i, (row-1)*numADCSamples+1:row*numADCSamples);
    end
end
%重组数据retVal:200*2048矩阵,每一列为一个chirp
retVal= reshape(adcData(1, :), numADCSamples, numChirps); %取第一个接收天线数据,数据存储方式为一个chirp一列

process_adc=zeros(numADCSamples,numChirps/2);%每帧中的两个chrip取第一个,200*1024

for nchirp = 1:2:numChirps  %1T4R (1T1R)只处理单发单收的数据,并且只处理两个chrip取出的第一个
    process_adc(:, (nchirp-1)/2+1) = retVal(:,nchirp);
end
(2)粗略的人体定位:距离维FFT
fft1d= zeros(numChirps/2,numADCSamples);

    for chirp_fft=1:numChirps/2
        fft1d(chirp_fft,:) = abs(fft((process_adc(:,chirp_fft))));%
    end

figure;
  mesh(X,Y,fft1d);
xlabel('距离(m)');
ylabel('脉冲chrip数');
zlabel('幅度');
title('距离维-1DFFT结果');

 (3)消除静态干扰算法【因为后面用了滑动平均去噪,故这里不做静态干扰算法处理】
%% 消除静态干扰
% 使用相量均值相消算法(平均相消算法):效果较差
%{
fft1d_avg = zeros(1024,256);
avg = sum(fft_data(:,:))/256;   %参考接收脉冲
for chirp=1:1024
        fft1d_avg(chirp,:) = fft_data(chirp,:)-avg;
end
fft_data=fft1d_avg;
%}
%
%MTI:动目标显示算法
%{
for ii=1:numChirps-1                % 滑动对消,少了一个脉冲
     fft_data(ii,:) = fft_data(ii+1,:)-fft_data(ii,:);
end
%在这里增加了最后一个chirp的消除:(有待改进)
 fft_data(numChirps,:) =fft_data(numChirps-1 ,:);
%}
%MTD:动目标检测
%{
for ii=1:256
    avg =  sum(fft_data(:,ii))/1024;
     fft_data(:,ii) =  fft_data(:,ii) -  avg ;
end
%}
 (4)经典算法提取相位:相位反正切

        提取人体定位的位置的相位信号,即胸腔振动信号x(t)(R):

TI毫米波雷达人体生命体征(呼吸、心跳)信号提取算法(IWR6843ISK+DCA1000EVM)

%% 提取相位 extract phase(相位反正切)
%实虚部分离(为了提取rangebin的相位)
real_data = real(fft_data);%实部
imag_data = imag(fft_data);%虚部

for i = 1:numChirps
    for j = 1:RangFFT  %对每一个range bin取相位 extract phase(弧度rad)
        angle_fft(i,j) = atan2(imag_data(i, j),real_data(i, j));
    end
end

% Range-bin tracking 找出能量最大的点,即人体的位置  
for j = 1:RangFFT
   if((j*detaR)<2.5 &&(j*detaR)>0.5) % 限定了检测距离为0.5-2.5m
        for i = 1:numChirps             % 进行非相干积累
            fft_data_last(j) = fft_data_last(j) + fft_data_abs(i,j);%通过FFT后的多普勒信号的幅值进行定位
        end
        
        if ( fft_data_last(j) > range_max)
            range_max = fft_data_last(j);
            max_num = j;  %最大能量序列号(range bin)maxnum
        end
    end
end 

%% 取出能量最大点的相位  extract phase from selected range bin
angle_fft_last = angle_fft(:,max_num);%1024个chrip的某列range bin的相位
% 提取相位信号(原始)
figure;
plot(angle_fft_last);
xlabel('时间/点数(N):对应每个chrip');
ylabel('相位');
title('未展开相位信号');
phi=angle_fft_last;

 

 (5)相位解缠绕
%% 进行相位解缠  phase unwrapping(手动解),自动解可以采用MATLAB自带的函数unwrap()
%或称为相位解卷绕,由于相位值在 [ − π ,π ] 之间,而我们需要相位展开以获取实际的位移曲线,
% 因此每当连续值之间的相位差大于或者小于±π时,通过从相位中减去2π来获得相位展开。
% n = 1;
% for i = 2:numChirps
%     diff = angle_fft_last(i) - angle_fft_last(i-1); %连续值之间的相位差
%     if diff > pi
%         angle_fft_last(i:end) = angle_fft_last(i:end) - 2*pi;
%         n = n + 1;  
%     elseif diff < -pi
%         angle_fft_last(i:end) = angle_fft_last(i:end) + 2*pi;  
%     end
% end
%相位解包方法2:
for i = 2:numChirps
    diff = angle_fft_last(i) - angle_fft_last(i-1); %连续值之间的相位差
    while((diff>pi) || (diff<-pi))
        if diff > pi
                angle_fft_last(i) = angle_fft_last(i) - 2*pi;
                  diff = angle_fft_last(i) - angle_fft_last(i-1); %连续值之间的相位差
        elseif diff < -pi
                angle_fft_last(i:end) = angle_fft_last(i:end) + 2*pi;  
                diff = angle_fft_last(i) - angle_fft_last(i-1); %连续值之间的相位差
        end
    end
end
%
figure;
plot(angle_fft_last);
xlabel('时间/点数(N):对应每个chirp');
ylabel('相位');
title('相位解缠  phase unwrapping后的结果');
%unwrap函数:
% phi=unwrap(phi);
% figure;
% plot(phi);

 

(6)相位差分
%% phase difference 相位差分
%通过减去连续的相位值,对展开的相位执行相位差运算,
% 这将有利于        :增强心跳信号并消除硬件接收机存在的相位漂移,抑制呼吸信号及其谐波
angle_fft_last2=zeros(1,numChirps);
% 方法:相位差分是通过不断将当前采样点展开相位与前一采样点做差实现
for i = 2:numChirps
    angle_fft_last2(i) = angle_fft_last(i) - angle_fft_last(i-1);
end 

figure;
plot(angle_fft_last2);
xlabel('点数(N):对应每个chrip');
ylabel('相位(rad)');
title('相位差分后信号');

(7)脉冲噪声去除:滑动平均滤波
%% 脉冲噪声去除:滑动平均滤波(选取 0.25 s 的滑动窗口,窗口长度为5)
%   去除由于测试环境引起的脉冲噪声
phi=smoothdata(angle_fft_last2,'movmean',5);
figure;
plot(phi);
title('滑动平均滤波相位信号');
%对相位信号作FFT 
N1=length(phi);
 FS=20;
FFT = abs(fft(phi));              %--FFT                         取模,幅度
f=(0:N1-1)*(FS/N1);             %其中每点的频率
%傅里叶变换结果对称
figure;
plot(f(1:N1/8),FFT(1:N1/8)) %取前一部分放大观察
xlabel('频率(f/Hz)');
ylabel('幅度');
title('相位信号FFT  ');

 

 (8)带通滤波器输出呼吸信号:
带通滤波器的设计可以参考上一篇内容:MATLAB设计滤波器之新版filterDesigner使用_CoCo哥的博客-CSDN博客
%%  IIR带通滤波 Bandpass Filter 0.1-0.5hz,输出呼吸信号
fs =20; %呼吸心跳信号的采样率
%设计IIR,4阶巴特沃斯带通滤波器
load('coe3.mat', 'breath_pass');
breath_data = filter(breath_pass,phi); 

figure;
plot(breath_data);
xlabel('时间(s)');
xticklabels({'0','10','20','30','40','50','60'});
ylabel('幅度');
title('呼吸时域波形');

%% 谱估计 -FFT -Peak interval
N1=length(breath_data);
fshift = (-N1/2:N1/2-1)*(fs/N1); % 
breath_fre = abs(fftshift(fft(breath_data)));              %--FFT                         取模,幅度(双边频谱)
breath = abs(fft(breath_data));                                     %
%傅里叶变换结果对称

figure;
% plot(fshift,breath_fre);
plot(f(1:130),breath(1:130));   %取前一部分放大观察
xlabel('频率(f/Hz)');
ylabel('幅度');
title('呼吸信号FFT  ');

breath_fre_max = 0; % 呼吸频率
for i = 1:length(breath_fre)                     %谱峰最大值搜索
    if (breath_fre(i) > breath_fre_max)    
        breath_fre_max = breath_fre(i);
        breath_index=i;
    end
end

breath_count =(fs*(numChirps/2-(breath_index-1))/numChirps)*60;        %呼吸频率解算

 

  (9)带通滤波器输出心跳信号:
%% IIR带通滤波 Bandpass Filter 0.8-2hz,输出心跳的数据
%  设计IIR,8阶巴特沃斯带通滤波器
load('coe4.mat', 'heart_pass');
heart_data = filter(heart_pass,phi); 
figure;
plot(heart_data);
xlabel('时间(s)');
xticklabels({'0','10','20','30','40','50','60'});
ylabel('幅度');
title('心跳时域波形');

N1=length(heart_data);
fshift = (-N1/2:N1/2-1)*(fs/N1); % zero-centered frequency
f=(0:N1-1)*(fs/N1);       %其中每点的频率
 heart_fre = abs(fftshift(fft(heart_data))); 
heart=abs(fft(heart_data));
figure;
% plot(fshift,heart_fre);
plot(f(1:200),heart(1:200));
xlabel('频率(f/Hz)');
ylabel('幅度');
title('心跳信号FFT');

heart_fre_max = 0; 
for i = 1:length(heart_fre)/2 
    if (heart_fre(i) > heart_fre_max)    
        heart_fre_max = heart_fre(i);
        if(heart_fre_max<1e-2)          %幅度置信 判断是否是存在人的心跳
            heart_index=1025;%不存在
        else
            heart_index=i;
        end
    end
end
heart_count =(fs*(numChirps/2-(heart_index-1))/numChirps)*60;%心跳频率解算

 

 

 (10)提取心跳波的包络线,归一化心跳波
%% 提取心跳波的包络线,归一化心跳波
% 通过取心跳分量绝对值的移动平均值估计心跳波的包络
heartdata=abs(heart_data);
[envHigh, envLow] = envelope(heart_data,15,'peak');
envMean = (envHigh+envLow)/2;
y=smooth(heartdata,10);
t=1:1024;
figure;
plot(t,heartdata, ...
    t,envHigh, ...
     t,envMean, ...
     t,envLow)
axis tight
legend('heart_data','High','Mean','Low','location','best')
title('提取心跳波包络曲线');
%移动平均滤波
yy=smooth(heart_data);
figure;
plot(t,heart_data,t,yy,'r',t,y);
legend('heartdata','filtered','envelop','location','best');
title('估计包络、滤波后的心跳波');

%归一化:归一化后的波是滤波后的心跳波和估计包络之间的比率
for k=1:1024
    mmave(k,1)=yy(k,1)/y(k,1);
end
figure
plot(t,mmave);
title('归一化后的心跳波');

 

 四、参考资料

已上代码资料到csdn的资源区:

【若无法下载可在评论区留言或私信留下邮箱】

【免费】毫米波雷达心跳呼吸信号提取算法及参考文献资源-CSDN文库

五 、总结

        本篇内容介绍的算法主要为传统的提取算法,但可实现在1m内呈现良好的检测效果,能够提取出非常可观的呼吸和心跳波形,但在超出1m的距离后便不适用这个算法了。远距离检测呼吸和心跳始终是这个领域一个很大的挑战。要实现远距离检测可在提取相位信号、分离呼吸和心跳信号上进行改进处理,例如线性解调提取相位、改进的VMD分离呼吸和心跳算法。        

        可参考以下nature论文:该论文能够实现远距离准确检测人体的呼吸和心跳。

《Vital-sign monitoring and spatial tracking of multiple people using a contactless radar-based sensor》

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
xiaoxingxing的头像xiaoxingxing管理团队
上一篇 2023年12月14日
下一篇 2023年12月14日

相关推荐