项目介绍:
提示:为了不影响整洁度,我将有关项目部署导入的步骤放在了文章最下面。
前言:下面呼吸和心跳引起的典型体表位移参数(人体正面与人体背部)
所以我们的目的是求微小的距离变化ΔR,
1Dfft后的结果可以帮我们找到目标的Rangbin数,在相同的Rangbin数的样本中,我们通过相位差可以确认这些微小的变化。
代码概述
本处借用了《基于毫米波雷达的生命体征检测---张兰春》一文中的结构图
而代码概述可以理解为—↓↓↓
//1、原始信号
//2、1d_FFT(距离维)/距离估计
cmplx16ReIm_t *tempPtr = obj->fftOut1D + (obj->rxAntennaProcess - 1)*obj->numRangeBins; //256
tempPtr += (obj->rangeBinStartIndex) ;
//3、前后样本间相同Rangebin下的相位计算
if (rangeBinIndex == (rangeBinIndexPhase))
{
rangeBinPhase = atan2(temp_imag, temp_real);//相位角度
}
//4、相位解缠绕/处理相位跳变,恢复相位的连续性
obj->unwrapPhasePeak = unwrap(rangeBinPhase, phasePrevFrame, &diffPhaseCorrectionCum);
//5、相位差计算
phaseUsedComputation = obj->unwrapPhasePeak - phaseUsedComputationPrev;
//6、获得准确的相位变化信息后,通过IIR数字滤波器对呼吸和心跳信号进行分离
outputFilterBreathOut = filter_IIR_BiquadCascade(phaseUsedComputation, obj->pFilterCoefsBreath, obj->pScaleValsBreath, obj->pDelayBreath, IIR_FILTER_BREATH_NUM_STAGES);
outputFilterHeartOut = filter_IIR_BiquadCascade(phaseUsedComputation, obj->pFilterCoefsHeart_4Hz, obj->pScaleValsHeart_4Hz, obj->pDelayHeart, IIR_FILTER_HEART_NUM_STAGES);
//7、上一步中得到的心率呼吸信号进行快速傅里叶变换(下面代码以呼吸为例,心率部分未列出,处理方式相同)
for (loopIndexBuffer = 0; loopIndexBuffer < obj->circularBufferSizeBreath; loopIndexBuffer++)
{
obj->pVitalSignsBuffer_Cplx[loopIndexBuffer].real = (int32_t) obj->scale_breathingWfm*obj->pVitalSigns_Breath_CircularBuffer[loopIndexBuffer];
obj->pVitalSignsBuffer_Cplx[loopIndexBuffer].imag=0;
}
DSP_fft32x32(
(int32_t *)obj->pVitalSignsSpectrumTwiddle32x32,
obj->breathingWfm_Spectrum_FftSize,
(int32_t *) obj->pVitalSignsBuffer_Cplx,
(int32_t *) obj->pVitalSigns_SpectrumCplx);
MmwDemo_magnitudeSquared(
obj->pVitalSigns_SpectrumCplx,
obj->pVitalSigns_Breath_AbsSpectrum,
obj->breathingWfm_Spectrum_FftSize);
//8、通过频域FFT计算心率和呼吸速率,找峰值的index乘以频率增量,以心率为例,呼吸相同未列出.
heartRateEst_FFT = (float) CONVERT_HZ_BPM * maxIndexHeartBeatSpect * (obj->freqIncrement_Hz);//CONVERT_HZ_BPM 是60(s) obj->freqIncrement_Hz是频率增量,maxIndexHeartBeatSpect * (obj->freqIncrement_Hz)代表心率频率(次/s)
代码改动:
硬编码启动修改
TI的工程都是要有一个Log口和一个Command口同时启用的,Command口用来接收CLI配置,也就是波形配置,滤波器配置,频率…配置,这比较麻烦,所以我们通过硬编码,可以让它进行自行启动.这部分我已经在其他文章中具体写了,请查看他来实现。
输出频率修改
呼吸心率中帧率/刷新率/输出频率 参与了呼吸心率的估计,所以官方的20Hz尽量不要修改,修改的话需要改很多很多地方,所以为了降低输出频率,我们可以在mss_main.c中添加一个原始帧数模除4的判断,来降低频率到5Hz。
协议修改 && GUI决策移植
在官方提供的GUI可视化工具中,可视化工具通过输出的字段,进行了后续的判断,如RCS加权平均,判断RCS大小来决定是否输出呼吸心率为0,RCS实际上就是1DFFT后absVal的最大值。
absVal = (float) temp_real * (float) temp_real + (float) temp_imag * (float) temp_imag;
还有其他一些决策,如运动判断,呼吸心率置信度(幅度最大周围的和/其余部分的幅度和,至于是周围多少个的和,已经在宏定义中定义了),还有其他一些决策,如果不想依靠它的可视化工具,那就需要移植这些判断,更改最终输出的结构体。
例如下面注释的就是原始输出:
python/C语言 脚本匹配协议输出呼吸心率估计
修改完协议之后,我们要做一个自己的脚本来接收或者可视化模组的输出。这就比较简单了,参照我们自己设置的协议解析。
解析关键函数
def open_data(self, select_com):
if not self.ser.is_open:
com = select_com
btr = 115200
try:
self.ser = serial.Serial(com, btr, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE,timeout=0.08)
self.ser.reset_output_buffer()
except Exception as e:
print('The serial port does not exist or is occupied.')
if self.ser.is_open:
while True:
dat = self.readAndParseUart(self.ser)
version = struct.unpack('I', dat[8:12])[0]
packet_length = struct.unpack('I', dat[12:16])[0]
hardware = struct.unpack('I', dat[16:20])[0]
frame = struct.unpack('I', dat[20:24])[0]
cpu = struct.unpack('I', dat[24:28])[0]
print("是否有人", struct.unpack('I', dat[28:32])[0])
print("frame:", frame)
print("packet_length", packet_length)
tlv_num = struct.unpack('I', dat[32:36])[0]
tlvindex = 40
if tlv_num > 0:
for i in range(tlv_num):
tlv = struct.unpack('I', dat[tlvindex:tlvindex + 4])[0] # tlv
if tlv == 6:
tlvlength = struct.unpack('I', dat[tlvindex + 4:tlvindex + 8])[0]
stats = {
'maxVal':
struct.unpack('f', dat[tlvindex + 8 + 4 * 0:tlvindex + 12 + 4 * 0])[0],
'heartRateEst_FFT':
struct.unpack('f', dat[tlvindex + 8 + 4 * 1:tlvindex + 12 + 4 * 1])[0],
'breathingRateEst_xCorr':
struct.unpack('f', dat[tlvindex + 8 + 4 * 2:tlvindex + 12 + 4 * 2])[0],
'sumEnergyBreathWfm':
struct.unpack('f', dat[tlvindex + 8 + 4 * 3:tlvindex + 12 + 4 * 3])[0],
'sumEnergyHeartWfm':
struct.unpack('f', dat[tlvindex + 8 + 4 * 4:tlvindex + 12 + 4 * 4])[0],
'range_output':
struct.unpack('f', dat[tlvindex + 8 + 4 * 5:tlvindex + 12 + 4 * 5])[0]
}
print("maxVal", stats['maxVal'])
print("heartRateEst_FFT", stats['heartRateEst_FFT'])
print("breathingRateEst_xCorr", stats['breathingRateEst_xCorr'])
print("sumEnergyBreathWfm", stats['sumEnergyBreathWfm'])
print("sumEnergyHeartWfm", stats['sumEnergyHeartWfm'])
print("range_output", stats['range_output'])
项目场景和环境配置:
TI呼吸心跳vital_signs工程:
- 项目集成开发环境: Code Composer Studio (CCS):版本 11.2.0,专用于C语言程序的编写、编译和调试。
Code Composer Studio下载
- 项目需要下载一些开发包,同时需要下载mmwave_industrial_toolbox 开发工具。
MMWAVE-SDK下载
mmwave_industrial_toolbox
SYS/BIOS XDCtools下载
- 项目的导入,当集成开发环境和开发工具下载好之后,开始导入工程:
- 创建一个空的文件夹,并且文件夹的名字不能包含中文。
- 打开CCS之后选择这个空的文件夹
- 打开后会弹出Getting Started 页面,点击Import Project
- 点击浏览(Browse),找到"D:\ti\mmwave_industrial_toolbox_4_12_1\labs\Vital_Signs…"(…代表的是对应你自己的设备型号而选择的)
- 选择(…)这个文件夹之后再点击Select ALL 工程就导入成功了
- 其他要下载的及检查
导入之后还要包含一些函数库,可以在ti上下载需要的。
dsplib 3_4_0_0下载
mathlib_c674x_3_1_2_1下载
ti_cgt_c6000下载
ARM CGT下载
导入后的两个模块中,选择dss,右键选择properties,点击Products查看项目,若没有那么手动添加