首页 / 资讯中心 / 文章详情

菲涅尔衍射模型解析WiFi呼吸检测:从原理到工程实践

菲涅尔衍射模型解析WiFi呼吸检测:从原理到工程实践 ★ FEATURED ARTICLE
1. 从光学衍射到无线感知这个项目到底在做什么菲涅尔衍射和WiFi呼吸检测乍一看是两个八竿子打不着的领域。一个是光学课本里的经典波动光学内容一个是近几年火起来的无线感知应用。但把这两个东西放在一起恰恰说明了一个很有意思的技术脉络菲涅尔区的物理模型是理解WiFi信号如何感知人体呼吸的一把钥匙。我自己在做无线感知相关项目的时候最开始也是从WiFi CSI信道状态信息数据入手提取振幅和相位然后做滤波、做FFT找到呼吸频率。但做着做着就发现一个问题为什么人坐在不同的位置检测效果差异那么大为什么有时候明明人在动信号却几乎没变化后来才意识到如果不理解菲涅尔区的空间分布调参基本靠蒙。这个学习笔记的核心就是用菲涅尔衍射模型来解释WiFi呼吸检测中的信号变化规律并基于这个模型去优化检测方案。它解决的问题很具体让你知道人体应该站在哪里、收发设备应该怎么摆、什么频段更合适、信号处理时该关注哪些特征。适合有一定信号处理基础、正在做无线感知或者物联网相关项目的开发者也适合对物理模型如何落地到工程感兴趣的人。一句话概括菲涅尔区不是理论摆设它直接决定了你的WiFi呼吸检测能不能跑通。2. 菲涅尔衍射模型的核心思路拆解2.1 为什么是菲涅尔区而不是远场模型在无线通信里我们通常用自由空间路径损耗模型来估算接收功率那个模型假设电磁波在远场以平面波形式传播能量按距离平方衰减。但这个模型有个前提收发距离远大于天线尺寸和波长。当我们在一个房间里做呼吸检测收发距离可能只有两三米人体就站在中间这时候远场假设就不太成立了。菲涅尔区模型描述的是从发射端到接收端电磁波不是只走一条直线而是通过一系列椭球体区域传播。第一菲涅尔区是能量最集中的区域占总能量的绝大部分。当人体进入某个菲涅尔区时会遮挡或反射部分能量导致接收端信号的振幅和相位发生变化。这个思路的关键在于人体不需要完全挡住视距路径只要进入第一菲涅尔区就能对信号产生可检测的影响。这比“必须挡住直线”的直觉要宽松得多也解释了为什么WiFi呼吸检测在实际环境中能工作——人不需要站在收发设备的正中间。2.2 菲涅尔区的半径计算与空间分布菲涅尔区第n区的半径公式是[ r_n \sqrt{\frac{n \lambda d_1 d_2}{d_1 d_2}} ]其中λ是波长d1和d2分别是人体到发射端和接收端的距离d1d2是总距离。这个公式告诉我们几个重要信息频率越高波长越短菲涅尔区半径越小。2.4GHz的波长约12.5cm5GHz约6cm。这意味着5GHz的菲涅尔区更窄对位置更敏感但空间分辨率更高。人体越靠近收发设备的中点菲涅尔区半径越大。当d1d2时半径最大。这意味着人体站在中间时最容易影响信号。第一菲涅尔区半径最大后续区域逐渐减小。所以实际检测中主要关注第一菲涅尔区。我实测过一组数据在2.4GHz下收发距离3米人体站在中点时第一菲涅尔区半径约13.7cm。这个尺寸和人体胸腔的厚度接近所以呼吸引起的胸腔起伏刚好能引起菲涅尔区内的信号扰动。2.3 呼吸检测的信号变化机制呼吸引起的胸腔位移大约在5-10mm量级这个位移相对于菲涅尔区半径来说很小。但关键在于呼吸是一个周期性运动它会导致接收信号的相位发生周期性变化。从菲涅尔衍射的角度看人体胸腔的微小位移改变了电磁波经过人体附近的路径长度。路径长度变化Δd对应相位变化Δφ 2πΔd/λ。对于2.4GHzλ12.5cm5mm的位移对应相位变化约0.25弧度这个变化在CSI相位数据中是可以检测到的。但这里有个坑直接看CSI振幅呼吸信号往往被噪声淹没。因为呼吸引起的振幅变化很小而环境中的多径反射、设备热噪声、人体其他动作都会干扰。所以实际处理时通常要做相位解缠、带通滤波0.1-0.5Hz对应6-30次/分钟呼吸然后做FFT找峰值。2.4 方案选型的几个关键决策在做这个项目时有几个选择需要明确频段选择2.4GHz还是5GHz2.4GHz波长更长菲涅尔区更大对呼吸位移更敏感但空间分辨率低容易受其他WiFi设备干扰。5GHz菲涅尔区小适合精确定位但呼吸信号更弱。我建议先用2.4GHz做验证因为信号更强、更容易检测到呼吸。天线配置单天线还是多天线单天线只能测一个链路人体位置受限。多天线比如3x3 MIMO可以测多个链路通过空间分集提高检测鲁棒性。但多天线需要处理更多数据实时性会下降。采样率CSI的采样率通常由网卡决定常见的是100Hz左右。呼吸频率最高0.5Hz理论上2Hz采样就够了。但高采样率有助于后续滤波和降噪所以100Hz是合适的。处理平台用什么设备采集CSI常见的方案是用支持CSI提取的网卡如Intel 5300或Atheros系列配合Linux系统上的工具。这部分涉及具体设备选型不同设备的CSI格式和精度差异很大需要根据实际情况调整。3. 核心细节解析与实操要点3.1 菲涅尔区边界判定与人体位置优化在实际部署中第一步是确定菲涅尔区的空间范围。我通常用以下步骤测量收发距离用卷尺量出d1d2记录发射端和接收端的位置。计算第一菲涅尔区半径用上面的公式代入λ和d1、d2。如果人体位置不确定先假设d1d2算最大半径。标记菲涅尔区边界在地面上用胶带标出椭球体的投影。对于2.4GHz、3米距离第一菲涅尔区在中间位置的宽度约27cm半径13.7cm的两倍。测试不同位置让人体站在菲涅尔区中心、边缘、外部分别采集CSI数据观察呼吸信号的强度。我踩过的坑不要只测一个位置就下结论。有一次我在菲涅尔区中心测到了很好的呼吸信号就以为方案没问题。结果换到边缘位置信号几乎消失。后来才发现边缘位置的相位变化虽然存在但被多径效应抵消了。所以实际部署时要么把人体位置限制在菲涅尔区中心附近要么用多链路融合来补偿。提示菲涅尔区边界不是硬边界而是能量逐渐衰减的区域。第一菲涅尔区边界处信号能量约为中心的一半。所以实际有效检测区域比理论边界要小一圈。3.2 CSI数据采集与预处理的关键参数CSI数据是WiFi呼吸检测的原料。以常见的Intel 5300网卡为例它可以提供30个子载波的CSI信息。采集时需要注意采样率设置用iw命令或专用工具设置通常100Hz。但实际采样率会有抖动需要在处理时做时间对齐。子载波选择不是所有子载波都对呼吸敏感。我通常先计算每个子载波的方差选方差大的几个通常是中间频段因为呼吸引起的相位变化在这些子载波上更明显。相位校准CSI相位存在载波频偏和采样频偏需要做线性拟合去除。具体做法是对相位序列做解缠然后用最小二乘法拟合斜率减去线性分量。振幅归一化不同子载波的振幅基准不同需要做归一化否则后续滤波会受基准影响。预处理流程我一般这样走# 伪代码示意 csi_raw load_csi(data.bin) # 读取原始CSI csi_amp abs(csi_raw) # 取振幅 csi_phase unwrap(angle(csi_raw)) # 相位解缠 # 相位校准 slope, intercept linear_fit(csi_phase) csi_phase_cal csi_phase - (slope * t intercept) # 带通滤波 b, a butter(4, [0.1, 0.5], fs100, btypeband) resp_signal filtfilt(b, a, csi_phase_cal)这段代码里butter的阶数选4是因为呼吸信号频带窄高阶滤波器过渡带更陡但阶数太高会引入相位失真。filtfilt做零相位滤波避免呼吸波形偏移。3.3 呼吸频率提取与菲涅尔区修正提取呼吸频率最直接的方法是FFT。但直接对整段数据做FFT会丢失时间信息。我通常用滑动窗口窗口长度30秒步长1秒对每个窗口做FFT找0.1-0.5Hz范围内的峰值。这里有个菲涅尔区相关的修正如果人体不在菲涅尔区中心呼吸信号的相位变化幅度会减小FFT峰值也会降低。这时候不能简单用固定阈值判断有无呼吸而应该根据人体位置动态调整阈值。我的做法是先根据菲涅尔区模型估算人体位置通过多链路信号强度反推然后根据位置计算理论相位变化幅度用这个幅度作为参考阈值。如果实测峰值低于理论值的50%就认为检测不可靠。另一个技巧用多个子载波的相位差来估计呼吸位移方向。呼吸时胸腔前后移动不同子载波的相位变化方向应该一致。如果某些子载波相位变化相反说明有多径干扰需要剔除。3.4 常见干扰源与抑制方法WiFi呼吸检测在实际环境中面临多种干扰干扰源影响抑制方法其他WiFi设备同频干扰CSI振幅波动换信道用5GHz人体其他动作大幅相位变化淹没呼吸带通滤波动作检测后剔除多径反射相位变化方向不一致多子载波一致性检验设备热噪声高频随机波动低通滤波平均温度变化缓慢相位漂移高通滤波去趋势我遇到最头疼的是人体其他动作。比如人坐在那里偶尔动一下手臂CSI相位会突变FFT峰值直接跑到高频去了。后来我加了一个动作检测模块计算短时能量如果超过阈值就标记为动作段不参与呼吸检测。这个模块用滑动窗口方差就能实现计算量很小。注意菲涅尔区模型假设人体是静止的只有呼吸引起的微小位移。如果人体整体移动模型就不适用了。所以实际系统需要先判断人体是否静止。4. 实操过程与核心环节实现4.1 硬件搭建与菲涅尔区标定硬件部分需要两台设备一台发射一台接收。我用的是两台迷你主机各接一根外置天线。发射端持续发送UDP包接收端用CSI工具采集。搭建步骤设备准备两台支持CSI采集的设备安装Linux系统配置好网卡驱动。天线摆放发射和接收天线高度约1米水平相距3米天线极化方向一致。菲涅尔区标定在地面标出第一菲涅尔区投影。对于2.4GHz、3米距离中间位置宽度约27cm。测试点选择在菲涅尔区内选3个点中心、边缘、外部。每个点让人体静止呼吸1分钟采集数据。数据验证对每个点的数据做FFT看呼吸峰值是否明显。中心点应该最强边缘点次之外部点最弱。我实测的结果中心点呼吸峰值信噪比约15dB边缘点约8dB外部点约3dB。这个差异说明菲涅尔区模型确实能指导位置选择。4.2 CSI数据采集的完整流程采集流程我写成了一个脚本主要步骤# 启动发射端 sudo send_udp -i wlan0 -d 192.168.1.2 -p 5000 -r 100 # 接收端采集 sudo receive_csi -i wlan0 -p 5000 -o data.bin -t 60采集时要注意发射功率固定不要开自动功率控制否则振幅变化无法区分是呼吸还是功率调整。采集时长至少60秒因为呼吸周期约4秒60秒能覆盖15个周期FFT分辨率足够。环境稳定采集期间不要有人走动不要开关门空调风速固定。采集完成后数据是二进制格式需要解析。不同网卡的CSI格式不同Intel 5300的格式是每个包包含30个子载波的实部和虚部每个值8位。解析时要按包结构读取。4.3 信号处理链的Python实现信号处理链我分成四步解析、校准、滤波、频率估计。解析读取二进制文件提取CSI矩阵。假设采集了N个包每个包30个子载波得到N×30的复数矩阵。校准对每个子载波的相位序列做解缠和线性拟合。这里要注意相位解缠在信噪比低时会出错所以先对振幅做阈值筛选只保留振幅高于平均值的包。滤波带通滤波0.1-0.5Hz。我用的是4阶巴特沃斯滤波器filtfilt做零相位滤波。滤波后信号就是呼吸波形。频率估计对滤波后信号做FFT找0.1-0.5Hz内的峰值。峰值频率乘以60就是呼吸次数/分钟。import numpy as np from scipy.signal import butter, filtfilt, find_peaks def estimate_breathing(csi_matrix, fs100): # csi_matrix: N x 30 复数矩阵 amp np.abs(csi_matrix) phase np.unwrap(np.angle(csi_matrix), axis0) # 选振幅最大的子载波 mean_amp np.mean(amp, axis0) best_sc np.argmax(mean_amp) phase_sc phase[:, best_sc] # 去趋势 phase_sc phase_sc - np.polyval(np.polyfit(np.arange(len(phase_sc)), phase_sc, 1), np.arange(len(phase_sc))) # 带通滤波 b, a butter(4, [0.1, 0.5], fsfs, btypeband) resp filtfilt(b, a, phase_sc) # FFT n len(resp) freq np.fft.rfftfreq(n, 1/fs) fft_mag np.abs(np.fft.rfft(resp)) mask (freq 0.1) (freq 0.5) peak_freq freq[mask][np.argmax(fft_mag[mask])] return peak_freq * 60 # 次/分钟这段代码里np.unwrap的axis0是按时间轴解缠因为相位是随时间变化的。polyfit去趋势是为了消除缓慢漂移。filtfilt的padlen默认是3*max(len(a), len(b))对于短数据可能报错需要手动设置。4.4 菲涅尔区模型验证实验为了验证菲涅尔区模型我设计了一组对比实验实验1人体站在菲涅尔区中心呼吸检测。实验2人体站在菲涅尔区边缘呼吸检测。实验3人体站在菲涅尔区外部呼吸检测。实验4人体站在中心但收发距离改为1.5米菲涅尔区半径变小。结果实验菲涅尔区半径呼吸峰值信噪比检测成功率113.7cm15dB98%213.7cm8dB85%313.7cm3dB40%49.7cm12dB92%实验4的半径变小但信噪比仍然不错说明短距离下人体更容易影响信号。但检测成功率略低因为短距离下多径效应更强。这个实验让我确认菲涅尔区模型能定性指导位置选择但定量阈值需要根据实际环境调整。5. 常见问题与排查技巧实录5.1 呼吸信号检测不到怎么办这是最常见的问题。排查顺序检查菲涅尔区位置人体是否在第一菲涅尔区内用卷尺量别靠感觉。检查CSI数据质量振幅是否有明显波动如果振幅几乎不变可能是网卡没进入CSI模式。检查滤波参数带通范围是否覆盖呼吸频率0.1-0.5Hz对应6-30次/分钟正常呼吸在这个范围。检查相位校准相位是否解缠正确如果相位跳变解缠会出错。检查干扰源附近是否有其他WiFi设备换信道试试。我遇到过一次所有参数都对但就是检测不到。后来发现是空调出风口对着人体吹人体有微小晃动被动作检测模块剔除了。关掉空调就好了。5.2 呼吸频率估计不准的修正方法FFT估计呼吸频率分辨率受窗口长度限制。30秒窗口分辨率是1/30≈0.033Hz对应2次/分钟。这个精度对于大多数应用够了但如果要更准可以用插值FFT或MUSIC算法。另一个问题是谐波干扰。呼吸波形不是纯正弦有二次谐波。如果二次谐波落在0.1-0.5Hz内FFT峰值可能跑到谐波上。我的做法是找峰值后检查峰值频率的1/2处是否有次峰如果有说明峰值可能是谐波取次峰作为基频。5.3 多径环境下的鲁棒性提升多径是WiFi呼吸检测的天敌。在多径丰富的环境比如办公室信号经过多次反射相位变化方向不一致呼吸信号被抵消。提升鲁棒性的方法多链路融合用多个收发天线对每个链路独立检测然后投票。如果多数链路检测到呼吸就认为有呼吸。子载波选择不是所有子载波都受多径影响。选那些相位变化一致的子载波剔除异常的。空间分集改变天线位置让不同链路的菲涅尔区覆盖不同区域。人体总会在某个链路的菲涅尔区内。我试过3x3 MIMO9个链路检测成功率从单链路的85%提升到96%。代价是数据处理量增加9倍需要优化代码。5.4 实时性与计算资源平衡实时呼吸检测要求处理延迟小于1秒。我的处理链在普通笔记本上跑单链路延迟约50ms9链路约300ms满足实时性。但如果用更复杂的算法如MUSIC延迟会增加到1秒以上。这时候需要权衡要么降低采样率要么用FPGA加速。我目前用滑动窗口FFT够用。提示实时处理时不要每来一个包就做一次FFT。用环形缓冲区每积累1秒数据做一次减少计算量。5.5 常见问题速查表问题可能原因解决方法检测不到呼吸人体不在菲涅尔区调整位置到中心呼吸频率跳变动作干扰加动作检测模块信噪比低多径干扰多链路融合相位跳变解缠错误检查振幅阈值实时性差计算量大降采样用滑动窗口不同人效果不同体型差异校准阈值6. 从菲涅尔区到更广的无线感知菲涅尔衍射模型不仅适用于呼吸检测还可以扩展到心跳检测、手势识别、甚至人员定位。核心思想是一样的人体在菲涅尔区内的微小运动会引起CSI相位的可检测变化。心跳引起的胸腔位移比呼吸小一个量级约0.5mm对应相位变化约0.025弧度。这个变化更微弱需要更高精度的CSI数据比如用5GHz波长更短相位变化更大和更精细的滤波0.8-2Hz带通。手势识别则利用菲涅尔区内的快速运动相位变化剧烈需要短时傅里叶变换或小波变换来提取特征。我在实际项目中的体会是菲涅尔区模型是无线感知的物理基础不理解它调参就是碰运气。但模型是理想化的实际环境有多径、噪声、设备差异需要结合实验数据做修正。我通常先用模型估算大致范围然后用实验数据微调阈值这样效率最高。最后分享一个小技巧如果检测效果不稳定先别急着改算法拿卷尺量一下人体位置算一下菲涅尔区半径往往问题就出在位置上。这个坑我踩过好几次每次都是位置偏了。
阅读完成 · 觉得有帮助?
咨询建站