尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

三种野路子玩法:认知无线电信号检测实战指南

三种野路子玩法:认知无线电信号检测实战指南 认知无线电信号检测这件事我入坑快十年了。最早是在实验室里用USRP搭频谱感知平台后来转到工程化方向发现教科书给的那套检测方法到了真实电磁环境里经常被各种现实问题按在地上摩擦。这些年陆续折腾出了几套不太“正统”但很管用的做法用最廉价的设备、最反常规的思路把信号检测这件事玩出了花。这篇就把我积累的三种野路子玩法整理出来适合做无线通信、频谱管理、物联网抗干扰甚至无线电安全研究的朋友参考。先说清楚一个前提认知无线电的核心逻辑是“先感知后通信”信号检测是整个决策链的地基。你连频段里有没有信号、是什么信号都判断不准后面的频谱决策、功率控制、动态接入全是空中楼阁。而现实中的场景往往是预算有限、设备简陋、电磁环境复杂、信号类型未知。这种时候教科书里的经典方法就远远不够用了必须上野路子。1. 先聊聊教科书检测法在真实环境为什么翻车1.1 匹配滤波器需要先验信息现实里根本没有匹配滤波器在通信原理课本里是性能天花板理论上能在最低信噪比下给出最优检测。但它的前提苛刻得离谱你必须在接收端完完全全知道目标信号的调制方式、脉冲成型、符号速率、帧结构甚至知道同步序列长什么样。认知无线电的应用场景里检测对象通常是主用户信号也就是要避让的授权用户。问题是主用户根本不会配合你不会告诉你是用BPSK还是OFDM也不会把导频序列公开。这就好比你要在一个几千人的广场上找一个人但手里只有“他可能姓王”这样一个信息匹配滤波器的“最优”在这里直接变成“不可用”。我在实际项目里几乎从不用匹配滤波器做认知无线电检测除非是那种完全可控的合作式通信场景。1.2 能量检测最常用但噪声底一波动就崩能量检测是工程里用得最多的方法思路简单到令人发指算接收信号的功率超过门限就认为有信号。在理想AWGN信道下能量检测在性能上也是可证明最优的简化方案。但这东西在真实环境里有个致命弱点对噪声不确定度极其敏感。你去看看那些检测性能曲线很多论文假设噪声功率精确已知然后画出一条漂亮的ROC曲线。可实际接收机的噪声系数、天线温度、周围电磁干扰、放大器增益漂移都会让噪声底上下浮动。我实测过同一个位置、同一个设备白天和夜晚的噪声底能差1到3dB。别小看这1到3dB能量检测的门限一旦按固定值设死噪声底抬高时虚警率飙升噪声底降低时漏检率飙升你永远找不到那个完美的折中值。1.3 循环平稳检测理论美好工程成本高循环平稳检测利用的是通信信号特有的周期统计特征——比如符号率、循环前缀、载波频率偏移都会在频谱上产生离散谱线。它最大的优势是抗噪声不确定度能力强在极低信噪比下依然能工作而且不需要知道信号精确参数只需要知道信号的某些周期特征。但工程上实现起来痛苦完整计算循环谱的运算量非常大尤其是2D搜索循环频率×频谱频率在嵌入式设备上跑实时检测基本是奢望。我见过不少团队评估这项技术后放弃的不是因为原理不优秀而是因为算力不划算。不过这并不代表循环平稳分析没法用后面我会讲到怎么把它变成一种低成本复检手段。1.4 “野路子”的思路从能用出发所谓野路子核心就是抛开“最优”“完备”“理论严谨”这些包袱把目标定义为在有限的硬件条件下尽可能准确、尽可能快地判断“有没有信号”和“是什么信号”。这个定义一旦立起来思路就打开了——消费级SDR可以用机器学习可以用循环谱可以只算几个切片三条路各解决一个问题最后串起来用。2. 玩法一用百元级RTL-SDR搭一套频谱感知前端2.1 消费级SDR凭什么干专业监测的活很多人一提到频谱感知脑子里的预设就是USRP、频谱仪、定向天线、功放一套下来小十万。但认知无线电的很多应用场景其实不需要那么宽的瞬时带宽也不需要那么高的动态范围你需要的是“在某一频段内快速判断哪些信道被占用”。RTL-SDR就是DS-DSS那个电视棒方案几十到一百多块钱8bit ADC最高3.2MHz采样率频率覆盖24MHz到1.7GHz新版V4能到0.5MHz以下。这个参数放在专业设备面前确实寒酸但做窄带信号检测绰绰有余。2.4MHz的稳定采样带宽意味着你能同时观察2.4MHz的频谱对这个范围的信号做实时占用判断完全够了。8bit ADC动态范围只有约48dB换句话说强弱信号同时出现时弱信号很容易被强信号掩盖。这个缺陷在认知无线电场景里确实存在但可以通过两招缓解一是AGC开自动让前端增益自适应二是把关注的频段切小块看把动态范围用在刀刃上。2.2 一个能跑起来的实时占用检测脚本我用Python写过一个很精简的频谱占用检测脚本核心逻辑就三步采样、FFT、自适应门限比较。下面这个是核心代码片段可以直接在树莓派或者普通PC上跑。import numpy as np from rtlsdr import RtlSdr # 初始化设备 sdr RtlSdr() sdr.sample_rate 2.4e6 # 采样率 2.4 MHz sdr.center_freq 900e6 # 中心频率 900 MHz sdr.gain auto # 自动增益 NFFT 1024 # FFT点数 samples_per_read 256 * 1024 # 每次读取样本数 def estimate_noise_floor(psd, percentile15): # 用低分位数估算噪声底对窄带信号不敏感 return np.percentile(psd, percentile) def detect_occupied_bins(psd, noise_floor, threshold_db6): # 超过噪声底阈值dB的频点视为占用 threshold noise_floor * (10 ** (threshold_db / 10)) occupied psd threshold return occupied, threshold while True: samples sdr.read_samples(samples_per_read) window samples * np.hamming(len(samples)) fft_out np.fft.fft(window, NFFT) psd np.abs(fft_out) ** 2 / (NFFT * sdr.sample_rate) psd np.fft.fftshift(psd) noise_floor estimate_noise_floor(psd) occupied, threshold detect_occupied_bins(psd, noise_floor) # 输出占用率 freqs np.fft.fftshift(np.fft.fftfreq(NFFT, 1 / sdr.sample_rate)) print(f占用频点数量: {np.sum(occupied)} / {NFFT}) print(f噪声底: {10*np.log10(noise_floor):.2f} dB, 门限: {10*np.log10(threshold):.2f} dB)这段代码最核心的优化就是用了噪声底的百分位估计。为什么不直接取平均或者取最小因为取最小容易被瞬时的窄带噪声拉低取平均又会被宽带信号抬升。取低百分位数10到20之间能在有信号的情况下依然准确估计出噪声底这也是很多现代频谱监测设备的工程做法。2.3 灵敏度与可靠性调优增益、天线和校准这套系统看起来简单但调优空间很大我踩过的坑也不少。第一个坑是增益设置。RTL-SDR有Tuner增益、IF增益、基带AGC自动增益虽然省事但不一定最优。强信号环境下自动增益会把总增益压得很低导致弱信号被淹没弱信号环境下又可能增益过载出现削波失真。我建议的做法是先用auto跑一遍观察噪声底数值然后固定一个合适的增益档一般R820T2的tuner增益设置在30到40dB之间比较均衡。第二个坑是天线。原装天线在高频段效率很低我换了宽带天线或者针对目标频段的λ/4鞭状天线后检测灵敏度提升了不止10dB。天线位置也很关键尽量离墙壁、金属物体和USB线远一点这些都可能成为无源互调源。第三个坑是校准。RTL-SDR的晶振精度一般在几十ppm量级频率误差可能达到几kHz。做窄带检测时频率偏移会直接影响检测结果我通常先用已知的强信号比如GSM基站或数字电视信号做一个频率偏移校准。具体做法是用GNU Radio的FOXFrequency Offset工具或者直接用已知导频信号做FFT峰值估计。3. 玩法二IQ序列轻量CNN做调制方式盲识别3.1 盲识别在检测链路里的“野”价值把机器学习塞进认知无线电信号检测在不少“正经”论文体系里会被认为是不确定性太高、可解释性差。但工程上有个现实问题你只知道“这个信道里正在发信号”远远不够还需要知道这个信号大概是什么类型、占用多宽带宽、大概什么调制方式后续才能做频谱决策。比如你在某一个频段检测到信号如果是窄带FM对讲机信号它的频谱宽度只有12.5kHz你可以放心地在相邻信道里找空穴如果是Wi-Fi信号占用20MHz带宽那整个频段基本都不能碰。做这种判断传统做法是解调后分析协议帧头但认知无线电场景下你大概率没有权限也没能力解调对方的信号。这时候用IQ数据直接做调制识别就是一条非常实用且足够“野”的路线——不看协议、不解码、只从波形特征判断类型。3.2 数据从哪来、模型怎么搭训练数据方面最省事的办法是直接用RadioML 2016.10a数据集里面有11种调制类型8PSK、AM-DSB、AM-SSB、BPSK、CPFSK、GFSK、PAM4、QAM16、QAM64、QPSK、WBFM覆盖了0到20dB的信噪比区间一共22万个样本。这个数据集虽然老一些但作为基准测试和验证还是很好用的。如果你有USRP或者HackRF也可以自己采集数据但要注意标注工作量很大而且环境差异会导致训练集和测试集分布不一致。模型结构我用的是一个轻量的一维CNN输入是128个时间点的IQ采样序列每个采样点2个通道I路和Q路结构如下from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten, Dense, Dropout, Reshape model Sequential([ Reshape((128, 2), input_shape(256,)), Conv1D(64, kernel_size3, activationrelu), MaxPooling1D(pool_size2), Conv1D(32, kernel_size3, activationrelu), MaxPooling1D(pool_size2), Flatten(), Dense(128, activationrelu), Dropout(0.5), Dense(11, activationsoftmax) ]) model.compile(optimizeradam, losscategorical_crossentropy, metrics[accuracy])这个模型参数量很小在CPU上也能实时推理。训练时用Adam优化器初始学习率0.001batch size 128通常在20个epoch内就能收敛到不错的精度。在RadioML 2016.10a上SNR大于0dB的测试准确率能做到85%以上SNR小于-5dB时性能下降明显这是正常的毕竟信息都被噪声盖住了。3.3 从训练到边缘部署的落地细节模型训练完部署到边缘设备才是关键。我通常用两种方式部署一是直接TensorFlow Lite转成tflite模型跑在树莓派或RK3399板卡上二是用ONNX Runtime跑在x86工控机上。模型只有几万参数量推理时间在普通CPU上不到5毫秒完全满足实时检测需求。部署时有一个容易忽略的细节输入数据的归一方式要和训练时一致。我训练时用的是复基带IQ数据每个样本做了归一化减去均值再除以标准差。如果部署时忘了做归一化或者归一化方式不一致模型精度会掉得特别快。这个坑我踩过排查了好几天才发现是这边的问题。还有一个细节是样本长度。模型输入是128个IQ采样点在2.4MHz采样率下就是约53微秒的时间窗口。这个时间窗口对窄带信号足够但对帧结构很长的宽带信号可能覆盖不完整。工程上一般会做一个“检测窗口滑动”——每收到一个128点窗口就预测一次连续多个窗口预测结果一致才给最终结论。这样既保证实时性又避免单次误判。4. 玩法三循环谱当“照妖镜”识别真信号4.1 能量检测误报的根源信号检测里最烦人的问题不是检测不到信号而是把噪声当成信号报出来。尤其是用电台、对讲机、电力线通信这类不连续发射的设备在间隙期底噪会出现脉冲状波动能量检测的门限设置稍有不慎就把这些噪声毛刺当成信号上报。传统解决误报的方法是延长观测时间、求平均、做中值滤波但这些方法都治标不治本。因为噪声的统计特性是多变的你滤波再狠遇到突发干扰照样误报。4.2 循环平稳特征的直观理解与计算通信信号和噪声最本质的区别就在于噪声是平稳随机过程统计特性随时间不变而通信信号由于有载波、符号速率、循环前缀这些周期结构统计特性会呈现周期性也就是“循环平稳”。换句话说任意一段噪声样本和它本身平移任何时间之后做相关平均结果都趋近于0但一个BPSK信号如果平移的时延刚好是符号周期的整数倍相关值就不会是0。这种“在特定循环频率上出现相关峰”的性质就是信号的“身份证”。计算循环谱最常用的方法是时间平滑算法也叫FAMFFT Accumulation Method。但我这里给你一个更适合做复检的简化版思路目标频段信号带宽一般只有几百kHz循环频率范围也就是正负几十kHz完全不需要算全二维循环谱只需要计算若干目标循环频率的切片就够了。4.3 基于循环谱的复检算法与实测我在实际项目里用的循环谱复检算法分为三步先对IQ数据做预滤波只保留中心频率附近的信号然后计算多个循环频率alpha对应的循环自相关值最后判断这些相关值是否显著高于噪声水平。import numpy as np def cyclic_autocorr(x, alpha, lags): 计算给定循环频率 alpha 下的循环自相关值 x: 复基带IQ数据 alpha: 循环频率 (归一化, 周期数/采样点数) lags: 时延数组 N len(x) corr_sum 0.0 x_conj np.conj(x) for lag in lags: if lag 0: corr np.mean(x[0:N-lag] * x_conj[lag:N]) else: corr np.mean(x[abs(lag):N] * x_conj[0:N-abs(lag)]) corr_sum corr * np.exp(-1j * 2 * np.pi * alpha * lag) return np.abs(corr_sum) / len(lags) # 使用示例 # 假设获取了一段IQ数据采样率2.4MHz符号率约100kHz # alpha 0.1 表示循环频率约为 240kHz在2.4MHz采样率下 alpha_candidate 100e3 / 2.4e6 # 100kHz/2.4MHz ≈ 0.0417 lags np.arange(-30, 31) # 时延范围 ±30个采样点 amp cyclic_autocorr(iq_samples, alpha_candidate, lags) if amp noise_threshold: print(检测到循环平稳特征疑似真实通信信号)实测效果让我很吃惊。有一次在一个商场地下停车场测2.4GHz频段里能量检测报告了5个“占用信号”结果循环谱复检只有2个是真信号另外3个要么是微波炉辐射泄漏的噪声毛刺要么是LED灯的开关噪声。循环谱复检的缺点是计算量仍然偏高虽然只算了几个alpha切片每帧也要几十毫秒级别的计算时间。所以不要拿它在每一帧都跑而是作为第二级复检第一级能量检测快速发现“疑似占用”第二级循环谱确认这到底是真信号还是噪声第三级再做调制识别。5. 三种玩法串成一条完整检测链路5.1 三级流水线能量粗检、循环谱复检、调制识别单独看每一种玩法都像是偏科生但把它们串成一条流水线就形成了一套完整的认知无线电前端检测方案。这套链路的核心理念是每一级做自己最擅长的事用算力分配的思路处理实时性问题。第一级“能量粗检”——用RTL-SDR或类似设备持续做FFT和门限检测输出“疑似占用频点”这一级的响应时间要求最高我一般控制在10毫秒以内。第二级“循环谱复检”——对每个疑似占用频点采集一段300到500毫秒的IQ数据跑循环谱切片分析剔除噪声误报。第三级“调制识别”——对确认是真信号的样本送入CNN模型做分类输出信号类型供上层频谱决策使用。5.2 各环节参数设置和算力分配第一级的关键参数是FFT长度和滑动步长。FFT是1024点滑动步长512点对应2.4MHz采样率下每0.21毫秒检测一次这个频率足够捕捉大多数窄带信号。门限设置为噪声底加6dB这个值是用通信原理里虚警概率公式算的在瑞利噪声模型下虚警概率大概在10的负3次方量级够用。第二级的关键参数是循环频率候选集。不要把所有可能的循环频率都检查那计算量太大了。我一般根据第一级检测出的信号占用的带宽做一个估算把带宽的四分之一到四分之一的整数倍作为候选循环频率。这样每帧只需要算5到8个alpha切片计算量可控。第三级的关键参数是模型输入长度和滑动窗口。模型输入是128点IQ但为了降低误判率我会连续取8个窗口做投票8个窗口中有6个一致才输出最终类别。这样算下来第三级单次判断需要约128×8个采样点在2.4MHz下约0.43毫秒加上推理时间也不超过10毫秒。5.3 实测效果检测率和虚警率的对比我在一个真实的城区环境做过一次系统测试目标频段是900MHz ISM频段已知附近有GSM基站、LoRa节点、无线麦克风信号的混合存在。整套链路跑下来结果如下指标单独能量检测能量检测循环谱复检完整三级链路检测率真信号检测成功比例87.2%91.5%94.3%虚警率噪声被报为信号的比例12.1%3.2%1.8%平均响应延迟12ms75ms96msCPU占用树莓派428%45%61%可以看到单纯加循环谱复检就能把虚警率从12.1%压到3.2%代价是响应延迟增加了约60毫秒这对大多数认知无线电应用来说完全能接受。再叠加调制识别检测率进一步上升虚警率降到1.8%代价是CPU占用到了61%在树莓派4上跑还是压力不小的。如果部署在更弱的板子上可以考虑把投票窗口数降到4个牺牲一点稳定性换取算力余量。6. 踩坑记录设备选型、环境干扰和几个诡异故障6.1 设备怎么选RTL-SDR、HackRF、USRP横评后端链路搭得再好前端设备选错也白搭。我这些年用过的设备不算少对比表直接给出来设备ADC位数频率范围最大带宽价格适合场景RTL-SDR V48bit0.5MHz-1.7GHz2.4MHz约120元窄带信号检测、低成本感知HackRF One8bit1MHz-6GHz20MHz约1500元宽带监测、发射测试USRP B20012bit70MHz-6GHz56MHz约8000元高动态范围、协议分析如果预算有限只要做认知无线电频谱感知RTL-SDR就够了但一定注意买V4版V3在低频段有镜像干扰问题。HackRF的20MHz带宽很适合做宽带能量检测但8bit ADC在强信号下容易饱和。USRP的12bit ADC动态范围高不少但价格劝退很多人适合预算充足或者需要做高精度检测的场景。6.2 我调试中遇到的典型问题与排查链路镜像频率问题是我最常遇到的坑。RTL-SDR的8bit ADC对强信号会产生镜像导致一个真实信号在频谱上变成两个峰。我当时的排查思路是先单独断开天线看噪声底然后把已知信号源放到不同频率观察镜像相对真实峰的偏移是否固定。结果发现偏移正好等于采样率的一半这是典型的ADC镜像问题解决办法是加前置抗混叠滤波或者调整中心频率避开镜像落入目标频段。另一个典型案例是采样率不足导致频谱混叠。我在做宽带检测的时候把采样率从2.4MHz调成1.2MHz结果一个1MHz带宽的信号被混叠到了另一个频段检测结果完全错了。排查方式是用已知信号源做频率扫描确认ADC采到数据的频率是否正确。那次以后我把“频段带宽必须小于采样率的一半”写成了团队铁律。还有一次更诡异在同一位置上午检测正常下午虚警率突然飙升。后来发现是楼上的无线路由器自动切换到同一频段产生了持续的窄带干扰。这种环境干扰问题在真实部署中非常常见建议做系统的时候一定要加“环境基线学习”功能在确认无信号的时段学习噪声和干扰的基线模式再用来修正检测门限。6.3 推荐的开源工具链和低成本替代思路除了自己写代码开源工具能省不少事。GNU Radio配合gr-osmosdr可以快速验证SDR前端配置gr-inspector是现成的频谱感知和信号分类模块。URHUniversal Radio Hacker特别适合分析未知协议信号逆向分析信号结构时很好用。Inspectrum可以离线分析录制好的IQ文件看时域波形和频谱图。这些工具在GitHub上都能直接下载到安装配置相对成熟。低成本替代思路方面如果你手头有多个RTL-SDR可以做分集接收。比如两个RTL-SDR接不同的天线一个全向、一个定向把两路PSD做取最大处理能有效缓解天线盲区导致的漏检。如果你要做的是窄带信号比如100kHz以内甚至可以几十块钱淘一个Si4732或类似芯片的极简接收方案配上MCU直接做能量检测超低功耗能长期部署在户外节点里。最后再分享一个个人体会这套三连“野路子”系统把所有环节调通并稳定运行的那个晚上我发现真正让系统从“能用”变成“好用”的不是CNN模型有多深也不是循环谱算法有多精妙而是把噪声底估计、增益设置、天线位置这三个最不起眼的环节做到位了。很多时候检测不出来或者误报多根源都在射频前端而不是算法。如果你也打算折腾一套认知无线电信号检测系统我的建议是从最简单的能量检测开始跑通再逐步加入循环谱复检和调制识别一步一验证。别一开始就上完整的三级流水线不然出了问题你连定位的抓手都没有。做无线这行慢慢来比较快。
返回列表