├── Data ├── raw1000_1000_8.mat └── raw500_1000_8.mat ├── Matlab ├── AMC_raw.m ├── Cumulant.m ├── HybridLRT.m ├── MaximumLikelihood.m ├── Test_Cumu.m ├── Test_ML.m ├── sig2pic.m ├── sig2pic_accu.m └── sig2pic_gaussian.m ├── Python ├── Model │ ├── cnn.json │ ├── cnn_8.h5 │ ├── cnnpolar.json │ └── cnnpolar_8.h5 ├── __pycache__ │ └── util.cpython-36.pyc ├── classify_cnn_pic.py ├── classify_cnnpolar_pic.py ├── model.h5 └── util.py └── README.md /Data/raw1000_1000_8.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JieFangD/Automatic-Modulation-Classification/dc46c30ea328382c1d2e95f4742aae89a86fd734/Data/raw1000_1000_8.mat -------------------------------------------------------------------------------- /Data/raw500_1000_8.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JieFangD/Automatic-Modulation-Classification/dc46c30ea328382c1d2e95f4742aae89a86fd734/Data/raw500_1000_8.mat -------------------------------------------------------------------------------- /Matlab/AMC_raw.m: -------------------------------------------------------------------------------- 1 | close all; 2 | M = [4 8 16 64]; 3 | 4 | symbol = 1000; 5 | resolution = 36; 6 | num = 1; 7 | SNR = [20]; 8 | x = zeros(num*4,symbol); 9 | y = zeros(num*4,1); 10 | 11 | for k = 1:length(SNR) 12 | for j = 1:4 13 | for i = 1:num 14 | data = randi([0 M(j)-1],symbol,1); 15 | if(j == 1) 16 | txSig = pskmod(data,M(j)); 17 | elseif(j == 2) 18 | txSig = pskmod(data,M(j)); 19 | else 20 | txSig = qammod(data,M(j)); 21 | txSig = txSig*1/sqrt(2/3*(M(j)-1)); 22 | end 23 | rxSig = awgn(txSig,SNR(k),'measured'); 24 | x(i+num*(j-1),:) = reshape(rxSig,1,symbol); 25 | y(i+num*(j-1),:) = j-1; 26 | end 27 | figure('position', [500, 500, 500, 500]); 28 | 29 | % plot gray Cartesian Coordinate figure 30 | % rxSig = [real(rxSig),imag(rxSig)]; 31 | % pic = sig2pic(rxSig,-1.5,1.5,-1.5,1.5,resolution,resolution); 32 | % image = imagesc(pic); 33 | % colormap gray 34 | % axis off 35 | 36 | % plot gray accumulated Polar Coordinate figure with Gaussian 37 | % rxSig = [abs(rxSig),atan2(real(rxSig),imag(rxSig))]; 38 | % pic = sig2pic_gaussian(rxSig,0,2,-3.2,3.2,resolution,resolution); 39 | % pic = pic < 0.8; 40 | % image = imagesc(pic); 41 | % colormap gray 42 | 43 | % plot colorful accumulated Cartesian Coordinate figure 44 | % rxSig = [real(rxSig),imag(rxSig)]; 45 | % pic = sig2pic_accu(rxSig,-1.5,1.5,-1.5,1.5,resolution,resolution); 46 | % image = imagesc(1-pic/(max(pic(:)))); 47 | % colormap hot 48 | % axis off 49 | 50 | % plot colorful accumulated Polar Coordinate figure 51 | rxSig = [abs(rxSig),atan2(real(rxSig),imag(rxSig))]; 52 | pic = sig2pic_accu(rxSig,0,2,-3.2,3.2,resolution,resolution); 53 | image = imagesc(1-pic/(max(pic(:)))); 54 | colormap hot 55 | axis off 56 | 57 | % plot colorful accumulated Polar Coordinate figure with Gaussian 58 | % rxSig = [abs(rxSig),atan2(real(rxSig),imag(rxSig))]; 59 | % pic = sig2pic_gaussian(rxSig,0,2,-3.2,3.2,resolution,resolution); 60 | % image = imagesc(1-pic/(max(pic(:)))); 61 | % colormap hot 62 | % axis off 63 | end 64 | filename = strcat('raw',num2str(num),'_',num2str(symbol),'_',num2str(SNR(k)),'.mat'); 65 | save(filename,'y','x'); 66 | end 67 | 68 | -------------------------------------------------------------------------------- /Matlab/Cumulant.m: -------------------------------------------------------------------------------- 1 | function y = Cumulant(Sig) 2 | modulationPool = {'4psk' '8psk' '16qam' '64qam'}; 3 | C20 = mean(Sig.^2); 4 | C21 = mean(abs(Sig).^2); 5 | M40 = mean(Sig.^4); 6 | C40 = M40 - 3*C20^2; 7 | % C41 = mean(Sig.^3.*conj(Sig)) - 3*C20*C21; 8 | C42 = mean(abs(Sig).^4) - abs(C20)^2 - 2*C21^2; 9 | % C60 = mean(Sig.^6) - 15*C20*M40 + 30*C20^3; 10 | % C63 = mean(Sig.^3.*conj(Sig).^3) - 9*C42*C21 - 6*C21^3; 11 | C63 = mean(abs(Sig).^6) - 9*mean(abs(Sig).^4)*C21 + 12*(abs(C20)^2)*C21 + 12*C21^3; 12 | % cumu = [C40/(C21^2) C41/(C21^2) C42/(C21^2) C63/(C21^2)]; 13 | % cumu = [C20/C21 C21/C21 C40/(C21^2) C41/(C21^2) C42/(C21^2)]; 14 | % cumu = [C40/(C21^2) C41/(C21^2) C42/(C21^2) C60 C63]; 15 | % cumu = [C40/(C21^2) C42/(C21^2)]; 16 | cumu = [C63]; 17 | % cumu = [C40/(C21^2) C42/(C21^2) C63]; 18 | % cumu = [C20 C21 C40/(C21^2) C41/(C21^2) C42/(C21^2)]; 19 | % cumu = [C40/(C21^2) C42/(C21^2) C63/(C21^3)]; 20 | % cumu = [C20 C21 C40 C41 C42] 21 | % cumu_ref = [1 0 -1 4;0 0 -1 4;-0.68 0 -0.68 2.08;-0.6191 0 -0.6191 1.79]; 22 | % cumu_ref = [0 1 1 0 -1; 0 1 0 0 -1; 0 1 -0.68 0 -0.68; 0 1 -0.6191 0 -0.6191]; 23 | % cumu_ref = [1 0 -1 0 4; 0 0 -1 0 4; -0.68 0 -0.68 0 2.08; -0.6191 0 -0.6191 0 1.79]; 24 | % cumu_ref = [1 -1; 0 -1; -0.68 -0.68; -0.6191 -0.6191]; 25 | cumu_ref = [4; 4; 2.08; 1.79]; 26 | % cumu_ref = [1 -1 4; 0 -1 4; -0.68 -0.68 2.08; -0.6191 -0.6191 1.79]; 27 | % cumu_ref = [1 -1 4; 0 -1 4; -0.68 -0.68 2.08; -0.6191 -0.6191 1.797]; 28 | % cumu_ref = [0 1 1 0 -1 4; 0 1 0 0 -1 4; 0 1 -0.68 0 -0.68 2.08; 0 1 -0.6191 0 -0.6191 1.8]; 29 | % cumu_ref = [0 2 4 0 -4; 0 2 0 0 -4; 0 1.12 -0.85 0 -0.85; 0 0.85 -0.44 0 -0.44]; 30 | err = abs(real(cumu-cumu_ref)); 31 | err = sum(err'); 32 | [A I] = min(err); 33 | y = modulationPool{I}; 34 | end -------------------------------------------------------------------------------- /Matlab/HybridLRT.m: -------------------------------------------------------------------------------- 1 | function [class,likelihood] = HybridLRT(x,SNR) 2 | M = [4 8 16 64]; 3 | modulationPool = {'4psk' '8psk' '16qam' '64qam'}; 4 | likelihood = zeros(1,4); 5 | N0 = 10^(-SNR/20); 6 | sigma = N0/sqrt(2); 7 | maxlike = zeros(1,90*17); 8 | for j = 1:4 9 | m = 1; 10 | data = [0:1:M(j)-1]; 11 | if(j == 1) 12 | txSig = pskmod(data,M(j)); 13 | elseif(j==2) 14 | txSig = pskmod(data,M(j),pi/M(j)); 15 | else 16 | txSig = qammod(data,M(j)); 17 | txSig = txSig*1/sqrt(2/3*(M(j)-1)); 18 | end 19 | for amplitude = 0.2:0.05:1 20 | for theta = 1:1:90 21 | liketemp = 0; 22 | for t = 1:length(x) 23 | liketemp = liketemp + log10(sum(1/M(j)/(2*pi*sigma^2).*exp(-(abs(x(t)-amplitude*exp(i*theta*pi/180)*txSig)).^2/2/(sigma^2)))); 24 | end 25 | maxlike(m) = liketemp; 26 | m = m+1; 27 | end 28 | end 29 | likelihood(j) = max(maxlike); 30 | end 31 | [A I] = max(likelihood); 32 | class = modulationPool{I}; 33 | end -------------------------------------------------------------------------------- /Matlab/MaximumLikelihood.m: -------------------------------------------------------------------------------- 1 | function [class,likelihood] = MaximunLikelihood(x,SNR) 2 | M = [4 8 16 64]; 3 | modulationPool = {'4psk' '8psk' '16qam' '64qam'}; 4 | likelihood = zeros(1,4); 5 | N0 = 10^(-SNR/20); 6 | sigma = N0/sqrt(2); 7 | for j = 1:4 8 | data = [0:1:M(j)-1]; 9 | if(j == 1) 10 | txSig = pskmod(data,M(j)); 11 | elseif(j==2) 12 | txSig = pskmod(data,M(j),pi/M(j)); 13 | else 14 | txSig = qammod(data,M(j)); 15 | txSig = txSig*1/sqrt(2/3*(M(j)-1)); 16 | end 17 | for i = 1:length(x) 18 | likelihood(j) = likelihood(j) + log10(sum(1/M(j)/(2*pi*sigma^2).*exp(-(abs(x(i)-txSig)).^2/2/(sigma^2)))); 19 | end 20 | end 21 | [A I] = max(likelihood); 22 | class = modulationPool{I}; 23 | end -------------------------------------------------------------------------------- /Matlab/Test_Cumu.m: -------------------------------------------------------------------------------- 1 | close all; 2 | M = [4 8 16 64]; 3 | modulationPool = {'4psk' '8psk' '16qam' '64qam'}; 4 | symbol = 1000; 5 | num = 1000; 6 | SNR = [12]; 7 | t = 0; 8 | 9 | for k = 1:length(SNR) 10 | error = zeros(1,4); 11 | for j = 1:4 12 | for i = 1:num 13 | data = randi([0 M(j)-1],symbol,1); 14 | if(j == 1) 15 | txSig = pskmod(data,M(j)); 16 | elseif(j == 2) 17 | txSig = pskmod(data,M(j),pi/M(j)); 18 | else 19 | txSig = qammod(data,M(j)); 20 | txSig = txSig*1/sqrt(2/3*(M(j)-1)); 21 | end 22 | S = SNR(k); 23 | rxSig = awgn(txSig,S,'measured'); 24 | tic 25 | class = Cumulant(rxSig); 26 | t = t + toc; 27 | if(~strcmp(class,modulationPool{j})) 28 | error(j) = error(j) + 1; 29 | end 30 | end 31 | end 32 | disp('Error for each modulation type:') 33 | disp(error); 34 | disp('Average accuracy:') 35 | disp(1-sum(error)/4/num); 36 | end 37 | disp(t/num/4) 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Matlab/Test_ML.m: -------------------------------------------------------------------------------- 1 | close all; 2 | M = [4 8 16 64]; 3 | modulationPool = {'4psk' '8psk' '16qam' '64qam'}; 4 | symbol = 1000; 5 | num = 100; 6 | SNR = [12]; 7 | t = 0; 8 | 9 | for k = 1:length(SNR) 10 | error = zeros(1,4); 11 | for j = 1:4 12 | for i = 1:num 13 | data = randi([0 M(j)-1],symbol,1); 14 | if(j == 1) 15 | txSig = pskmod(data,M(j)); 16 | elseif(j == 2) 17 | txSig = pskmod(data,M(j),pi/M(j)); 18 | else 19 | txSig = qammod(data,M(j)); 20 | txSig = txSig*1/sqrt(2/3*(M(j)-1)); 21 | end 22 | S = SNR(k); 23 | rxSig = awgn(txSig,S,'measured'); 24 | tic 25 | [class likelihood]= MaximumLikelihood(rxSig,S); 26 | % [class likelihood] = HybridLRT(rxSig,S); 27 | t = t + toc; 28 | if(~strcmp(class,modulationPool{j})) 29 | error(j) = error(j) + 1; 30 | end 31 | end 32 | end 33 | disp('Error for each modulation type:') 34 | disp(error); 35 | disp('Average accuracy:') 36 | disp(1-sum(error)/4/num); 37 | end 38 | disp(t/num/4) -------------------------------------------------------------------------------- /Matlab/sig2pic.m: -------------------------------------------------------------------------------- 1 | function [ out ] = sig2pic(sig,x0,x1,y0,y1,r0,r1) 2 | linx = linspace(x0,x1,r0); 3 | liny = linspace(y0,y1,r1); 4 | out = ones(r0,r1); 5 | for i = 1:size(sig,1)/2 6 | [~,x] = min(abs(linx-sig(i,1))); 7 | [~,y] = min(abs(liny-sig(i,2))); 8 | out(x,y) = 0; 9 | end -------------------------------------------------------------------------------- /Matlab/sig2pic_accu.m: -------------------------------------------------------------------------------- 1 | function [ out ] = sig2pic_accu(sig,x0,x1,y0,y1,r0,r1) 2 | linx = linspace(x0,x1,r0); 3 | liny = linspace(y0,y1,r1); 4 | out = zeros(r0,r1); 5 | for i = 1:size(sig,1) 6 | [~,x] = min(abs(linx-sig(i,1))); 7 | [~,y] = min(abs(liny-sig(i,2))); 8 | out(x,y) = out(x,y) + 1; 9 | end -------------------------------------------------------------------------------- /Matlab/sig2pic_gaussian.m: -------------------------------------------------------------------------------- 1 | function [ out ] = sig2pic_gaussian(sig,x0,x1,y0,y1,r0,r1) 2 | linx = linspace(x0,x1,r0); 3 | liny = linspace(y0,y1,r1); 4 | [Px,Py] = meshgrid(linx(2:end-1),liny(2:end-1)); 5 | P = cat(3,Px,Py); 6 | out = zeros(r0,r1); 7 | for i = 1:size(sig,1) 8 | for j = 1:r0 9 | for k = 1:r1 10 | tmp = sum((sig(i,:)-[linx(j),liny(k)]).^2); 11 | out(j,k) = out(j,k) + exp(-tmp/2/0.01); 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /Python/Model/cnn.json: -------------------------------------------------------------------------------- 1 | {"class_name": "Model", "config": {"name": "model_1", "layers": [{"name": "input_1", "class_name": "InputLayer", "config": {"batch_input_shape": [null, 36, 36, 1], "dtype": "float32", "sparse": false, "name": "input_1"}, "inbound_nodes": []}, {"name": "batch_normalization_1", "class_name": "BatchNormalization", "config": {"name": "batch_normalization_1", "trainable": true, "dtype": "float32", "axis": -1, "momentum": 0.99, "epsilon": 0.001, "center": true, "scale": true, "beta_initializer": {"class_name": "Zeros", "config": {}}, "gamma_initializer": {"class_name": "Ones", "config": {}}, "moving_mean_initializer": {"class_name": "Zeros", "config": {}}, "moving_variance_initializer": {"class_name": "Ones", "config": {}}, "beta_regularizer": null, "gamma_regularizer": null, "beta_constraint": null, "gamma_constraint": null}, "inbound_nodes": [[["input_1", 0, 0, {}]]]}, {"name": "conv2d_1", "class_name": "Conv2D", "config": {"name": "conv2d_1", "trainable": true, "dtype": "float32", "filters": 8, "kernel_size": [3, 3], "strides": [1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["batch_normalization_1", 0, 0, {}]]]}, {"name": "max_pooling2d_1", "class_name": "MaxPooling2D", "config": {"name": "max_pooling2d_1", "trainable": true, "dtype": "float32", "pool_size": [3, 3], "padding": "valid", "strides": [3, 3], "data_format": "channels_last"}, "inbound_nodes": [[["conv2d_1", 0, 0, {}]]]}, {"name": "batch_normalization_2", "class_name": "BatchNormalization", "config": {"name": "batch_normalization_2", "trainable": true, "dtype": "float32", "axis": -1, "momentum": 0.99, "epsilon": 0.001, "center": true, "scale": true, "beta_initializer": {"class_name": "Zeros", "config": {}}, "gamma_initializer": {"class_name": "Ones", "config": {}}, "moving_mean_initializer": {"class_name": "Zeros", "config": {}}, "moving_variance_initializer": {"class_name": "Ones", "config": {}}, "beta_regularizer": null, "gamma_regularizer": null, "beta_constraint": null, "gamma_constraint": null}, "inbound_nodes": [[["max_pooling2d_1", 0, 0, {}]]]}, {"name": "conv2d_2", "class_name": "Conv2D", "config": {"name": "conv2d_2", "trainable": true, "dtype": "float32", "filters": 4, "kernel_size": [3, 3], "strides": [1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["batch_normalization_2", 0, 0, {}]]]}, {"name": "max_pooling2d_2", "class_name": "MaxPooling2D", "config": {"name": "max_pooling2d_2", "trainable": true, "dtype": "float32", "pool_size": [3, 3], "padding": "valid", "strides": [3, 3], "data_format": "channels_last"}, "inbound_nodes": [[["conv2d_2", 0, 0, {}]]]}, {"name": "flatten_1", "class_name": "Flatten", "config": {"name": "flatten_1", "trainable": true, "dtype": "float32", "data_format": "channels_last"}, "inbound_nodes": [[["max_pooling2d_2", 0, 0, {}]]]}, {"name": "dense_1", "class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 8, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["flatten_1", 0, 0, {}]]]}, {"name": "batch_normalization_3", "class_name": "BatchNormalization", "config": {"name": "batch_normalization_3", "trainable": true, "dtype": "float32", "axis": -1, "momentum": 0.99, "epsilon": 0.001, "center": true, "scale": true, "beta_initializer": {"class_name": "Zeros", "config": {}}, "gamma_initializer": {"class_name": "Ones", "config": {}}, "moving_mean_initializer": {"class_name": "Zeros", "config": {}}, "moving_variance_initializer": {"class_name": "Ones", "config": {}}, "beta_regularizer": null, "gamma_regularizer": null, "beta_constraint": null, "gamma_constraint": null}, "inbound_nodes": [[["dense_1", 0, 0, {}]]]}, {"name": "dense_2", "class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 4, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["batch_normalization_3", 0, 0, {}]]]}, {"name": "batch_normalization_4", "class_name": "BatchNormalization", "config": {"name": "batch_normalization_4", "trainable": true, "dtype": "float32", "axis": -1, "momentum": 0.99, "epsilon": 0.001, "center": true, "scale": true, "beta_initializer": {"class_name": "Zeros", "config": {}}, "gamma_initializer": {"class_name": "Ones", "config": {}}, "moving_mean_initializer": {"class_name": "Zeros", "config": {}}, "moving_variance_initializer": {"class_name": "Ones", "config": {}}, "beta_regularizer": null, "gamma_regularizer": null, "beta_constraint": null, "gamma_constraint": null}, "inbound_nodes": [[["dense_2", 0, 0, {}]]]}, {"name": "dense_3", "class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "dtype": "float32", "units": 4, "activation": "softmax", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["batch_normalization_4", 0, 0, {}]]]}], "input_layers": [["input_1", 0, 0]], "output_layers": [["dense_3", 0, 0]]}, "keras_version": "2.2.5", "backend": "tensorflow"} -------------------------------------------------------------------------------- /Python/Model/cnn_8.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JieFangD/Automatic-Modulation-Classification/dc46c30ea328382c1d2e95f4742aae89a86fd734/Python/Model/cnn_8.h5 -------------------------------------------------------------------------------- /Python/Model/cnnpolar.json: -------------------------------------------------------------------------------- 1 | {"class_name": "Model", "config": {"name": "model_2", "layers": [{"name": "input_2", "class_name": "InputLayer", "config": {"batch_input_shape": [null, 36, 36, 1], "dtype": "float32", "sparse": false, "name": "input_2"}, "inbound_nodes": []}, {"name": "batch_normalization_1", "class_name": "BatchNormalization", "config": {"name": "batch_normalization_1", "trainable": true, "dtype": "float32", "axis": -1, "momentum": 0.99, "epsilon": 0.001, "center": true, "scale": true, "beta_initializer": {"class_name": "Zeros", "config": {}}, "gamma_initializer": {"class_name": "Ones", "config": {}}, "moving_mean_initializer": {"class_name": "Zeros", "config": {}}, "moving_variance_initializer": {"class_name": "Ones", "config": {}}, "beta_regularizer": null, "gamma_regularizer": null, "beta_constraint": null, "gamma_constraint": null}, "inbound_nodes": [[["input_2", 0, 0, {}]]]}, {"name": "conv2d_1", "class_name": "Conv2D", "config": {"name": "conv2d_1", "trainable": true, "dtype": "float32", "filters": 8, "kernel_size": [3, 3], "strides": [1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["batch_normalization_1", 0, 0, {}]]]}, {"name": "max_pooling2d_1", "class_name": "MaxPooling2D", "config": {"name": "max_pooling2d_1", "trainable": true, "dtype": "float32", "pool_size": [3, 3], "padding": "valid", "strides": [3, 3], "data_format": "channels_last"}, "inbound_nodes": [[["conv2d_1", 0, 0, {}]]]}, {"name": "batch_normalization_2", "class_name": "BatchNormalization", "config": {"name": "batch_normalization_2", "trainable": true, "dtype": "float32", "axis": -1, "momentum": 0.99, "epsilon": 0.001, "center": true, "scale": true, "beta_initializer": {"class_name": "Zeros", "config": {}}, "gamma_initializer": {"class_name": "Ones", "config": {}}, "moving_mean_initializer": {"class_name": "Zeros", "config": {}}, "moving_variance_initializer": {"class_name": "Ones", "config": {}}, "beta_regularizer": null, "gamma_regularizer": null, "beta_constraint": null, "gamma_constraint": null}, "inbound_nodes": [[["max_pooling2d_1", 0, 0, {}]]]}, {"name": "conv2d_2", "class_name": "Conv2D", "config": {"name": "conv2d_2", "trainable": true, "dtype": "float32", "filters": 4, "kernel_size": [3, 3], "strides": [1, 1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1, 1], "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["batch_normalization_2", 0, 0, {}]]]}, {"name": "max_pooling2d_2", "class_name": "MaxPooling2D", "config": {"name": "max_pooling2d_2", "trainable": true, "dtype": "float32", "pool_size": [3, 3], "padding": "valid", "strides": [3, 3], "data_format": "channels_last"}, "inbound_nodes": [[["conv2d_2", 0, 0, {}]]]}, {"name": "flatten_1", "class_name": "Flatten", "config": {"name": "flatten_1", "trainable": true, "dtype": "float32", "data_format": "channels_last"}, "inbound_nodes": [[["max_pooling2d_2", 0, 0, {}]]]}, {"name": "dense_1", "class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 8, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["flatten_1", 0, 0, {}]]]}, {"name": "batch_normalization_3", "class_name": "BatchNormalization", "config": {"name": "batch_normalization_3", "trainable": true, "dtype": "float32", "axis": -1, "momentum": 0.99, "epsilon": 0.001, "center": true, "scale": true, "beta_initializer": {"class_name": "Zeros", "config": {}}, "gamma_initializer": {"class_name": "Ones", "config": {}}, "moving_mean_initializer": {"class_name": "Zeros", "config": {}}, "moving_variance_initializer": {"class_name": "Ones", "config": {}}, "beta_regularizer": null, "gamma_regularizer": null, "beta_constraint": null, "gamma_constraint": null}, "inbound_nodes": [[["dense_1", 0, 0, {}]]]}, {"name": "dense_2", "class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 4, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["batch_normalization_3", 0, 0, {}]]]}, {"name": "batch_normalization_4", "class_name": "BatchNormalization", "config": {"name": "batch_normalization_4", "trainable": true, "dtype": "float32", "axis": -1, "momentum": 0.99, "epsilon": 0.001, "center": true, "scale": true, "beta_initializer": {"class_name": "Zeros", "config": {}}, "gamma_initializer": {"class_name": "Ones", "config": {}}, "moving_mean_initializer": {"class_name": "Zeros", "config": {}}, "moving_variance_initializer": {"class_name": "Ones", "config": {}}, "beta_regularizer": null, "gamma_regularizer": null, "beta_constraint": null, "gamma_constraint": null}, "inbound_nodes": [[["dense_2", 0, 0, {}]]]}, {"name": "dense_3", "class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "dtype": "float32", "units": 4, "activation": "softmax", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["batch_normalization_4", 0, 0, {}]]]}], "input_layers": [["input_2", 0, 0]], "output_layers": [["dense_3", 0, 0]]}, "keras_version": "2.2.5", "backend": "tensorflow"} -------------------------------------------------------------------------------- /Python/Model/cnnpolar_8.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JieFangD/Automatic-Modulation-Classification/dc46c30ea328382c1d2e95f4742aae89a86fd734/Python/Model/cnnpolar_8.h5 -------------------------------------------------------------------------------- /Python/__pycache__/util.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JieFangD/Automatic-Modulation-Classification/dc46c30ea328382c1d2e95f4742aae89a86fd734/Python/__pycache__/util.cpython-36.pyc -------------------------------------------------------------------------------- /Python/classify_cnn_pic.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import time 3 | import numpy as np 4 | import sys 5 | import random 6 | import itertools 7 | import pydot 8 | import graphviz 9 | import keras.backend as K 10 | from keras.models import Sequential, model_from_json, Model 11 | from keras.layers.core import Dense, Dropout, Activation 12 | from keras.layers.normalization import BatchNormalization 13 | from keras.layers import Convolution2D, ZeroPadding2D, MaxPooling2D, AveragePooling2D, Flatten, Reshape, Input, Lambda 14 | from keras.optimizers import SGD, Adam 15 | from keras.utils import np_utils,plot_model 16 | from keras import regularizers 17 | from keras.callbacks import ReduceLROnPlateau 18 | from keras.preprocessing.image import ImageDataGenerator 19 | from sklearn.metrics import confusion_matrix 20 | from keras.callbacks import EarlyStopping,ModelCheckpoint 21 | import matplotlib.pyplot as plt 22 | import scipy.io 23 | from util import * 24 | 25 | train_path = sys.argv[1] 26 | test_path = sys.argv[2] 27 | resolution = 36 28 | tmp = train_path.split('_') 29 | tmp = tmp[2].split('.') 30 | SNR = tmp[0] 31 | R = 0 #Read Polar Model 32 | duplicate = 0 33 | 34 | def train(x_train, y_train, x_val, y_val, x_test, y_test): 35 | t = int(2**(int(sys.argv[3]))) 36 | cnn_input = Input(shape=(36,36,1)) 37 | cnn_batch = BatchNormalization()(cnn_input) 38 | conv1 = Convolution2D(2*t,(3,3),padding='same',activation='relu')(cnn_batch) 39 | max1 = MaxPooling2D((3,3))(conv1) 40 | bat1 = BatchNormalization()(max1) 41 | conv2 = Convolution2D(1*t,(3,3),padding='same',activation='relu')(bat1) 42 | max2 = MaxPooling2D((3,3))(conv2) 43 | flat = Flatten()(max2) 44 | den1 = Dense(2*t,activation='relu')(flat) 45 | den1 = BatchNormalization()(den1) 46 | den2 = Dense(1*t,activation='relu')(den1) 47 | den2 = BatchNormalization()(den2) 48 | den3 = Dense(4,activation='softmax')(den2) 49 | model = Model(cnn_input,den3) 50 | model.summary() 51 | 52 | sgd = SGD(lr=0.1, decay=1e-6, momentum=0.8, nesterov=True) 53 | model.compile(loss='categorical_crossentropy',optimizer='adadelta',metrics=['accuracy']) 54 | 55 | earlystopping = EarlyStopping(monitor='val_acc', patience = 8, verbose=0, mode='max') 56 | checkpoint = ModelCheckpoint(filepath='model.h5', 57 | verbose=1, 58 | save_best_only=True, 59 | save_weights_only=True, 60 | monitor='val_acc', 61 | mode='max') 62 | start_time = time.time() 63 | result = model.fit(x_train,y_train,validation_data=(x_val,y_val),batch_size=100,epochs=20,shuffle=True,callbacks=[earlystopping,checkpoint],verbose=1) 64 | print("---Train: %s seconds ---" % (time.time() - start_time)) 65 | 66 | #model.summary() 67 | model.load_weights('model.h5') 68 | start_time = time.time() 69 | y = model.predict(x_test) 70 | print("---Test: %s seconds ---" % (time.time() - start_time)) 71 | 72 | scores = model.evaluate(x_test,y_test) 73 | print('scores: ',scores) 74 | #plot_fig(result) 75 | return model 76 | 77 | def to2dim(sig): 78 | out = np.zeros((sig.shape[0],sig.shape[1],2)) 79 | out[:,:,0] = sig.real 80 | out[:,:,1] = sig.imag 81 | return out 82 | 83 | def main(): 84 | (x_train, y_train) = load_mat(train_path,0) 85 | (x_train, y_train),(x_val,y_val) = split_data(x_train,y_train,0.2) 86 | indices = np.arange(x_train.shape[0]) 87 | np.random.shuffle(indices) 88 | x_train = x_train[indices] 89 | y_train = y_train[indices] 90 | indices = np.arange(x_val.shape[0]) 91 | np.random.shuffle(indices) 92 | x_val = x_val[indices] 93 | y_val = y_val[indices] 94 | 95 | x_train = sig2pic(x_train,-3,3,resolution) 96 | x_val = sig2pic(x_val,-3,3,resolution) 97 | 98 | (x_test, y_test) = load_mat(test_path,0) 99 | x_test = sig2pic(x_test,-3,3,resolution) 100 | 101 | model = train(x_train, y_train, x_val, y_val, x_test, y_test) 102 | model_json = model.to_json() 103 | with open("Model/cnn.json", "w") as json_file: 104 | json_file.write(model_json) 105 | model.save_weights("Model/cnn_"+SNR+".h5") 106 | for i in range(4): 107 | n = int(x_test.shape[0]/4) 108 | scores = model.evaluate(x_test[n*i:n*(i+1),:],y_test[n*i:n*(i+1),:]) 109 | print('scores: ',scores) 110 | 111 | if __name__ == "__main__": 112 | main() 113 | -------------------------------------------------------------------------------- /Python/classify_cnnpolar_pic.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import time 3 | import numpy as np 4 | import sys 5 | import random 6 | import itertools 7 | import pydot 8 | import graphviz 9 | import keras.backend as K 10 | from keras.models import Sequential, model_from_json, Model 11 | from keras.layers.core import Dense, Dropout, Activation 12 | from keras.layers.normalization import BatchNormalization 13 | from keras.layers import Convolution2D, ZeroPadding2D, MaxPooling2D, AveragePooling2D, Flatten, Reshape, Input, Lambda 14 | from keras.optimizers import SGD, Adam 15 | from keras.utils import np_utils,plot_model 16 | from keras import regularizers 17 | from keras.callbacks import ReduceLROnPlateau 18 | from keras.preprocessing.image import ImageDataGenerator 19 | from sklearn.metrics import confusion_matrix 20 | from keras.callbacks import EarlyStopping,ModelCheckpoint 21 | import matplotlib.pyplot as plt 22 | import scipy.io 23 | from util import * 24 | 25 | train_path = sys.argv[1] 26 | test_path = sys.argv[2] 27 | resolution = 36 28 | resolution2 = 36 29 | tmp = train_path.split('_') 30 | tmp = tmp[2].split('.') 31 | SNR = tmp[0] 32 | R = 0 #Read Polar Model 33 | duplicate = 0 34 | 35 | def polar(x): 36 | square = K.square(x) 37 | abs_sig = K.sqrt(K.sum(square,axis=2,keepdims=True)) 38 | abs_sig = K.reshape(abs_sig,(K.shape(abs_sig)[0],K.shape(abs_sig)[1],)) 39 | div = tf.div(x[:,:,1],x[:,:,0]) 40 | arctan = tf.atan(div) 41 | return K.concatenate([abs_sig,arctan],axis=1) 42 | 43 | def pic2gauss(sig,x0,x1,y0,y1,r0,r1,l): 44 | linx = np.linspace(x0, x1, r0) 45 | liny = np.linspace(y0, y1, r1) 46 | Px = tf.reshape(sig[:,:l],(-1,l,1)) 47 | Py = tf.reshape(sig[:,l:],(-1,l,1)) 48 | tmpx = tf.reshape(tf.square(Px-linx),(-1,l,r0,1)) 49 | tmpy = tf.reshape(tf.square(Py-liny),(-1,l,1,r1)) 50 | tmp = tmpx+tmpy 51 | out = tf.reduce_sum(tf.exp(-1*tmp/2/0.05),axis=1) 52 | out = tf.reshape(out,(-1,r0,r1,1)) 53 | return out 54 | 55 | def train(x_train, y_train, x_val, y_val, x_test, y_test): 56 | t = int(2**(int(sys.argv[3]))) 57 | cnn_input = Input(shape=(36,36,1)) 58 | cnn_batch = BatchNormalization()(cnn_input) 59 | conv1 = Convolution2D(2*t,(3,3),padding='same',activation='relu')(cnn_batch) 60 | max1 = MaxPooling2D((3,3))(conv1) 61 | bat1 = BatchNormalization()(max1) 62 | conv2 = Convolution2D(1*t,(3,3),padding='same',activation='relu')(bat1) 63 | max2 = MaxPooling2D((3,3))(conv2) 64 | flat = Flatten()(max2) 65 | den1 = Dense(2*t,activation='relu')(flat) 66 | den1 = BatchNormalization()(den1) 67 | den2 = Dense(1*t,activation='relu')(den1) 68 | den2 = BatchNormalization()(den2) 69 | den3 = Dense(4,activation='softmax')(den2) 70 | model = Model(cnn_input,den3) 71 | model.summary() 72 | 73 | sgd = SGD(lr=0.1, decay=1e-6, momentum=0.8, nesterov=True) 74 | model.compile(loss='categorical_crossentropy',optimizer='adadelta',metrics=['accuracy']) 75 | 76 | earlystopping = EarlyStopping(monitor='val_acc', patience = 8, verbose=0, mode='max') 77 | checkpoint = ModelCheckpoint(filepath='model.h5', 78 | verbose=1, 79 | save_best_only=True, 80 | save_weights_only=True, 81 | monitor='val_acc', 82 | mode='max') 83 | start_time = time.time() 84 | result = model.fit(x_train,y_train,validation_data=(x_val,y_val),batch_size=100,epochs=20,shuffle=True,callbacks=[earlystopping,checkpoint],verbose=1) 85 | print("---Train: %s seconds ---" % (time.time() - start_time)) 86 | 87 | #model.summary() 88 | model.load_weights('model.h5') 89 | start_time = time.time() 90 | y = model.predict(x_test) 91 | print("---Test: %s seconds ---" % (time.time() - start_time)) 92 | 93 | scores = model.evaluate(x_test,y_test) 94 | print('scores: ',scores) 95 | #plot_fig(result) 96 | return model 97 | 98 | def fine_tune(x_train, y_train, x_val, y_val, x_test, y_test, model): 99 | i = 0 100 | for layer in model.layers: 101 | layer.trainable = True 102 | 103 | sgd = SGD(lr=0.1, decay=1e-6, momentum=0.8, nesterov=True) 104 | model.compile(loss='categorical_crossentropy',optimizer='adadelta',metrics=['accuracy']) 105 | 106 | earlystopping = EarlyStopping(monitor='val_acc', patience = 30, verbose=0, mode='max') 107 | checkpoint = ModelCheckpoint(filepath='model.h5', 108 | verbose=1, 109 | save_best_only=True, 110 | save_weights_only=True, 111 | monitor='val_acc', 112 | mode='max') 113 | start_time = time.time() 114 | result = model.fit(x_train,y_train,validation_data=(x_val,y_val),batch_size=10,epochs=500,shuffle=True,callbacks=[earlystopping,checkpoint],verbose=1) 115 | print("---Train: %s seconds ---" % (time.time() - start_time)) 116 | model.load_weights('model.h5') 117 | scores = model.evaluate(x_test,y_test) 118 | print(scores) 119 | pre = model.predict(x_test,batch_size=100) 120 | print(pre) 121 | prob = np.mean(np.amax(pre,axis=1)) 122 | print(prob) 123 | return model 124 | 125 | def topolar(sig): 126 | out = np.zeros((sig.shape[0],sig.shape[1]*2)) 127 | for i in range(sig.shape[0]): 128 | out[i][:sig.shape[1]] = np.abs(sig[i]) 129 | out[i][sig.shape[1]:] = np.arctan(sig[i].imag/sig[i].real) 130 | return out 131 | 132 | def main(): 133 | (x_train, y_train) = load_mat(train_path,0) 134 | (x_train, y_train),(x_val,y_val) = split_data(x_train,y_train,0.2) 135 | indices = np.arange(x_train.shape[0]) 136 | np.random.shuffle(indices) 137 | x_train = x_train[indices] 138 | y_train = y_train[indices] 139 | indices = np.arange(x_val.shape[0]) 140 | np.random.shuffle(indices) 141 | x_val = x_val[indices] 142 | y_val = y_val[indices] 143 | 144 | x_train = topolar(x_train) 145 | x_val = topolar(x_val) 146 | 147 | l = x_train.shape[1] 148 | input_sig = Input(shape=(l,2)) 149 | sig = Lambda(polar,output_shape=[2*l])(input_sig) 150 | output_pic = Lambda(pic2gauss,arguments={'x0':0,'x1':3,'y0':-1.6,'y1':1.6,'r0':resolution,'r1':resolution2,'l':l})(sig) 151 | final = Model(input_sig,output_pic) 152 | start_time = time.time() 153 | # Use Gaussian distribution 154 | #x_train = final.predict(x_train,batch_size=100) 155 | #x_val = final.predict(x_val,batch_size=100) 156 | x_train = sig2pic1(x_train,0,3,-1.6,1.6,resolution,resolution2) 157 | x_val = sig2pic1(x_val,0,3,-1.6,1.6,resolution,resolution2) 158 | 159 | print(time.time()-start_time) 160 | 161 | (x_test, y_test) = load_mat(test_path,0) 162 | x_test = topolar(x_test) 163 | # Use Gaussian distribution 164 | #x_test = final.predict(x_test,batch_size=100) 165 | x_test = sig2pic1(x_test,0,3,-1.6,1.6,resolution,resolution2) 166 | 167 | 168 | model = train(x_train, y_train, x_val, y_val, x_test, y_test) 169 | model_json = model.to_json() 170 | with open("Model/cnnpolar.json", "w") as json_file: 171 | json_file.write(model_json) 172 | model.save_weights("Model/cnnpolar_"+SNR+".h5") 173 | for i in range(4): 174 | n = int(x_test.shape[0]/4) 175 | scores = model.evaluate(x_test[n*i:n*(i+1),:],y_test[n*i:n*(i+1),:]) 176 | print('scores: ',scores) 177 | 178 | if __name__ == "__main__": 179 | main() 180 | -------------------------------------------------------------------------------- /Python/model.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JieFangD/Automatic-Modulation-Classification/dc46c30ea328382c1d2e95f4742aae89a86fd734/Python/model.h5 -------------------------------------------------------------------------------- /Python/util.py: -------------------------------------------------------------------------------- 1 | import scipy.io 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | import itertools 5 | import pydot 6 | import graphviz 7 | from sklearn.metrics import confusion_matrix 8 | from keras.utils import np_utils,plot_model 9 | from keras.models import Sequential, model_from_json 10 | import keras.backend as K 11 | import tensorflow as tf 12 | import os 13 | os.environ['CUDA_VISIBLE_DEVICES'] = "1" 14 | config = tf.ConfigProto() 15 | config.gpu_options.allow_growth=True 16 | sess = tf.Session(config=config) 17 | 18 | def load_mat(path,s): 19 | Data = scipy.io.loadmat(path) 20 | x_train = Data['x'] 21 | y_train = np_utils.to_categorical(Data['y'],4) 22 | ''' 23 | Data1 = scipy.io.loadmat('raw20000_1000_8.mat') 24 | Data2 = scipy.io.loadmat('raw20000_1000_8_2.mat') 25 | Data3 = scipy.io.loadmat('raw20000_1000_8_3.mat') 26 | Data4 = scipy.io.loadmat('raw20000_1000_8_4.mat') 27 | Data5 = scipy.io.loadmat('raw20000_1000_8_5.mat') 28 | Data6 = scipy.io.loadmat('raw20000_1000_8_6.mat') 29 | Data7 = scipy.io.loadmat('raw20000_1000_8_7.mat') 30 | Data8 = scipy.io.loadmat('raw20000_1000_8_8.mat') 31 | x_train1 = Data1['x'] 32 | y_train1 = np_utils.to_categorical(Data1['y'],4) 33 | x_train2 = Data2['x'] 34 | y_train2 = np_utils.to_categorical(Data2['y'],4) 35 | x_train3 = Data3['x'] 36 | y_train3 = np_utils.to_categorical(Data3['y'],4) 37 | x_train4 = Data4['x'] 38 | y_train4 = np_utils.to_categorical(Data4['y'],4) 39 | x_train5 = Data5['x'] 40 | y_train5 = np_utils.to_categorical(Data5['y'],4) 41 | x_train6 = Data6['x'] 42 | y_train6 = np_utils.to_categorical(Data6['y'],4) 43 | x_train7 = Data7['x'] 44 | y_train7 = np_utils.to_categorical(Data7['y'],4) 45 | x_train8 = Data8['x'] 46 | y_train8 = np_utils.to_categorical(Data8['y'],4) 47 | ''' 48 | #x_train = np.concatenate((x_train1,x_train2),axis=0) 49 | #x_train = np.concatenate((x_train,Data1['x'],Data2['x'],Data3['x'],Data4['x']),axis=0) 50 | #y_train = np.concatenate((y_train1,y_train2),axis=0) 51 | #y_train = np.concatenate((y_train,np_utils.to_categorical(Data1['y'],4),np_utils.to_categorical(Data2['y'],4),np_utils.to_categorical(Data3['y'],4),np_utils.to_categorical(Data4['y'],4)),axis=0) 52 | if(s): 53 | v = Data['v'] 54 | return (x_train, y_train, v) 55 | return (x_train, y_train) 56 | 57 | def load_mat1(path): 58 | Data = scipy.io.loadmat(path) 59 | x_train = Data['x'] 60 | y_train = Data['y'] 61 | return (x_train, y_train) 62 | 63 | def write_loss(result,name): 64 | scipy.io.savemat(name,{'loss':result.history['val_loss']}) 65 | 66 | def split_data(X,Y,split_ratio): 67 | l = int(X.shape[0]/4) 68 | indices = np.arange(l) 69 | np.random.shuffle(indices) 70 | num = int(split_ratio * l) 71 | indices_train = np.concatenate((indices[num:],indices[num:]+l,indices[num:]+2*l,indices[num:]+3*l)) 72 | indices_test = np.concatenate((indices[:num],indices[:num]+l,indices[:num]+2*l,indices[:num]+3*l)) 73 | 74 | X_train = X[indices_train] 75 | Y_train = Y[indices_train] 76 | X_val = X[indices_test] 77 | Y_val = Y[indices_test] 78 | 79 | indices = np.arange(X_train.shape[0]) 80 | np.random.shuffle(indices) 81 | X_train = X_train[indices] 82 | Y_train = Y_train[indices] 83 | #print(indices_train) 84 | #print(indices_test) 85 | 86 | indices = np.arange(X_val.shape[0]) 87 | np.random.shuffle(indices) 88 | X_val = X_val[indices] 89 | Y_val = Y_val[indices] 90 | 91 | return (X_train,Y_train),(X_val,Y_val) 92 | 93 | def split_data2(X,Y,Z,split_ratio): 94 | indices = np.arange(X.shape[0]) 95 | np.random.shuffle(indices) 96 | 97 | X_data = X[indices] 98 | Y_data = Y[indices] 99 | Z_data = Z[indices] 100 | 101 | num_validation_sample = int(split_ratio * X_data.shape[0] ) 102 | 103 | X_train = X_data[num_validation_sample:] 104 | Y_train = Y_data[num_validation_sample:] 105 | Z_train = Z_data[num_validation_sample:] 106 | 107 | X_val = X_data[:num_validation_sample] 108 | Y_val = Y_data[:num_validation_sample] 109 | Z_val = Z_data[:num_validation_sample] 110 | 111 | return (X_train,Y_train,Z_train),(X_val,Y_val,Z_val) 112 | 113 | def sig2pic(sig,v0,v1,resolution): 114 | v = (v1-v0)/resolution 115 | out = np.zeros((sig.shape[0],resolution,resolution,1)) 116 | for j in range(sig.shape[0]): 117 | for i in range(sig.shape[1]): 118 | x = int((sig[j][i].real-v0)/v) 119 | y = int((sig[j][i].imag-v0)/v) 120 | if(x > resolution-1): 121 | x = resolution-1 122 | elif(x < 0): 123 | x = 0 124 | if(y > resolution-1): 125 | y = resolution-1 126 | elif(y < 0): 127 | y = 0 128 | out[j,x,y,0] = 1 #non accumulated 129 | #out[j,x,y,0] = out[j,x,y,0] + 1 #accumulated 130 | return out 131 | 132 | def sig2pic1(sig,x0,x1,y0,y1,resolution,resolution2): 133 | linx = (x1-x0)/(resolution-1) 134 | liny = (y1-y0)/(resolution2-1) 135 | out = np.zeros((sig.shape[0],resolution,resolution2,1)) 136 | l = int(sig.shape[1]/2) 137 | for j in range(sig.shape[0]): 138 | for i in range(l): 139 | x = int((sig[j][i]-x0)/linx) 140 | y = int((sig[j][l+i]-y0)/liny) 141 | if(x > resolution-1): 142 | x = resolution-1 143 | elif(x < 0): 144 | x = 0 145 | if(y > resolution2-1): 146 | y = resolution2-1 147 | elif(y < 0): 148 | y = 0 149 | #out[j,x,y,0] = 1 #non accumulated 150 | out[j,x,y,0] = out[j,x,y,0] + 1 #accumulated 151 | return out 152 | 153 | def sig2gauss(sig,x0,x1,y0,y1,r0,r1): 154 | l = int(sig.shape[1]/2) 155 | linx = np.linspace(x0, x1, r0) 156 | liny = np.linspace(y0, y1, r1) 157 | Px = np.reshape(sig[:,:l],(-1,l,1)) 158 | Py = np.reshape(sig[:,l:],(-1,l,1)) 159 | tmpx = np.reshape(np.square(Px-linx),(-1,l,r0,1)) 160 | tmpy = np.reshape(np.square(Py-liny),(-1,l,1,r1)) 161 | out = np.zeros((sig.shape[0],r0,r1,1)) 162 | for i in range(sig.shape[0]): 163 | tmp = tmpx[i]+tmpy[i] 164 | tmp = np.sum(np.exp(-1*tmp/2/0.05),axis=0) 165 | out[i] = np.reshape(tmp,(-1,r0,r1,1)) 166 | return out 167 | 168 | def readModel(f1, f2): 169 | import keras.backend as K 170 | json_file = open(f1, 'r') 171 | loaded_model_json = json_file.read() 172 | json_file.close() 173 | model = model_from_json(loaded_model_json,custom_objects={"backend": K,'tf':tf}) 174 | model.load_weights(f2) 175 | return model 176 | 177 | def plot_fig(result): 178 | plt.figure 179 | plt.plot(result.epoch,result.history['acc'],label="acc") 180 | plt.plot(result.epoch,result.history['val_acc'],label="val_acc") 181 | plt.scatter(result.epoch,result.history['acc'],marker='*') 182 | plt.scatter(result.epoch,result.history['val_acc']) 183 | plt.legend(loc='under right') 184 | plt.show() 185 | 186 | plt.figure 187 | plt.plot(result.epoch,result.history['loss'],label="loss") 188 | plt.plot(result.epoch,result.history['val_loss'],label="val_loss") 189 | plt.scatter(result.epoch,result.history['loss'],marker='*') 190 | plt.scatter(result.epoch,result.history['val_loss'],marker='*') 191 | plt.legend(loc='upper right') 192 | plt.show() 193 | 194 | def plot_confusion_matrix(cm, classes, title='Confusion matrix', cmap=plt.cm.jet): 195 | cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis] 196 | plt.figure 197 | plt.imshow(cm, interpolation='nearest', cmap=cmap) 198 | plt.title(title) 199 | plt.colorbar() 200 | tick_marks = np.arange(len(classes)) 201 | plt.xticks(tick_marks, classes, rotation=45) 202 | plt.yticks(tick_marks, classes) 203 | 204 | thresh = cm.max() / 2. 205 | for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])): 206 | plt.text(j, i, '{:.2f}'.format(cm[i, j]), horizontalalignment="center",color="white" if cm[i, j] > thresh else "black") 207 | plt.tight_layout() 208 | plt.ylabel('True label') 209 | plt.xlabel('Predicted label') 210 | plt.show() 211 | 212 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deep Learning for Automatic Modulation Classification 2 | 3 | We propose an efficient and lightweight convolutional neural network (CNN) for the task of automatic modulation classification (AMC). Before sending the received signal into our CNN model, we transform the signal to image domain with the proposed accumulated polar feature. It significantly improves the prediction accuracy and makes it more robust under fading channel. 4 | We provide the source code for the implementation of conventional approaches (Maximum Likelihood and Cumulant) and our deep learning based approaches. Hope this code is useful for peer researchers. If you use this code or parts of it in your research, please kindly cite our paper: 5 | 6 | - **Related publication 1:** Chieh-Fang Teng, Ching-Chun Liao, Chun-Hsiang Chen, and An-Yeu (Andy) Wu, "[Polar Feature Based Deep Architectures for Automatic Modulation Classification Considering Channel Fading](https://ieeexplore.ieee.org/document/8646375)," *published in 2018 IEEE Global Conference on Signal and Information Processing (GlobalSIP).* 7 | 8 | - **Related publication 2:** Chieh-Fang Teng, Ching-Yao Chou, Chun-Hsiang Chen, and An-Yeu (Andy) Wu, "[Accumulated Polar Feature-based Deep Learning for Efficient and Lightweight Automatic Modulation Classification with Channel Compensation Mechanism](https://ieeexplore.ieee.org/document/9277923)," *published in 2020 IEEE Transactions on Vehicular Technology (TVT).* 9 | --- 10 | 11 | ## Required Packages 12 | 13 | - python 3.6.5 14 | - numpy 1.16.4 15 | - tensorflow 1.14.0 16 | - keras 2.2.5 17 | - Matlab R2017a 18 | 19 | ## Source Code 20 | ### Matlab 21 | - Test_ML.m: test the conventional likelohood-based approach of maximum likelihood (ML) and hybrid likelihood ratio test (HLRT) 22 | - Adjust the use of ML or HLRT 23 | - MaximunLikelihood.m 24 | - HybridLRT.m: set the preferred searching space for amplitude and phase 25 | 26 | - Test_Cumu.m: test the conventional feature-based approach of cumulant 27 | - Cumulant.m: adjust the feature used for the classification 28 | 29 | - AMC_raw.m: generate the training data for NN model and visualize the figure used in our paper 30 | - sig2pic.m: transform the received signal to image 31 | - sig2pic_accu.m: transform the received signal to image with historical information 32 | - sig2pic_gaussian.m: transform the received signal to image by Gaussian distribution 33 | 34 | ### Python 35 | - classify_cnn_pic.py: transform the received signal to image in I/Q domain and train CNN model 36 | - python3 classify_cnn_pic.py [training data] [testing data] [model size] 37 | - e.g.: python3 classify_cnn_pic.py ../Data/raw1000_1000_8.mat ../Data/raw500_1000_8.mat 2 38 | 39 | - classify_cnnpolar_pic.py: transform the received signal to image in polar domain and train CNN model 40 | - Adjust whether using Gaussian distribution to generate image 41 | - python3 classify_cnnpolar_pic.py [training data] [testing data] [model size] 42 | - e.g.: python3 classify_cnnpolar_pic.py ../Data/raw1000_1000_8.mat ../Data/raw500_1000_8.mat 2 43 | 44 | - util.py 45 | - Adjust the generated image with accumulated information or not 46 | 47 | ## Contact Information 48 | 49 | ``` 50 | Chieh-Fang Teng: 51 | + jeff@access.ee.ntu.edu.tw 52 | + d06943020@ntu.edu.tw 53 | ``` 54 | --------------------------------------------------------------------------------