├── Data ├── Evaluate_Trained_network.m ├── FrameStoreOutputFormat.m ├── Generat_Frames_Optional.m ├── ModClassFrameGenerator.m ├── ModClassFrameStore.m ├── ModClassGetModulator.m ├── ModClassIQAsPages.m ├── ModClassPlotFrequencyDomain.m ├── ModClassTestChannel.m ├── NET_model_CNN.m ├── NET_model_DNN.m ├── NET_model_RNN.m ├── README.md ├── audio.wav ├── getAudio.m ├── getSource.m └── show_signal.m /Data: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Evaluate_Trained_network.m: -------------------------------------------------------------------------------- 1 | %% CNN 2 | % load('TrainedNet_CNN.mat'); 3 | fprintf('%s - Classifying test frames for CNN\n', datestr(toc/86400,'HH:MM:SS')) 4 | rxTestPred_CNN = classify(CNN_NET, rxTest); 5 | testAccuracy_CNN = mean(rxTestPred_CNN == rxTestLabel); 6 | 7 | % 计算混淆矩阵 8 | cm_CNN = confusionmat(rxTestLabel, rxTestPred_CNN); 9 | % 计算召回率 10 | recall_CNN = cm_CNN(2, 2) / (cm_CNN(2, 2) + cm_CNN(2, 1)); 11 | % 计算精确率 12 | precision_CNN = cm_CNN(2, 2) / (cm_CNN(2, 2) + cm_CNN(1, 2)); 13 | % 计算F1分数 14 | f1_CNN = 2 * (precision_CNN * recall_CNN) / (precision_CNN + recall_CNN); 15 | % 计算准确率 16 | accuracy_CNN = sum(diag(cm_CNN)) / sum(cm_CNN(:)); 17 | % 计算特异度 18 | specificity_CNN = cm_CNN(1, 1) / (cm_CNN(1, 1) + cm_CNN(1, 2)); 19 | % 计算假正率 20 | fpr_CNN = 1 - specificity_CNN; 21 | 22 | figure; 23 | % Calculate confusion matrix 24 | cm_CNN = confusionchart(rxTestLabel, rxTestPred_CNN); 25 | cm_CNN.Title = 'Confusion Matrix for Test Data (CNN)'; 26 | cm_CNN.RowSummary = 'row-normalized'; 27 | sortClasses(cm_CNN,'descending-diagonal') 28 | cm_CNN.Parent.Position = [cm_CNN.Parent.Position(1:2) 740 424]; 29 | disp(['CNN召回率:', num2str(recall_CNN)]) 30 | disp(['CNNF1分数:', num2str(f1_CNN)]) 31 | disp(['CNN精确率:', num2str(precision_CNN)]) 32 | disp(['CNN准确率:', num2str(accuracy_CNN)]) 33 | disp(['CNN特异度:', num2str(specificity_CNN)]) 34 | disp(['CNN假正率:', num2str(fpr_CNN)]) 35 | 36 | %% DNN 37 | % load('TrainedNet_DNN.mat'); 38 | % 初始化用于存储特征的单元数组 39 | trainFeatures_DNN = cell(size(rxTraining, 4), 1); 40 | validationFeatures_DNN = cell(size(rxValidation, 4), 1); 41 | testFeatures_DNN = cell(size(rxTest, 4), 1); 42 | 43 | % 提取训练、验证和测试数据的特征 44 | for ii = 1:size(rxTraining, 4) 45 | trainFeatures_DNN{ii} = extractFeatures(rxTraining(:, :, :, ii)); 46 | end 47 | 48 | for ii = 1:size(rxValidation, 4) 49 | validationFeatures_DNN{ii} = extractFeatures(rxValidation(:, :, :, ii)); 50 | end 51 | 52 | for ii = 1:size(rxTest, 4) 53 | testFeatures_DNN{ii} = extractFeatures(rxTest(:, :, :, ii)); 54 | end 55 | 56 | % 将特征转换为矩阵形式,保留四维结构 57 | trainingData_DNN = cat(4, trainFeatures_DNN{:}); 58 | validationData_DNN = cat(4, validationFeatures_DNN{:}); 59 | testData_DNN = cat(4, testFeatures_DNN{:}); 60 | 61 | % Classify test frames using DNN model 62 | fprintf('%s - Classifying test frames for DNN\n', datestr(toc/86400,'HH:MM:SS')) 63 | rxTestPred_DNN = classify(DNN_NET, testData_DNN); 64 | testAccuracy_DNN = mean(rxTestPred_DNN == rxTestLabel); 65 | 66 | % 计算混淆矩阵 67 | cm_DNN = confusionmat(rxTestLabel, rxTestPred_DNN); 68 | 69 | % 计算召回率 70 | recall_DNN = cm_DNN(2, 2) / (cm_DNN(2, 2) + cm_DNN(2, 1)); 71 | 72 | % 计算精确率 73 | precision_DNN = cm_DNN(2, 2) / (cm_DNN(2, 2) + cm_DNN(1, 2)); 74 | 75 | % 计算F1分数 76 | f1_DNN = 2 * (precision_DNN * recall_DNN) / (precision_DNN + recall_DNN); 77 | 78 | % 计算准确率 79 | accuracy_DNN = sum(diag(cm_DNN)) / sum(cm_DNN(:)); 80 | 81 | % 计算特异度 82 | specificity_DNN = cm_DNN(1, 1) / (cm_DNN(1, 1) + cm_DNN(1, 2)); 83 | 84 | % 计算假正率 85 | fpr_DNN = 1 - specificity_DNN; 86 | 87 | figure; 88 | % Calculate confusion matrix for DNN 89 | cm_DNN = confusionchart(rxTestLabel, rxTestPred_DNN); 90 | cm_DNN.Title = 'Confusion Matrix for Test Data (DNN)'; 91 | cm_DNN.RowSummary = 'row-normalized'; 92 | sortClasses(cm_DNN,'descending-diagonal') 93 | cm_DNN.Parent.Position = [cm_DNN.Parent.Position(1:2) 740 424]; 94 | 95 | disp(['DNN召回率:', num2str(recall_DNN)]) 96 | disp(['DNNF1分数:', num2str(f1_DNN)]) 97 | disp(['DNN精确率:', num2str(precision_DNN)]) 98 | disp(['DNN准确率:', num2str(accuracy_DNN)]) 99 | disp(['DNN特异度:', num2str(specificity_DNN)]) 100 | disp(['DNN假正率:', num2str(fpr_DNN)]) 101 | 102 | 103 | %% LSTM 104 | % load('TrainedNet_RNN.mat'); 105 | % 初始化用于存储特征的单元数组 106 | trainFeatures_RNN = cell(size(rxTraining, 4), 1); 107 | validationFeatures_RNN = cell(size(rxValidation, 4), 1); 108 | testFeatures_RNN = cell(size(rxTest, 4), 1); 109 | 110 | % 提取训练、验证和测试数据的特征 111 | for ii = 1:size(rxTraining, 4) 112 | trainFeatures_RNN{ii} = extractFeatures(rxTraining(:, :, :, ii)); 113 | end 114 | 115 | for ii = 1:size(rxValidation, 4) 116 | validationFeatures_RNN{ii} = extractFeatures(rxValidation(:, :, :, ii)); 117 | end 118 | 119 | for ii = 1:size(rxTest, 4) 120 | testFeatures_RNN{ii} = extractFeatures(rxTest(:, :, :, ii)); 121 | end 122 | 123 | %初始化 124 | trainingData_RNN = cellfun(@(x) reshape(x, [], 2066, 1), trainFeatures_RNN, 'UniformOutput', false); 125 | testData_RNN = cellfun(@(x) reshape(x, [], 2066, 1), testFeatures_RNN, 'UniformOutput', false); 126 | validationData_RNN = cellfun(@(x) reshape(x, [], 2066, 1), validationFeatures_RNN, 'UniformOutput', false); 127 | 128 | trainingData_RNN = cellfun(@(x) permute(x, [2, 1, 3]), trainingData_RNN, 'UniformOutput', false); 129 | testData_RNN = cellfun(@(x) permute(x, [2, 1, 3]), testData_RNN, 'UniformOutput', false); 130 | validationData_RNN = cellfun(@(x) permute(x, [2, 1, 3]), validationData_RNN, 'UniformOutput', false); 131 | 132 | % Classify test frames using RNN (LSTM) model 133 | fprintf('%s - Classifying test frames for RNN (LSTM)\n', datestr(toc/86400,'HH:MM:SS')) 134 | rxTestPred_RNN = classify(RNN_NET, testData_RNN); 135 | testAccuracy_RNN = mean(rxTestPred_RNN == rxTestLabel); 136 | % 计算混淆矩阵 137 | cm_RNN = confusionmat(rxTestLabel, rxTestPred_RNN); 138 | % 计算召回率 139 | recall_RNN = cm_RNN(2, 2) / (cm_RNN(2, 2) + cm_RNN(2, 1)); 140 | % 计算精确率 141 | precision_RNN = cm_RNN(2, 2) / (cm_RNN(2, 2) + cm_RNN(1, 2)); 142 | % 计算F1分数 143 | f1_RNN = 2 * (precision_RNN * recall_RNN) / (precision_RNN + recall_RNN); 144 | % 计算准确率 145 | accuracy_RNN = sum(diag(cm_RNN)) / sum(cm_RNN(:)); 146 | % 计算特异度 147 | specificity_RNN = cm_RNN(1, 1) / (cm_RNN(1, 1) + cm_RNN(1, 2)); 148 | % 计算假正率 149 | fpr_RNN = 1 - specificity_RNN; 150 | 151 | figure; 152 | % Calculate confusion matrix for RNN 153 | cm_RNN = confusionchart(rxTestLabel, rxTestPred_RNN); 154 | cm_RNN.Title = 'Confusion Matrix for Test Data (LSTM)'; 155 | cm_RNN.RowSummary = 'row-normalized'; 156 | sortClasses(cm_RNN,'descending-diagonal') 157 | cm_RNN.Parent.Position = [cm_RNN.Parent.Position(1:2) 740 424]; 158 | 159 | disp(['RNN召回率:', num2str(recall_RNN)]) 160 | disp(['RNNF1分数:', num2str(f1_RNN)]) 161 | disp(['RNN精确率:', num2str(precision_RNN)]) 162 | disp(['RNN准确率:', num2str(accuracy_RNN)]) 163 | disp(['RNN特异度:', num2str(specificity_RNN)]) 164 | disp(['RNN假正率:', num2str(fpr_RNN)]) 165 | %% 输出图表 166 | figure; 167 | 168 | barData = [recall_CNN, recall_DNN, recall_RNN; 169 | f1_CNN, f1_DNN, f1_RNN; 170 | precision_CNN, precision_DNN, precision_RNN; 171 | accuracy_CNN, accuracy_DNN, accuracy_RNN; 172 | specificity_CNN, specificity_DNN, specificity_RNN; 173 | fpr_CNN, fpr_DNN, fpr_RNN]; 174 | 175 | bar(barData); 176 | 177 | xticklabels({'Recall', 'F1 Score', 'Precision', 'Accuracy', 'Specificity', 'False Positive Rate'}); 178 | ylabel('Score'); 179 | title('Comparison of Model Performance Metrics'); 180 | legend({'CNN', 'DNN', 'LSTM'}, 'Location', 'northoutside'); 181 | -------------------------------------------------------------------------------- /FrameStoreOutputFormat.m: -------------------------------------------------------------------------------- 1 | classdef FrameStoreOutputFormat 2 | enumeration 3 | IQAsRows 4 | IQAsPages 5 | end 6 | end -------------------------------------------------------------------------------- /Generat_Frames_Optional.m: -------------------------------------------------------------------------------- 1 | % 清除环境并关闭所有窗口 2 | clear; 3 | close all 4 | clc; 5 | 6 | % 定义调制类型 7 | modulationTypes = categorical(sort(["BPSK", "QPSK", "8PSK", ... 8 | "16QAM", "64QAM", "PAM4", "GFSK", "CPFSK", ... 9 | "B-FM", "DSB-AM", "SSB-AM"])); 10 | 11 | %% 设置控制变量 12 | runChannelInterference = true; % 设置为 true 以运行通道干扰 13 | runClockOffset = true; % 设置为 true 以运行时钟偏移 14 | runFrequencyOffset = true; % 设置为 true 以运行频率偏移 15 | runSampleRateOffset = true; % 设置为 true 以运行采样率偏移 16 | SNR = 18;%设置信噪比 17 | %% 生成用于训练的波形 18 | numFramesPerModType = 10000; 19 | percentTrainingSamples = 80; %训练百分比 20 | percentValidationSamples = 10; %验证百分比 21 | percentTestSamples = 10; %测试百分比 22 | sps = 8; % 每个符号样本数 23 | spf = 1024; %仿真时隙 24 | symbolsPerFrame = spf / sps; 25 | fs = 200e3; %采样率 26 | fc = [900e3 100e3]; % 中心频率 27 | % RRADAR 波形的起始百分 28 | rangeFc = [fs/7, fs/5]; % Center frequency (Hz) range 29 | 30 | %% 创建通道干扰 31 | std = sqrt(10.^(SNR/10)); 32 | 33 | awgnChannel = comm.AWGNChannel(... 34 | 'NoiseMethod', 'Signal to noise ratio (SNR)', ... 35 | 'SignalPower', 0.5, ... 36 | 'SNR', SNR); 37 | 38 | multipathChannel = comm.RicianChannel(... 39 | 'SampleRate', fs, ... 40 | 'PathDelays', [0 1.8 3.4]/fs, ... 41 | 'AveragePathGains', [0 -2 -10]./2, ... 42 | 'KFactor', 2, ... 43 | 'MaximumDopplerShift', 2); 44 | 45 | %% Clock Offset 46 | maxDeltaOff = 2;%5 47 | deltaOff = (rand()*2*maxDeltaOff) - maxDeltaOff; 48 | C = 1 + (deltaOff/1e6); 49 | 50 | %% 频率偏移 51 | offset = -(C-1)*fc(1); 52 | frequencyShifter = comm.PhaseFrequencyOffset(... 53 | 'SampleRate', fs, ... 54 | 'FrequencyOffset', offset); 55 | 56 | %% 采样率偏移 57 | channel = ModClassTestChannel(... 58 | 'SampleRate', fs, ... 59 | 'SNR', SNR, ... 60 | 'PathDelays', [0 1.8 3.4] / fs, ... 61 | 'AveragePathGains', [0 -2 -10]./2, ... 62 | 'KFactor', 2, ... 63 | 'MaximumDopplerShift', 2, ... 64 | 'MaximumClockOffset', 2, ... 65 | 'CenterFrequency', 900e3); 66 | 67 | chInfo = info(channel); 68 | 69 | %% 波形生成 70 | rng(12375) 71 | tic 72 | 73 | numModulationTypes = length(modulationTypes); 74 | 75 | channelInfo = info(channel); 76 | frameStore = ModClassFrameStore(... 77 | numFramesPerModType*numModulationTypes,spf,modulationTypes); 78 | transDelay = 20; 79 | 80 | for modType = 1:numModulationTypes 81 | fprintf('%s - 正在生成 %s \n', ... 82 | datestr(toc/86400,'HH:MM:SS'), modulationTypes(modType)) 83 | numSymbols = (numFramesPerModType / sps); 84 | dataSrc = getSource(modulationTypes(modType), sps, 2*spf, fs); 85 | modulator = ModClassGetModulator(modulationTypes(modType), sps, fs); 86 | 87 | if contains(char(modulationTypes(modType)), {'B-FM','DSB-AM','SSB-AM'}) 88 | channel.CenterFrequency = 100e3; 89 | else 90 | channel.CenterFrequency = 900e3; 91 | end 92 | 93 | for p=1:numFramesPerModType 94 | x = dataSrc(); 95 | y = modulator(x); 96 | 97 | % 添加通道干扰 98 | if runChannelInterference 99 | rxSamples = multipathChannel(y); % 多径衰落通道 100 | rxSamples = awgnChannel(rxSamples); % AWGN 通道 101 | else 102 | rxSamples = y; % 不添加通道干扰 103 | end 104 | 105 | % 添加时钟偏移 106 | if runClockOffset 107 | deltaOff = (rand()*2*maxDeltaOff) - maxDeltaOff; 108 | C = 1 + (deltaOff/1e6); 109 | else 110 | C = 1; % 不添加时钟偏移 111 | end 112 | 113 | % 添加频率偏移 114 | if runFrequencyOffset 115 | offset = -(C-1)*fc(1); 116 | rxSamples = frequencyShifter(rxSamples); % 频率偏移 117 | end 118 | 119 | % 添加采样率偏移 120 | if runSampleRateOffset 121 | channel.SampleRate = fs * C; % 采样率偏移 122 | end 123 | 124 | frame = ModClassFrameGenerator(rxSamples, spf, spf, transDelay, sps); 125 | add(frameStore, frame, modulationTypes(modType)); % 添加到框架存储 126 | end 127 | end 128 | 129 | %% 数据划分 130 | [mcfsTraining,mcfsValidation,mcfsTest] = splitData(frameStore,... 131 | [percentTrainingSamples,percentValidationSamples,percentTestSamples]); 132 | 133 | mcfsTraining.OutputFormat = "IQAsPages"; 134 | [rxTraining,rxTrainingLabel] = get(mcfsTraining); 135 | 136 | mcfsValidation.OutputFormat = "IQAsPages"; 137 | [rxValidation,rxValidationLabel] = get(mcfsValidation); 138 | 139 | mcfsTest.OutputFormat = "IQAsPages"; 140 | [rxTest,rxTestLabel] = get(mcfsTest); 141 | -------------------------------------------------------------------------------- /ModClassFrameGenerator.m: -------------------------------------------------------------------------------- 1 | function y = ModClassFrameGenerator(x, windowLength, stepSize, offset, sps) 2 | % %helperModClassFrameGenerator 生成用于机器学习的帧 3 | % % Y = helperModClassFrameGenerator(X,WLEN,STEP,OFFSET) 分段 4 | % % input, X,用于生成要用于机器学习算法的帧。 5 | % % X 必须是复值列向量。输出 Y 是一个大小 6 | % % WLENxN 复值数组,其中 N 是输出帧数。 7 | % % 每个单独的帧都有 WLEN 样本。窗口进行 STEP 8 | % 新帧的样本百分比。STEP 可以小于或大于 WLEN。 9 | % % 该函数在计算出 10 | % 基于 OFFSET 值的 % 初始偏移量。OFFSET 是双元素 11 | % % 实值向量,其中第一个元素是确定性偏移量 12 | % % 值,第二个元素是随机偏移量的最大值 13 | % % 值。总偏移量为 OFFSET(1)+randi([0 OFFSET(2)]) 个样本。这 14 | % 偏移的 % 确定性部分消除瞬态,而随机 15 | % % 部分使网络能够适应未知延迟值 16 | 17 | 18 | numSamples = length(x); 19 | numFrames = ... 20 | floor(((numSamples-offset)-(windowLength-stepSize))/stepSize); 21 | 22 | y = zeros([windowLength,numFrames],class(x)); 23 | 24 | startIdx = offset + randi([0 sps]); 25 | frameCnt = 1; 26 | 27 | while startIdx + windowLength < numSamples 28 | xWindowed = x(startIdx+(0:windowLength-1),1); 29 | framePower = sum(abs(xWindowed).^2); 30 | xWindowed = xWindowed / sqrt(framePower); 31 | y(:,frameCnt) = xWindowed; 32 | frameCnt = frameCnt + 1; 33 | startIdx = startIdx + stepSize; 34 | end 35 | -------------------------------------------------------------------------------- /ModClassFrameStore.m: -------------------------------------------------------------------------------- 1 | classdef ModClassFrameStore < handle 2 | %helperModClassFrameStore 管理调制分类数据 3 | % FS = helperModClassFrameStore 创建一个帧存储对象 FS,该对象 4 | % 以机器中可用的格式存储复杂的基带信号 5 | % 学习算法。 6 | % 7 | % FS = helperModClassFrameStore(MAXFR,SPF,LABELS) 创建帧存储 8 | % object,FH,最大帧数,MAXFR,每个 9 | % 帧、SPF 和预期标签 LABELS。 10 | % 11 | % 方法: 12 | % 13 | % add(FS,FRAMES,LABEL) 将 frame(s), FRAMES, with label, 添加到 14 | % 帧存储。 15 | % % 16 | % % [FRAMES,LABELS] = get(FS) 返回存储的帧和相应的 17 | % 来自帧存储的标签百分比,FS。 18 | % % 19 | % % 20 | 21 | properties 22 | OutputFormat = FrameStoreOutputFormat.IQAsRows 23 | end 24 | 25 | properties (SetAccess=private) 26 | %NumFrames 帧存储中的帧数 27 | NumFrames = 0 28 | %最大帧数 存储帧的容量 29 | MaximumNumFrames 30 | %每帧采样 每帧采样 31 | SamplesPerFrame 32 | %标签 预期标签集 33 | Labels 34 | end 35 | 36 | properties (Access=private) 37 | Frames 38 | Label 39 | end 40 | 41 | methods 42 | function obj = ModClassFrameStore(varargin) 43 | % 存储复杂的 I/Q 帧 44 | % FS = ModClassFrameStore(MAXFR,SPF,LABELS) 返回一个帧 45 | % 存储对象 FS,用于存储复 I/Q 基带帧,其类型为 46 | % LABEL,帧大小为 SPF。帧存储为 47 | % [SPFxNUMFRAMES] 数组。 48 | 49 | inputs = inputParser; 50 | addRequired(inputs, 'MaximumNumFrames') 51 | addRequired(inputs, 'SamplesPerFrame') 52 | addRequired(inputs, 'Labels') 53 | parse(inputs, varargin{:}) 54 | 55 | obj.SamplesPerFrame = inputs.Results.SamplesPerFrame; 56 | obj.MaximumNumFrames = inputs.Results.MaximumNumFrames; 57 | obj.Labels = inputs.Results.Labels; 58 | obj.Frames = ... 59 | zeros(obj.SamplesPerFrame,obj.MaximumNumFrames); 60 | obj.Label = repmat(obj.Labels(1),obj.MaximumNumFrames,1); 61 | end 62 | 63 | function add(obj,frames,label,varargin) 64 | % 将基带帧添加到帧存储中 65 | % add(FS,FRAMES,LABEL) 将带有标签 LABEL 的帧 FRAMES 添加到 66 | %帧存储 FS。 67 | 68 | numNewFrames = size(frames,2); 69 | if (~isscalar(label) && numNewFrames ~= length(label)) ... 70 | && (size(frames,1) ~= obj.SamplesPerFrame) 71 | error(message('comm_demos:ModClassFrameStore:MismatchedInputSize')); 72 | end 73 | 74 | % 添加框架 75 | startIdx = obj.NumFrames+1; 76 | endIdx = obj.NumFrames+numNewFrames; 77 | obj.Frames(:,startIdx:endIdx) = frames; 78 | 79 | % 添加标签类型 80 | if all(ismember(label,obj.Labels)) 81 | obj.Label(startIdx:endIdx,1) = label; 82 | else 83 | error(message('comm_demos:ModClassFrameStore:UnknownLabel',... 84 | label(~ismember(label,obj.Labels)))) 85 | end 86 | 87 | obj.NumFrames = obj.NumFrames + numNewFrames; 88 | end 89 | 90 | function [frames,labels] = get(obj) 91 | %get 返回帧和标签 92 | % [FRAMES,LABELS]=get(FS) 返回帧存储区 FS 中的帧和相应的 93 | % 返回帧存储区 FS 中的帧和相应的标签。 94 | % 95 | % 如果输出格式是 IQAsRows,那么 FRAMES 是一个大小为 96 | % [2xSPFx1xNUMFRAMES],其中第一行是同相分量,第二行是相位分量。 97 | % 第二行是正交分量。 98 | % 99 | % 如果输出格式为 IQAsPages,则 FRAMES 是大小为 % [1xSPFx2xNUMFRAMES] 的数组。 100 | % [1xSPFx2xNUMFRAMES],其中第一页(第 3 维)是同相分量,第二页是正交分量。 101 | % 同相分量,第二页为正交分量。 102 | % 分量。 103 | 104 | switch obj.OutputFormat 105 | case FrameStoreOutputFormat.IQAsRows 106 | I = real(obj.Frames(:,1:obj.NumFrames)); 107 | Q = imag(obj.Frames(:,1:obj.NumFrames)); 108 | I = permute(I,[3 1 4 2]); 109 | Q = permute(Q,[3 1 4 2]); 110 | frames = cat(1,I,Q); 111 | case FrameStoreOutputFormat.IQAsPages 112 | I = real(obj.Frames(:,1:obj.NumFrames)); 113 | Q = imag(obj.Frames(:,1:obj.NumFrames)); 114 | I = permute(I,[3 1 4 2]); 115 | Q = permute(Q,[3 1 4 2]); 116 | frames = cat(3,I,Q); 117 | end 118 | 119 | labels = obj.Label(1:obj.NumFrames,1); 120 | end 121 | 122 | function [fsTraining,fsValidation,fsTest] = ... 123 | splitData(obj,splitPercentages) 124 | % 将数据分为训练、验证和测试 125 | %[FSTRAIN,FSVALID,FSTEST]=splitData(FS,PER)会将存储的帧 126 | %的帧分成训练组、验证组和测试组。 127 | %的百分比,即 PER。PER 是一个三元素向量、 128 | % [PERTRAIN,PERVALID,PERTEST],指定了训练、验证和测试的百分比、 129 | % 验证和测试百分比。FSTRAIN、FSVALID 和 FSTEST 130 | % 分别是训练帧、验证帧和测试帧的存储空间。 131 | 132 | fsTraining = ModClassFrameStore(... 133 | ceil(obj.MaximumNumFrames*splitPercentages(1)/100), ... 134 | obj.SamplesPerFrame, obj.Labels); 135 | fsValidation = ModClassFrameStore(... 136 | ceil(obj.MaximumNumFrames*splitPercentages(2)/100), ... 137 | obj.SamplesPerFrame, obj.Labels); 138 | fsTest = ModClassFrameStore(... 139 | ceil(obj.MaximumNumFrames*splitPercentages(3)/100), ... 140 | obj.SamplesPerFrame, obj.Labels); 141 | 142 | for modType = 1:length(obj.Labels) 143 | rawIdx = find(obj.Label == obj.Labels(modType)); 144 | numFrames = length(rawIdx); 145 | 146 | % 首先洗框 147 | shuffleIdx = randperm(numFrames); 148 | frames = obj.Frames(:,rawIdx); 149 | frames = frames(:,shuffleIdx); 150 | 151 | numTrainingFrames = round(numFrames*splitPercentages(1)/100); 152 | numValidationFrames = round(numFrames*splitPercentages(2)/100); 153 | numTestFrames = round(numFrames*splitPercentages(3)/100); 154 | extraFrames = sum([numTrainingFrames,numValidationFrames,numTestFrames]) - numFrames; 155 | if (extraFrames > 0) 156 | numTestFrames = numTestFrames - extraFrames; 157 | end 158 | 159 | add(fsTraining, ... 160 | frames(:,1:numTrainingFrames), ... 161 | obj.Labels(modType)); 162 | add(fsValidation, ... 163 | frames(:,numTrainingFrames+(1:numValidationFrames)), ... 164 | obj.Labels(modType)); 165 | add(fsTest, ... 166 | frames(:,numTrainingFrames+numValidationFrames+(1:numTestFrames)), ... 167 | obj.Labels(modType)); 168 | end 169 | 170 | % 洗牌新帧存储 171 | shuffle(fsTraining); 172 | shuffle(fsValidation); 173 | shuffle(fsTest); 174 | end 175 | 176 | function shuffle(obj) 177 | % 洗卷存储的帧 178 | %shuffle(FS) 更改存储帧的顺序。 179 | 180 | shuffleIdx = randperm(obj.NumFrames); 181 | obj.Frames = obj.Frames(:,shuffleIdx); 182 | obj.Label = obj.Label(shuffleIdx,1); 183 | end 184 | end 185 | end 186 | 187 | -------------------------------------------------------------------------------- /ModClassGetModulator.m: -------------------------------------------------------------------------------- 1 | function modulator = ModClassGetModulator(modType, sps, fs) 2 | %ModClassGetModulator Modulation function selector 3 | % MOD = ModClassGetModulator(TYPE,SPS,FS) returns the modulator 4 | % function handle MOD based on TYPE. SPS is the number of samples per 5 | % symbol and FS is the sample rate. 6 | % 7 | % See also ModulationClassificationWithDeepLearningExample. 8 | 9 | % Copyright 2019 The MathWorks, Inc. 10 | 11 | switch modType 12 | case "BPSK" 13 | modulator = @(x)bpskModulator(x,sps); 14 | case "QPSK" 15 | modulator = @(x)qpskModulator(x,sps); 16 | case "8PSK" 17 | modulator = @(x)psk8Modulator(x,sps); 18 | case "16QAM" 19 | modulator = @(x)qam16Modulator(x,sps); 20 | case "64QAM" 21 | modulator = @(x)qam64Modulator(x,sps); 22 | case "GFSK" 23 | modulator = @(x)gfskModulator(x,sps); 24 | case "CPFSK" 25 | modulator = @(x)cpfskModulator(x,sps); 26 | case "PAM4" 27 | modulator = @(x)pam4Modulator(x,sps); 28 | case "B-FM" 29 | modulator = @(x)bfmModulator(x, fs); 30 | case "DSB-AM" 31 | modulator = @(x)dsbamModulator(x, fs); 32 | case "SSB-AM" 33 | modulator = @(x)ssbamModulator(x, fs); 34 | end 35 | end 36 | 37 | function y = bpskModulator(x,sps) 38 | %bpskModulator BPSK modulator with pulse shaping 39 | % Y = bpskModulator(X,SPS) BPSK modulates the input X, and returns the 40 | % root-raised cosine pulse shaped signal Y. X must be a column vector 41 | % of values in the set [0 1]. The root-raised cosine filter has a 42 | % roll-off factor of 0.35 and spans four symbols. The output signal 43 | % Y has unit power. 44 | 45 | persistent filterCoeffs 46 | if isempty(filterCoeffs) 47 | filterCoeffs = rcosdesign(0.35, 4, sps); 48 | end 49 | % Modulate 50 | syms = pskmod(x,2); 51 | % Pulse shape 52 | y = filter(filterCoeffs, 1, upsample(syms,sps)); 53 | end 54 | 55 | function y = qpskModulator(x,sps) 56 | %qpskModulator QPSK modulator with pulse shaping 57 | % Y = qpskModulator(X,SPS) QPSK modulates the input X, and returns the 58 | % root-raised cosine pulse shaped signal Y. X must be a column vector 59 | % of values in the set [0 3]. The root-raised cosine filter has a 60 | % roll-off factor of 0.35 and spans four symbols. The output signal 61 | % Y has unit power. 62 | 63 | persistent filterCoeffs 64 | if isempty(filterCoeffs) 65 | filterCoeffs = rcosdesign(0.35, 4, sps); 66 | end 67 | % Modulate 68 | syms = pskmod(x,4,pi/4); 69 | % Pulse shape 70 | y = filter(filterCoeffs, 1, upsample(syms,sps)); 71 | end 72 | 73 | function y = psk8Modulator(x,sps) 74 | %psk8Modulator 8-PSK modulator with pulse shaping 75 | % Y = psk8Modulator(X,SPS) 8-PSK modulates the input X, and returns the 76 | % root-raised cosine pulse shaped signal Y. X must be a column vector 77 | % of values in the set [0 7]. The root-raised cosine filter has a 78 | % roll-off factor of 0.35 and spans four symbols. The output signal 79 | % Y has unit power. 80 | 81 | persistent filterCoeffs 82 | if isempty(filterCoeffs) 83 | filterCoeffs = rcosdesign(0.35, 4, sps); 84 | end 85 | % Modulate 86 | syms = pskmod(x,8); 87 | % Pulse shape 88 | y = filter(filterCoeffs, 1, upsample(syms,sps)); 89 | end 90 | 91 | function y = qam16Modulator(x,sps) 92 | %qam16Modulator 16-QAM modulator with pulse shaping 93 | % Y = qam16Modulator(X,SPS) 16-QAM modulates the input X, and returns the 94 | % root-raised cosine pulse shaped signal Y. X must be a column vector 95 | % of values in the set [0 15]. The root-raised cosine filter has a 96 | % roll-off factor of 0.35 and spans four symbols. The output signal 97 | % Y has unit power. 98 | 99 | persistent filterCoeffs 100 | if isempty(filterCoeffs) 101 | filterCoeffs = rcosdesign(0.35, 4, sps); 102 | end 103 | % Modulate and pulse shape 104 | syms = qammod(x,16,'UnitAveragePower',true); 105 | % Pulse shape 106 | y = filter(filterCoeffs, 1, upsample(syms,sps)); 107 | end 108 | 109 | function y = qam64Modulator(x,sps) 110 | %qam64Modulator 64-QAM modulator with pulse shaping 111 | % Y = qam64Modulator(X,SPS) 64-QAM modulates the input X, and returns the 112 | % root-raised cosine pulse shaped signal Y. X must be a column vector 113 | % of values in the set [0 63]. The root-raised cosine filter has a 114 | % roll-off factor of 0.35 and spans four symbols. The output signal 115 | % Y has unit power. 116 | 117 | persistent filterCoeffs 118 | if isempty(filterCoeffs) 119 | filterCoeffs = rcosdesign(0.35, 4, sps); 120 | end 121 | % Modulate 122 | syms = qammod(x,64,'UnitAveragePower',true); 123 | % Pulse shape 124 | y = filter(filterCoeffs, 1, upsample(syms,sps)); 125 | end 126 | 127 | function y = pam4Modulator(x,sps) 128 | %pam4Modulator PAM4 modulator with pulse shaping 129 | % Y = pam4Modulator(X,SPS) PAM4 modulates the input X, and returns the 130 | % root-raised cosine pulse shaped signal Y. X must be a column vector 131 | % of values in the set [0 3]. The root-raised cosine filter has a 132 | % roll-off factor of 0.35 and spans four symbols. The output signal 133 | % Y has unit power. 134 | 135 | persistent filterCoeffs amp 136 | if isempty(filterCoeffs) 137 | filterCoeffs = rcosdesign(0.35, 4, sps); 138 | amp = 1 / sqrt(mean(abs(pammod(0:3, 4)).^2)); 139 | end 140 | % Modulate 141 | syms = amp * pammod(x,4); 142 | % Pulse shape 143 | y = filter(filterCoeffs, 1, upsample(syms,sps)); 144 | end 145 | 146 | function y = gfskModulator(x,sps) 147 | %gfskModulator GFSK modulator 148 | % Y = gfskModulator(X,SPS) GFSK modulates the input X and returns the 149 | % signal Y. X must be a column vector of values in the set [0 1]. The 150 | % BT product is 0.35 and the modulation index is 1. The output signal 151 | % Y has unit power. 152 | 153 | persistent mod meanM 154 | if isempty(mod) 155 | M = 2; 156 | mod = comm.CPMModulator(... 157 | 'ModulationOrder', M, ... 158 | 'FrequencyPulse', 'Gaussian', ... 159 | 'BandwidthTimeProduct', 0.35, ... 160 | 'ModulationIndex', 1, ... 161 | 'SamplesPerSymbol', sps); 162 | meanM = mean(0:M-1); 163 | end 164 | % Modulate 165 | y = mod(2*(x-meanM)); 166 | end 167 | 168 | function y = cpfskModulator(x,sps) 169 | %cpfskModulator CPFSK modulator 170 | % Y = cpfskModulator(X,SPS) CPFSK modulates the input X and returns 171 | % the signal Y. X must be a column vector of values in the set [0 1]. 172 | % the modulation index is 0.5. The output signal Y has unit power. 173 | 174 | persistent mod meanM 175 | if isempty(mod) 176 | M = 2; 177 | mod = comm.CPFSKModulator(... 178 | 'ModulationOrder', M, ... 179 | 'ModulationIndex', 0.5, ... 180 | 'SamplesPerSymbol', sps); 181 | meanM = mean(0:M-1); 182 | end 183 | % Modulate 184 | y = mod(2*(x-meanM)); 185 | end 186 | 187 | function y = bfmModulator(x,fs) 188 | %bfmModulator Broadcast FM modulator 189 | % Y = bfmModulator(X,FS) broadcast FM modulates the input X and returns 190 | % the signal Y at the sample rate FS. X must be a column vector of 191 | % audio samples at the sample rate FS. The frequency deviation is 75 kHz 192 | % and the pre-emphasis filter time constant is 75 microseconds. 193 | 194 | persistent mod 195 | if isempty(mod) 196 | mod = comm.FMBroadcastModulator(... 197 | 'AudioSampleRate', fs, ... 198 | 'SampleRate', fs); 199 | end 200 | y = mod(x); 201 | end 202 | 203 | function y = dsbamModulator(x,fs) 204 | %dsbamModulator Double sideband AM modulator 205 | % Y = dsbamModulator(X,FS) double sideband AM modulates the input X and 206 | % returns the signal Y at the sample rate FS. X must be a column vector of 207 | % audio samples at the sample rate FS. The IF frequency is 50 kHz. 208 | 209 | y = ammod(x,50e3,fs); 210 | end 211 | 212 | function y = ssbamModulator(x,fs) 213 | %ssbamModulator Single sideband AM modulator 214 | % Y = ssbamModulator(X,FS) single sideband AM modulates the input X and 215 | % returns the signal Y at the sample rate FS. X must be a column vector of 216 | % audio samples at the sample rate FS. The IF frequency is 50 kHz. 217 | 218 | y = ssbmod(x,50e3,fs); 219 | end -------------------------------------------------------------------------------- /ModClassIQAsPages.m: -------------------------------------------------------------------------------- 1 | function out = ModClassIQAsPages(in) 2 | %helperModClassIQAsPages Transform complex input to I/Q as pages 3 | % OUT = helperModClassIQAsPages(IN) transforms input, IN, which is a cell 4 | % array where the first element is the complex frame and the second 5 | % element is the label string. The output, OUT, has a frame where I/Q are 6 | % placed in the third dimension, separately, such that the size of the 7 | % output frame is [1xSPFx2], where SPF is samples per frame. 8 | % 9 | % See also ModulationClassificationWithDeepLearningExample. 10 | 11 | % Copyright 2019 The MathWorks, Inc. 12 | 13 | frameComplex = in{1}; 14 | frameLabel = in{2}; 15 | 16 | I = permute(real(frameComplex), [2 1]); 17 | Q = permute(imag(frameComplex), [2 1]); 18 | frameReal = cat(3, I, Q); 19 | 20 | 21 | out = {frameReal, frameLabel}; 22 | end 23 | 24 | -------------------------------------------------------------------------------- /ModClassPlotFrequencyDomain.m: -------------------------------------------------------------------------------- 1 | function ModClassPlotFrequencyDomain(dataDirectory, modulationTypes, fs) 2 | numTypes = length(modulationTypes); 3 | numRows = ceil(numTypes / 4); 4 | figure('Name', 'Frequency Domain Signals'); 5 | 6 | for modTypeIdx = 1:numTypes 7 | subplot(numRows, 4, modTypeIdx); 8 | files = dir(fullfile(dataDirectory, "*" + string(modulationTypes(modTypeIdx)) + "*")); 9 | idx = randi([1, length(files)]); 10 | load(fullfile(files(idx).folder, files(idx).name), 'frame'); 11 | 12 | spf = size(frame, 1); 13 | f = (-fs/2:fs/spf:fs/2 - fs/spf); 14 | 15 | frame_fft = fftshift(fft(frame)); 16 | plot(f, abs(frame_fft), '-'); 17 | grid on; 18 | axis tight; 19 | title(string(modulationTypes(modTypeIdx))); 20 | xlabel('Frequency (Hz)'); 21 | ylabel('Magnitude'); 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /ModClassTestChannel.m: -------------------------------------------------------------------------------- 1 | classdef ModClassTestChannel < matlab.System 2 | %ModClassTestChannel Test channel for modulation classification 3 | % CH = helperModClassTestChannel creates an channel System object, CH. 4 | % This object adds multipath fading, clock offset effects, and white 5 | % Gaussian noise to a framed signal. 6 | % 7 | % CH = ModClassTestChannel(Name,Value) creates a channel object, 8 | % CH, with the specified property Name set to the specified Value. You 9 | % can specify additional name-value pair arguments in any order as 10 | % (Name1,Value1,...,NameN,ValueN). 11 | % 12 | % The channel object uses the default MATLAB random stream. Reset the 13 | % default stream for repeatable simulations. Type 'help RandStream' for 14 | % more information. 15 | % 16 | % Step method syntax: 17 | % 18 | % Y = step(CH,X) adds multipath fading, clock offset effects, and white 19 | % Gaussian noise to input X and returns the result in Y. The input X must 20 | % be a double or single precision data type column vector. Each frame is 21 | % impaired with an independent channel. The channel applies following 22 | % impairments in the given order: 23 | % 24 | % 1) Add Rician multipath fading to input, X, based on PathDelays, 25 | % AveragePathGains, KFactor, and MaximumDopplerShift settings. Channel 26 | % path gains are regenerated for each frame, which provides independent 27 | % path gain values for each frame. 28 | % 29 | % 2) Add clock offset effects. 30 | % a) Frequency offset, which is determined by the clock offset (ppm) 31 | % and the center frequency, as fOffset = -(C-1)*fc, where fc is the 32 | % center frequency in Hz and C is the clock offset factor. clock offset 33 | % factor, C, is calculated as C = (1+offset/1e6), where offset is the 34 | % clock offset in ppm. 35 | % b) Sampling offset, which is determined by the clock offset (ppm) and 36 | % sampling rate, fs. This method first generates a clock offset value, 37 | % offset, in ppm, based on the specified maximum clock offset and 38 | % calculates the offset factor, C, as C = (1+offset/1e6), where offset 39 | % is the clock offset in ppm. The signal is resampled using interp1 40 | % function at a new sampling rate of C*fs. 41 | % 42 | % 3) Add Gaussian noise based on the specified SNR value. Channel object, 43 | % CH, assumes that the input signal is normalized to unity power. 44 | % 45 | % System objects may be called directly like a function instead of using 46 | % the step method. For example, y = step(obj, x) and y = obj(x) are 47 | % equivalent. 48 | % 49 | % ModClassTestChannel methods: 50 | % 51 | % step - Add channel impairments to input signal (see above) 52 | % release - Allow property value and input characteristics changes 53 | % clone - Create a channel object with same property values 54 | % isLocked - Locked status (logical) 55 | % reset - Reset channel object 56 | % 57 | % ModClassTestChannel properties: 58 | % 59 | % SNR - SNR (dB) 60 | % CenterFrequency - Center frequency (Hz) 61 | % SampleRate - Input signal sample rate (Hz) 62 | % PathDelays - Discrete path delay vector (s) 63 | % AveragePathGains - Average path gain vector (dB) 64 | % KFactor - Rician K-factor (linear scale) 65 | % MaximumDopplerShift - Maximum Doppler shift (Hz) 66 | % MaximumClockOffset - Maximum clock offset (ppm) 67 | % 68 | % See also ModulationClassificationWithDeepLearningExample. 69 | 70 | % Copyright 2018 The MathWorks, Inc. 71 | 72 | properties 73 | %SNR SNR (dB) 74 | % Specify the SNR value in decibels. Set this property to a numeric, 75 | % real scalar. The default is 20 dB. This property is tunable. 76 | SNR = 20 77 | %CenterFrequency Center frequency (Hz) 78 | % Specify the center frequency as a double precision nonnegative 79 | % scalar. The default is 2.4 GHz. Center frequency value is used to 80 | % calculate expected frequency offset in the received signal based on 81 | % the maximum clock offset value. This property is tunable. 82 | CenterFrequency = 2.4e9 83 | end 84 | 85 | properties (Nontunable) 86 | %SampleRate Sample rate (Hz) 87 | % Specify the sample rate of the input signal in Hz as a double 88 | % precision, real, positive scalar. The default is 1 Hz. 89 | SampleRate = 1 90 | %PathDelays Discrete path delays (s) 91 | % Specify the delays of the discrete paths in seconds as a double 92 | % precision, real, scalar or row vector. When PathDelays is a scalar, 93 | % the channel is frequency-flat; When PathDelays is a vector, the 94 | % channel is frequency-selective. The default is 0. 95 | PathDelays = 0 96 | %AveragePathGains Average path gains (dB) 97 | % Specify the average gains of the discrete paths in dB as a double 98 | % precision, real, scalar or row vector. AveragePathGains must have 99 | % the same size as PathDelays. The default is 0. 100 | AveragePathGains = 0 101 | %KFactor K-factors 102 | % Specify the K factor of a Rician fading channel as a double 103 | % precision, real, positive scalar. The first discrete path is a 104 | % Rician fading process with a Rician K-factor of KFactor and the 105 | % remaining discrete paths are independent Rayleigh fading processes. 106 | % The default is 3. 107 | KFactor = 3 108 | %MaximumDopplerShift Maximum Doppler shift (Hz) 109 | % Specify the maximum Doppler shift for the path(s) of the channel in 110 | % Hz as a double precision, real, nonnegative scalar. It applies to 111 | % all the paths of the channel. When MaximumDopplerShift is 0, the 112 | % channel is static for the entire input and you can use the reset 113 | % method to generate a new channel realization. The 114 | % MaximumDopplerShift must be smaller than SampleRate/10 for each 115 | % path. The default is 0. 116 | MaximumDopplerShift = 0 117 | %MaximumClockOffset Maximum clock offset (ppm) 118 | % Specify the maximum clock offset in ppm as a double precision, 119 | % real, non-negative scalar. Channel generates a uniformly 120 | % distributed random clock offset value between -MaximumClockOffset 121 | % and MaximumClockOffset for each frame. This clock offset value is 122 | % used to calculate frequency and timing offset for the current 123 | % frame. The default is 0. 124 | MaximumClockOffset = 0 125 | end 126 | 127 | properties(Access = private) 128 | MultipathChannel 129 | FrequencyShifter 130 | TimingShifter 131 | C % 1+(ppm/1e6) 132 | end 133 | 134 | methods 135 | function obj = ModClassTestChannel(varargin) 136 | % Support name-value pair arguments when constructing object 137 | setProperties(obj,nargin,varargin{:}) 138 | end 139 | end 140 | 141 | methods(Access = protected) 142 | function setupImpl(obj) 143 | obj.MultipathChannel = comm.RicianChannel(... 144 | 'SampleRate', obj.SampleRate, ... 145 | 'PathDelays', obj.PathDelays, ... 146 | 'AveragePathGains', obj.AveragePathGains, ... 147 | 'KFactor', obj.KFactor, ... 148 | 'MaximumDopplerShift', obj.MaximumDopplerShift); 149 | obj.FrequencyShifter = comm.PhaseFrequencyOffset(... 150 | 'SampleRate', obj.SampleRate); 151 | end 152 | 153 | function y = stepImpl(obj,x) 154 | % Add channel impairments 155 | 156 | yInt1 = addMultipathFading(obj,x); 157 | yInt2 = addClockOffset(obj, yInt1); 158 | y = addNoise(obj, yInt2); 159 | end 160 | 161 | function out = addMultipathFading(obj, in) 162 | %addMultipathFading Add Rician multipath fading 163 | % Y=addMultipathFading(CH,X) adds Rician multipath fading effects 164 | % to input, X, based on PathDelays, AveragePathGains, KFactor, and 165 | % MaximumDopplerShift settings. Channel path gains are regenerated 166 | % for each frame, which provides independent path gain values for 167 | % each frame. 168 | 169 | % Get new path gains 170 | reset(obj.MultipathChannel) 171 | % Pass input through the new channel 172 | out = obj.MultipathChannel(in); 173 | end 174 | 175 | function out = addClockOffset(obj, in) 176 | %addClockOffset Add effects of clock offset 177 | % Y=addClockOffset(CH,X) adds effects of clock offset. Clock offset 178 | % has two effects on the received signal: 1) Frequency offset, 179 | % which is determined by the clock offset (ppm) and the carrier 180 | % frequency; 2) Sampling time drift, which is determined by the 181 | % clock offset (ppm) and sampling rate. This method first generates 182 | % a clock offset value in ppm, based on the specified maximum clock 183 | % offset and calculates the offset factor, C, as 184 | % 185 | % C = (1+offset/1e6), where offset is the clock offset in ppm. 186 | % 187 | % applyFrequencyOffset and applyTimingDrift add frequency offset 188 | % and sampling time drift to the signal, respectively. 189 | 190 | % Determine clock offset factor 191 | maxOffset = obj.MaximumClockOffset; 192 | clockOffset = (rand() * 2*maxOffset) - maxOffset; 193 | obj.C = 1 + clockOffset / 1e6; 194 | 195 | % Add frequency offset 196 | outInt1 = applyFrequencyOffset(obj, in); 197 | 198 | % Add sampling time drift 199 | out = applyTimingDrift(obj, outInt1); 200 | end 201 | 202 | function out = applyFrequencyOffset(obj, in) 203 | %applyFrequencyOffset Apply frequency offset 204 | % Y=applyFrequencyOffset(CH,X) applies frequency offset to input, 205 | % X, based on the clock offset for the current frame and center 206 | % frequency. 207 | % 208 | % fOffset = -(C-1)*fc, where fc is center frequency in Hz 209 | % y = x .* exp(1i*2*pi*fOffset*t) 210 | 211 | obj.FrequencyShifter.FrequencyOffset = ... 212 | -(obj.C-1)*obj.CenterFrequency; 213 | out = obj.FrequencyShifter(in); 214 | end 215 | 216 | function out = applyTimingDrift(obj, in) 217 | %applyTimingDrift Apply sampling time drift 218 | % Y=applyTimingDrift(CH,X) applies sampling time drift to 219 | % input, X, based on the clock offset for the current frame and 220 | % specified sampling rate, Fs. X is resampled at C*Fs Hz using 221 | % linear interpolation. 222 | 223 | originalFs = obj.SampleRate; 224 | x = (0:length(in)-1)' / originalFs; 225 | newFs = originalFs * obj.C; 226 | xp = (0:length(in)-1)' / newFs; 227 | out = interp1(x, in, xp); 228 | end 229 | 230 | function out = addNoise(obj, in) 231 | %addNoise Add Gaussian noise 232 | % Y=addNoise(CH,X) adds Gaussian noise to input, X, based on the 233 | % specified SNR value. Channel object, CH, assumes that the input 234 | % signal is normalized to unity power. 235 | out = awgn(in,obj.SNR); 236 | end 237 | 238 | function resetImpl(obj) 239 | reset(obj.MultipathChannel); 240 | reset(obj.FrequencyShifter); 241 | end 242 | 243 | function s = infoImpl(obj) 244 | if isempty(obj.MultipathChannel) 245 | setupImpl(obj); 246 | end 247 | 248 | % Get channel delay from fading channel object delay 249 | mpInfo = info(obj.MultipathChannel); 250 | 251 | % Calculate maximum frequency offset 252 | maxClockOffset = obj.MaximumClockOffset; 253 | maxFreqOffset = (maxClockOffset / 1e6) * obj.CenterFrequency; 254 | 255 | % Calculate maximum timing offset 256 | maxClockOffset = obj.MaximumClockOffset; 257 | maxSampleRateOffset = (maxClockOffset / 1e6) * obj.SampleRate; 258 | 259 | s = struct('ChannelDelay', ... 260 | mpInfo.ChannelFilterDelay, ... 261 | 'MaximumFrequencyOffset', maxFreqOffset, ... 262 | 'MaximumSampleRateOffset', maxSampleRateOffset); 263 | end 264 | end 265 | end 266 | -------------------------------------------------------------------------------- /NET_model_CNN.m: -------------------------------------------------------------------------------- 1 | %% 定义神经网络模型 2 | numModTypes = numel(modulationTypes); 3 | netWidth = 2; 4 | filterSize = [1 sps]; 5 | poolSize = [1 2]; 6 | 7 | Layers_CNN = [ 8 | imageInputLayer([1 spf 2], 'Normalization', 'none', 'Name', 'Input Layer') 9 | 10 | convolution2dLayer(filterSize, 8*netWidth, 'Padding', 'same', 'Name', 'CNN1') 11 | batchNormalizationLayer('Name', 'BN1') 12 | reluLayer('Name', 'ReLU1') 13 | maxPooling2dLayer(poolSize, 'Stride', [1 2], 'Name', 'MaxPool1') 14 | 15 | convolution2dLayer(filterSize, 16*netWidth, 'Padding', 'same', 'Name', 'CNN2') 16 | batchNormalizationLayer('Name', 'BN2') 17 | reluLayer('Name', 'ReLU2') 18 | maxPooling2dLayer(poolSize, 'Stride', [1 2], 'Name', 'MaxPool2') 19 | 20 | convolution2dLayer(filterSize, 24*netWidth, 'Padding', 'same', 'Name', 'CNN3') 21 | batchNormalizationLayer('Name', 'BN3') 22 | reluLayer('Name', 'ReLU3') 23 | maxPooling2dLayer(poolSize, 'Stride', [1 2], 'Name', 'MaxPool3') 24 | 25 | convolution2dLayer(filterSize, 40*netWidth, 'Padding', 'same', 'Name', 'CNN4') 26 | batchNormalizationLayer('Name', 'BN4') 27 | reluLayer('Name', 'ReLU4') 28 | maxPooling2dLayer(poolSize, 'Stride', [1 2], 'Name', 'MaxPool4') 29 | 30 | convolution2dLayer(filterSize, 56*netWidth, 'Padding', 'same', 'Name', 'CNN5') 31 | batchNormalizationLayer('Name', 'BN5') 32 | reluLayer('Name', 'ReLU5') 33 | maxPooling2dLayer(poolSize, 'Stride', [1 2], 'Name', 'MaxPool5') 34 | 35 | convolution2dLayer(filterSize, 72*netWidth, 'Padding', 'same', 'Name', 'CNN6') 36 | batchNormalizationLayer('Name', 'BN6') 37 | reluLayer('Name', 'ReLU6') 38 | maxPooling2dLayer(poolSize, 'Stride', [1 2], 'Name', 'MaxPool6') 39 | 40 | % Added by Rachana 41 | convolution2dLayer(filterSize, 104*netWidth, 'Padding', 'same', 'Name', 'CNN7') 42 | batchNormalizationLayer('Name', 'BN7') 43 | reluLayer('Name', 'ReLU7') 44 | 45 | averagePooling2dLayer([1 ceil(spf/64)], 'Name', 'AP1') 46 | 47 | fullyConnectedLayer(numModTypes, 'Name', 'FC1') 48 | softmaxLayer('Name', 'SoftMax') 49 | 50 | classificationLayer('Name', 'Output') ]; 51 | 52 | 53 | % 定义训练选项 54 | 55 | maxEpochs = 20; 56 | miniBatchSize = 1024; 57 | validationFrequency = floor(numel(rxTrainingLabel)/miniBatchSize); 58 | Options_CNN = trainingOptions('adam', ... 59 | 'InitialLearnRate',1e-2, ... 60 | 'MaxEpochs',maxEpochs, ... 61 | 'MiniBatchSize',miniBatchSize, ... 62 | 'Shuffle','every-epoch', ... 63 | 'Plots','training-progress', ... 64 | 'Verbose',true, ... 65 | 'ValidationData',{rxValidation,rxValidationLabel}, ... 66 | 'ValidationFrequency',validationFrequency, ... 67 | 'LearnRateSchedule', 'piecewise', ... 68 | 'LearnRateDropPeriod', 9, ... 69 | 'LearnRateDropFactor', 0.2, ... 70 | 'ExecutionEnvironment', 'multi-gpu'); 71 | %% 训练 CNN 模型 72 | fprintf('%s - Training the CNN network\n', datestr(toc/86400,'HH:MM:SS')) 73 | CNN_NET = trainNetwork(rxTraining,rxTrainingLabel,Layers_CNN,Options_CNN); 74 | % 评估网络 75 | 76 | fprintf('%s - Classifying test frames\n', datestr(toc/86400,'HH:MM:SS')) 77 | rxTestPred_CNN = classify(CNN_NET,rxTest); 78 | testAccuracy_CNN = mean(rxTestPred_CNN == rxTestLabel); 79 | disp("Test accuracy: " + testAccuracy_CNN*100 + "%") 80 | 81 | %% 混淆矩阵绘制 82 | 83 | figure 84 | cm = confusionchart(rxTestLabel, rxTestPred_CNN); 85 | cm.Title = 'Confusion Matrix for Test Data(CNN)'; 86 | cm.RowSummary = 'row-normalized'; 87 | % cm.Normalization = 'total-normalized'; 88 | sortClasses(cm,'descending-diagonal') 89 | cm.Parent.Position = [cm.Parent.Position(1:2) 740 424]; -------------------------------------------------------------------------------- /NET_model_DNN.m: -------------------------------------------------------------------------------- 1 | %% 定义特征提取函数 2 | % 计算波形形状特征 3 | function shapeFeatures = computeWaveformShape(signal) 4 | 5 | 6 | % 峰值 7 | peakToPeak = max(signal) - min(signal); 8 | 9 | % 均方根值 10 | rmsValue = rms(signal); 11 | 12 | % 波形因子 13 | waveformFactor = rmsValue / mean(abs(signal), 'all'); % 明确指定在所有维度上取平均值 14 | 15 | % 时域零交叉率 16 | zeroCrossingRate = sum(abs(diff(sign(signal)))) / (2 * length(signal)); 17 | 18 | % 波形斜率 19 | slope = diff(signal); 20 | 21 | % 汇总波形形状特征 22 | shapeFeatures = [peakToPeak, rmsValue, waveformFactor, ... 23 | zeroCrossingRate, slope]; 24 | end 25 | function features = extractFeatures(signal) 26 | % 时域特征 27 | meanVal = mean(signal); 28 | variance = var(signal); 29 | peakValue = max(signal); 30 | skewnessVal = skewness(signal); 31 | kurtosisVal = kurtosis(signal); 32 | meanAbsDev = mean(abs(signal - meanVal)); 33 | % 波形特征 34 | waveformShape = computeWaveformShape(signal); 35 | 36 | % 汇总所有特征 37 | features = [meanVal, variance, peakValue, skewnessVal, kurtosisVal,... 38 | meanAbsDev, waveformShape]; 39 | end 40 | %% 特征提取 41 | % 初始化用于存储特征的单元数组 42 | trainFeatures_DNN = cell(size(rxTraining, 4), 1); 43 | validationFeatures_DNN = cell(size(rxValidation, 4), 1); 44 | testFeatures_DNN = cell(size(rxTest, 4), 1); 45 | 46 | % 提取训练、验证和测试数据的特征 47 | for ii = 1:size(rxTraining, 4) 48 | trainFeatures_DNN{ii} = extractFeatures(rxTraining(:, :, :, ii)); 49 | end 50 | 51 | for ii = 1:size(rxValidation, 4) 52 | validationFeatures_DNN{ii} = extractFeatures(rxValidation(:, :, :, ii)); 53 | end 54 | 55 | for ii = 1:size(rxTest, 4) 56 | testFeatures_DNN{ii} = extractFeatures(rxTest(:, :, :, ii)); 57 | end 58 | 59 | % 将特征转换为矩阵形式,保留四维结构 60 | trainingData_DNN = cat(4, trainFeatures_DNN{:}); 61 | validationData_DNN = cat(4, validationFeatures_DNN{:}); 62 | testData_DNN = cat(4, testFeatures_DNN{:}); 63 | 64 | 65 | %% 定义神经网络模型 66 | numModTypes = numel(modulationTypes); 67 | Layers_DNN = [ 68 | imageInputLayer([1 1033 2], 'Normalization', 'none', 'Name', 'InputLayer') 69 | fullyConnectedLayer(64 * numModTypes, 'Name', 'FC1') 70 | reluLayer('Name', 'ReLU1') 71 | dropoutLayer() 72 | fullyConnectedLayer(64 * numModTypes, 'Name', 'FC2') 73 | reluLayer('Name', 'ReLU2') 74 | dropoutLayer() 75 | fullyConnectedLayer(numModTypes, 'Name', 'FC3') 76 | softmaxLayer('Name', 'SoftMax') 77 | classificationLayer('Name', 'OutputLayer')]; 78 | 79 | % 定义训练选项 80 | maxEpochs = 50; 81 | miniBatchSize = 1024; 82 | validationFrequency = floor(numel(rxTrainingLabel)/miniBatchSize); 83 | Options_DNN = trainingOptions('adam', ... 84 | 'InitialLearnRate', 0.0013, ... 85 | 'MaxEpochs', maxEpochs, ... 86 | 'MiniBatchSize', miniBatchSize, ... 87 | 'Shuffle', 'every-epoch', ... 88 | 'Plots', 'training-progress', ... 89 | 'Verbose', true, ... 90 | 'ValidationData', {validationData_DNN, rxValidationLabel}, ... 91 | 'ValidationFrequency', validationFrequency, ... 92 | 'LearnRateSchedule', 'piecewise', ... 93 | 'LearnRateDropPeriod', 15, ... 94 | 'LearnRateDropFactor', 0.9,... 95 | 'ExecutionEnvironment', 'multi-gpu'); 96 | %% 训练 DNN 模型 97 | fprintf('%s - Training the DNN network\n', datestr(toc/86400,'HH:MM:SS')) 98 | DNN_NET = trainNetwork(trainingData_DNN, rxTrainingLabel, Layers_DNN, Options_DNN); 99 | 100 | % 评估网络 101 | fprintf('%s - Classifying test frames\n', datestr(toc/86400,'HH:MM:SS')) 102 | rxTestPred_DNN = classify(DNN_NET, testData_DNN); 103 | testAccuracy_DNN = mean(rxTestPred_DNN == rxTestLabel); 104 | disp("Test accuracy: " + testAccuracy_DNN*100 + "%") 105 | 106 | %% 混淆矩阵绘制 107 | figure 108 | cm = confusionchart(rxTestLabel, rxTestPred_DNN); 109 | cm.Title = 'Confusion Matrix for Validation Data (DNN)'; 110 | cm.RowSummary = 'row-normalized'; 111 | %cm.Normalization = 'total-normalized'; 112 | sortClasses(cm,'descending-diagonal') 113 | cm.Parent.Position = [cm.Parent.Position(1:2) 740 424]; 114 | -------------------------------------------------------------------------------- /NET_model_RNN.m: -------------------------------------------------------------------------------- 1 | 2 | % 初始化用于存储特征的单元数组 3 | trainFeatures_RNN = cell(size(rxTraining, 4), 1); 4 | validationFeatures_RNN = cell(size(rxValidation, 4), 1); 5 | testFeatures_RNN = cell(size(rxTest, 4), 1); 6 | 7 | % 提取训练、验证和测试数据的特征 8 | for ii = 1:size(rxTraining, 4) 9 | trainFeatures_RNN{ii} = extractFeatures(rxTraining(:, :, :, ii)); 10 | end 11 | 12 | for ii = 1:size(rxValidation, 4) 13 | validationFeatures_RNN{ii} = extractFeatures(rxValidation(:, :, :, ii)); 14 | end 15 | 16 | for ii = 1:size(rxTest, 4) 17 | testFeatures_RNN{ii} = extractFeatures(rxTest(:, :, :, ii)); 18 | end 19 | 20 | % 模型训练和测试 21 | numModTypes=numel(modulationTypes); 22 | %初始化 23 | trainingData_RNN = cellfun(@(x) reshape(x, [], 2066, 1), trainFeatures_RNN, 'UniformOutput', false); 24 | testData_RNN = cellfun(@(x) reshape(x, [], 2066, 1), testFeatures_RNN, 'UniformOutput', false); 25 | validationData_RNN = cellfun(@(x) reshape(x, [], 2066, 1), validationFeatures_RNN, 'UniformOutput', false); 26 | 27 | trainingData_RNN = cellfun(@(x) permute(x, [2, 1, 3]), trainingData_RNN, 'UniformOutput', false); 28 | testData_RNN = cellfun(@(x) permute(x, [2, 1, 3]), testData_RNN, 'UniformOutput', false); 29 | validationData_RNN = cellfun(@(x) permute(x, [2, 1, 3]), validationData_RNN, 'UniformOutput', false); 30 | 31 | % 定义神经网络模型 32 | Layers_RNN = [ 33 | sequenceInputLayer(2066, 'Name', 'input') 34 | bilstmLayer(256, 'OutputMode', 'last', 'Name', 'bilstm1') 35 | dropoutLayer(0.2) 36 | lstmLayer(512, 'OutputMode', 'last', 'Name', 'lstm2') 37 | dropoutLayer(0.2) 38 | fullyConnectedLayer(128) 39 | reluLayer 40 | fullyConnectedLayer(numModTypes) 41 | softmaxLayer 42 | classificationLayer]; 43 | 44 | % 定义训练选项 45 | maxEpochs = 50; 46 | miniBatchSize = 1024; 47 | validationFrequency = floor(numel(rxTrainingLabel)/miniBatchSize); 48 | Options_RNN = trainingOptions('adam', ... 49 | 'InitialLearnRate', 0.009, ... 50 | 'MaxEpochs', maxEpochs, ... 51 | 'MiniBatchSize', miniBatchSize, ... 52 | 'Shuffle', 'every-epoch', ... 53 | 'ValidationData', {validationData_RNN, rxValidationLabel}, ... 54 | 'ValidationFrequency', validationFrequency, ... 55 | 'Plots', 'training-progress', ... 56 | 'Verbose', true, ... 57 | 'LearnRateSchedule', 'piecewise', ... 58 | 'LearnRateDropPeriod', 10, ... 59 | 'LearnRateDropFactor', 0.9, ... 60 | 'ExecutionEnvironment', 'gpu'); 61 | 62 | 63 | % 训练 LSTM 模型 64 | fprintf('%s - Training the RNN(LSTM) network\n', datestr(toc/86400,'HH:MM:SS')) 65 | RNN_NET = trainNetwork(trainingData_RNN, rxTrainingLabel, Layers_RNN, Options_RNN); 66 | 67 | % 测试模型 68 | fprintf('%s - Classifying test frames\n', datestr(toc/86400,'HH:MM:SS')) 69 | rxTestPred_RNN = classify(RNN_NET, testData_RNN); 70 | testAccuracy_RNN = mean(rxTestPred_RNN == rxTestLabel); 71 | disp("Test accuracy: " + testAccuracy_RNN*100 + "%") 72 | % 混淆矩阵绘制 73 | figure; 74 | cm=confusionchart(rxTestLabel,rxTestPred_RNN); 75 | cm.Title = 'Confusion Matrix for Test Data(LSTM)'; 76 | cm.RowSummary = 'row-normalized'; 77 | %cm.Normalization = 'total-normalized'; 78 | sortClasses(cm,'descending-diagonal') 79 | cm.Parent.Position = [cm.Parent.Position(1:2) 740 424]; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The codes can be run in MATLAB to generate BPSK , QPSK , 8PSK, 16QAM , 64QAM , PAM4 , GFSK , CPFSK , B-FM , DSB-AM , and SSB-AM signals. 2 | 3 | 可以在MATLAB中运行这些代码,生成BPSK、QPSK、8PSK、16QAM、64QAM、PAM4、GFSK、CPFSK、B-FM、DSB-AM和SSB-AM信号。 4 | 5 | 6 | You can run the script `show_signal.m` to view the waveform, spectrum, and constellation diagram of the generated signals. 7 | 8 | 你可以运行show_signal.m来查看生成信号的波形、频谱和星座图。 9 | 10 | 11 | The interference options can be freely adjusted in the file "Generat_Frames_Optional.m". 12 | 13 | 干扰选项可以在“Generat_Frames_Optional.m”中自由调节。 14 | 15 | 16 | The design and training of the three models are in the files `NET_model_CNN.m`, `NET_model_DNN.m`, and `NET_model_RNN.m`. 17 | 18 | 三种模型的设计和训练在NET_model_CNN.m、NET_model_DNN.m和NET_model_RNN.m文件中。 19 | 20 | 21 | Finally, you can run `Evaluate_Trained_network.m` to evaluate the training results. 22 | 23 | 最后,你可以运行Evaluate_Trained_network.m来对训练效果进行评估。 24 | 25 | 26 | Of course, you can also design your own better algorithms to achieve this. This project is a very rudimentary algorithm. 27 | 28 | 当然你也可以设计你自己的更好的算法来实现,本项目是一个非常粗糙的算法。 29 | -------------------------------------------------------------------------------- /audio.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Miner-Zhang/Deep-Learning-Models-in-Modulation-Classification/c3dd5d539f7c83698d47d4370bfe0908ac93caea/audio.wav -------------------------------------------------------------------------------- /getAudio.m: -------------------------------------------------------------------------------- 1 | function x = getAudio(spf,fs) 2 | %getAudio Audio source for analog modulation types 3 | % A = getAudio(SPF,FS) returns the audio source A, with the 4 | % number of samples per frame SPF, and the sample rate FS. 5 | 6 | persistent audioSrc audioRC 7 | 8 | if isempty(audioSrc) 9 | audioSrc = dsp.AudioFileReader('audio.wav',... 10 | 'SamplesPerFrame',spf,'PlayCount',inf); 11 | audioRC = dsp.SampleRateConverter('Bandwidth',30e3,... 12 | 'InputSampleRate',audioSrc.SampleRate,... 13 | 'OutputSampleRate',fs); 14 | [~,decimFactor] = getRateChangeFactors(audioRC); 15 | audioSrc.SamplesPerFrame = ceil(spf / fs * audioSrc.SampleRate / decimFactor) * decimFactor; 16 | end 17 | 18 | x = audioRC(audioSrc()); 19 | x = x(1:spf,1); 20 | end -------------------------------------------------------------------------------- /getSource.m: -------------------------------------------------------------------------------- 1 | function src = getSource(modType, sps, spf, fs) 2 | % 调制类型的 %getSource 源选择器 3 | % % SRC = getSource(TYPE,SPS,SPF,fs) 返回数据源 4 | % % 表示调制类型 TYPE,包含样本数 5 | % 每个符号的百分比 SPS、每帧 SPF 的样本数,以及 6 | % 采样频率 fs 的百分比。 7 | 8 | switch modType 9 | case {"BPSK","2FSK","GFSK","CPFSK"} 10 | M = 2; 11 | src = @()randi([0 M-1],spf/sps,1); 12 | case {"QPSK","PAM4"} 13 | M = 4; 14 | src = @()randi([0 M-1],spf/sps,1); 15 | case {"8PSK","8FSK"} 16 | M = 8; 17 | src = @()randi([0 M-1],spf/sps,1); 18 | case "16QAM" 19 | M = 16; 20 | src = @()randi([0 M-1],spf/sps,1); 21 | case "64QAM" 22 | M = 64; 23 | src = @()randi([0 M-1],spf/sps,1); 24 | case {"B-FM","DSB-AM","SSB-AM"} 25 | src = @()getAudio(spf,fs); 26 | case "LFM" 27 | rangeN = [512, 1920]; 28 | rangeB = [fs/20, fs/16]; % 带宽 (Hz) 范围 29 | sweepDirections = {'Up','Down'}; 30 | Ts = 1/fs; 31 | 32 | %获取随机参数的百分比 33 | B = randOverInterval(rangeB); 34 | Ncc = round(randOverInterval(rangeN)); 35 | hLfm = phased.LinearFMWaveform('SampleRate',fs,'OutputFormat','Samples'); 36 | % 生成 LFM 37 | hLfm.SweepBandwidth = B; 38 | hLfm.PulseWidth = Ncc*Ts; 39 | hLfm.NumSamples = 256; 40 | hLfm.PRF = 1/(Ncc*Ts); 41 | hLfm.SweepDirection = sweepDirections{randi(2)}; 42 | src = hLfm(); 43 | 44 | 45 | case 'Rect' 46 | %创建信号 47 | hRect = phased.RectangularWaveform(... 48 | 'SampleRate',fs,... 49 | 'OutputFormat','Samples'); 50 | 51 | %获取随机参数 52 | rangeN = [512, 1920]; % Number of collected signal samples range 53 | Ts = 1/fs; 54 | Ncc = round(randOverInterval(rangeN)); 55 | 56 | % 创建波形 57 | hRect.PulseWidth = Ncc*Ts; 58 | hRect.PRF = 1/(Ncc*Ts); 59 | hRect.NumSamples = 256; 60 | src = hRect(); 61 | 62 | % filter = phased.MatchedFilter( ... 63 | % 'Coefficients',getMatchedFilter(hRect),... 64 | % 'SampleRate', fs,... 65 | % 'SpectrumWindow','None'); 66 | % src = filter(wav); 67 | 68 | case 'Barker' 69 | rangeNChip = [3,4,5,7,11]; % 芯片数量 70 | rangeNcc = [1,5]; % 每相代码的周期数 71 | rangeFc = [fs/6, fs/5]; %中心频率 (Hz) 范围 72 | Ts = 1/fs; 73 | % 创建信号并更新 SNR 74 | hPhaseBarker = phased.PhaseCodedWaveform(... 75 | 'SampleRate',fs,... 76 | 'Code',string(modType),... 77 | 'OutputFormat','Samples'); 78 | 79 | % 获取随机参数 80 | Fc = randOverInterval(rangeFc); 81 | N = rangeNChip(randi(length(rangeNChip),1)); 82 | Ncc = rangeNcc(randi(length(rangeNcc),1)); 83 | 84 | % 创建信号并更新 SNR 85 | chipWidth = Ncc/Fc; 86 | chipWidthSamples = round(chipWidth*fs)-1; % This must be an integer! 87 | chipWidth = chipWidthSamples*Ts; 88 | hPhaseBarker.ChipWidth = chipWidth; 89 | hPhaseBarker.NumChips = N; 90 | hPhaseBarker.PRF = 1/((chipWidthSamples*N+1)*Ts); 91 | hPhaseBarker.NumSamples = 256; 92 | src = hPhaseBarker(); 93 | 94 | % filter = phased.MatchedFilter( ... 95 | % 'Coefficients',getMatchedFilter(hPhaseBarker),... 96 | % 'SampleRate', fs,... 97 | % 'SpectrumWindow','None'); 98 | % src = filter(wav); 99 | 100 | case 'Frank' 101 | rangeNChip = 4; % 芯片数量 102 | rangeNcc = [1,5]; % 每相代码的周期数 103 | rangeFc = [fs/6, fs/5]; % 中心频率 (Hz) 范围 104 | Ts = 1/fs; 105 | % 创建信号并更新 SNR 106 | hPhaseFrank = phased.PhaseCodedWaveform(... 107 | 'SampleRate',fs,... 108 | 'Code',string(modType),... 109 | 'OutputFormat','Samples'); 110 | 111 | 112 | % 获取随机参数 113 | 114 | Fc = randOverInterval(rangeFc); 115 | N = rangeNChip(randi(length(rangeNChip),1)); 116 | Ncc = rangeNcc(randi(length(rangeNcc),1)); 117 | 118 | % 创建信号并更新 SNR 119 | chipWidth = Ncc/Fc; 120 | chipWidthSamples = round(chipWidth*fs)-1; % 这必须是一个整数! 121 | chipWidth = chipWidthSamples*Ts; 122 | hPhaseFrank.ChipWidth = chipWidth; 123 | hPhaseFrank.NumChips = N; 124 | hPhaseFrank.PRF = 1/((chipWidthSamples*N+1)*Ts); 125 | hPhaseFrank.NumSamples = 256; 126 | src = hPhaseFrank(); 127 | 128 | % filter = phased.MatchedFilter( ... 129 | % 'Coefficients',getMatchedFilter(hPhaseFrank),... 130 | % 'SampleRate', fs,... 131 | % 'SpectrumWindow','None'); 132 | % src = filter(wav); 133 | 134 | case 'P1' 135 | rangeNChip = 4; % 芯片数量 136 | rangeNcc = [1,5]; % 每相代码的周期数 137 | 138 | % 创建信号并更新 SNR 139 | hPhaseP1 = phased.PhaseCodedWaveform(... 140 | 'SampleRate',fs,... 141 | 'Code',string(modType),... 142 | 'OutputFormat','Samples'); 143 | rangeFc = [fs/6, fs/5]; %中心频率 (Hz) 范围 144 | Ts = 1/fs; 145 | 146 | 147 | %获取随机参数 148 | Fc = randOverInterval(rangeFc); 149 | N = rangeNChip(randi(length(rangeNChip),1)); 150 | Ncc = rangeNcc(randi(length(rangeNcc),1)); 151 | 152 | 153 | % 创建信号并更新 SNR 154 | chipWidth = Ncc/Fc; 155 | chipWidthSamples = round(chipWidth*fs)-1; % 这必须是一个整数! 156 | chipWidth = chipWidthSamples*Ts; 157 | hPhaseP1.ChipWidth = chipWidth; 158 | hPhaseP1.NumChips = N; 159 | hPhaseP1.PRF = 1/((chipWidthSamples*N+1)*Ts); 160 | hPhaseP1.NumSamples = 256; 161 | src = hPhaseP1(); 162 | 163 | % filter = phased.MatchedFilter( ... 164 | % 'Coefficients',getMatchedFilter(hPhaseP1),... 165 | % 'SampleRate', fs,... 166 | % 'SpectrumWindow','None'); 167 | % src = filter(wav); 168 | 169 | 170 | case 'P2' 171 | rangeNChip = 4; % 芯片数量 172 | rangeNcc = [1,5]; %每相代码的周期数 173 | rangeFc = [fs/6, fs/5]; % 中心频率 (Hz) 范围 174 | Ts = 1/fs; 175 | % 创建信号并更新SNR 176 | hPhaseP2 = phased.PhaseCodedWaveform(... 177 | 'SampleRate',fs,... 178 | 'Code',string(modType),... 179 | 'OutputFormat','Samples'); 180 | 181 | 182 | %获取随机参数 183 | 184 | Fc = randOverInterval(rangeFc); 185 | N = rangeNChip(randi(length(rangeNChip),1)); 186 | Ncc = rangeNcc(randi(length(rangeNcc),1)); 187 | 188 | 189 | % 创建信号并更新 SNR 190 | chipWidth = Ncc/Fc; 191 | chipWidthSamples = round(chipWidth*fs)-1; % 这必须是一个整数! 192 | chipWidth = chipWidthSamples*Ts; 193 | hPhaseP2.ChipWidth = chipWidth; 194 | hPhaseP2.NumChips = N; 195 | hPhaseP2.PRF = 1/((chipWidthSamples*N+1)*Ts); 196 | hPhaseP2.NumSamples = 256; 197 | src = hPhaseP2(); 198 | 199 | % filter = phased.MatchedFilter( ... 200 | % 'Coefficients',getMatchedFilter(hPhaseP2),... 201 | % 'SampleRate', fs,... 202 | % 'SpectrumWindow','None'); 203 | % src = filter(wav); 204 | 205 | case 'P3' 206 | rangeNChip = 4; % 芯片数量 207 | rangeNcc = [1,5]; % 每相代码的周期数 208 | 209 | %创建信号并更新SNR 210 | hPhaseP3 = phased.PhaseCodedWaveform(... 211 | 'SampleRate',fs,... 212 | 'Code',string(modType),... 213 | 'OutputFormat','Samples'); 214 | rangeFc = [fs/6, fs/5]; % 中心频率 (Hz) 范围 215 | Ts = 1/fs; 216 | 217 | 218 | %获取随机参数 219 | Fc = randOverInterval(rangeFc); 220 | N = rangeNChip(randi(length(rangeNChip),1)); 221 | Ncc = rangeNcc(randi(length(rangeNcc),1)); 222 | 223 | 224 | 225 | %创建信号并更新SNR 226 | chipWidth = Ncc/Fc; 227 | chipWidthSamples = round(chipWidth*fs)-1; % 这必须是一个整数! 228 | chipWidth = chipWidthSamples*Ts; 229 | hPhaseP3.ChipWidth = chipWidth; 230 | hPhaseP3.NumChips = N; 231 | hPhaseP3.PRF = 1/((chipWidthSamples*N+1)*Ts); 232 | hPhaseP3.NumSamples = 256; 233 | src = hPhaseP3(); 234 | 235 | % filter = phased.MatchedFilter( ... 236 | % 'Coefficients',getMatchedFilter(hPhaseP3),... 237 | % 'SampleRate', fs,... 238 | % 'SpectrumWindow','None'); 239 | % src = filter(wav); 240 | 241 | case 'P4' 242 | rangeNChip = 4; % 芯片数量 243 | rangeNcc = [1,5]; % 每相代码的周期数 244 | rangeFc = [fs/6, fs/5]; % 中心频率 (Hz) 范围 245 | Ts = 1/fs; 246 | %创建信号并更新SNR 247 | hPhaseP4 = phased.PhaseCodedWaveform(... 248 | 'SampleRate',fs,... 249 | 'Code',string(modType),... 250 | 'OutputFormat','Samples'); 251 | 252 | 253 | 254 | %获取随机参数 255 | Fc = randOverInterval(rangeFc); 256 | N = rangeNChip(randi(length(rangeNChip),1)); 257 | Ncc = rangeNcc(randi(length(rangeNcc),1)); 258 | 259 | 260 | %创建信号并更新SNR 261 | chipWidth = Ncc/Fc; 262 | chipWidthSamples = round(chipWidth*fs)-1; % 这必须是一个整数! 263 | chipWidth = chipWidthSamples*Ts; 264 | hPhaseP4.ChipWidth = chipWidth; 265 | hPhaseP4.NumChips = N; 266 | hPhaseP4.PRF = 1/((chipWidthSamples*N+1)*Ts); 267 | hPhaseP4.NumSamples = 256; 268 | src = hPhaseP4(); 269 | 270 | % filter = phased.MatchedFilter( ... 271 | % 'Coefficients',getMatchedFilter(hPhaseP4),... 272 | % 'SampleRate', fs,... 273 | % 'SpectrumWindow','None'); 274 | % src = filter(wav); 275 | 276 | case 'Zadoff-Chu' 277 | rangeNChip = 4; % 芯片数量 278 | rangeNcc = [1,5]; % 每相代码的周期数 279 | rangeFc = [fs/6, fs/5]; % 中心频率 (Hz) 范围 280 | Ts = 1/fs; 281 | % 创建信号并更新SNR 282 | hPhaseZadoffChu = phased.PhaseCodedWaveform(... 283 | 'SampleRate',fs,... 284 | 'Code',string(modType),... 285 | 'OutputFormat','Samples'); 286 | 287 | %获取随机参数 288 | Fc = randOverInterval(rangeFc); 289 | N = rangeNChip(randi(length(rangeNChip),1)); 290 | Ncc = rangeNcc(randi(length(rangeNcc),1)); 291 | 292 | % 创建信号并更新SNR 293 | chipWidth = Ncc/Fc; 294 | chipWidthSamples = round(chipWidth*fs)-1; % 这必须是一个整数! 295 | chipWidth = chipWidthSamples*Ts; 296 | hPhaseZadoffChu.ChipWidth = chipWidth; 297 | hPhaseZadoffChu.NumChips = N; 298 | hPhaseZadoffChu.PRF = 1/((chipWidthSamples*N+1)*Ts); 299 | hPhaseZadoffChu.NumSamples = 256; 300 | src = hPhaseZadoffChu(); 301 | 302 | % filter = phased.MatchedFilter( ... 303 | % 'Coefficients',getMatchedFilter(hPhaseZadoffChu),... 304 | % 'SampleRate', fs,... 305 | % 'SpectrumWindow','None'); 306 | % src = filter(wav); 307 | otherwise 308 | error('Modulation type not recognized.'); 309 | end 310 | 311 | 312 | %% 子例程 313 | function val = randOverInterval(interval) 314 | % 预计间隔为 <1x2>,格式为 [minVal maxVal] 315 | val = (interval(2) - interval(1)).*rand + interval(1); 316 | end 317 | end 318 | -------------------------------------------------------------------------------- /show_signal.m: -------------------------------------------------------------------------------- 1 | % 清除环境并关闭所有窗口 2 | clear; 3 | close all 4 | clc; 5 | 6 | % 定义调制类型 7 | modulationTypes = categorical(sort(["BPSK", "QPSK", "8PSK", ... 8 | "16QAM", "64QAM", "PAM4", "GFSK", "CPFSK", ... 9 | "B-FM", "DSB-AM", "SSB-AM"])); 10 | 11 | %% 生成用于训练的波形 12 | 13 | numFramesPerModType = 10000; 14 | percentTrainingSamples = 80; %训练百分比 15 | percentValidationSamples = 10; %验证百分比 16 | percentTestSamples = 10; %测试百分比 17 | 18 | sps = 8; % 每个符号样本数 19 | spf = 1024; %仿真时隙 20 | symbolsPerFrame = spf / sps; 21 | fs = 200e3; %采样率 22 | fc = [900e3 100e3]; % 中心频率 23 | % RRADAR 波形的起始百分 24 | rangeFc = [fs/7, fs/5]; % Center frequency (Hz) range 25 | 26 | %% 创建通道干扰 27 | % 每帧通过一个通道,AWGN,Rician 多径衰落, 28 | % 时钟偏移,导致中心频率偏移和采样时间漂移 29 | SNR = 30; 30 | std = sqrt(10.^(SNR/10)); 31 | 32 | awgnChannel = comm.AWGNChannel(... 33 | 'NoiseMethod', 'Signal to noise ratio (SNR)', ... 34 | 'SignalPower', 0.5, ... 35 | 'SNR', SNR); 36 | 37 | %% Rician平坦衰落信道 38 | % 通道使用 39 | % 通信。RicianChannel System 对象。假设 [0 1.8 3.4] 个样本的延迟曲线 40 | % 对应的平均路径增益为 [0 -2 -10] dB。K 因子为 4,最大值为 41 | % 多普勒频移为 2 Hz 42 | multipathChannel = comm.RicianChannel(... 43 | 'SampleRate', fs, ... 44 | 'PathDelays', [0 1.8 3.4]/fs, ... 45 | 'AveragePathGains', [0 -2 -10]./2, ... 46 | 'KFactor', 2, ... 47 | 'MaximumDopplerShift', 2); 48 | 49 | %% Clock Offset 50 | 51 | maxDeltaOff = 2;%5 52 | deltaOff = (rand()*2*maxDeltaOff) - maxDeltaOff; 53 | C = 1 + (deltaOff/1e6); 54 | 55 | %% 频率偏移 56 | % 使每个帧具有基于时钟偏移因子 C 和中心的频率偏移 57 | % 频率 58 | offset = -(C-1)*fc(1); 59 | frequencyShifter = comm.PhaseFrequencyOffset(... 60 | 'SampleRate', fs, ... 61 | 'FrequencyOffset', offset); 62 | 63 | 64 | %% 采样率偏移 65 | %使每个帧受到基于时钟偏移因子 C 的采样率偏移 66 | channel = ModClassTestChannel(... 67 | 'SampleRate', fs, ... 68 | 'SNR', SNR, ... 69 | 'PathDelays', [0 1.8 3.4] / fs, ... 70 | 'AveragePathGains', [0 -2 -10]./2, ... 71 | 'KFactor', 2, ... 72 | 'MaximumDopplerShift', 2, ... 73 | 'MaximumClockOffset', 2, ... 74 | 'CenterFrequency', 900e3); 75 | 76 | chInfo = info(channel); 77 | 78 | %% 波形生成 79 | % 将随机数生成器设置为已知状态以便能够重新生成 80 | % 每次运行模拟时相同帧数的百分比 81 | rng(20010611) 82 | tic 83 | 84 | numModulationTypes = length(modulationTypes); 85 | 86 | channelInfo = info(channel); 87 | frameStore = ModClassFrameStore(... 88 | numFramesPerModType*numModulationTypes,spf,modulationTypes); 89 | transDelay = 20; 90 | 91 | % 创建用于绘制波形的图形 92 | figure('Name', '各种信号的时域波形'); 93 | for modType = 1:numModulationTypes 94 | fprintf('%s - 正在生成 %s 的时域波形\n', ... 95 | datestr(toc/86400,'HH:MM:SS'), modulationTypes(modType)) 96 | 97 | subplot(6, 2, modType); 98 | hold on; 99 | title(char(modulationTypes(modType)),'FontSize',32); 100 | xlabel('样本','FontSize',24); 101 | ylabel('幅度','FontSize',24); 102 | grid on; 103 | set(gca,'FontSize',9); 104 | 105 | numSymbols = (numFramesPerModType / sps); 106 | dataSrc = getSource(modulationTypes(modType), sps, 2*spf, fs); 107 | modulator = ModClassGetModulator(modulationTypes(modType), sps, fs); 108 | if contains(char(modulationTypes(modType)), {'B-FM','DSB-AM','SSB-AM'}) 109 | % Analog modulation types use a center frequency of 100 MHz 110 | channel.CenterFrequency = 100e3; 111 | else 112 | % Digital modulation types use a center frequency of 900 MHz 113 | channel.CenterFrequency = 900e3; 114 | end 115 | 116 | % 生成随机数据 117 | x = dataSrc(); 118 | 119 | % 调制 120 | y = modulator(x); 121 | 122 | % 通过通道传输并接收信号 123 | rxSamples = channel(y); 124 | 125 | % 处理接收到的信号,删除瞬态等 126 | frame = ModClassFrameGenerator(rxSamples, spf, spf, transDelay, sps); 127 | 128 | % 绘制时域波形 129 | plot(1:length(frame), frame); 130 | end 131 | 132 | % 创建用于绘制频谱图的图形 133 | figure('Name', '各种信号的频谱图'); 134 | for modType = 1:numModulationTypes 135 | fprintf('%s - 正在生成 %s 的频谱图\n', ... 136 | datestr(toc/86400,'HH:MM:SS'), modulationTypes(modType)) 137 | 138 | subplot(6, 2, modType); 139 | hold on; 140 | title(char(modulationTypes(modType)),'FontSize',32); 141 | xlabel('频率 (Hz)','FontSize',24); 142 | ylabel('功率谱密度 (dB)','FontSize',24); 143 | grid on; 144 | set(gca,'FontSize',9); 145 | 146 | numSymbols = (numFramesPerModType / sps); 147 | dataSrc = getSource(modulationTypes(modType), sps, 2*spf, fs); 148 | modulator = ModClassGetModulator(modulationTypes(modType), sps, fs); 149 | if contains(char(modulationTypes(modType)), {'B-FM','DSB-AM','SSB-AM'}) 150 | % Analog modulation types use a center frequency of 100 MHz 151 | channel.CenterFrequency = 100e3; 152 | else 153 | % Digital modulation types use a center frequency of 900 MHz 154 | channel.CenterFrequency = 900e3; 155 | end 156 | 157 | % 生成随机数据 158 | x = dataSrc(); 159 | 160 | % 调制 161 | y = modulator(x); 162 | 163 | % 通过通道传输并接收信号 164 | rxSamples = channel(y); 165 | 166 | % 处理接收到的信号,删除瞬态等 167 | frame = ModClassFrameGenerator(rxSamples, spf, spf, transDelay, sps); 168 | 169 | % 计算频谱 170 | f = (-fs/2:fs/spf:fs/2-fs/spf); 171 | spectrum = fftshift(fft(frame)); 172 | 173 | % 绘制频谱图 174 | plot(f, 10*log10(abs(spectrum).^2)); 175 | end 176 | 177 | % 创建用于绘制星座图的图形 178 | figure('Name', '各种信号的星座图'); 179 | for modType = 1:numModulationTypes 180 | fprintf('%s - 正在生成 %s 的星座图\n', ... 181 | datestr(toc/86400,'HH:MM:SS'), modulationTypes(modType)) 182 | 183 | subplot(6, 2, modType); 184 | hold on; 185 | title(char(modulationTypes(modType)),'FontSize',32); 186 | xlabel('实部','FontSize',24); 187 | ylabel('虚部','FontSize',24); 188 | grid on; 189 | set(gca,'FontSize',9); 190 | 191 | numSymbols = (numFramesPerModType / sps); 192 | dataSrc = getSource(modulationTypes(modType), sps, 2*spf, fs); 193 | modulator = ModClassGetModulator(modulationTypes(modType), sps, fs); 194 | 195 | % 生成随机数据 196 | x = dataSrc(); 197 | 198 | % 调制 199 | y = modulator(x); 200 | 201 | % 绘制星座图 202 | scatter(real(y), imag(y), '.'); 203 | end 204 | --------------------------------------------------------------------------------