ARTICLE DETAIL

资讯详情

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

循环累积量+BP神经网络:低信噪比调制识别复现全攻略

循环累积量+BP神经网络:低信噪比调制识别复现全攻略 简介这是一份面向无线通信、信号处理与人工智能交叉方向学习者的技术论文PDF聚焦基于循环累积量与神经网络相结合的调制识别算法。资源围绕非合作通信中的信号自动分类需求系统阐述了二阶、四阶循环累积量的理论推导与特征提取方法并采用三层神经网络作为智能分类器无需人为设置判决门限。内容从接收信号模型、分类器设计到多类调制信号识别实验逐步展开覆盖BPSK、QPSK、8PSK、8QAM与16QAM等常见体制同时给出低信噪比下的鲁棒性验证结果适合通信专业研究生及相关工程师用于算法复现、毕业设计或课题参考。包内为1个PDF文档文件大小仅338KB文字公式完整便于快速查阅。已有101人学习可作为调制识别与神经网络应用方向的数据建模入门资料。1. 为什么我冲着「不用设门限」去复现这篇调制识别算法做调制识别方案选型时最让人头疼的往往不是分类器而是判决门限怎么定。决策树那条路看着简单但门限值随信噪比、信道环境漂得厉害换个场景就要重新标定。这篇论文的做法是把决策问题交给神经网络前置只用循环累积量在离散循环频率处的谱峰做特征门限这件事直接绕开。论文用这个方法把 BPSK、QPSK、8PSK、8QAM 和 16QAM 五类信号在低信噪比下做到了不错的识别率实验平台是 GNU Radio 和 MATLAB数据链路完整适合做调制识别入门到复现的参照。这篇笔记按我实际的复现路径来讲先啃理论再过参数最后给避坑和能直接跑的流程。2. 理论根基循环累积量是怎么把五类信号分开的2.1 接收信号模型与循环平稳假设论文的接收信号模型是经典的加性噪声模型r(t) s(t) n(t)其中 s(t) 是经过升余弦成形脉冲的有用信号n(t) 是零均值平稳噪声载波频率为 fc码元宽度为 T。关键在于一个前置假设通信信号经过成形脉冲、载波调制之后统计特性不再是平稳的而是呈现循环平稳特性。平稳噪声的循环累积量在非零循环频率处恒为零这意味着在循环频率域里噪声会被天然滤掉这是循环累积量相对普通高阶累积量最大的优势。我在复现时把模型拆成了三块理解成形脉冲决定循环频率出现在哪些位置载波频率决定谱峰在哪码元序列的统计特性决定哪些阶数的循环累积量不为零。三块加起来每种调制方式就有一组独特的循环频率组合。后续的特征提取、神经网络输入全部建立在「循环频率可区分」这个前提上。2.2 二阶、四阶循环累积量与循环频率表论文用了两个时变累积量二阶的 Cx,2,0、Cx,2,1 和四阶的 Cx,4,0延迟向量取零。代入信号模型后各调制方式的循环频率特征如表 1 所示。调制方式Cx,2,0 循环频率Cx,2,1 循环频率Cx,4,0 循环频率BPSK2fc2fc ± 1/T±1/T4fc4fc ± 1/2TQPSK无±1/T4fc4fc ± 1/2T8PSK无±1/T无8QAM2fc2fc ± 1/T±1/T4fc4fc ± 1/2T16QAM无±1/T4fc4fc ± 1/2T这张表是整篇论文的地基。只看表 1 的话能分出三类BPSK 和 8QAM 一类QPSK 和 16QAM 一类8PSK 单独一类。但类内还是混的BPSK 和 8QAM 的循环频率完全一致光靠频率位置区分不开。论文的解法是继续看谱峰幅度循环频率相同不代表谱峰幅度相同这就有下文了。2.3 谱峰特征 vs 整段循环谱复杂度换来什么很多做调制识别的方案直接提取整段循环谱做特征特征维度高、计算量大而且循环谱估计需要很长的观测数据。论文的取舍是只取循环频率处的谱峰值而且是二阶和四阶各取一个关键位置|C2fc_x,2,0| 和 |C4fc_x,4,0|。这是整套方法里最值得借鉴的点。表 2 是论文给出的归一化理论峰值。BPSK 在两个位置都是 1QPSK 只在四阶位置有值 18PSK 两个位置都是 08QAM 分别是 0.68 和 116QAM 分别是 0 和 0.68。组合来看五个类在这个二维特征空间里没有重叠点。这就意味着用极低维的特征就能完成分类神经网络的输入层不需要做得很大训练样本需求也小很多。表 2 里那个 0.68 是复现时最容易对不上的值后面避坑章节会细说。3. 特征构造与 BP 分类器论文里的参数我逐条过了一遍3.1 特征向量怎么拼两个谱峰 归一化处理论文理论上用两个谱峰特征就能区分五类信号但工程实现时我建议把特征按实际能检出的循环频率谱峰值做扩展。为什么因为仿真时滚降系数、定时误差、噪声都会让谱峰幅度偏离理论值只靠两个特征的话低信噪比下容错空间太小。我复现时的做法是对每个信号样本在循环频率轴上扫描检测出所有明显谱峰提取主峰幅度和次谐波幅度再按表 2 的理论值做归一化。归一化不是可有可无的步骤——谱峰的绝对值受信号幅度 A 影响同一调制方式在不同接收功率下谱峰值可能差好几倍归一化之后才能让特征与幅度解耦。import numpy as np def extract_cyclic_features(r, fs, fc, T): # r: 接收信号序列fs: 采样率fc: 载波频率T: 码元宽度 # 简化实现在特征循环频率处估计循环累积量幅度并做归一化 N len(r) t np.arange(N) / fs # 在 2fc 处的二阶循环矩幅度x,2,0 特征 C2fc np.abs(np.sum(r**2 * np.exp(-1j * 4 * np.pi * fc * t)) / N) # 在 4fc 处的四阶循环累积量幅度x,4,0 特征 C4fc np.abs(np.sum(r**4 * np.exp(-1j * 8 * np.pi * fc * t)) / N) # 零频率处的二阶矩用于归一化 C0 np.abs(np.sum(r**2 * np.exp(0)) / N) C0 max(C0, 1e-12) # 归一化特征 feat np.array([C2fc / C0, C4fc / C0]) return feat这段代码对应论文式 (6)(8) 的工程近似信号平方后做频移再求均值本质是在 2fc 处估计循环频率谱线强度四次方对应 4fc 处。实际工程中不能只取一个时延点我会在 1/T 和 1/2T 的偏移处各取几个点做平均谱峰估计会更稳。归一化用零频二阶矩做基准是为了抵消幅度 A 的影响。3.2 BP 网络结构与激活函数选型论文的神经网络结构直接给出了一张参数表我复现时按这个基准搭输入层 6 个节点输出层 5 个节点隐含层 12 个节点隐藏层激活函数 ReLU输出层 softmax代价函数交叉熵学习率 0.01最大迭代次数 5000最大误差 0.001。其中输出层 5 个节点对应五类信号的独热编码BPSK(10000)、QPSK(01000)、8PSK(00100)、8QAM(00010)、16QAM(00001)。这里有个严谨性提醒论文正文在特征部分只强调两个谱峰但表 3 里输入层却给了 6 个节点这说明实际送入网络的特征向量比理论上的二维特征更宽。我推断作者把二阶、四阶多个循环频率处的谱峰值都拼了进去比如 2fc±1/T、4fc±1/2T 处的次峰。复现时不必死磕输入层必须等于 6先按你的特征维度定输入层隐含层按经验公式 H I sqrt(O T) 估算T 取 1 到 10 的整数然后在小范围里调。ReLU 做隐藏层激活、softmax 做输出层——这个组合在分类任务里很常见但要注意 ReLU 的输出没有上界如果特征没做归一化进入 softmax 之前数值可能溢出。所以特征归一化不是可选项是网络能正常训练的前提。3.3 仿真参数与训练流程可复现版论文实验参数的复现版本如下表所示参数值待识别信号BPSK、QPSK、8PSK、8QAM、16QAM码元速率 Rb900 bps采样频率 fs7200 Hz载波频率 fc1800 Hz成形脉冲升余弦滚降系数 ≤ 0.5信噪比范围-6 ~ 12 dB步长 1 dB每信噪比每类样本数1000 条训练/测试划分4:1观测码元个数256 / 512 / 1024 / 2048识别流程按六步走接收信号 → 归一化和循环平稳变换 → 循环频率检测并提取谱峰 → 划分训练测试集 → 训练神经网络 → 测试并输出类别。我一般把流程拆成独立的脚本信号生成脚本、特征提取脚本、训练脚本、测试脚本中间结果存成.mat或.npy文件这样换参数时不需要重跑前面所有步骤。import numpy as np from sklearn.neural_network import MLPClassifier from sklearn.preprocessing import StandardScaler # X_feat: 每行是一个样本的循环累积量特征shape(N, feature_dim) # y_label: 独热编码前的类别索引0~4 对应 BPSK/QPSK/8PSK/8QAM/16QAM scaler StandardScaler() X_scaled scaler.fit_transform(X_feat) # 与论文结构对齐单隐藏层ReLUsoftmax 输出交叉熵学习率 0.01 clf MLPClassifier( hidden_layer_sizes(12,), # 论文表3隐含层 12 节点 activationrelu, solversgd, # 梯度下降对应论文式(15)~(18) learning_rate_init0.01, max_iter5000, tol0.001, random_state42 ) clf.fit(X_scaled, y_label) acc clf.score(X_test_scaled, y_test) print(ftest accuracy: {acc:.4f})MLPClassifier 的参数与论文表 3 是一一对应的。有个细节要注意sklearn 的tol0.001是损失函数变化阈值对应论文的「最大误差 0.001」但 sklearn 默认还会受n_iter_no_change控制提前停止复现论文的 5000 次迭代时要把这个参数设大或设为None否则训练可能提前收场实验结果对不上论文。4. 避坑与常见问题复现时最容易翻车的五个点4.1 采样频率与码元速率不成整数倍循环频率检测不到现象按论文参数设 fs7200、Rb900、fc1800MATLAB 里怎么也找不到 2fc 处的谱峰频谱图一片糊。原因fs 和 Rb 的比值是 8这个整数关系让循环频率恰好落在 FFT 的某些频点上但如果你的实现里没对齐 FFT 分辨率或者用psd估计时窗长不是码元周期的整数倍谱峰会泄漏到相邻频点幅度掉一大截。解决做循环频率检测时FFT 点数取码元周期整数倍并且循环频率轴的频点要和 fs/N 对齐。我一般用fft(r.^2, N)后直接在频点索引上找2*fc*N/fs对应的位置而不是用连续的linspace频率轴去近似。4.2 理论特征表里的 0.68 复现不出来现象BPSK、QPSK 这些信号的谱峰比值都能对上表 2唯独 8QAM 和 16QAM 的 0.68 无论如何测不到有的仿真出来是 0.5有的是 0.7 几。原因表 2 的 0.68 是在特定假设下推导的——等概率符号、归一化星座图、升余弦脉冲、特定滚降系数。滚降系数一变谱峰比值就会偏移。论文中写「滚降系数 β≤1/2」但没给具体值0.68 是按某个固定 β 算出来的理论值。解决复现时不要纠结把 0.68 精确测出来把特征归一化后直接丢给神经网络学习就行。神经网络对轻微的常数偏移不敏感关键是每类信号的相对位置关系要保持。如果硬要对齐论文数值先固定滚降系数为 0.5符号数取 2048再做多次蒙特卡罗平均。4.3 独热编码顺序和输出层神经元的对应关系错位现象训练时 loss 能收敛但测试混淆矩阵里 BPSK 和 8PSK 的预测结果整体偏了一位。原因数据集的标签编码顺序和神经网络输出向量的定义顺序不一致。论文定义 BPSK(10000)、QPSK(01000) 依次排下去但很多数据增强或特征提取脚本里把类别按字母序排序8PSK 排到了 8QAM 后面错位就产生了。解决在训练脚本开头加一行注释性质的断言打印类别和索引的映射表确认 0~4 与 BPSK、QPSK、8PSK、8QAM、16QAM 严格对应。输出层是 softmax 时类别顺序错位不会报错只会让准确率下降这类 bug 非常隐蔽。4.4 l2 正则化系数调太大低信噪比下模型学不动现象论文提到施加 l2 正则化避免过拟合但给了一个较大的惩罚系数后SNR 低于 0 dB 时识别率比不加正则化还差。原因l2 惩罚项会限制权重幅度而低信噪比下特征本身噪声大模型需要更大的权重才能把微弱的有用特征放大出来。惩罚系数设太大相当于限制了模型的表达能力。解决从 λ0.001 起步按数量级递增试 0.0001、0.001、0.01 三档低信噪比场景选最小的那一档。这个参数在论文里没给具体值属于必须自己调的部分别指望抄一遍论文就能跳过。4.5 忘了对特征做归一化softmax 输出直接坍缩现象训练时 loss 下降很快但输出层的概率分布总是集中在某一类上测试时几乎全部判成同一类。原因循环累积量谱峰的绝对值动态范围很大不同信号幅度下的特征值可能差两个数量级。没归一化直接喂给 ReLU 隐藏层某个神经元会一直饱和梯度传不下去。解决训练前对特征做标准化。论文没明说但从表 2 的归一化谱峰值可以推断特征在送入网络前是做了幅度对齐的。我习惯用 StandardScaler 拟合训练集的均值和方差再用同一组参数变换测试集避免测试集信息泄漏到训练过程里。5. 从公式到仿真GNU Radio MATLAB/Python 的完整复现路径5.1 信号产生与数据集生成论文实验平台是 GNU Radio 和 MATLAB我在本地复现时用 Python 替代 MATLAB 做信号生成流程完全一致。核心是五类信号的基带产生、IQ 调制、升余弦成形和加噪声。升余弦成形用scipy.signal的rcosdesign等价函数完成滚降系数取 0.5。import numpy as np from scipy.signal import upfirdn, lfilter def generate_signal(mod_type, n_symbols, Rb900, fs7200, fc1800, beta0.5): T 1 / Rb sps int(fs / Rb) # 每个码元的采样点数这里是 8 n np.arange(n_symbols) if mod_type bpsk: symbols np.exp(1j * np.random.choice([0, np.pi], n_symbols)) elif mod_type qpsk: phases np.random.choice([np.pi/4, 3*np.pi/4, 5*np.pi/4, 7*np.pi/4], n_symbols) symbols np.exp(1j * phases) elif mod_type 8psk: phases np.random.choice(np.arange(8) * np.pi/4, n_symbols) symbols np.exp(1j * phases) # 8QAM 和 16QAM 按星座点生成此处省略详细实现 # 升余弦成形脉冲滚降系数 beta8 倍上采样 pulse rcosdesign(beta, 6, sps) # 6 个符号跨度的根升余弦 baseband upfirdn(symbols, pulse, sps) # 上变频到载波 fc t np.arange(len(baseband)) / fs rf np.real(baseband * np.exp(1j * 2 * np.pi * fc * t)) return rf def rcosdesign(beta, span, sps): # 根升余弦脉冲的简化实现 N span * sps 1 t np.arange(-span//2, span//2 1/sps, 1/sps)[:N] h np.sinc(t) * np.cos(np.pi * beta * t) / (1 - (2 * beta * t)**2 1e-8) return h / np.sqrt(np.sum(h**2))生成信号后加噪声要用每个符号的能量 Es 来算不能按采样点功率算这是新手最容易搞错的地方。对每个 SNR 值噪声功率按N0 Es / (10^(SNR/10))得到再用np.random.normal生成复高斯噪声叠加到信号上。5.2 循环累积量特征提取代码特征提取是整个方案的核心也是计算量最大的环节。对每个样本需要循环频率扫描。扫描范围覆盖 2fc±1/T 和 4fc±1/2T谱峰幅度用 FFT 峰值估计。完整实现里建议分两遍第一遍粗扫定位谱峰位置第二遍在谱峰附近做精细插值提高幅度估计精度。def scan_cyclic_spectrum(signal, fs, fc, Rb, scan_range(-4, 4)): # 扫描循环频率范围 [2fc scan_range[0]/T, 2fc scan_range[1]/T] # 返回循环频率轴与对应的循环累积量幅度 T 1 / Rb N len(signal) freqs np.fft.fftfreq(N, 1/fs) spectrum np.fft.fft(signal**2) # 对应 Cx,2,0 spectrum 2 * np.abs(spectrum) / N # 取 2fc 附近的频段 lo int((2*fc scan_range[0]/T) / (fs/N)) hi int((2*fc scan_range[1]/T) / (fs/N)) return freqs[lo:hi], spectrum[lo:hi]注意signal**2对应的是 Cx,2,0signal**4对应 Cx,4,0 的 FFT 估计。四阶的谱峰比二阶弱很多低信噪比下会被噪声淹没所以论文才强调要用循环累积量而不是循环矩——四阶累积量在循环频率处能抑制平稳噪声的贡献。工程上如果四阶谱峰不稳可以多帧平均把信号切成长度相等的段每段算一次 FFT 再平均谱峰估计的方差会显著下降。5.3 BP 网络训练与识别代码训练部分我直接用了 3.3 节的MLPClassifier更贴近论文原意的是自己写一个单隐藏层 BP 类方便调节论文式 (15)~(18) 里的权重更新细节。但实际工程中 sklearn 的实现足够稳交叉熵损失加 softmax 输出在MLPClassifier里是默认配置不需要重复造轮子。数据集划分方面论文按 4:1 随机划分训练集和测试集这个比例在 1000 条样本/类/SNR 的前提下是合理的。我复现时在每个 SNR 下单独训练一个分类器而不是把所有 SNR 的样本混在一起训练——论文图 2 和图 3 的数据就是按 SNR 逐点测的混在一起会拉高低 SNR 的识别率、压低高 SNR 的识别率混淆对比关系。def train_per_snr(features, labels, snr_list): models {} for snr in snr_list: X features[snr] y labels[snr] X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42) scaler StandardScaler().fit(X_train) clf MLPClassifier(hidden_layer_sizes(12,), activationrelu, solversgd, learning_rate_init0.01, max_iter5000, tol0.001) clf.fit(scaler.transform(X_train), y_train) models[snr] (scaler, clf) print(fSNR{snr} dB, acc{clf.score(scaler.transform(X_test), y_test):.4f}) return models单独训练的好处是能复现论文图 3 的「识别率随 SNR 变化曲线」也方便观察低信噪比下的台阶效应。坏处是模型数量多每个 SNR 都要训练一次总训练时间会拉长。如果只是为了验证方案可行性可以只选 -6、0、6、12 dB 四个点训练曲线趋势足以说明问题。6. 一个值得记住的技巧符号数比特征复杂度更管用6.1 符号个数和识别率的关系论文图 2 给了一组很直观的数据SNR2 dB 时符号数 256、512、1024、2048 对应的识别率分别是 73.25%、84.23%、92.02%、93.83%。趋势很明显——符号数翻一倍识别率提升幅度递减但只要是往 2048 这个方向走低信噪比下的增益始终是正的。SNR5 dB 时 1024 和 2048 的识别率都接近 100%。这说明一个工程判断在特征设计合理的前提下把观测时间做长比堆更复杂的分类器更划算。符号数从 256 涨到 1024增加了约 4 倍数据量和 FFT 点数但识别率提升了近 19 个百分点而更换分类器从决策树到神经网络提升幅度远没有这么大。所以做实际系统时先确定你能接受的观测时长上限再回头定特征维度和网络规模。6.2 神经网络的收益集中在低信噪比段论文图 3 对比了循环累积量特征下的神经网络、SVM 和决策树。结论是神经网络略优于 SVM明显优于决策树差距集中在低信噪比段。高信噪比下三类都接近满分区分度不大。这意味着如果你只关心 6 dB 以上的场景用 SVM 就够了训练速度快、部署简单只有做低信噪比场景才值得上神经网络。这个判断能帮你省很多调参时间。6.3 如果我要在这个基础上往下走论文的循环累积量方法有个天然扩展方向把识别集合扩大到更多调制类型比如 MSK、GMSK、APSK。因为这些信号同样具有循环平稳特性只是循环频率的位置和幅度值不同。我自己的做法是先把表 1 那种循环频率表画出来确认新信号和现有五类在循环频率域有区分度再考虑数据生成和网络重训。另外一个方向是把特征从固定谱峰换成循环谱密度切片牺牲一些计算量换取更强的鲁棒性。最后说一个我自己的教训第一次复现时我图省事直接在某个开源数据集上跑结果那数据集的符号率和论文完全不同特征提取的参数全部作废。从那以后我每次做调制识别复现都强制自己从信号生成这一步开始走一遍完整流程参数全部手写确认绝不拿现成数据糊弄。这份论文的方案本身不难复现难的是每一步都对得上号希望这篇笔记能帮你在复现时少走我走过的弯路。本文还有配套的精品资源点击获取
返回列表