ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OFDM接收机分组检测:从原理到MATLAB与FPGA实现

OFDM接收机分组检测:从原理到MATLAB与FPGA实现 做OFDM接收机最磨人的往往不是FFT也不是信道估计而是第一步——你辛苦把基带信号从天线抓下来之后满屏看起来全是噪声根本不知道数据包从哪个采样点开始。分组检测packet detection干的事情就是在这种连续样点流里判断“有效信号来了没有”并给出一个尽可能准的粗起始位置。它是OFDM接收机同步的第一关也是整个接收状态机从监听模式跳到接收模式的关键触发信号。这篇文章适合正在做WLAN/LTE物理层算法、打算用FPGA实现OFDM接收机、或者刚开始接触OFDM同步想搞懂原理的工程师读完可以直接用MATLAB跑通一套完整的分组检测流程。1. 分组检测到底要解决什么问题1.1 接收机同步链路里它排在最前面OFDM接收机的同步从来不是一件事而是一条链。按我自己的习惯通常拆成四块分组检测、符号定时同步、载波频偏估计与校正、采样钟同步。分组检测排在最前它解决的是“包从哪儿开始”的问题。对突发OFDM系统来说比如WiFi、LTE的PRACH前导检测、LoRa帧同步接收机平时一直处于监听状态ADC不断在采样但绝大多数时间采到的都是噪声。只有在某个瞬间发射机开始发送数据包接收信号里才出现有效分量。分组检测就是要在这种“海量噪声样点 突然出现的信号”里捕捉到信号到达的时刻输出一个触发脉冲或者一个粗起始索引。这个索引不需要很精确通常有几十个采样点的误差都能接受但它必须可靠——漏检意味着整包数据直接丢掉虚警则会让后续模块去解调一堆不存在的数据。在连续OFDM系统里比如DVB-T分组检测可以简化甚至省略因为信号一直在传输接收机只需要做符号定时和频偏跟踪。但突发系统不行接收机不知道发射机什么时候发必须有一个专门的检测机制这就是分组检测存在的根本原因。1.2 本质是一个二元假设检验问题把分组检测放到数学框架里看它做的是一个非常经典的二元假设检验。定义两个假设H0假设当前接收样点只有噪声r[n] w[n]H1假设当前接收样点包含信号分量r[n] s[n] w[n]算法要做的事情就是构造一个检测统计量M(d)然后拿它和门限lambda比较。如果M(d) lambda判为H1即信号到达否则判为H0继续监听。这里有两个关键错误类型值得先想清楚。第一类叫漏检miss detection信号明明在却判成了噪声。在突发通信里漏检基本等于丢包发射机那边重传机制再好这一包也算废了。第二类叫虚警false alarm噪声被误判成信号。虚警看起来好像“只是浪费点资源”但实际上危害也不小——它会把AGC拉乱、触发错误的频偏估计甚至导致后续连续几个符号都解错。所以好的分组检测算法本质上是在漏检和虚警之间找一个合理的平衡点而不是一味追求指标。1.3 为什么OFDM不能直接用瞬时幅度判断有人会问既然要判断信号来没来直接看接收功率不就行了信号来了功率肯定变大。理论上没问题但OFDM有个特点时域波形是多路子载波叠加出来的幅度分布非常接近高斯分布峰值和谷值差距很大峰均比PAPR普遍在10dB以上。也就是说即使信号已经来了某些时刻的瞬时幅度也可能低于纯噪声的峰值反过来噪声的突发毛刺也可能比信号某些样本还高。用瞬时幅度或者简单的功率阈值去判断误判会非常严重。OFDM训练序列的设计正好为分组检测开了一扇窗前导preamble里的短训练序列STS通常是周期重复结构。比如802.11a的短训练序列长度0.8us的序列会重复10次。这种周期性给了算法一个非常强的信号特征——自相关性。即使信号的绝对幅度在波动、存在一定频偏相邻重复段之间的相关性依然稳定存在噪声则没有这种规律。因此主流分组检测算法几乎都是围绕“自相关”或者“前导已知模式”来构造的而不是比幅度。2. 三类主流分组检测算法与选型2.1 能量检测做辅助可以单独用要小心能量检测是最朴素、最容易理解的一种方法。它的做法很简单取一段长度为L的滑动窗口计算窗口内N个样点的平均功率把这个功率和某个门限比较。如果功率超过门限就认为有信号到达。这个算法的优点非常突出计算量极小、实现简单、不依赖任何训练序列格式而且对频偏完全不敏感——因为频偏只改变相位不改变模值。在不知道前导结构的盲检测场景里能量检测几乎是唯一选择。但它的问题也同样明显接收信号的绝对功率受很多因素影响包括AGC增益状态、发射功率、路径损耗、阴影衰落甚至前端滤波器的插损。同一个门限在近距离强信号场景下可能非常灵敏在远距离弱信号场景下可能完全漏检。如果做动态门限就得实时估计噪声功率噪声基底在突发干扰下又很难测准。所以我的建议是工程上不要拿能量检测做最终判决它更适合作为粗检测、AGC触发辅助或者配合自相关算法做双确认。单独使用的话大概率会在现场被各种边缘场景折磨。2.2 延迟自相关主流方案里的主力选手延迟自相关是目前突发OFDM接收机里用得最普遍的手段也是IEEE 802.11系列前导检测的核心思想。只要前导训练序列具有周期重复结构比如短训练序列重复周期为D个采样点那么理想情况下r[n]和r[nD]是同一个序列高度相关。于是定义两个中间量P(d) sum_{m0}^{L-1} r[dm] * conj(r[dmD])R(d) sum_{m0}^{L-1} |r[dmD]|^2P(d)是滑动自相关值反映的是相隔D个采样点的两段数据有多像R(d)是后一段窗口的能量用来做归一化。检测统计量为M(d) |P(d)|^2 / R(d)^2当滑动窗口恰好落在训练序列上时P(d)的模接近R(d)M(d)趋近于1当窗口落在纯噪声上时P(d)里噪声的随机乘积相互抵消M(d)接近0。用一个中间门限比如0.5就能很好地区分两种状态。这个方案最大的优点是抗频偏能力强。载波频偏虽然会给P(d)引入一个固定的相位旋转——因为相隔D个采样点相位差是2πΔfD/fs——但取模之后这个相位信息完全消失所以分组检测可以在频偏估计还没做的时候就能可靠工作。这在接收机同步流程上是一个非常理想的特性意味着“检测”可以先于“频偏校正”完成模块之间不用反复迭代。选择D和L时有讲究。D必须等于训练序列的重复周期对应的采样点数L一般取一个重复周期的长度。以802.11a为例20MHz采样率下短训练序列周期是0.8us对应16个采样点所以D16、L16是最常见的配置。窗口太长反而会把多个重复段混合进来虽然也能检测但峰值平台会变宽起始点定位精度变差。2.3 双滑动窗口与互相关两种各有针对的方案除了能量检测和延迟自相关还有两个方案在不同场景下有价值。一个是双滑动窗口法。它开两个连续的能量窗口A和B计算M E(A) / E(B)。信号还没到的时候两个窗口都只装噪声比值接近1当信号前沿进入A窗口而B还在噪声里比值迅速上升超过门限就判定检测到信号。这种方法的好处是不需要已知训练序列结构也不需要周期重复假设对任意突发信号都有效。缺点是门限需要根据噪声波动来定而且位置精度不如自相关。另一个是互相关检测或者叫匹配滤波检测。如果接收机能拿到完整的前导序列副本——比如收发双方约定好一个固定PN序列作为前导——就可以用滑动互相关扫描。互相关在正确对齐位置会产生一个尖峰检测精度远高于自相关还能顺便给出多径时延信息。但它对频偏极其敏感频偏稍大相关峰就展宽、变矮甚至彻底淹没在噪声里。工程上常见的做法是先用延迟自相关做粗检测拿下粗位置和粗略频偏再做频偏校正然后用互相关做精同步。直接把互相关放在第一级风险很高。2.4 三种算法怎么选一张表讲清楚算法核心原理抗频偏是否依赖前导格式计算量检测精度推荐场景能量检测窗口功率与门限比较完全不敏感不依赖极低低AGC触发、盲检测粗判延迟自相关利用训练序列周期重复性强需要周期结构低中高WiFi/LTE前导检测主流方案双滑动窗口前后窗口能量比值完全不敏感不依赖低中任意突发信号无前导知识滑动互相关与已知前导模式匹配弱需要完整副本高高频偏校正后的精同步实际项目里我通常会把“延迟自相关”作为主检测器拿“能量检测”作为AGC触发再在精同步阶段上“互相关”。三层配合既保证可靠性又兼顾精度和资源效率。3. MATLAB仿真从公式到可跑通的检测器3.1 先用802.11a前导结构把参数定下来做仿真时我习惯直接把参数映射到802.11a的20MHz模式因为这套参数是公开的、验证充分的而且和很多实际OFDM系统结构相近。关键参数如下采样率 fs 20MHz采样间隔50nsFFT点数 N 64循环前缀长度 CP 16短训练序列周期 T_sts 0.8us对应采样点数 16短训练序列重复10次总长度8us共160个采样点分组检测这边只需要一个参数延迟D 16相关窗长L 16。这个参数是怎么来的就是短训练序列的重复周期。采样点数和时间的换算关系是点数 时间 × 采样率。0.8us × 20MHz 16个样点。这个换算关系在做任何OFDM同步时都会反复用到建议刻在脑子里。还要注意信噪比的定义。仿真里一般用每个OFDM符号能量和噪声功率谱密度之比来定义SNR。为了方便观察检测指标的分布我会在接收信号里加高斯白噪声把SNR分别设成20dB、10dB、0dB三档跑一遍看看M(d)曲线在这几个档位下的表现差异。0dB虽然接近实际系统的工作下限但能暴露出很多门限设置问题。3.2 检测核心代码可以直接抄的版本MATLAB里实现延迟自相关检测非常直接。下面这个函数是我在项目里用的一个精简版本function [detected, coarse_pos] packet_detect(rx, D, L, threshold) % rx: 接收基带复信号行向量 % D: 延迟点数即训练序列重复周期 % L: 相关窗长度一般取一个重复周期长度 % threshold: 判决门限0~1之间 % detected: 布尔值是否检测到分组 % coarse_pos: 检测到的粗起始位置未检测到返回-1 N length(rx); P zeros(1, N); R zeros(1, N); M zeros(1, N); for d 1 : N - L - D x1 rx(d : dL-1); x2 rx(dD : dDL-1); P(d) sum(x1 .* conj(x2)); R(d) sum(abs(x2).^2); M(d) abs(P(d))^2 / (R(d)^2 eps); end % 找第一个超过门限的点 idx find(M threshold); if isempty(idx) detected false; coarse_pos -1; else detected true; % 取第一个连续超过门限区间的起点 coarse_pos idx(1); end end写这段代码时有几个细节我特别想强调。第一分母里必须加一个很小的eps防止R(d)为0时出现除零这在纯噪声段是完全可能发生的。第二分子用abs(P(d))^2而不是abs(P(d))好处是可以把幅值差异拉大让超过门限的部分更明显门限设起来更方便。第三实际工程里建议加一个“连续N点超过门限”的判据单纯取第一个超过门限的点容易受单点毛刺影响但单点虚警在极低SNR下确实会发生。用的时候先构造一段带延迟的接收信号fs 20e6; % 使用WLAN工具箱或者手动构造802.11a前导 % 这里简化为一个周期性重复序列 stf [1 1 -1 -1 1 1 -1 1 -1 1 1 1 1 1 1 -1]; % 16点短训练序列 preamble repmat(stf, 10, 1); % 重复10次共160点 % 模拟接收信号前200个点噪声然后信号到达 tx [zeros(200,1); preamble; zeros(100,1)]; noise 0.1 * (randn(size(tx)) 1j*randn(size(tx))) / sqrt(2); rx tx noise; % 检测 [flag, pos] packet_detect(rx., 16, 16, 0.5); fprintf(Detected: %d, position: %d\n, flag, pos);在这个例子里真实信号起点是201。因为延迟自相关需要等窗口滑到第DL个点处才能形成完整相关峰而且分子P(d)从信号到达后一点点积累所以检测出的pos会略大于201通常落在201附近再往后偏一点。这个偏差是正常的粗检测不追求精确对齐后续符号定时会修正。3.3 门限选择不要拍脑袋要看统计分布门限怎么设这是分组检测里最容易翻车的地方。我最开始做的时候随便设了个0.5仿真跑得挺好一到低SNR就频繁虚警后来才意识到门限必须结合M(d)的统计分布来定。准确的流程是在目标SNR范围里做蒙特卡洛仿真分别统计“纯噪声段M(d)的分布”和“信号段M(d)的分布”然后选一个能让两类错误概率都可接受的门限。实际操作时我习惯先把M(d)曲线画出来看。在SNR10dB时信号段的M值通常能到0.8到0.95噪声段基本在0.1以下中间留了很大的空隙门限设在0.5左右非常稳。SNR降到0dB信号段的M值会跌到0.5到0.7噪声段可能涨到0.2附近空隙变小门限就得往下调到0.35到0.4同时加“连续超过门限”的判据来压制虚警。另外有一个便宜的技巧不要只用一个门限。实际系统可以在AGC/噪声估计模块里维护一个粗略的SNR估计低SNR环境自动把门限调低高SNR环境把门限调高。这比单一固定门限稳健得多而且实现成本很低。3.4 从仿真到FPGA有四个注意点要提前想用FPGA做分组检测时MATLAB里那些方便的东西全都不方便了有四个问题几乎每个项目都会遇到。第一是定点化。MATLAB里默认浮点而FPGA里P(d)和R(d)的累加需要定点表示。P(d)是复数的乘积累加动态范围很大我一般用两个方向的饱和截位乘法结果先截到合适位宽累加器再根据窗长留出足够的比特增长空间。R(d)是能量值相当于功率增长更快需要更多位数。这个过程一定要做量化误差仿真不能拍脑袋截。第二是流水线。FPGA里不可能像MATLAB这样每个d点暴力计算通常用滑动窗更新新进来一个样点P(d)加一项新的乘法结果、减一项滑出的乘法结果。这样每个时钟周期只需要一次复数乘法和两次复数加法资源占用立刻降下来。但滑动更新会引入累积误差需要定期清空或者做一些补偿。第三是打拍对齐。检测模块输出的触发信号要和数据的延迟精确对齐。自相关计算本身有延迟后续的AGC、频偏估计模块如果直接拿触发信号去处理缓存数据很可能取到错误的位置。常见的做法是在数据路径上加上匹配的延迟线或者用FIFO缓存保证触发信号和数据样点同步到达。第四是门限和判据的硬件化。“连续N点超过门限”这个逻辑在FPGA里就是一个N位的移位寄存器外加一个计数器逻辑非常简单但非常管用值得为了它牺牲一点点检测延迟。4. 常见问题与排错实录4.1 虚警和漏检的对照速查表分组检测翻车翻来翻去无非就是两个方向该响的时候不响不该响的时候乱响。以下是我在实际调试中总结的排查顺序现象可能原因处理办法频繁虚警门限设置过低提高门限或增加“连续N点”判据频繁虚警直流偏置未被扣除先做直流估计并扣除再进检测器频繁虚警窄带干扰抬高了噪声平台加陷波器或者用带通滤波限制检测带宽该检不检门限过高降低门限配合低噪底场景单独设档该检不检D参数和训练序列周期不匹配核对训练序列重复周期对应的采样点数该检不检频偏过大导致能量检测失效改用延迟自相关做检测位置偏后自相关平台效应导致起点模糊取平台起点别取平台中点后续用互相关精同步直流偏置这个点特别容易忽略。射频前端的I/Q不平衡、ADC的偏置都会在基带信号里叠一个直流分量。直流分量在延迟相关里会形成一个恒定的基底让噪声段的M值整体抬升而且这个基底对信噪比完全不敏感SNR越高虚警越明显。所以我在接收链路里几乎总是放一个隔直滤波器或者直流估计扣除模块放在分组检测前面。4.2 平台效应、多径和采样钟偏差的坑自相关检测有一个所有教材都会提、但不一定说透的问题峰值不是一个尖峰而是一片平台。因为训练序列持续时间内滑动窗口一直都处在“前后相关”的状态M(d)在整个训练序列区间都会维持高位。这个平台会导致起始位置模糊——你只知道信号在某一段范围里到了但不知道具体从哪一个点开始的。解决平台效应有两条路。一条是取“第一个超过门限的点”作为粗位置这样至少保证了位置不会偏后。另一条是在后续精同步里用长训练序列LTS做互相关因为LTS相关峰非常尖锐可以把起始点精确锁定到几个采样点以内。802.11a接收机为什么设计成STS做粗同步、LTS做精同步两段式就是为了配合这个思路。多径信道则是另一类问题。如果多径时延扩展超过了训练序列重复周期的间隔前一个多径分量和后一个多径分量会破坏周期相关性。最典型的情况是短训练序列周期是0.8us如果信道时延扩展接近或者超过这个值自相关峰值会被明显展宽和削弱。在强多径场景下我建议把训练序列设计得更长一些或者检测时用较长的相关窗做部分平均让多径的能量尽量被包含在窗内。采样钟偏差clock offset对分组检测的影响相对小但也不能完全无视。如果收发两端采样钟偏差较大D的值会在长数据包里缓慢漂移导致后段的检测统计量逐渐不过门限。好在分组检测发生在包的最前端累计漂移还不大影响有限。真正受采样钟偏差影响严重的是后面的符号定时和频偏跟踪模块。4.3 和AGC、符号定时联动时的工程经验分组检测不是一个孤立的模块它和AGC、符号定时之间存在很强的联动关系这里有几个我踩过坑后总结出来的联动经验。AGC和分组检测的联动最微妙。AGC需要分组检测来触发增益调整但AGC调整本身又会改变信号幅度反过来影响检测器的归一化。延迟自相关的优势在这里体现得淋漓尽致因为分子分母都被信号幅度归一化了AGC在检测过程中改增益M(d)基本不受影响。所以建议AGC触发用能量检测或者能量检测的粗判分组检测的最终判决用自相关两者互不干扰。符号定时同步则要求分组检测给出的触发信号尽量可靠、尽量早。实际实现时我会让分组检测多输出一个“置信度”信号比如M(d)峰值超过门限的余量。定时同步模块可以等置信度高的时候再启动避免在临界SNR下被噪声带偏。还有一点心得检测器的状态机一定要做防抖。检测到信号之后不能立刻把状态从IDLE切到SYNC建议连续几个采样点确认后再切换同时在状态转换时对数据路径做复位。否则一个毛刺就可能让整个接收机跳到错误状态很久都回不来。这个防抖逻辑在FPGA里实现很简单但能省掉大量现场排查的功夫。5. 关于这套检测流程我最后想说的分组检测这个东西理论上看好像就是一个相关公式加一个门限但真正拿到实际系统里跑你会发现在不同SNR、不同信道、不同AGC状态下算法表现差异非常大。我自己做这套流程的习惯是先拿MATLAB把M(d)的统计分布跑透确定门限的合理区间再上FPGA而且绝不指望一个门限吃遍所有场景。给接收机准备至少两套检测参数——一套给正常链路一套给低噪底、强干扰的恶劣环境——这样现场调试的时候会从容很多。分组检测是OFDM同步的第一关它不追求精细但必须可靠这一关稳了后面的定时、频偏、信道估计才有得玩。
返回列表