北邮 AI无线通信 | 基于KNN的调制模式识别(4)样本信号调制模式识别仿真设计的参数探究

目录

一、什么是KNN

二、为什么要在OSI的物理层中引入KNN

三、基于KNN算法的调制识别技术建模

四、数据生成部分仿真设计

五、调制识别部分仿真设计

六、变参对比

6.1、调整k参

6.2、调整N参

6.2.1、MATLAB端

6.2.2、Python端

6.2.3、仿真结果分析

七、高阶累积量下的训练

7.1、MATLAB端

文件结构和功能

BPSKModulator.m

feat6_func_get_cumulants.m

feat6_getSample.m

feat6_getTest16QAM.m

feat6_getTestBPSK.m

feat6_getTestQPSK.m

feat9_func_get_cumulants.m

feat9_getSample.m

feat9_getTest16QAM.m

feat9_getTestBPSK.m

feat9_getTestQPSK.m

QPSKModulator.m

7.2、Python端

[cell-1 导入包及数据 --- 9特征 vs 6特征对比](#cell-1 导入包及数据 — 9特征 vs 6特征对比)

[cell-2 训练两个KNN分类器:9特征 (C20~C63) vs 6特征 (C20~C42)](#cell-2 训练两个KNN分类器:9特征 (C20~C63) vs 6特征 (C20~C42))

[cell-3 BPSK 对比测试](#cell-3 BPSK 对比测试)

[cell-4 QPSK对比测试](#cell-4 QPSK对比测试)

[cell-5 16QAM对比测试](#cell-5 16QAM对比测试)

7.3、仿真结果分析


一、什么是KNN

北邮 AI无线通信 | 基于KNN的调制模式识别(1)理论基础+仿真建模

二、为什么要在OSI的物理层中引入KNN

北邮 AI无线通信 | 基于KNN的调制模式识别(1)理论基础+仿真建模

三、基于KNN算法的调制识别技术建模

北邮 AI无线通信 | 基于KNN的调制模式识别(1)理论基础+仿真建模

四、数据生成部分仿真设计

北邮 AI无线通信 | 基于KNN的调制模式识别(2)依托于MatlabR2023b对调制信号训练数据生成部分的仿真设计(data_generation_module)

五、调制识别部分仿真设计

北邮 AI无线通信 | 基于KNN的调制模式识别(3)依托于Jupyter Notebook对样本信号调制模式识别的仿真设计(modulation_recognition_module)

六、变参对比

6.1、调整k参

同一时间训练了三个KNN分类器,分别k=10、k=20、k=30,并将同一种调制方式的识别结果绘制在同一张图中,代码如下:

python 复制代码
### 导入包及数据部分
import ssl
import numpy as np  #导入numpy,用于科学计算,如,矩阵运算
from sklearn.neighbors import KNeighborsClassifier   # 包装好的knn算法
from collections import defaultdict
import collections
import matplotlib.pyplot as plt


def file2matrix(filename):
    fr = open(filename)
    numberOfLines = len(fr.readlines())         #get the number of lines in the file
    returnMat = np.zeros((numberOfLines,5))        #prepare matrix to return  the number of features
    classLabelVector = []                       #prepare labels return
    fr = open(filename)
    index = 0
    for line in fr.readlines():
        line = line.strip()
        listFromLine = line.split('\t')
        returnMat[index,:] = listFromLine[0:5]     #chose features
        classLabelVector.append(float(listFromLine[-1]))
        #classLabelVector.append(float(0))
        index += 1
    return returnMat,classLabelVector
### 训练三个KNN分类器 (k=10, k=20, k=30)
# 加载训练数据
data_X, data_y = file2matrix('data/sample.dat')
data_y_name = ['BPSK', 'QPSK', '16QAM', '64QAM']  # 分类名称

X_train = data_X  # numpy ndarray格式
y_train = data_y  # numpy ndarray格式

print(f"训练集大小: {X_train.shape[0]} 样本, {X_train.shape[1]} 特征")
label_names = {2: 'BPSK', 4: 'QPSK', 16: '16QAM', 64: '64QAM'}
unique, counts = np.unique(y_train, return_counts=True)
for u, c in zip(unique, counts):
    print(f"  {label_names[u]}: {c} 样本")

# 训练三个不同 k 值的分类器
k_values = [10, 20, 30]
classifiers = {}  # {k: classifier}

for k in k_values:
    knn = KNeighborsClassifier(n_neighbors=k)
    knn.fit(X_train, y_train)
    classifiers[k] = knn
    print(f"KNN(k={k}) 训练完成")
### BPSKModulationClassTest
k_values = [10, 20, 30]
SNR = [2*x for x in range(-2,6)]

# 为每个 k 分别存储准确率
accuracy_by_k = {k: defaultdict(list) for k in k_values}

for k in k_values:
    knn = classifiers[k]
    print(f"\n{'='*50}")
    print(f"  k = {k}")
    print(f"{'='*50}")
    correctCount = defaultdict(list)
    QPSKnumber = defaultdict(list)
    QAM16number = defaultdict(list)
    QAM64number = defaultdict(list)
    for snr in SNR:
        testDataMat, testLabels = file2matrix('data/testBPSK-' + str(snr) + '.dat')
        numTestVecs = testDataMat.shape[0]
        correctCount[snr] = 0.0
        QPSKnumber[snr] = 0.0
        QAM16number[snr] = 0.0
        QAM64number[snr] = 0.0
        for i in range(numTestVecs):
            X_predict = testDataMat[i, :].reshape(1, -1)
            y_predict = knn.predict(X_predict)
            if (y_predict == 2): correctCount[snr] += 1.0
            if (y_predict == 4): QPSKnumber[snr] += 1.0
            if (y_predict == 16): QAM16number[snr] += 1.0
            if (y_predict == 64): QAM64number[snr] += 1.0
        accuracy_by_k[k][snr] = correctCount[snr] / numTestVecs
        print(f"SNR={snr:3d} dB: accuracy={accuracy_by_k[k][snr]:.4f}  "
              f"(→BPSK:{int(correctCount[snr])}  →QPSK:{int(QPSKnumber[snr])}  "
              f"→16QAM:{int(QAM16number[snr])}  →64QAM:{int(QAM64number[snr])})")

# 画图:三条线对比,k 值决定颜色(三张图统一)
plt.style.use('classic')
plt.figure(figsize=(10, 6), dpi=100)

colors = {10: 'royalblue', 20: '#CC0000', 30: '#228B22'}
markers = {10: 'o', 20: 's', 30: '^'}
for k in k_values:
    sorted_acc = collections.OrderedDict(sorted(accuracy_by_k[k].items()))
    x = list(sorted_acc.keys())
    y = list(sorted_acc.values())
    plt.plot(x, y, marker=markers[k], linewidth=2.0, linestyle='dashed',
             color=colors[k], label=f'k={k}', markersize=8)

plt.axis([0, 10, 0, 1])
plt.xticks(np.arange(min(x), max(x)+1, 2.0))
plt.yticks(np.arange(0, 1, 0.10))

ttl = plt.title('SNR vs Accuracy --- BPSK (k=10 vs k=20 vs k=30)', fontsize=16)
ttl.set_weight('bold')
plt.xlabel('SNR (dB)', fontsize=14)
plt.ylabel('Test accuracy', fontsize=14)
plt.legend(fontsize=12)
plt.grid()
plt.show()
### QPSKModulationClassTest
k_values = [10, 20, 30]
SNR = [2*x for x in range(-2,6)]

accuracy_by_k = {k: defaultdict(list) for k in k_values}

for k in k_values:
    knn = classifiers[k]
    print(f"\n{'='*50}")
    print(f"  k = {k}")
    print(f"{'='*50}")
    correctCount = defaultdict(list)
    BPSKnumber = defaultdict(list)
    QAM16number = defaultdict(list)
    QAM64number = defaultdict(list)
    for snr in SNR:
        testDataMat, testLabels = file2matrix('data/testQPSK-' + str(snr) + '.dat')
        numTestVecs = testDataMat.shape[0]
        correctCount[snr] = 0.0
        BPSKnumber[snr] = 0.0
        QAM16number[snr] = 0.0
        QAM64number[snr] = 0.0
        for i in range(numTestVecs):
            X_predict = testDataMat[i, :].reshape(1, -1)
            y_predict = knn.predict(X_predict)
            if (y_predict == 2): BPSKnumber[snr] += 1.0
            if (y_predict == 4): correctCount[snr] += 1.0
            if (y_predict == 16): QAM16number[snr] += 1.0
            if (y_predict == 64): QAM64number[snr] += 1.0
        accuracy_by_k[k][snr] = correctCount[snr] / numTestVecs
        print(f"SNR={snr:3d} dB: accuracy={accuracy_by_k[k][snr]:.4f}  "
              f"(→BPSK:{int(BPSKnumber[snr])}  →QPSK:{int(correctCount[snr])}  "
              f"→16QAM:{int(QAM16number[snr])}  →64QAM:{int(QAM64number[snr])})")

# 画图:颜色与 BPSK 图统一,k 决定颜色
plt.style.use('classic')
plt.figure(figsize=(10, 6), dpi=100)

colors = {10: 'royalblue', 20: '#CC0000', 30: '#228B22'}
markers = {10: 'o', 20: 's', 30: '^'}
for k in k_values:
    sorted_acc = collections.OrderedDict(sorted(accuracy_by_k[k].items()))
    x = list(sorted_acc.keys())
    y = list(sorted_acc.values())
    plt.plot(x, y, marker=markers[k], linewidth=2.0, linestyle='dashed',
             color=colors[k], label=f'k={k}', markersize=8)

plt.axis([0, 10, 0, 1])
plt.xticks(np.arange(min(x), max(x)+1, 2.0))
plt.yticks(np.arange(0, 1, 0.10))

ttl = plt.title('SNR vs Accuracy --- QPSK (k=10 vs k=20 vs k=30)', fontsize=16)
ttl.set_weight('bold')
plt.xlabel('SNR (dB)', fontsize=14)
plt.ylabel('Test accuracy', fontsize=14)
plt.legend(fontsize=12)
plt.grid()
plt.show()
### 16QAM ModulationClassTest
k_values = [10, 20, 30]
SNR = [5*x for x in range(0, 9)]

accuracy_by_k = {k: defaultdict(list) for k in k_values}

for k in k_values:
    knn = classifiers[k]
    print(f"\n{'='*50}")
    print(f"  k = {k}")
    print(f"{'='*50}")
    correctCount = defaultdict(list)
    BPSKnumber = defaultdict(list)
    QPSKnumber = defaultdict(list)
    QAM64number = defaultdict(list)
    for snr in SNR:
        testDataMat, testLabels = file2matrix('data/test16QAM-' + str(snr) + '.dat')
        numTestVecs = testDataMat.shape[0]
        correctCount[snr] = 0.0
        BPSKnumber[snr] = 0.0
        QPSKnumber[snr] = 0.0
        QAM64number[snr] = 0.0
        for i in range(numTestVecs):
            X_predict = testDataMat[i, :].reshape(1, -1)
            y_predict = knn.predict(X_predict)
            if (y_predict == 2): BPSKnumber[snr] += 1.0
            if (y_predict == 4): QPSKnumber[snr] += 1.0
            if (y_predict == 16): correctCount[snr] += 1.0
            if (y_predict == 64): QAM64number[snr] += 1.0
        accuracy_by_k[k][snr] = correctCount[snr] / numTestVecs
        print(f"SNR={snr:3d} dB: accuracy={accuracy_by_k[k][snr]:.4f}  "
              f"(→BPSK:{int(BPSKnumber[snr])}  →QPSK:{int(QPSKnumber[snr])}  "
              f"→16QAM:{int(correctCount[snr])}  →64QAM:{int(QAM64number[snr])})")

# 画图:颜色与 BPSK/QPSK 图统一,k 决定颜色
plt.style.use('classic')
plt.figure(figsize=(10, 6), dpi=100)

colors = {10: 'royalblue', 20: '#CC0000', 30: '#228B22'}
markers = {10: 'o', 20: 's', 30: '^'}
for k in k_values:
    sorted_acc = collections.OrderedDict(sorted(accuracy_by_k[k].items()))
    x = list(sorted_acc.keys())
    y = list(sorted_acc.values())
    plt.plot(x, y, marker=markers[k], linewidth=2.0, linestyle='dashed',
             color=colors[k], label=f'k={k}', markersize=8)

plt.axis([0, 40, 0, 1])
plt.xticks(np.arange(min(x), max(x)+1, 5.0))
plt.yticks(np.arange(0, 1, 0.10))

ttl = plt.title('SNR vs Accuracy --- 16QAM (k=10 vs k=20 vs k=30)', fontsize=16)
ttl.set_weight('bold')
plt.xlabel('SNR (dB)', fontsize=14)
plt.ylabel('Test accuracy', fontsize=14)
plt.legend(fontsize=12)
plt.grid()
plt.show()

对BPSK、QPSK、16QAM,运行仿真后仿真结果如图6-1、图6-2、图6-3所示。
图6-1 BPSK的k参对比

Q:观察sample.dat前10行可以发现,BPSK每组高阶累积量特征都相同,这是为什么?

A:

对于理想 BPSK 信号,C21 是信号平均功率。BPSK 经过comm.BPSKModulator调制后,每个符号都是 ±1,功率恒等于 1,所以 C21 始终为 1,C21_norm 始终为 1。同理,C20C40C41C42 的计算公式只依赖于信号的统计矩,而 BPSK 的 ±1 符号经过这些公式运算后,结果永远收敛到同一组理论值 [1, 1, 2, 2, 2]。500 个符号长度足够大,统计波动可以忽略不计。

所以, 根本原因是 BPSK 信号调制后符号恒为 ±1,功率恒定,高阶累积量在无噪声条件下必定收敛到固定的理论值。无论你输入多少组不同的随机比特,只要没有加噪声,算出来的特征就始终是 [1,1,2,2,2]

图6-2 QPSK的k参对比

Q:观察发现,对QPSK k=30的KNN分类器调制识别结果来说,准确率都为100%,原因是?

**A:QPSK 在 k=30 时准确率恒为 1.0,根本原因在于投票机制。训练集共 40 个样本,四类调制方式各占 10 个。当 k 取 30 时,分类器对每个 QPSK 测试样本都要拉入 30 个最近邻进行投票,其中 QPSK 的 10 个训练样本因特征相似度最高必然全部入选,贡献 10 票。剩余 20 席由 BPSK、16QAM 和 64QAM 的训练样本瓜分,任何一方的票数上限就是 20,最多和 QPSK 打平。**由于 QPSK 的 10 票始终是最大单一票仓,而其他票分散在三个不同类别中无法形成合力,QPSK 在每一轮投票中都稳居多数,预测结果永远不出错,准确率自然恒为 1.0。
Q:那是不是说明k=30的分类器更好?

**A:**不是。恰恰相反,这说明 k=30 的分类器质量很差。

k=30 让 QPSK 准确率全 1.0,不是因为分类器学会了辨别 QPSK,而是因为投票机制保护了它。无论输入什么样的测试样本,只要它的特征离 QPSK 稍微近一点,30 个邻居里 QPSK 的 10 票就足够压制其他三类分散的票数。这掩盖了一个关键问题:分类器对 BPSK、16QAM 和 64QAM 的区分能力究竟如何,从这个数字里完全看不出来。

一个好的 k 值应该让分类器在各类测试集上都能表现出真实的判别能力,而不是靠扩大投票池来制造假象。k=10 时,邻居范围更小,投票结果更依赖测试样本周围的局部特征分布,各类之间的区分能力才能真正被检验。

图6-3 16QAM的k参对比

Q:观察发现,对16QAM k=20的KNN分类器调制识别结果来说,准确率都为100%,原因是?

**A:训练集总共 40 个样本,4 类各 10 个。k=20 时,对每个 16QAM 测试样本找 20 个最近邻,其中 16QAM 的 10 个训练样本必然全部入选,贡献 10 票。剩余 10 席由 BPSK、QPSK 和 64QAM 瓜分,任何一方的票数上限就是 10,最多和 16QAM 打平。**16QAM 的 10 票是最大单一票仓,其他票分散在三个类里,永远凑不出超过 10 票的对手,所以 16QAM 每次都赢,准确率恒为 1.0。
Q:观察发现,对16QAM k=30的KNN分类器调制识别结果来说,准确率都为0%,原因是?

A:因为 k=30 时投票池扩大,20 个非 16QAM 的邻居中,有一类能集中超过 10 票,把 16QAM 压下去了。

最可能的情况是 BPSK 抢走了足够多的票。BPSK 的 10 个训练样本特征完全一致,全挤在同一个点上。在 5 维特征空间中,低 SNR 下的 16QAM 测试样本的特征可能刚好靠近 BPSK 那个点,10 个 BPSK 副本一起入选 30 个最近邻,再加上 QPSK 和 64QAM 的零星票数,BPSK 的 10 票就成了多数。

而 16QAM 自己的 10 个训练样本虽然在 30 个邻居里全部到齐,但它们的特征散布较开(不像 BPSK 那样 10 个样本重合在一个点上),在距离排序中可能排不过 BPSK 那 10 个位置完全相同的副本。一旦 BPSK 的 10 票加其他类的几票超过了 16QAM 的 10 票,16QAM 就输了。

6.2、调整N参

为了保证单一变量原则,调整训练集中每组符号的长度length时,应保持k=10不变。

本仿真取四组平行实验,分别令length=200、length=500、length=800、length=1000,在MATLAB端分别训练各自的特征向量集,并在python端,对同一类型的调制信号类型识别,在同一图像中用不同颜色绘制不同训练集训练出的特征向量对准确率的贡献曲线。

6.2.1、MATLAB端

基于get_Sample.m修改,新建了getSample_compare_N.m文件,能够一次性训练四种length下的特征向量集,并将结果自动保存在data_200、data_500、data_800、data_1000四个已经存在的子文件夹中。

Matlab 复制代码
%% Clean up
clear all;
clc;

lengths = [200, 500, 800, 1000];
rows = 10;
NFeatures = 5;

for idx = 1:length(lengths)
    L = lengths(idx);
    folderName = ['data_', num2str(L)];

    %% ===== 生成训练数据 sample.dat =====
    sample_data = zeros(4 * rows, NFeatures + 1);

    % --- BPSK ---
    data = randi([0 1], rows, L);
    [data1] = data';
    data_cell = mat2cell(data1, L, ones(1, rows));
    signalData = cellfun(@(x) BPSKModulator(x), data_cell, 'UniformOutput', false);
    signalData1 = cell2mat(signalData);
    signalData2 = mat2cell(signalData1', ones(1, rows), L);

    cumulants = cellfun(@(x) func_get_cumulants(x), signalData2, 'UniformOutput', false);
    cumulantsMat = cell2mat(cumulants);

    for row = 1:rows
        for i = 1:NFeatures
            sample_data(row, i) = cumulantsMat(row, i);
        end
        sample_data(row, NFeatures + 1) = 2;
    end

    % --- QPSK ---
    data = randi([0 1], rows, 2 * L);
    [data1] = data';
    data_cell = mat2cell(data1, 2 * L, ones(1, rows));
    signalData = cellfun(@(x) QPSKModulator(x), data_cell, 'UniformOutput', false);
    signalData1 = cell2mat(signalData);
    signalData2 = mat2cell(signalData1', ones(1, rows), L);

    cumulants = cellfun(@(x) func_get_cumulants(x), signalData2, 'UniformOutput', false);
    cumulantsMat = cell2mat(cumulants);

    for row = 1:rows
        row_r = rows + row;
        for i = 1:NFeatures
            sample_data(row_r, i) = cumulantsMat(row, i);
        end
        sample_data(row_r, NFeatures + 1) = 4;
    end

    % --- 16QAM ---
    data = randi([0 1], rows, 4 * L);
    [data1] = data';
    data_cell = mat2cell(data1, 4 * L, ones(1, rows));
    signalData = cellfun(@(x) qammod(x, 16, 'InputType', 'bit', 'UnitAveragePower', true), data_cell, 'UniformOutput', false);
    signalData1 = cell2mat(signalData);
    signalData2 = mat2cell(signalData1', ones(1, rows), L);

    cumulants = cellfun(@(x) func_get_cumulants(x), signalData2, 'UniformOutput', false);
    cumulantsMat = cell2mat(cumulants);

    for row = 1:rows
        row_r = 2 * rows + row;
        for i = 1:NFeatures
            sample_data(row_r, i) = cumulantsMat(row, i);
        end
        sample_data(row_r, NFeatures + 1) = 16;
    end

    % --- 64QAM ---
    data = randi([0 1], rows, 6 * L);
    [data1] = data';
    data_cell = mat2cell(data1, 6 * L, ones(1, rows));
    signalData = cellfun(@(x) qammod(x, 64, 'InputType', 'bit', 'UnitAveragePower', true), data_cell, 'UniformOutput', false);
    signalData1 = cell2mat(signalData);
    signalData2 = mat2cell(signalData1', ones(1, rows), L);

    cumulants = cellfun(@(x) func_get_cumulants(x), signalData2, 'UniformOutput', false);
    cumulantsMat = cell2mat(cumulants);

    for row = 1:rows
        row_r = 3 * rows + row;
        for i = 1:NFeatures
            sample_data(row_r, i) = cumulantsMat(row, i);
        end
        sample_data(row_r, NFeatures + 1) = 64;
    end

    trainFilename = [folderName, '\sample.dat'];
    dlmwrite(trainFilename, sample_data, 'delimiter', '\t', 'newline', 'pc');
    disp(['[L=', num2str(L), '] sample.dat saved to ', trainFilename]);

    %% ===== 生成 BPSK 测试数据 =====
    test_rows = 1000;
    SNR_BPSK = [-4:2:10];
    for s = 1:length(SNR_BPSK)
        snr = SNR_BPSK(s);
        test_data = zeros(test_rows, NFeatures);

        data = randi([0 1], test_rows, L);
        [data1] = data';
        data_cell = mat2cell(data1, L, ones(1, test_rows));
        signalData = cellfun(@(x) BPSKModulator(x), data_cell, 'UniformOutput', false);
        signalDataMat = cell2mat(signalData);
        dataMod = mat2cell(signalDataMat', ones(1, test_rows), L);

        dataRx = cellfun(@(x) awgn(x, snr), dataMod, 'UniformOutput', false);

        cumulants = cellfun(@(x) func_get_cumulants(x), dataRx, 'UniformOutput', false);
        cumulantsMat = cell2mat(cumulants);

        for row = 1:test_rows
            for i = 1:NFeatures
                test_data(row, i) = cumulantsMat(row, i);
            end
        end

        testFilename = [folderName, '\testBPSK-', num2str(snr), '.dat'];
        dlmwrite(testFilename, test_data, 'delimiter', '\t', 'newline', 'pc');
    end
    disp(['[L=', num2str(L), '] BPSK test data saved']);

    %% ===== 生成 QPSK 测试数据 =====
    SNR_QPSK = [-4:2:10];
    for s = 1:length(SNR_QPSK)
        snr = SNR_QPSK(s);
        test_data = zeros(test_rows, NFeatures);

        data = randi([0 1], test_rows, 2 * L);
        [data1] = data';
        data_cell = mat2cell(data1, 2 * L, ones(1, test_rows));
        signalData = cellfun(@(x) QPSKModulator(x), data_cell, 'UniformOutput', false);
        signalDataMat = cell2mat(signalData);
        dataMod = mat2cell(signalDataMat', ones(1, test_rows), L);

        dataRx = cellfun(@(x) awgn(x, snr), dataMod, 'UniformOutput', false);

        cumulants = cellfun(@(x) func_get_cumulants(x), dataRx, 'UniformOutput', false);
        cumulantsMat = cell2mat(cumulants);

        for row = 1:test_rows
            for i = 1:NFeatures
                test_data(row, i) = cumulantsMat(row, i);
            end
        end

        testFilename = [folderName, '\testQPSK-', num2str(snr), '.dat'];
        dlmwrite(testFilename, test_data, 'delimiter', '\t', 'newline', 'pc');
    end
    disp(['[L=', num2str(L), '] QPSK test data saved']);

    %% ===== 生成 16QAM 测试数据 =====
    SNR_16QAM = [0:5:40];
    for s = 1:length(SNR_16QAM)
        snr = SNR_16QAM(s);
        test_data = zeros(test_rows, NFeatures);

        data = randi([0 1], test_rows, 4 * L);
        [data1] = data';
        data_cell = mat2cell(data1, 4 * L, ones(1, test_rows));
        signalData = cellfun(@(x) qammod(x, 16, 'InputType', 'bit', 'UnitAveragePower', true), data_cell, 'UniformOutput', false);
        signalDataMat = cell2mat(signalData);
        dataMod = mat2cell(signalDataMat', ones(1, test_rows), L);

        dataRx = cellfun(@(x) awgn(x, snr), dataMod, 'UniformOutput', false);

        cumulants = cellfun(@(x) func_get_cumulants(x), dataRx, 'UniformOutput', false);
        cumulantsMat = cell2mat(cumulants);

        for row = 1:test_rows
            for i = 1:NFeatures
                test_data(row, i) = cumulantsMat(row, i);
            end
        end

        testFilename = [folderName, '\test16QAM-', num2str(snr), '.dat'];
        dlmwrite(testFilename, test_data, 'delimiter', '\t', 'newline', 'pc');
    end
    disp(['[L=', num2str(L), '] 16QAM test data saved']);

    disp(['===== L=', num2str(L), ' done =====']);
end

disp('All done.');

6.2.2、Python端

将生成的data_200、data_500、data_800、data_1000四个文件夹,复制到调制识别模块文件夹目录下,新建compare_N.ipynb文件,基于main.ipynb文件改写,用于对比不同训练空间训练出的特征向量对识别准确率的影响。

cell-1 导入包及数据部分

python 复制代码
import ssl
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
from collections import defaultdict
import collections
import matplotlib.pyplot as plt


def file2matrix(filename):
    fr = open(filename)
    numberOfLines = len(fr.readlines())
    returnMat = np.zeros((numberOfLines, 5))
    classLabelVector = []
    fr = open(filename)
    index = 0
    for line in fr.readlines():
        line = line.strip()
        listFromLine = line.split('\t')
        returnMat[index, :] = listFromLine[0:5]
        classLabelVector.append(float(listFromLine[-1]))
        index += 1
    return returnMat, classLabelVector

cell-2 训练四个KNN分类器(k=10,四组不同length)

python 复制代码
# 四组不同的 length: L=200, L=500, L=800, L=1000
lengths = [200, 500, 800, 1000]
data_dir = 'data_{}/'  # 相对于 modulation_recognition 文件夹的路径

classifiers = {}  # {L: classifier}

label_names = {2: 'BPSK', 4: 'QPSK', 16: '16QAM', 64: '64QAM'}

for L in lengths:
    sample_path = data_dir.format(L) + 'sample.dat'
    data_X, data_y = file2matrix(sample_path)
    
    print(f"\n===== L={L} =====")
    print(f"训练集: {data_X.shape[0]} 样本, {data_X.shape[1]} 特征")
    unique, counts = np.unique(data_y, return_counts=True)
    for u, c in zip(unique, counts):
        print(f"  {label_names[u]}: {c} 样本")
    
    knn = KNeighborsClassifier(n_neighbors=10)
    knn.fit(data_X, data_y)
    classifiers[L] = knn
    print(f"KNN(k=10, L={L}) 训练完成")

cell-3 BPSK调制模式识别测试

python 复制代码
SNR = [2 * x for x in range(-2, 6)]

# 存储: accuracy_by_L[L][snr] = accuracy
accuracy_by_L = {L: defaultdict(float) for L in lengths}

for L in lengths:
    knn = classifiers[L]
    test_dir = data_dir.format(L)
    print(f"\n{'='*50}")
    print(f"  L = {L}")
    print(f"{'='*50}")
    for snr in SNR:
        testDataMat, _ = file2matrix(test_dir + 'testBPSK-' + str(snr) + '.dat')
        numTestVecs = testDataMat.shape[0]
        correctCount = 0.0
        QPSKcount = 0.0
        QAM16count = 0.0
        QAM64count = 0.0
        for i in range(numTestVecs):
            X_predict = testDataMat[i, :].reshape(1, -1)
            y_predict = knn.predict(X_predict)
            if y_predict == 2:
                correctCount += 1.0
            elif y_predict == 4:
                QPSKcount += 1.0
            elif y_predict == 16:
                QAM16count += 1.0
            elif y_predict == 64:
                QAM64count += 1.0
        accuracy_by_L[L][snr] = correctCount / numTestVecs
        print(f"SNR={snr:3d} dB: accuracy={accuracy_by_L[L][snr]:.4f}  "
              f"(->BPSK:{int(correctCount)}  ->QPSK:{int(QPSKcount)}  "
              f"->16QAM:{int(QAM16count)}  ->64QAM:{int(QAM64count)})")

# 画图: L=200红, L=500蓝, L=800橙, L=1000绿 (跨三张图统一)
plt.style.use('classic')
plt.figure(figsize=(10, 6), dpi=100)

colors = {200: '#CC0000', 500: 'royalblue', 800: '#FF8C00', 1000: '#228B22'}
markers = {200: 'o', 500: 's', 800: 'D', 1000: '^'}

for L in lengths:
    sorted_acc = collections.OrderedDict(sorted(accuracy_by_L[L].items()))
    x = list(sorted_acc.keys())
    y = list(sorted_acc.values())
    plt.plot(x, y, marker=markers[L], linewidth=2.0, linestyle='dashed',
             color=colors[L], label=f'L={L}', markersize=8)

plt.axis([0, 10, 0, 1])
plt.xticks(np.arange(min(x), max(x) + 1, 2.0))
plt.yticks(np.arange(0, 1, 0.10))

ttl = plt.title('SNR vs Accuracy - BPSK (L=200 vs L=500 vs L=800 vs L=1000, k=10)', fontsize=16)
ttl.set_weight('bold')
plt.xlabel('SNR (dB)', fontsize=14)
plt.ylabel('Test accuracy', fontsize=14)
plt.legend(fontsize=12)
plt.grid()
plt.show()

cell-4 QPSK调制模式识别测试

python 复制代码
SNR = [2 * x for x in range(-2, 6)]

accuracy_by_L = {L: defaultdict(float) for L in lengths}

for L in lengths:
    knn = classifiers[L]
    test_dir = data_dir.format(L)
    print(f"\n{'='*50}")
    print(f"  L = {L}")
    print(f"{'='*50}")
    for snr in SNR:
        testDataMat, _ = file2matrix(test_dir + 'testQPSK-' + str(snr) + '.dat')
        numTestVecs = testDataMat.shape[0]
        correctCount = 0.0
        BPSKcount = 0.0
        QAM16count = 0.0
        QAM64count = 0.0
        for i in range(numTestVecs):
            X_predict = testDataMat[i, :].reshape(1, -1)
            y_predict = knn.predict(X_predict)
            if y_predict == 2:
                BPSKcount += 1.0
            elif y_predict == 4:
                correctCount += 1.0
            elif y_predict == 16:
                QAM16count += 1.0
            elif y_predict == 64:
                QAM64count += 1.0
        accuracy_by_L[L][snr] = correctCount / numTestVecs
        print(f"SNR={snr:3d} dB: accuracy={accuracy_by_L[L][snr]:.4f}  "
              f"(->BPSK:{int(BPSKcount)}  ->QPSK:{int(correctCount)}  "
              f"->16QAM:{int(QAM16count)}  ->64QAM:{int(QAM64count)})")

# 画图: L=200红, L=500蓝, L=800橙, L=1000绿 (跨三张图统一)
plt.style.use('classic')
plt.figure(figsize=(10, 6), dpi=100)

colors = {200: '#CC0000', 500: 'royalblue', 800: '#FF8C00', 1000: '#228B22'}
markers = {200: 'o', 500: 's', 800: 'D', 1000: '^'}

for L in lengths:
    sorted_acc = collections.OrderedDict(sorted(accuracy_by_L[L].items()))
    x = list(sorted_acc.keys())
    y = list(sorted_acc.values())
    plt.plot(x, y, marker=markers[L], linewidth=2.0, linestyle='dashed',
             color=colors[L], label=f'L={L}', markersize=8)

plt.axis([0, 10, 0, 1])
plt.xticks(np.arange(min(x), max(x) + 1, 2.0))
plt.yticks(np.arange(0, 1, 0.10))

ttl = plt.title('SNR vs Accuracy - QPSK (L=200 vs L=500 vs L=800 vs L=1000, k=10)', fontsize=16)
ttl.set_weight('bold')
plt.xlabel('SNR (dB)', fontsize=14)
plt.ylabel('Test accuracy', fontsize=14)
plt.legend(fontsize=12)
plt.grid()
plt.show()

cell-5 16QAM调制模式识别测试

python 复制代码
SNR = [5 * x for x in range(0, 9)]

accuracy_by_L = {L: defaultdict(float) for L in lengths}

for L in lengths:
    knn = classifiers[L]
    test_dir = data_dir.format(L)
    print(f"\n{'='*50}")
    print(f"  L = {L}")
    print(f"{'='*50}")
    for snr in SNR:
        testDataMat, _ = file2matrix(test_dir + 'test16QAM-' + str(snr) + '.dat')
        numTestVecs = testDataMat.shape[0]
        correctCount = 0.0
        BPSKcount = 0.0
        QPSKcount = 0.0
        QAM64count = 0.0
        for i in range(numTestVecs):
            X_predict = testDataMat[i, :].reshape(1, -1)
            y_predict = knn.predict(X_predict)
            if y_predict == 2:
                BPSKcount += 1.0
            elif y_predict == 4:
                QPSKcount += 1.0
            elif y_predict == 16:
                correctCount += 1.0
            elif y_predict == 64:
                QAM64count += 1.0
        accuracy_by_L[L][snr] = correctCount / numTestVecs
        print(f"SNR={snr:3d} dB: accuracy={accuracy_by_L[L][snr]:.4f}  "
              f"(->BPSK:{int(BPSKcount)}  ->QPSK:{int(QPSKcount)}  "
              f"->16QAM:{int(correctCount)}  ->64QAM:{int(QAM64count)})")

# 画图: L=200红, L=500蓝, L=800橙, L=1000绿 (跨三张图统一)
plt.style.use('classic')
plt.figure(figsize=(10, 6), dpi=100)

colors = {200: '#CC0000', 500: 'royalblue', 800: '#FF8C00', 1000: '#228B22'}
markers = {200: 'o', 500: 's', 800: 'D', 1000: '^'}

for L in lengths:
    sorted_acc = collections.OrderedDict(sorted(accuracy_by_L[L].items()))
    x = list(sorted_acc.keys())
    y = list(sorted_acc.values())
    plt.plot(x, y, marker=markers[L], linewidth=2.0, linestyle='dashed',
             color=colors[L], label=f'L={L}', markersize=8)

plt.axis([0, 40, 0, 1])
plt.xticks(np.arange(min(x), max(x) + 1, 5.0))
plt.yticks(np.arange(0, 1, 0.10))

ttl = plt.title('SNR vs Accuracy - 16QAM (L=200 vs L=500 vs L=800 vs L=1000, k=10)', fontsize=16)
ttl.set_weight('bold')
plt.xlabel('SNR (dB)', fontsize=14)
plt.ylabel('Test accuracy', fontsize=14)
plt.legend(fontsize=12)
plt.grid()
plt.show()

6.2.3、仿真结果分析

按流程操作6.2.1节和6.2.2节,执行6.2.2节后,仿真结果图图6-4、图6-5、图6-6所示。
图6-4 不同length下的BPSK准确率
图6-5 不同length下的QPSK准确率
图6-6 不同length下的16QAM准确率

可以发现,训练集空间越大,特征向量描述越精准,对识别准确率贡献越大。

七、高阶累积量下的训练

7.1、MATLAB端

MATLAB端:每种调制方式生成10个样本不变,但每组样本信号长度为500不变;四种调制方式各10个样本,共计40个训练样本。

文件结构和功能

文件结构和功能如下:

文件 作用
BPSKModulator.m BPSK 调制器,输入比特流,输出复基带符号(公共模块,两个方案共用)
QPSKModulator.m QPSK 调制器,BitInput=true,输入 2N 比特输出 N 个符号(公共模块)
feat6_func_get_cumulants.m 6特征版累积量计算函数,计算 C20/C21/C40/C41/C42 共 5 维特征,归一化后取绝对值
feat6_getSample.m 6特征版数据生成主脚本,生成训练数据(40样本)+ 一键自动生成全部测试数据(BPSK 8 SNR + QPSK 8 SNR + 16QAM 9 SNR = 25个文件)
feat6_getTestBPSK.m 6特征版 BPSK 测试数据独立生成脚本(可单独运行)
feat6_getTestQPSK.m 6特征版 QPSK 测试数据独立生成脚本(可单独运行)
feat6_getTest16QAM.m 6特征版 16QAM 测试数据独立生成脚本(可单独运行)
feat9_func_get_cumulants.m 9特征版累积量计算函数,在 5 维基础上增加 C60/C61/C62/C63 共 9 维特征
feat9_getSample.m 9特征版数据生成主脚本,一键生成训练+全部测试数据
feat9_getTestBPSK.m 9特征版 BPSK 测试数据独立生成脚本
feat9_getTestQPSK.m 9特征版 QPSK 测试数据独立生成脚本
feat9_getTest16QAM.m 9特征版 16QAM 测试数据独立生成脚本

BPSKModulator.m

Matlab 复制代码
function [out] = BPSKModulator(in)
persistent Modulator   
if isempty(Modulator)
    Modulator=comm.BPSKModulator;
    %Modulator=comm.PSKModulator(2,'BitInput',true);
end
out = Modulator(in);
end

feat6_func_get_cumulants.m

Matlab 复制代码
function [cumulants] = feat6_func_get_cumulants(signalData)

shape = size(signalData);
H = shape(1);
L = shape(2);
cumulants = zeros(H, L);

for row = 1:H
    M20 = sum(signalData(row,:).^2)/L;
    M21 = sum(abs(signalData(row,:)).^2)/L;
    M40 = sum(signalData(row,:).^4)/L;
    M41 = sum(abs(signalData(row,:)).^2.*signalData(row,:).^2)/L;
    M42 = sum(abs(signalData(row,:)).^4)/L;

    C20 = M20;
    C21 = M21;
    C40 = M40 - 3*M20^2;
    C41 = M41 - 3*M20*M21;
    C42 = M42 - abs(M20)^2 - 2*M21^2;

    C21_modify = C21;
    C20_norm = C20/(C21_modify^2);
    C21_norm = C21/(C21_modify^2);
    C40_norm = C40/(C21_modify^2);
    C41_norm = C41/(C21_modify^2);
    C42_norm = C42/(C21_modify^2);

    cumulants(row, 1) = abs(C20_norm);
    cumulants(row, 2) = abs(C21_norm);
    cumulants(row, 3) = abs(C40_norm);
    cumulants(row, 4) = abs(C41_norm);
    cumulants(row, 5) = abs(C42_norm);

end

feat6_getSample.m

Matlab 复制代码
%% Clean up
clear all;
clc;

rows = 10;
sigLen = 500;
NFeatures = 5;
sample_data = zeros(rows, NFeatures + 1);

%% Simulation parameters

%% Simulate
    %BPSK
    % Generate random data
    data = randi([0 1], rows, sigLen);

    % QAM mapping
    [data1] = data';
    data_cell = mat2cell(data1,sigLen,ones(1,rows));
    signalData = cellfun(@(x) BPSKModulator(x), data_cell, 'UniformOutput',false);
    %signalData = cellfun(@(x) qammod(x, 2, 'InputType', 'bit', 'UnitAveragePower', true), data_cell, 'UniformOutput',false);
    signalData1 = cell2mat(signalData);
    signalData2 = mat2cell(signalData1',ones(1,rows),sigLen);

    % get cumulants
    cumulants = cellfun(@(x) feat6_func_get_cumulants(x), signalData2, 'UniformOutput',false);
    cumulantsMat = cell2mat(cumulants);

    for row = 1: rows
        for i = 1:NFeatures
                sample_data(row, i) = cumulantsMat(row, i);
        end
        sample_data(row, NFeatures + 1) = 2;
    end

    %QPSK
    % Generate random data
    data = randi([0 1], rows, 2*sigLen);

    % QAM mapping
    [data1] = data';
    data_cell = mat2cell(data1,2*sigLen,ones(1,rows));
    signalData = cellfun(@(x) QPSKModulator(x), data_cell, 'UniformOutput',false);
    %signalData = cellfun(@(x) qammod(x, 4, 'InputType', 'bit', 'UnitAveragePower', true), data_cell, 'UniformOutput',false);
    signalData1 = cell2mat(signalData);
    signalData2 = mat2cell(signalData1',ones(1,rows),sigLen);

    % get cumulants
    cumulants = cellfun(@(x) feat6_func_get_cumulants(x), signalData2, 'UniformOutput',false);
    cumulantsMat = cell2mat(cumulants);

    for row = 1: rows
        row_r = rows + row;
        for i = 1:NFeatures
                sample_data(row_r, i) = cumulantsMat(row, i);
        end
        sample_data(row_r, NFeatures + 1) = 4;
    end

 %16QAM
    % Generate random data
    data = randi([0 1], rows, 4*sigLen);

    % QAM mapping
    [data1] = data';
    data_cell = mat2cell(data1,4*sigLen,ones(1,rows));
    signalData = cellfun(@(x) qammod(x, 16, 'InputType', 'bit', 'UnitAveragePower', true), data_cell, 'UniformOutput',false);
    signalData1 = cell2mat(signalData);
    signalData2 = mat2cell(signalData1',ones(1,rows),sigLen);

    % get cumulants
    cumulants = cellfun(@(x) feat6_func_get_cumulants(x), signalData2, 'UniformOutput',false);
    cumulantsMat = cell2mat(cumulants);

    for row = 1: rows
        row_r = 2*rows + row;
        for i = 1:NFeatures
                sample_data(row_r, i) = cumulantsMat(row, i);
        end
        sample_data(row_r, NFeatures + 1) = 16;
    end

 %64QAM
    % Generate random data
    data = randi([0 1], rows, 6*sigLen);
    % QAM mapping
    [data1] = data';
    data_cell = mat2cell(data1,6*sigLen,ones(1,rows));
    signalData = cellfun(@(x) qammod(x, 64, 'InputType', 'bit', 'UnitAveragePower', true), data_cell, 'UniformOutput',false);
    signalData1 = cell2mat(signalData);
    signalData2 = mat2cell(signalData1',ones(1,rows),sigLen);

    % get cumulants
    cumulants = cellfun(@(x) feat6_func_get_cumulants(x), signalData2, 'UniformOutput',false);
    cumulantsMat = cell2mat(cumulants);

    for row = 1: rows
        row_r = 3*rows + row;
        for i = 1:NFeatures
                sample_data(row_r, i) = cumulantsMat(row, i);
        end
        sample_data(row_r, NFeatures + 1) = 64;
    end

filename = ['digits', filesep, 'feat6_sample.dat'];
dlmwrite(filename, sample_data, 'delimiter', '\t', 'newline', 'pc');

disp('Training data saved.');

%% ============================================================
%% Auto-generate test data
%% ============================================================
disp('Now generating test data...');

%% BPSK Test Data
disp('--- BPSK test data ---');
test_rows = 1000;
test_cols = sigLen;
test_NFeatures = NFeatures;
SNR_list = [-4, -2, 0, 2, 4, 6, 8, 10];
for idx = 1:length(SNR_list)
    snr = SNR_list(idx);
    test_data = zeros(test_rows, test_NFeatures);
    data = randi([0 1], test_rows, test_cols);
    data1 = data';
    data_cell = mat2cell(data1, test_cols, ones(1, test_rows));
    signalData = cellfun(@(x) BPSKModulator(x), data_cell, 'UniformOutput', false);
    signalDataMat = cell2mat(signalData);
    dataMod = mat2cell(signalDataMat', ones(1, test_rows), test_cols);
    dataRx = cellfun(@(x) awgn(x, snr), dataMod, 'UniformOutput', false);
    cumulants = cellfun(@(x) feat6_func_get_cumulants(x), dataRx, 'UniformOutput', false);
    cumulantsMat = cell2mat(cumulants);
    for row = 1:test_rows
        for j = 1:test_NFeatures
            test_data(row, j) = cumulantsMat(row, j);
        end
    end
    fname = ['digits', filesep, 'feat6_testBPSK-', num2str(snr), '.dat'];
    dlmwrite(fname, test_data, 'delimiter', '\t', 'newline', 'pc');
    disp(['  SNR = ', num2str(snr), ' dB done.']);
end
disp('BPSK test data done.');

%% QPSK Test Data
disp('--- QPSK test data ---');
test_cols = sigLen * 2;
for idx = 1:length(SNR_list)
    snr = SNR_list(idx);
    test_data = zeros(test_rows, test_NFeatures);
    data = randi([0 1], test_rows, test_cols);
    data1 = data';
    data_cell = mat2cell(data1, test_cols, ones(1, test_rows));
    signalData = cellfun(@(x) QPSKModulator(x), data_cell, 'UniformOutput', false);
    signalDataMat = cell2mat(signalData);
    dataMod = mat2cell(signalDataMat', ones(1, test_rows), test_cols/2);
    dataRx = cellfun(@(x) awgn(x, snr), dataMod, 'UniformOutput', false);
    cumulants = cellfun(@(x) feat6_func_get_cumulants(x), dataRx, 'UniformOutput', false);
    cumulantsMat = cell2mat(cumulants);
    for row = 1:test_rows
        for j = 1:test_NFeatures
            test_data(row, j) = cumulantsMat(row, j);
        end
    end
    fname = ['digits', filesep, 'feat6_testQPSK-', num2str(snr), '.dat'];
    dlmwrite(fname, test_data, 'delimiter', '\t', 'newline', 'pc');
    disp(['  SNR = ', num2str(snr), ' dB done.']);
end
disp('QPSK test data done.');

%% 16QAM Test Data
disp('--- 16QAM test data ---');
test_cols = sigLen * 4;
SNR_16QAM = [0, 5, 10, 15, 20, 25, 30, 35, 40];
for idx = 1:length(SNR_16QAM)
    snr = SNR_16QAM(idx);
    test_data = zeros(test_rows, test_NFeatures);
    data = randi([0 1], test_rows, test_cols);
    data1 = data';
    data_cell = mat2cell(data1, test_cols, ones(1, test_rows));
    signalData = cellfun(@(x) qammod(x, 16, 'InputType', 'bit', 'UnitAveragePower', true), data_cell, 'UniformOutput', false);
    signalDataMat = cell2mat(signalData);
    dataMod = mat2cell(signalDataMat', ones(1, test_rows), test_cols/4);
    dataRx = cellfun(@(x) awgn(x, snr), dataMod, 'UniformOutput', false);
    cumulants = cellfun(@(x) feat6_func_get_cumulants(x), dataRx, 'UniformOutput', false);
    cumulantsMat = cell2mat(cumulants);
    for row = 1:test_rows
        for j = 1:test_NFeatures
            test_data(row, j) = cumulantsMat(row, j);
        end
    end
    fname = ['digits', filesep, 'feat6_test16QAM-', num2str(snr), '.dat'];
    dlmwrite(fname, test_data, 'delimiter', '\t', 'newline', 'pc');
    disp(['  SNR = ', num2str(snr), ' dB done.']);
end
disp('16QAM test data done.');

disp('========================================');
disp('All data generation complete!');
fprintf('Training: digits\\feat6_sample.dat (%d samples)\n', 4*rows);
fprintf('BPSK test:  digits\\feat6_testBPSK-*.dat  (%d files x %d samples)\n', length(SNR_list), test_rows);
fprintf('QPSK test:  digits\\feat6_testQPSK-*.dat  (%d files x %d samples)\n', length(SNR_list), test_rows);
fprintf('16QAM test: digits\\feat6_test16QAM-*.dat (%d files x %d samples)\n', length(SNR_16QAM), test_rows);

feat6_getTest16QAM.m

Matlab 复制代码
%% Clean up
clear all;
clc;

rows = 1000;
cols = 1000*4;
NFeatures = 5;
test_data = zeros(rows, NFeatures);
SNR = [0:5:40];
for i = 1:length(SNR)
    
%% Simulation parameters
M = 16;
snr = SNR(i);

%% Simulate
    %16QAM
    % Generate random data
    data = randi([0 1], rows, cols);   
    
    % QAM 映射
    [data1] = data';
    data_cell = mat2cell(data1,cols,ones(1,rows));
    signalData = cellfun(@(x) qammod(x, M, 'InputType', 'bit', 'UnitAveragePower', true), data_cell, 'UniformOutput',false);
    signalDataMat = cell2mat(signalData);
    dataMod = mat2cell(signalDataMat',ones(1,rows),cols/4);
    
     % AWGN 加噪
    dataRx = cellfun(@(x) awgn(x, snr), dataMod, 'UniformOutput',false);
    
    % 获取高阶累积量
    cumulants = cellfun(@(x) feat6_func_get_cumulants(x), dataRx, 'UniformOutput',false);
    cumulantsMat = cell2mat(cumulants);
    
    for row = 1: rows
        for i = 1:NFeatures
                test_data(row, i) = cumulantsMat(row, i);
        end
    end 

%% save
filename=['digits\feat6_test16QAM-',num2str(snr),'.dat'];
dlmwrite(filename,test_data,'delimiter','\t','newline','pc');
end

feat6_getTestBPSK.m

Matlab 复制代码
%% Clean up
clear all;
clc;

rows = 1000;
cols = 1000;
NFeatures = 5;
test_data = zeros(rows, NFeatures);
SNR = [-4:2:10];
for i = 1:length(SNR)
    
%% Simulation parameters
M = 2;
snr = SNR(i);
%% Simulate
    %BPSK
    % Generate random data
    data = randi([0 1], rows, cols);   
    
    % PSK 映射
    [data1] = data';
    data_cell = mat2cell(data1,cols,ones(1,rows));
    signalData = cellfun(@(x) BPSKModulator(x), data_cell, 'UniformOutput',false);
    signalDataMat = cell2mat(signalData);
    dataMod = mat2cell(signalDataMat',ones(1,rows),cols);
    
     % AWGN 加噪
    dataRx = cellfun(@(x) awgn(x, snr), dataMod, 'UniformOutput',false);
    
    % 获取高阶累积量
    cumulants = cellfun(@(x) feat6_func_get_cumulants(x), dataRx, 'UniformOutput',false);
    cumulantsMat = cell2mat(cumulants);
    
    for row = 1: rows
        for i = 1:NFeatures
                test_data(row, i) = cumulantsMat(row, i);
        end
    end 

%% save
filename=['digits\feat6_testBPSK-',num2str(snr),'.dat'];
dlmwrite(filename,test_data,'delimiter','\t','newline','pc');
end

feat6_getTestQPSK.m

Matlab 复制代码
%% Clean up
clear all;
clc;

rows = 1000;
cols = 1000*2;
NFeatures = 5;
test_data = zeros(rows, NFeatures);
SNR = [-4:2:10];
for i = 1:length(SNR)
    
%% Simulation parameters
M = 4;
snr = SNR(i);

%% Simulate
    %QPSK
    % Generate random data
    data = randi([0 1], rows, cols);   
    
    % PSK 映射
    [data1] = data';
    data_cell = mat2cell(data1,cols,ones(1,rows));
    signalData = cellfun(@(x) QPSKModulator(x), data_cell, 'UniformOutput',false);
    %signalData = cellfun(@(x) qammod(x, M, 'InputType', 'bit', 'UnitAveragePower', true), data_cell, 'UniformOutput',false);
    signalDataMat = cell2mat(signalData);
    dataMod = mat2cell(signalDataMat',ones(1,rows),cols/2);
    
     % AWGN 加噪
    dataRx = cellfun(@(x) awgn(x, snr), dataMod, 'UniformOutput',false);
    
    % 获取高阶累积量
    cumulants = cellfun(@(x) feat6_func_get_cumulants(x), dataRx, 'UniformOutput',false);
    cumulantsMat = cell2mat(cumulants);
    
    for row = 1: rows
        for i = 1:NFeatures
                test_data(row, i) = cumulantsMat(row, i);
        end
    end 

%% save
filename=['digits\feat6_testQPSK-',num2str(snr),'.dat'];
dlmwrite(filename,test_data,'delimiter','\t','newline','pc');
end

feat9_func_get_cumulants.m

Matlab 复制代码
function [cumulants] = feat9_func_get_cumulants(signalData)

shape = size(signalData);
H = shape(1);
L = shape(2);
cumulants = zeros(H, 9);

for row = 1:H
    % Second-order moments
    M20 = sum(signalData(row,:).^2)/L;
    M21 = sum(abs(signalData(row,:)).^2)/L;

    % Fourth-order moments
    M40 = sum(signalData(row,:).^4)/L;
    M41 = sum(abs(signalData(row,:)).^2.*signalData(row,:).^2)/L;
    M42 = sum(abs(signalData(row,:)).^4)/L;

    % Sixth-order moments
    M60 = sum(signalData(row,:).^6)/L;
    M61 = sum(signalData(row,:).^5 .* conj(signalData(row,:)))/L;
    M62 = sum(signalData(row,:).^4 .* abs(signalData(row,:)).^2)/L;
    M63 = sum(abs(signalData(row,:)).^6)/L;

    % Second-order cumulants
    C20 = M20;
    C21 = M21;

    % Fourth-order cumulants
    C40 = M40 - 3*M20^2;
    C41 = M41 - 3*M20*M21;
    C42 = M42 - abs(M20)^2 - 2*M21^2;

    % Sixth-order cumulants
    % C60: cum[xxxxxx] = M60 - 15*M40*M20 + 30*M20^3
    C60 = M60 - 15*M40*M20 + 30*M20^3;
    % C61: cum[xxxxxx*] = M61 - 5*M41*M20 - 10*M40*M21 + 30*M20^2*M21
    C61 = M61 - 5*M41*M20 - 10*M40*M21 + 30*M20^2*M21;
    % C62: cum[xxxxx*x*] = M62 - 6*M42*M20 - 8*M41*M21 - M40*conj(M20) + 6*M40*conj(M20) + 12*M21^2*M20
    C62 = M62 - 6*M42*M20 - 8*M41*M21 - M40*conj(M20) + 6*M40*conj(M20) + 12*M21^2*M20;
    % C63: cum[xxx*x*x*] = M63 - 9*M42*M21 + 12*M21^3
    C63 = M63 - 9*M42*M21 + 12*M21^3;

    % Normalization by C21^2
    C21_modify = C21;
    C20_norm = C20/(C21_modify^2);
    C21_norm = C21/(C21_modify^2);
    C40_norm = C40/(C21_modify^2);
    C41_norm = C41/(C21_modify^2);
    C42_norm = C42/(C21_modify^2);
    C60_norm = C60/(C21_modify^2);
    C61_norm = C61/(C21_modify^2);
    C62_norm = C62/(C21_modify^2);
    C63_norm = C63/(C21_modify^2);

    cumulants(row, 1) = abs(C20_norm);
    cumulants(row, 2) = abs(C21_norm);
    cumulants(row, 3) = abs(C40_norm);
    cumulants(row, 4) = abs(C41_norm);
    cumulants(row, 5) = abs(C42_norm);
    cumulants(row, 6) = abs(C60_norm);
    cumulants(row, 7) = abs(C61_norm);
    cumulants(row, 8) = abs(C62_norm);
    cumulants(row, 9) = abs(C63_norm);

end

feat9_getSample.m

Matlab 复制代码
%% Clean up
clear all;
clc;

rows = 10;
sigLen = 500;
NFeatures = 9;
sample_data = zeros(rows, NFeatures + 1);

%% Simulation parameters

%% Simulate
    %BPSK
    % Generate random data
    data = randi([0 1], rows, sigLen);

    % QAM mapping
    [data1] = data';
    data_cell = mat2cell(data1,sigLen,ones(1,rows));
    signalData = cellfun(@(x) BPSKModulator(x), data_cell, 'UniformOutput',false);
    %signalData = cellfun(@(x) qammod(x, 2, 'InputType', 'bit', 'UnitAveragePower', true), data_cell, 'UniformOutput',false);
    signalData1 = cell2mat(signalData);
    signalData2 = mat2cell(signalData1',ones(1,rows),sigLen);

    % get cumulants
    cumulants = cellfun(@(x) feat9_func_get_cumulants(x), signalData2, 'UniformOutput',false);
    cumulantsMat = cell2mat(cumulants);

    for row = 1: rows
        for i = 1:NFeatures
                sample_data(row, i) = cumulantsMat(row, i);
        end
        sample_data(row, NFeatures + 1) = 2;
    end

    %QPSK
    % Generate random data
    data = randi([0 1], rows, 2*sigLen);

    % QAM mapping
    [data1] = data';
    data_cell = mat2cell(data1,2*sigLen,ones(1,rows));
    signalData = cellfun(@(x) QPSKModulator(x), data_cell, 'UniformOutput',false);
    %signalData = cellfun(@(x) qammod(x, 4, 'InputType', 'bit', 'UnitAveragePower', true), data_cell, 'UniformOutput',false);
    signalData1 = cell2mat(signalData);
    signalData2 = mat2cell(signalData1',ones(1,rows),sigLen);

    % get cumulants
    cumulants = cellfun(@(x) feat9_func_get_cumulants(x), signalData2, 'UniformOutput',false);
    cumulantsMat = cell2mat(cumulants);

    for row = 1: rows
        row_r = rows + row;
        for i = 1:NFeatures
                sample_data(row_r, i) = cumulantsMat(row, i);
        end
        sample_data(row_r, NFeatures + 1) = 4;
    end

 %16QAM
    % Generate random data
    data = randi([0 1], rows, 4*sigLen);

    % QAM mapping
    [data1] = data';
    data_cell = mat2cell(data1,4*sigLen,ones(1,rows));
    signalData = cellfun(@(x) qammod(x, 16, 'InputType', 'bit', 'UnitAveragePower', true), data_cell, 'UniformOutput',false);
    signalData1 = cell2mat(signalData);
    signalData2 = mat2cell(signalData1',ones(1,rows),sigLen);

    % get cumulants
    cumulants = cellfun(@(x) feat9_func_get_cumulants(x), signalData2, 'UniformOutput',false);
    cumulantsMat = cell2mat(cumulants);

    for row = 1: rows
        row_r = 2*rows + row;
        for i = 1:NFeatures
                sample_data(row_r, i) = cumulantsMat(row, i);
        end
        sample_data(row_r, NFeatures + 1) = 16;
    end

 %64QAM
    % Generate random data
    data = randi([0 1], rows, 6*sigLen);
    % QAM mapping
    [data1] = data';
    data_cell = mat2cell(data1,6*sigLen,ones(1,rows));
    signalData = cellfun(@(x) qammod(x, 64, 'InputType', 'bit', 'UnitAveragePower', true), data_cell, 'UniformOutput',false);
    signalData1 = cell2mat(signalData);
    signalData2 = mat2cell(signalData1',ones(1,rows),sigLen);

    % get cumulants
    cumulants = cellfun(@(x) feat9_func_get_cumulants(x), signalData2, 'UniformOutput',false);
    cumulantsMat = cell2mat(cumulants);

    for row = 1: rows
        row_r = 3*rows + row;
        for i = 1:NFeatures
                sample_data(row_r, i) = cumulantsMat(row, i);
        end
        sample_data(row_r, NFeatures + 1) = 64;
    end

filename = ['digits', filesep, 'feat9_sample.dat'];
dlmwrite(filename, sample_data, 'delimiter', '\t', 'newline', 'pc');

disp('Training data saved.');

%% ============================================================
%% Auto-generate test data
%% ============================================================
disp('Now generating test data...');

%% BPSK Test Data
disp('--- BPSK test data ---');
test_rows = 1000;
test_cols = sigLen;
test_NFeatures = NFeatures;
SNR_list = [-4, -2, 0, 2, 4, 6, 8, 10];
for idx = 1:length(SNR_list)
    snr = SNR_list(idx);
    test_data = zeros(test_rows, test_NFeatures);
    data = randi([0 1], test_rows, test_cols);
    data1 = data';
    data_cell = mat2cell(data1, test_cols, ones(1, test_rows));
    signalData = cellfun(@(x) BPSKModulator(x), data_cell, 'UniformOutput', false);
    signalDataMat = cell2mat(signalData);
    dataMod = mat2cell(signalDataMat', ones(1, test_rows), test_cols);
    dataRx = cellfun(@(x) awgn(x, snr), dataMod, 'UniformOutput', false);
    cumulants = cellfun(@(x) feat9_func_get_cumulants(x), dataRx, 'UniformOutput', false);
    cumulantsMat = cell2mat(cumulants);
    for row = 1:test_rows
        for j = 1:test_NFeatures
            test_data(row, j) = cumulantsMat(row, j);
        end
    end
    fname = ['digits', filesep, 'feat9_testBPSK-', num2str(snr), '.dat'];
    dlmwrite(fname, test_data, 'delimiter', '\t', 'newline', 'pc');
    disp(['  SNR = ', num2str(snr), ' dB done.']);
end
disp('BPSK test data done.');

%% QPSK Test Data
disp('--- QPSK test data ---');
test_cols = sigLen * 2;
for idx = 1:length(SNR_list)
    snr = SNR_list(idx);
    test_data = zeros(test_rows, test_NFeatures);
    data = randi([0 1], test_rows, test_cols);
    data1 = data';
    data_cell = mat2cell(data1, test_cols, ones(1, test_rows));
    signalData = cellfun(@(x) QPSKModulator(x), data_cell, 'UniformOutput', false);
    signalDataMat = cell2mat(signalData);
    dataMod = mat2cell(signalDataMat', ones(1, test_rows), test_cols/2);
    dataRx = cellfun(@(x) awgn(x, snr), dataMod, 'UniformOutput', false);
    cumulants = cellfun(@(x) feat9_func_get_cumulants(x), dataRx, 'UniformOutput', false);
    cumulantsMat = cell2mat(cumulants);
    for row = 1:test_rows
        for j = 1:test_NFeatures
            test_data(row, j) = cumulantsMat(row, j);
        end
    end
    fname = ['digits', filesep, 'feat9_testQPSK-', num2str(snr), '.dat'];
    dlmwrite(fname, test_data, 'delimiter', '\t', 'newline', 'pc');
    disp(['  SNR = ', num2str(snr), ' dB done.']);
end
disp('QPSK test data done.');

%% 16QAM Test Data
disp('--- 16QAM test data ---');
test_cols = sigLen * 4;
SNR_16QAM = [0, 5, 10, 15, 20, 25, 30, 35, 40];
for idx = 1:length(SNR_16QAM)
    snr = SNR_16QAM(idx);
    test_data = zeros(test_rows, test_NFeatures);
    data = randi([0 1], test_rows, test_cols);
    data1 = data';
    data_cell = mat2cell(data1, test_cols, ones(1, test_rows));
    signalData = cellfun(@(x) qammod(x, 16, 'InputType', 'bit', 'UnitAveragePower', true), data_cell, 'UniformOutput', false);
    signalDataMat = cell2mat(signalData);
    dataMod = mat2cell(signalDataMat', ones(1, test_rows), test_cols/4);
    dataRx = cellfun(@(x) awgn(x, snr), dataMod, 'UniformOutput', false);
    cumulants = cellfun(@(x) feat9_func_get_cumulants(x), dataRx, 'UniformOutput', false);
    cumulantsMat = cell2mat(cumulants);
    for row = 1:test_rows
        for j = 1:test_NFeatures
            test_data(row, j) = cumulantsMat(row, j);
        end
    end
    fname = ['digits', filesep, 'feat9_test16QAM-', num2str(snr), '.dat'];
    dlmwrite(fname, test_data, 'delimiter', '\t', 'newline', 'pc');
    disp(['  SNR = ', num2str(snr), ' dB done.']);
end
disp('16QAM test data done.');

disp('========================================');
disp('All data generation complete!');
fprintf('Training: digits\\feat9_sample.dat (%d samples)\n', 4*rows);
fprintf('BPSK test:  digits\\feat9_testBPSK-*.dat  (%d files x %d samples)\n', length(SNR_list), test_rows);
fprintf('QPSK test:  digits\\feat9_testQPSK-*.dat  (%d files x %d samples)\n', length(SNR_list), test_rows);
fprintf('16QAM test: digits\\feat9_test16QAM-*.dat (%d files x %d samples)\n', length(SNR_16QAM), test_rows);

feat9_getTest16QAM.m

Matlab 复制代码
%% Clean up
clear all;
clc;

rows = 1000;
cols = 1000*4;
NFeatures = 9;
test_data = zeros(rows, NFeatures);
SNR = [0:5:40];
for i = 1:length(SNR)

%% Simulation parameters
M = 16;
snr = SNR(i);

%% Simulate
    %16QAM
    % Generate random data
    data = randi([0 1], rows, cols);

    % QAM mapping
    [data1] = data';
    data_cell = mat2cell(data1,cols,ones(1,rows));
    signalData = cellfun(@(x) qammod(x, M, 'InputType', 'bit', 'UnitAveragePower', true), data_cell, 'UniformOutput',false);
    signalDataMat = cell2mat(signalData);
    dataMod = mat2cell(signalDataMat',ones(1,rows),cols/4);

     % AWGN channel
    dataRx = cellfun(@(x) awgn(x, snr), dataMod, 'UniformOutput',false);

    % get high-order cumulants
    cumulants = cellfun(@(x) feat9_func_get_cumulants(x), dataRx, 'UniformOutput',false);
    cumulantsMat = cell2mat(cumulants);

    for row = 1: rows
        for i = 1:NFeatures
                test_data(row, i) = cumulantsMat(row, i);
        end
    end

%% save
filename=['digits\feat9_test16QAM-',num2str(snr),'.dat'];
dlmwrite(filename,test_data,'delimiter','\t','newline','pc');
end

feat9_getTestBPSK.m

Matlab 复制代码
%% Clean up
clear all;
clc;

rows = 1000;
cols = 1000;
NFeatures = 9;
test_data = zeros(rows, NFeatures);
SNR = [-4:2:10];
for i = 1:length(SNR)

%% Simulation parameters
M = 2;
snr = SNR(i);
%% Simulate
    %BPSK
    % Generate random data
    data = randi([0 1], rows, cols);

    % PSK mapping
    [data1] = data';
    data_cell = mat2cell(data1,cols,ones(1,rows));
    signalData = cellfun(@(x) BPSKModulator(x), data_cell, 'UniformOutput',false);
    signalDataMat = cell2mat(signalData);
    dataMod = mat2cell(signalDataMat',ones(1,rows),cols);

     % AWGN channel
    dataRx = cellfun(@(x) awgn(x, snr), dataMod, 'UniformOutput',false);

    % get high-order cumulants
    cumulants = cellfun(@(x) feat9_func_get_cumulants(x), dataRx, 'UniformOutput',false);
    cumulantsMat = cell2mat(cumulants);

    for row = 1: rows
        for i = 1:NFeatures
                test_data(row, i) = cumulantsMat(row, i);
        end
    end

%% save
filename=['digits\feat9_testBPSK-',num2str(snr),'.dat'];
dlmwrite(filename,test_data,'delimiter','\t','newline','pc');
end

feat9_getTestQPSK.m

Matlab 复制代码
%% Clean up
clear all;
clc;

rows = 1000;
cols = 1000*2;
NFeatures = 9;
test_data = zeros(rows, NFeatures);
SNR = [-4:2:10];
for i = 1:length(SNR)

%% Simulation parameters
M = 4;
snr = SNR(i);

%% Simulate
    %QPSK
    % Generate random data
    data = randi([0 1], rows, cols);

    % PSK mapping
    [data1] = data';
    data_cell = mat2cell(data1,cols,ones(1,rows));
    signalData = cellfun(@(x) QPSKModulator(x), data_cell, 'UniformOutput',false);
    %signalData = cellfun(@(x) qammod(x, M, 'InputType', 'bit', 'UnitAveragePower', true), data_cell, 'UniformOutput',false);
    signalDataMat = cell2mat(signalData);
    dataMod = mat2cell(signalDataMat',ones(1,rows),cols/2);

     % AWGN channel
    dataRx = cellfun(@(x) awgn(x, snr), dataMod, 'UniformOutput',false);

    % get high-order cumulants
    cumulants = cellfun(@(x) feat9_func_get_cumulants(x), dataRx, 'UniformOutput',false);
    cumulantsMat = cell2mat(cumulants);

    for row = 1: rows
        for i = 1:NFeatures
                test_data(row, i) = cumulantsMat(row, i);
        end
    end

%% save
filename=['digits\feat9_testQPSK-',num2str(snr),'.dat'];
dlmwrite(filename,test_data,'delimiter','\t','newline','pc');
end

QPSKModulator.m

Matlab 复制代码
function [out] = QPSKModulator(in)
persistent Modulator   
if isempty(Modulator)
    Modulator=comm.QPSKModulator('BitInput',true);
    %demodLLR=comm.QPSKDemodulator('BitOutput',true,'DecisionMethod','Log-likelihood ratio','VarianceSource','Input port');
end
out = Modulator(in);
end

7.2、Python端

用四阶累积量(5个特征维度)和六阶累积量(9个特征维度)分别训练了两个KNN分类器,分别对每种调制方式的样本信号进行识别,并将准确率曲线共同绘制在一张图中。

main_6feat_compare_9feat.ipynb

cell-1 导入包及数据 --- 9特征 vs 6特征对比

python 复制代码
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
from collections import defaultdict
import collections
import matplotlib.pyplot as plt

def file2matrix(filename, nFeatures):
    fr = open(filename)
    numberOfLines = len(fr.readlines())
    returnMat = np.zeros((numberOfLines, nFeatures))
    classLabelVector = []
    fr = open(filename)
    index = 0
    for line in fr.readlines():
        line = line.strip()
        listFromLine = line.split('\t')
        returnMat[index, :] = listFromLine[0:nFeatures]
        classLabelVector.append(float(listFromLine[-1]))
        index += 1
    return returnMat, classLabelVector

cell-2 训练两个KNN分类器:9特征 (C20~C63) vs 6特征 (C20~C42)

python 复制代码
# 9-feature classifier
data_X9, data_y9 = file2matrix('data/feat9_sample.dat', 9)
knn9 = KNeighborsClassifier(n_neighbors=10)
knn9.fit(data_X9, data_y9)

# 6-feature classifier
data_X6, data_y6 = file2matrix('data/feat6_sample.dat', 5)
knn6 = KNeighborsClassifier(n_neighbors=10)
knn6.fit(data_X6, data_y6)

print('9-feature classifier trained on %d samples' % data_X9.shape[0])
print('6-feature classifier trained on %d samples' % data_X6.shape[0])

cell-3 BPSK 对比测试

python 复制代码
SNR = [2*x for x in range(-2, 6)]
acc9 = defaultdict(list)
acc6 = defaultdict(list)

for snr in SNR:
    # 9feat
    test9, _ = file2matrix('data/feat9_testBPSK-' + str(snr) + '.dat', 9)
    pred9 = knn9.predict(test9)
    acc9[snr] = np.sum(pred9 == 2) / len(pred9)

    # 6feat
    test6, _ = file2matrix('data/feat6_testBPSK-' + str(snr) + '.dat', 5)
    pred6 = knn6.predict(test6)
    acc6[snr] = np.sum(pred6 == 2) / len(pred6)

    print('SNR=%2d dB: 9feat=%.4f  6feat=%.4f' % (snr, acc9[snr], acc6[snr]))

acc9 = collections.OrderedDict(sorted(acc9.items()))
acc6 = collections.OrderedDict(sorted(acc6.items()))

plt.style.use('classic')
plt.figure(figsize=(10, 6), dpi=100)
x = SNR
plt.plot(x, list(acc9.values()), 'o-', linewidth=2.0, color='royalblue', label='9feat (C20~C63)')
plt.plot(x, list(acc6.values()), 's--', linewidth=2.0, color='darkorange', label='6feat (C20~C42)')
plt.axis([0, 10, 0, 1])
plt.xticks(np.arange(min(x), max(x)+1, 2.0))
plt.yticks(np.arange(0, 1.05, 0.10))
plt.title('SNR vs Accuracy - BPSK', fontsize=16, fontweight='bold')
plt.xlabel('SNR (dB)', fontsize=14)
plt.ylabel('Test accuracy', fontsize=14)
plt.legend(fontsize=12)
plt.grid()
plt.show()

cell-4 QPSK对比测试

python 复制代码
SNR = [2*x for x in range(-2, 6)]
acc9 = defaultdict(list)
acc6 = defaultdict(list)

for snr in SNR:
    # 9feat
    test9, _ = file2matrix('data/feat9_testQPSK-' + str(snr) + '.dat', 9)
    pred9 = knn9.predict(test9)
    acc9[snr] = np.sum(pred9 == 4) / len(pred9)

    # 6feat
    test6, _ = file2matrix('data/feat6_testQPSK-' + str(snr) + '.dat', 5)
    pred6 = knn6.predict(test6)
    acc6[snr] = np.sum(pred6 == 4) / len(pred6)

    print('SNR=%2d dB: 9feat=%.4f  6feat=%.4f' % (snr, acc9[snr], acc6[snr]))

acc9 = collections.OrderedDict(sorted(acc9.items()))
acc6 = collections.OrderedDict(sorted(acc6.items()))

plt.style.use('classic')
plt.figure(figsize=(10, 6), dpi=100)
x = SNR
plt.plot(x, list(acc9.values()), 'o-', linewidth=2.0, color='royalblue', label='9feat (C20~C63)')
plt.plot(x, list(acc6.values()), 's--', linewidth=2.0, color='darkorange', label='6feat (C20~C42)')
plt.axis([0, 10, 0, 1])
plt.xticks(np.arange(min(x), max(x)+1, 2.0))
plt.yticks(np.arange(0, 1.05, 0.10))
plt.title('SNR vs Accuracy - QPSK', fontsize=16, fontweight='bold')
plt.xlabel('SNR (dB)', fontsize=14)
plt.ylabel('Test accuracy', fontsize=14)
plt.legend(fontsize=12)
plt.grid()
plt.show()

cell-5 16QAM对比测试

python 复制代码
SNR = [5*x for x in range(0, 9)]
acc9 = defaultdict(list)
acc6 = defaultdict(list)

for snr in SNR:
    # 9feat
    test9, _ = file2matrix('data/feat9_test16QAM-' + str(snr) + '.dat', 9)
    pred9 = knn9.predict(test9)
    acc9[snr] = np.sum(pred9 == 16) / len(pred9)

    # 6feat
    test6, _ = file2matrix('data/feat6_test16QAM-' + str(snr) + '.dat', 5)
    pred6 = knn6.predict(test6)
    acc6[snr] = np.sum(pred6 == 16) / len(pred6)

    print('SNR=%2d dB: 9feat=%.4f  6feat=%.4f' % (snr, acc9[snr], acc6[snr]))

acc9 = collections.OrderedDict(sorted(acc9.items()))
acc6 = collections.OrderedDict(sorted(acc6.items()))

plt.style.use('classic')
plt.figure(figsize=(10, 6), dpi=100)
x = SNR
plt.plot(x, list(acc9.values()), 'o-', linewidth=2.0, color='royalblue', label='9feat (C20~C63)')
plt.plot(x, list(acc6.values()), 's--', linewidth=2.0, color='darkorange', label='6feat (C20~C42)')
plt.axis([0, 40, 0, 1])
plt.xticks(np.arange(min(x), max(x)+1, 5.0))
plt.yticks(np.arange(0, 1.05, 0.10))
plt.title('SNR vs Accuracy - 16QAM', fontsize=16, fontweight='bold')
plt.xlabel('SNR (dB)', fontsize=14)
plt.ylabel('Test accuracy', fontsize=14)
plt.legend(fontsize=12)
plt.grid()
plt.show()

7.3、仿真结果分析

运行后生成的图像如图7-1、图7-2、图7-3所示。
图7-1 BPSK调制模式下的四阶累积量和六阶累积量对识别准确率的影响
图7-2 QPSK调制模式下的四阶累积量和六阶累积量对识别准确率的影响
图7-3 16QAM调制模式下的四阶累积量和六阶累积量对识别准确率的影响

可以发现,在BPSK的准确率判别时,六阶累积量下的特征向量判别更为准确。