├── BTP Report 16EC01026.pdf ├── Data Generation ├── generate_awgn_test_data.m ├── generate_awgn_train_data.m ├── generate_rayleigh_test_data.m └── generate_rayleigh_train_data.m ├── Jupyter Notebooks ├── cnn.ipynb ├── lstm.ipynb └── plots.ipynb ├── Plots ├── Accuracy_Curve_CLDNN_RML.png ├── Accuracy_Curve_CNN2_RML.png ├── Accuracy_Curve_CNN4_RML.png ├── Accuracy_Curve_RNN_RML.png ├── all_awgn.jpg ├── all_rayleigh.jpg ├── cldnn_vs_cum_awgn.jpg ├── cldnn_vs_cum_rayleigh.jpg ├── cnn2_vs_cum_awgn.jpg ├── cnn2_vs_cum_rayleigh.jpg ├── cnn4_vs_cum_awgn.jpg ├── cnn4_vs_cum_rayleigh.jpg ├── lstm_vs_cum_awgn.jpg └── lstm_vs_cum_rayleigh.jpg └── README.md /BTP Report 16EC01026.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaushikYenni/Deep-Learning-based-Modulation-Classification/a9c0e97f438f0ef5cda8e2951b0d5d9b37b28b60/BTP Report 16EC01026.pdf -------------------------------------------------------------------------------- /Data Generation/generate_awgn_test_data.m: -------------------------------------------------------------------------------- 1 | function [esno_array, acc_array] = test_awgn(EsNo_low, EsNo_high, gap, N, L) 2 | %% init 3 | NClass = 4; 4 | NTrain=1600; 5 | j = sqrt(-1); 6 | esno_array = EsNo_low:gap:EsNo_high; 7 | acc_array = zeros(1, length(esno_array)); 8 | train_data = zeros(NClass * NTrain, L); 9 | train_label = zeros(NClass * NTrain, 2); 10 | Phase_low = 0; 11 | Phase_high = pi/8; 12 | offset=0; 13 | 14 | for idx = 1:length(esno_array) 15 | EsNo = esno_array(idx); 16 | P = 10^(EsNo/10); 17 | %fprintf("EsNo = %f\n", EsNo); 18 | confusion_cnt = zeros(NClass, NClass); % bpsk, pam4, psk8, qam4 19 | %% bpsk 20 | signalData = zeros(N, L); 21 | noiseData = zeros(N, L); 22 | mod = comm.BPSKModulator(); 23 | x = constellation(mod); 24 | xN = length(x); 25 | for row = 1:N 26 | 27 | h = sqrt(1/2)*(randn+j*randn); 28 | for col = 1:L 29 | s = x(unidrnd(xN)); 30 | phase_jitter = 2*Phase_high*rand() - Phase_high; 31 | signalData(row, col) = sqrt(P)*exp(j*phase_jitter)*s + sqrt(1/2)*(randn+j*randn); 32 | noiseData(row, col) = sqrt(1/2)*(randn+j*randn); 33 | end 34 | end 35 | for row = 1:N 36 | C20 = sum(signalData(row,:).^2)/L; 37 | C21 = sum(abs(signalData(row,:)).^2)/L; 38 | C21 = C21 - var(noiseData(row,:)); 39 | C40 = sum(signalData(row,:).^4)/L - 3*(C20^2); 40 | C40_norm = C40/(C21^2); 41 | % bpsk, pam4, psk8, qam16 42 | if abs(C40_norm) < 0.34 43 | confusion_cnt(1, 3) = confusion_cnt(1, 3) + 1; 44 | elseif abs(C40_norm) >= 0.34 && abs(C40_norm) < 1.02 45 | confusion_cnt(1, 4) = confusion_cnt(1, 4) + 1; 46 | elseif abs(C40_norm) >= 1.02 && abs(C40_norm) < 1.68 47 | confusion_cnt(1, 2) = confusion_cnt(1, 2) + 1; 48 | else 49 | confusion_cnt(1, 1) = confusion_cnt(1, 1) + 1; 50 | end 51 | train_data(row+(offset*N), :) = signalData(row, :); 52 | train_label(row+(offset*N), 1) = 0; 53 | train_label(row+(offset*N), 2) = EsNo; 54 | end 55 | offset=offset+1; 56 | 57 | %% pam4 58 | signalData = zeros(N, L); 59 | noiseData = zeros(N, L); 60 | mod = comm.PAMModulator('ModulationOrder',4,'NormalizationMethod',... 61 | 'Average power','AveragePower',1); 62 | x = constellation(mod); 63 | xN = length(x); 64 | for row = 1:N 65 | 66 | h = sqrt(1/2)*(randn+j*randn); 67 | for col = 1:L 68 | s = x(unidrnd(xN)); 69 | phase_jitter = 2*Phase_high*rand() - Phase_high; 70 | signalData(row, col) = sqrt(P)*exp(j*phase_jitter)*s + sqrt(1/2)*(randn+j*randn); 71 | noiseData(row, col) = sqrt(1/2)*(randn+j*randn); 72 | end 73 | end 74 | for row = 1:N 75 | C20 = sum(signalData(row,:).^2)/L; 76 | C21 = sum(abs(signalData(row,:)).^2)/L; 77 | C21 = C21 - var(noiseData(row,:)); 78 | C40 = sum(signalData(row,:).^4)/L - 3*(C20^2); 79 | C40_norm = C40/(C21^2); 80 | if abs(C40_norm) < 0.34 81 | confusion_cnt(2, 3) = confusion_cnt(2, 3) + 1; 82 | elseif abs(C40_norm) >= 0.34 && abs(C40_norm) < 1.02 83 | confusion_cnt(2, 4) = confusion_cnt(2, 4) + 1; 84 | elseif abs(C40_norm) >= 1.02 && abs(C40_norm) < 1.68 85 | confusion_cnt(2, 2) = confusion_cnt(2, 2) + 1; 86 | else 87 | confusion_cnt(2, 1) = confusion_cnt(2, 1) + 1; 88 | end 89 | train_data(row+(offset*N), :) = signalData(row, :); 90 | train_label(row+(offset*N), 1) = 1; 91 | train_label(row+(offset*N), 2) = EsNo; 92 | end 93 | offset=offset+1; 94 | 95 | %% psk8 96 | signalData = zeros(N, L); 97 | noiseData = zeros(N, L); 98 | mod = comm.PSKModulator('ModulationOrder',8,'PhaseOffset',0); 99 | x = constellation(mod); 100 | xN = length(x); 101 | for row = 1:N 102 | 103 | h = sqrt(1/2)*(randn+j*randn); 104 | for col = 1:L 105 | s = x(unidrnd(xN)); 106 | phase_jitter = 2*Phase_high*rand() - Phase_high; 107 | signalData(row, col) = sqrt(P)*exp(j*phase_jitter)*s + sqrt(1/2)*(randn+j*randn); 108 | noiseData(row, col) = sqrt(1/2)*(randn+j*randn); 109 | end 110 | end 111 | for row = 1:N 112 | C20 = sum(signalData(row,:).^2)/L; 113 | C21 = sum(abs(signalData(row,:)).^2)/L; 114 | C21 = C21 - var(noiseData(row,:)); 115 | C40 = sum(signalData(row,:).^4)/L - 3*(C20^2); 116 | C40_norm = C40/(C21^2); 117 | if abs(C40_norm) < 0.34 118 | confusion_cnt(3, 3) = confusion_cnt(3, 3) + 1; 119 | elseif abs(C40_norm) >= 0.34 && abs(C40_norm) < 1.02 120 | confusion_cnt(3, 4) = confusion_cnt(3, 4) + 1; 121 | elseif abs(C40_norm) >= 1.02 && abs(C40_norm) < 1.68 122 | confusion_cnt(3, 2) = confusion_cnt(3, 2) + 1; 123 | else 124 | confusion_cnt(3, 1) = confusion_cnt(3, 1) + 1; 125 | end 126 | train_data(row+(offset*N), :) = signalData(row, :); 127 | train_label(row+(offset*N), 1) = 0; 128 | train_label(row+(offset*N), 2) = EsNo; 129 | end 130 | offset=offset+1; 131 | 132 | %% qam4 133 | signalData = zeros(N, L); 134 | noiseData = zeros(N, L); 135 | mod = comm.RectangularQAMModulator('ModulationOrder',4,... 136 | 'NormalizationMethod','Average power','AveragePower',1); 137 | x = constellation(mod); 138 | xN = length(x); 139 | for row = 1:N 140 | 141 | h = sqrt(1/2)*(randn+j*randn); 142 | for col = 1:L 143 | s = x(unidrnd(xN)); 144 | phase_jitter = 2*Phase_high*rand() - Phase_high; 145 | signalData(row, col) = sqrt(P)*exp(j*phase_jitter)*s + sqrt(1/2)*(randn+j*randn); 146 | noiseData(row, col) = sqrt(1/2)*(randn+j*randn); 147 | end 148 | end 149 | for row = 1:N 150 | C20 = sum(signalData(row,:).^2)/L; 151 | C21 = sum(abs(signalData(row,:)).^2)/L; 152 | C21 = C21 - var(noiseData(row,:)); 153 | C40 = sum(signalData(row,:).^4)/L - 3*(C20^2); 154 | C40_norm = C40/(C21^2); 155 | if abs(C40_norm) < 0.34 156 | confusion_cnt(4, 3) = confusion_cnt(4, 3) + 1; 157 | elseif abs(C40_norm) >= 0.34 && abs(C40_norm) < 1.02 158 | confusion_cnt(4, 4) = confusion_cnt(4, 4) + 1; 159 | elseif abs(C40_norm) >= 1.02 && abs(C40_norm) < 1.68 160 | confusion_cnt(4, 2) = confusion_cnt(4, 2) + 1; 161 | else 162 | confusion_cnt(4, 1) = confusion_cnt(4, 1) + 1; 163 | end 164 | train_data(row+(offset*N), :) = signalData(row, :); 165 | train_label(row+(offset*N), 1) = 0; 166 | train_label(row+(offset*N), 2) = EsNo; 167 | end 168 | offset=offset+1; 169 | 170 | cnt = 0; 171 | for idx2 = 1:NClass 172 | cnt = cnt + confusion_cnt(idx2, idx2); 173 | end 174 | acc_array(idx) = cnt/(NClass*N); 175 | %fprintf("acc = %f\n", cnt/(NClass*N)); 176 | end 177 | save('test_data_cum4_awgn.mat', 'train_data', '-mat'); 178 | save('test_label_cum4_awgn.mat', 'train_label', '-mat'); 179 | % %% figure out 180 | % fig1 = figure(1); 181 | % plot(phase_array, acc_array, '-x'); 182 | % hold on; 183 | % axis([Phase_low Phase_high 0 1]); 184 | % %legend('phase_jitter', 'Location', 'southeast'); 185 | % grid on; 186 | % saveas(fig1, 'paper_re_simulation_3.jpg') 187 | -------------------------------------------------------------------------------- /Data Generation/generate_awgn_train_data.m: -------------------------------------------------------------------------------- 1 | clear 2 | clc 3 | %% init 4 | j = sqrt(-1); 5 | L = 128; 6 | NTrain = 10000; 7 | snrs=-10:2:20 8 | 9 | Phase_low = 0; 10 | Phase_high = pi/8; 11 | NClass = 4; 12 | train_data = zeros(NClass * NTrain, L); 13 | train_label = zeros(NClass * NTrain, 2); 14 | %% get train data 15 | % bpsk 16 | disp('bpsk begin'); 17 | signal_data = zeros(NTrain, L); 18 | mod = comm.BPSKModulator(); 19 | x = constellation(mod); 20 | xN = length(x); 21 | for row = 1:NTrain 22 | EsNo = snrs(randperm(length(snrs),1)); % EsNo ~ U(EsNoLow, EsNoHigh) 23 | P = 10^(EsNo/10); 24 | train_label(row, 2) = EsNo; 25 | for col = 1:L 26 | s = x(unidrnd(xN)); 27 | phase_jitter = 2*Phase_high*rand() - Phase_high; % phase jitter ~ U(-PhaseHigh, PhaseHigh) 28 | signal_data(row, col) = sqrt(P)*exp(j*phase_jitter)*s + sqrt(1/2)*(randn+j*randn); 29 | end 30 | end 31 | for row = 1:NTrain 32 | train_data(row, :) = signal_data(row, :); 33 | train_label(row, 1) = 0; 34 | end 35 | % pam4 36 | disp('pam4 begin'); 37 | signal_data = zeros(NTrain, L); 38 | noise_data = zeros(NTrain, L); 39 | mod = comm.PAMModulator('ModulationOrder',4,'NormalizationMethod',... 40 | 'Average power','AveragePower',1); 41 | x = constellation(mod); 42 | xN = length(x); 43 | for row = 1:NTrain 44 | EsNo = snrs(randperm(length(snrs),1)); 45 | P = 10^(EsNo/10); 46 | train_label(row+NTrain, 2) = EsNo; 47 | for col = 1:L 48 | s = x(unidrnd(xN)); 49 | phase_jitter = 2*Phase_high*rand() - Phase_high; 50 | signal_data(row, col) = sqrt(P)*exp(j*phase_jitter)*s + sqrt(1/2)*(randn+j*randn); 51 | end 52 | end 53 | for row = 1:NTrain 54 | train_data(row + NTrain, :) = signal_data(row, :); 55 | train_label(row + NTrain, 1) = 1; 56 | end 57 | % psk8 58 | disp('8psk begin'); 59 | signal_data = zeros(NTrain, L); 60 | mod = comm.PSKModulator('ModulationOrder',8,'PhaseOffset',0); 61 | x = constellation(mod); 62 | xN = length(x); 63 | for row = 1:NTrain 64 | EsNo = snrs(randperm(length(snrs),1)); 65 | P = 10^(EsNo/10); 66 | train_label(row+ 2*NTrain, 2) = EsNo; 67 | for col = 1:L 68 | s = x(unidrnd(xN)); 69 | phase_jitter = 2*Phase_high*rand() - Phase_high; 70 | signal_data(row, col) = sqrt(P)*exp(j*phase_jitter)*s + sqrt(1/2)*(randn+j*randn); 71 | end 72 | end 73 | for row = 1:NTrain 74 | train_data(row + 2*NTrain, :) = signal_data(row, :); 75 | train_label(row + 2*NTrain, 1) = 2; 76 | end 77 | % qam4 78 | disp('qam4 begin'); 79 | signal_data = zeros(NTrain, L); 80 | mod = comm.RectangularQAMModulator('ModulationOrder',4,... 81 | 'NormalizationMethod','Average power','AveragePower',1); 82 | x = constellation(mod); 83 | xN = length(x); 84 | for row = 1:NTrain 85 | EsNo = snrs(randperm(length(snrs),1)); 86 | P = 10^(EsNo/10); 87 | train_label(row+ 3*NTrain, 2) = EsNo; 88 | for col = 1:L 89 | s = x(unidrnd(xN)); 90 | phase_jitter = 2*Phase_high*rand() - Phase_high; 91 | signal_data(row, col) = sqrt(P)*exp(j*phase_jitter)*s + sqrt(1/2)*(randn+j*randn); 92 | end 93 | end 94 | for row = 1:NTrain 95 | train_data(row + 3*NTrain, :) = signal_data(row, :); 96 | train_label(row + 3*NTrain, 1) = 3; 97 | end 98 | 99 | save('train_data_awgn_10k.mat', 'train_data', '-mat'); 100 | save('train_label_awgn_10k.mat', 'train_label', '-mat'); 101 | -------------------------------------------------------------------------------- /Data Generation/generate_rayleigh_test_data.m: -------------------------------------------------------------------------------- 1 | clear 2 | clc 3 | 4 | %% init 5 | N = 960; 6 | Phase_low = 0; 7 | Phase_high = pi/8; 8 | L = 128; 9 | EsNo = 10; 10 | P = 10^(EsNo/10); 11 | NClass = 4; 12 | j = sqrt(-1); 13 | acc_array = zeros(1, length(phase_array)); 14 | EsNo_low = -10; 15 | EsNo_high = 20; 16 | 17 | %% get acc_array 18 | %for idx = 1:length(phase_array) 19 | %PhaseBound = phase_array(idx)*pi/180; 20 | %fprintf("PhaseBound = %f\n", phase_array(idx)); 21 | %fprintf("PhaseBound = %f\n", PhaseBound); 22 | confusion_cnt = zeros(NClass, NClass); % bpsk, pam4, psk8, qam4 23 | %% bpsk 24 | signalData = zeros(N, L); 25 | noiseData = zeros(N, L); 26 | mod = comm.BPSKModulator(); 27 | x = constellation(mod); 28 | xN = length(x); 29 | for row = 1:N 30 | EsNo = (EsNo_high - EsNo_low)*rand + EsNo_low; % EsNo ~ U(EsNoLow, EsNoHigh) 31 | P = 10^(EsNo/10); 32 | h = sqrt(1/2)*(randn+j*randn); 33 | for col = 1:L 34 | s = x(unidrnd(xN)); 35 | phase_jitter = 2*Phase_high*rand() - Phase_high; 36 | signalData(row, col) = sqrt(P)*h*exp(j*phase_jitter)*s + sqrt(1/2)*(randn+j*randn); 37 | noiseData(row, col) = sqrt(1/2)*(randn+j*randn); 38 | end 39 | end 40 | for row = 1:N 41 | C20 = sum(signalData(row,:).^2)/L; 42 | C21 = sum(abs(signalData(row,:)).^2)/L; 43 | C21 = C21 - var(noiseData(row,:)); 44 | C40 = sum(signalData(row,:).^4)/L - 3*(C20^2); 45 | C40_norm = C40/(C21^2); 46 | % bpsk, pam4, psk8, qam16 47 | if abs(C40_norm) < 0.34 48 | confusion_cnt(1, 3) = confusion_cnt(1, 3) + 1; 49 | elseif abs(C40_norm) >= 0.34 && abs(C40_norm) < 1.02 50 | confusion_cnt(1, 4) = confusion_cnt(1, 4) + 1; 51 | elseif abs(C40_norm) >= 1.02 && abs(C40_norm) < 1.68 52 | confusion_cnt(1, 2) = confusion_cnt(1, 2) + 1; 53 | else 54 | confusion_cnt(1, 1) = confusion_cnt(1, 1) + 1; 55 | end 56 | end 57 | %% pam4 58 | signalData = zeros(N, L); 59 | noiseData = zeros(N, L); 60 | mod = comm.PAMModulator('ModulationOrder',4,'NormalizationMethod',... 61 | 'Average power','AveragePower',1); 62 | x = constellation(mod); 63 | xN = length(x); 64 | for row = 1:N 65 | EsNo = (EsNo_high - EsNo_low)*rand + EsNo_low; % EsNo ~ U(EsNoLow, EsNoHigh) 66 | P = 10^(EsNo/10); 67 | h = sqrt(1/2)*(randn+j*randn); 68 | for col = 1:L 69 | s = x(unidrnd(xN)); 70 | phase_jitter = 2*Phase_high*rand() - Phase_high; 71 | signalData(row, col) = sqrt(P)*h*exp(j*phase_jitter)*s + sqrt(1/2)*(randn+j*randn); 72 | noiseData(row, col) = sqrt(1/2)*(randn+j*randn); 73 | end 74 | end 75 | for row = 1:N 76 | C20 = sum(signalData(row,:).^2)/L; 77 | C21 = sum(abs(signalData(row,:)).^2)/L; 78 | C21 = C21 - var(noiseData(row,:)); 79 | C40 = sum(signalData(row,:).^4)/L - 3*(C20^2); 80 | C40_norm = C40/(C21^2); 81 | if abs(C40_norm) < 0.34 82 | confusion_cnt(2, 3) = confusion_cnt(2, 3) + 1; 83 | elseif abs(C40_norm) >= 0.34 && abs(C40_norm) < 1.02 84 | confusion_cnt(2, 4) = confusion_cnt(2, 4) + 1; 85 | elseif abs(C40_norm) >= 1.02 && abs(C40_norm) < 1.68 86 | confusion_cnt(2, 2) = confusion_cnt(2, 2) + 1; 87 | else 88 | confusion_cnt(2, 1) = confusion_cnt(2, 1) + 1; 89 | end 90 | end 91 | %% psk8 92 | signalData = zeros(N, L); 93 | noiseData = zeros(N, L); 94 | mod = comm.PSKModulator('ModulationOrder',8,'PhaseOffset',0); 95 | x = constellation(mod); 96 | xN = length(x); 97 | for row = 1:N 98 | EsNo = (EsNo_high - EsNo_low)*rand + EsNo_low; % EsNo ~ U(EsNoLow, EsNoHigh) 99 | P = 10^(EsNo/10); 100 | h = sqrt(1/2)*(randn+j*randn); 101 | for col = 1:L 102 | s = x(unidrnd(xN)); 103 | phase_jitter = 2*Phase_high*rand() - Phase_high; 104 | signalData(row, col) = sqrt(P)*h*exp(j*phase_jitter)*s + sqrt(1/2)*(randn+j*randn); 105 | noiseData(row, col) = sqrt(1/2)*(randn+j*randn); 106 | end 107 | end 108 | for row = 1:N 109 | C20 = sum(signalData(row,:).^2)/L; 110 | C21 = sum(abs(signalData(row,:)).^2)/L; 111 | C21 = C21 - var(noiseData(row,:)); 112 | C40 = sum(signalData(row,:).^4)/L - 3*(C20^2); 113 | C40_norm = C40/(C21^2); 114 | if abs(C40_norm) < 0.34 115 | confusion_cnt(3, 3) = confusion_cnt(3, 3) + 1; 116 | elseif abs(C40_norm) >= 0.34 && abs(C40_norm) < 1.02 117 | confusion_cnt(3, 4) = confusion_cnt(3, 4) + 1; 118 | elseif abs(C40_norm) >= 1.02 && abs(C40_norm) < 1.68 119 | confusion_cnt(3, 2) = confusion_cnt(3, 2) + 1; 120 | else 121 | confusion_cnt(3, 1) = confusion_cnt(3, 1) + 1; 122 | end 123 | end 124 | %% qam4 125 | signalData = zeros(N, L); 126 | noiseData = zeros(N, L); 127 | mod = comm.RectangularQAMModulator('ModulationOrder',4,... 128 | 'NormalizationMethod','Average power','AveragePower',1); 129 | x = constellation(mod); 130 | xN = length(x); 131 | for row = 1:N 132 | EsNo = (EsNo_high - EsNo_low)*rand + EsNo_low; % EsNo ~ U(EsNoLow, EsNoHigh) 133 | P = 10^(EsNo/10); 134 | h = sqrt(1/2)*(randn+j*randn); 135 | for col = 1:L 136 | s = x(unidrnd(xN)); 137 | phase_jitter = 2*Phase_high*rand() - Phase_high; 138 | signalData(row, col) = sqrt(P)*h*exp(j*phase_jitter)*s + sqrt(1/2)*(randn+j*randn); 139 | noiseData(row, col) = sqrt(1/2)*(randn+j*randn); 140 | end 141 | end 142 | for row = 1:N 143 | C20 = sum(signalData(row,:).^2)/L; 144 | C21 = sum(abs(signalData(row,:)).^2)/L; 145 | C21 = C21 - var(noiseData(row,:)); 146 | C40 = sum(signalData(row,:).^4)/L - 3*(C20^2); 147 | C40_norm = C40/(C21^2); 148 | if abs(C40_norm) < 0.34 149 | confusion_cnt(4, 3) = confusion_cnt(4, 3) + 1; 150 | elseif abs(C40_norm) >= 0.34 && abs(C40_norm) < 1.02 151 | confusion_cnt(4, 4) = confusion_cnt(4, 4) + 1; 152 | elseif abs(C40_norm) >= 1.02 && abs(C40_norm) < 1.68 153 | confusion_cnt(4, 2) = confusion_cnt(4, 2) + 1; 154 | else 155 | confusion_cnt(4, 1) = confusion_cnt(4, 1) + 1; 156 | end 157 | end 158 | cnt = 0; 159 | for idx2 = 1:NClass 160 | cnt = cnt + confusion_cnt(idx2, idx2); 161 | end 162 | %acc_array(idx) = cnt/(NClass*N); 163 | fprintf("acc = %f\n", cnt/(NClass*N)); 164 | %end 165 | 166 | % %% figure out 167 | % fig1 = figure(1); 168 | % plot(phase_array, acc_array, '-x'); 169 | % hold on; 170 | % axis([Phase_low Phase_high 0 1]); 171 | % %legend('phase_jitter', 'Location', 'southeast'); 172 | % grid on; 173 | % saveas(fig1, 'paper_re_simulation_3.jpg') 174 | -------------------------------------------------------------------------------- /Data Generation/generate_rayleigh_train_data.m: -------------------------------------------------------------------------------- 1 | clear 2 | clc 3 | %% init 4 | j = sqrt(-1); 5 | L = 128; 6 | NTrain = 100000; 7 | snrs=-10:2:20 8 | Phase_low = 0; 9 | Phase_high = pi/8; 10 | NClass = 4; 11 | train_data = zeros(NClass * NTrain, L); 12 | train_label = zeros(NClass * NTrain, 2); 13 | %% get train data 14 | % bpsk 15 | disp('bpsk begin'); 16 | signal_data = zeros(NTrain, L); 17 | mod = comm.BPSKModulator(); 18 | x = constellation(mod); 19 | xN = length(x); 20 | for row = 1:NTrain 21 | EsNo = snrs(randperm(length(snrs),1)); % EsNo ~ U(EsNoLow, EsNoHigh) 22 | P = 10^(EsNo/10); 23 | train_label(row, 2) = EsNo; 24 | h = sqrt(1/2)*(randn+j*randn); 25 | for col = 1:L 26 | s = x(unidrnd(xN)); 27 | phase_jitter = 2*Phase_high*rand() - Phase_high; % phase jitter ~ U(-PhaseHigh, PhaseHigh) 28 | signal_data(row, col) = sqrt(P)*h*exp(j*phase_jitter)*s + sqrt(1/2)*(randn+j*randn); 29 | end 30 | end 31 | for row = 1:NTrain 32 | train_data(row, :) = signal_data(row, :); 33 | train_label(row, 1) = 0; 34 | end 35 | % pam4 36 | disp('pam4 begin'); 37 | signal_data = zeros(NTrain, L); 38 | noise_data = zeros(NTrain, L); 39 | mod = comm.PAMModulator('ModulationOrder',4,'NormalizationMethod',... 40 | 'Average power','AveragePower',1); 41 | x = constellation(mod); 42 | xN = length(x); 43 | for row = 1:NTrain 44 | EsNo = snrs(randperm(length(snrs),1)); % EsNo ~ U(EsNoLow, EsNoHigh) 45 | P = 10^(EsNo/10); 46 | train_label(row+NTrain, 2) = EsNo; 47 | h = sqrt(1/2)*(randn+j*randn); 48 | for col = 1:L 49 | s = x(unidrnd(xN)); 50 | phase_jitter = 2*Phase_high*rand() - Phase_high; 51 | signal_data(row, col) = sqrt(P)*h*exp(j*phase_jitter)*s + sqrt(1/2)*(randn+j*randn); 52 | end 53 | end 54 | for row = 1:NTrain 55 | train_data(row + NTrain, :) = signal_data(row, :); 56 | train_label(row + NTrain, 1) = 1; 57 | end 58 | % psk8 59 | disp('8psk begin'); 60 | signal_data = zeros(NTrain, L); 61 | mod = comm.PSKModulator('ModulationOrder',8,'PhaseOffset',0); 62 | x = constellation(mod); 63 | xN = length(x); 64 | for row = 1:NTrain 65 | EsNo = snrs(randperm(length(snrs),1)); % EsNo ~ U(EsNoLow, EsNoHigh) 66 | P = 10^(EsNo/10); 67 | train_label(row+(2*NTrain), 2) = EsNo; 68 | h = sqrt(1/2)*(randn+j*randn); 69 | 70 | for col = 1:L 71 | s = x(unidrnd(xN)); 72 | phase_jitter = 2*Phase_high*rand() - Phase_high; 73 | signal_data(row, col) = sqrt(P)*h*exp(j*phase_jitter)*s + sqrt(1/2)*(randn+j*randn); 74 | end 75 | end 76 | for row = 1:NTrain 77 | train_data(row + 2*NTrain, :) = signal_data(row, :); 78 | train_label(row + 2*NTrain, 1) = 2; 79 | end 80 | % qam4 81 | disp('qam4 begin'); 82 | signal_data = zeros(NTrain, L); 83 | mod = comm.RectangularQAMModulator('ModulationOrder',4,... 84 | 'NormalizationMethod','Average power','AveragePower',1); 85 | x = constellation(mod); 86 | xN = length(x); 87 | for row = 1:NTrain 88 | EsNo = snrs(randperm(length(snrs),1)); 89 | P = 10^(EsNo/10); 90 | h = sqrt(1/2)*(randn+j*randn); 91 | train_label(row + 3*NTrain, 2) = EsNo; 92 | for col = 1:L 93 | s = x(unidrnd(xN)); 94 | phase_jitter = 2*Phase_high*rand() - Phase_high; 95 | signal_data(row, col) = sqrt(P)*h*exp(j*phase_jitter)*s + sqrt(1/2)*(randn+j*randn); 96 | end 97 | end 98 | for row = 1:NTrain 99 | train_data(row + 3*NTrain, :) = signal_data(row, :); 100 | train_label(row + 3*NTrain, 1) = 3; 101 | end 102 | 103 | save('train_data_rayleigh_100k.mat', 'train_data', '-mat'); 104 | save('train_label_rayleigh_100k.mat', 'train_label', '-mat'); 105 | -------------------------------------------------------------------------------- /Jupyter Notebooks/lstm.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "rnn_lite.ipynb", 7 | "provenance": [], 8 | "collapsed_sections": [] 9 | }, 10 | "kernelspec": { 11 | "name": "python3", 12 | "display_name": "Python 3" 13 | }, 14 | "accelerator": "GPU" 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "code", 19 | "metadata": { 20 | "id": "M8EB4U1MqbdW", 21 | "colab_type": "code", 22 | "colab": { 23 | "base_uri": "https://localhost:8080/", 24 | "height": 147 25 | }, 26 | "outputId": "14da3ebb-385e-4264-ff75-4ac82c10881f" 27 | }, 28 | "source": [ 29 | "from google.colab import drive\n", 30 | "drive.mount('/gdrive')\n", 31 | "%cd /gdrive" 32 | ], 33 | "execution_count": null, 34 | "outputs": [ 35 | { 36 | "output_type": "stream", 37 | "text": [ 38 | "Go to this URL in a browser: https://accounts.google.com/o/oauth2/auth?client_id=947318989803-6bn6qk8qdgf4n4g3pfee6491hc0brc4i.apps.googleusercontent.com&redirect_uri=urn%3aietf%3awg%3aoauth%3a2.0%3aoob&response_type=code&scope=email%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdocs.test%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdrive%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdrive.photos.readonly%20https%3a%2f%2fwww.googleapis.com%2fauth%2fpeopleapi.readonly\n", 39 | "\n", 40 | "Enter your authorization code:\n", 41 | "··········\n", 42 | "Mounted at /gdrive\n", 43 | "/gdrive\n" 44 | ], 45 | "name": "stdout" 46 | } 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "metadata": { 52 | "id": "UdPPFCzxBQ5K", 53 | "colab_type": "code", 54 | "colab": { 55 | "base_uri": "https://localhost:8080/", 56 | "height": 1000 57 | }, 58 | "outputId": "70e21fd1-8722-4852-d341-f383368314af" 59 | }, 60 | "source": [ 61 | "import numpy as np\n", 62 | "import tensorflow as tf\n", 63 | "import random as rn\n", 64 | "import os\n", 65 | "import json\n", 66 | "\n", 67 | "from keras import metrics, regularizers, optimizers, backend\n", 68 | "from keras.callbacks import TensorBoard, EarlyStopping\n", 69 | "from keras.models import Model\n", 70 | "from keras.layers import Input, Dense, LSTM, CuDNNLSTM, Flatten, Dropout, BatchNormalization\n", 71 | "from keras.utils import np_utils, vis_utils\n", 72 | "\n", 73 | "import scipy.io as sio\n", 74 | "\n", 75 | "# fix random seed\n", 76 | "os.environ['PYTHONHASHSEED'] = '0'\n", 77 | "np.random.seed(2018)\n", 78 | "rn.seed(2018)\n", 79 | "session_conf = tf.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=4)\n", 80 | "tf.set_random_seed(2018)\n", 81 | "sess = tf.Session(graph=tf.get_default_graph(), config=session_conf)\n", 82 | "backend.set_session(sess)\n", 83 | "\n", 84 | "seqLen = 128\n", 85 | "nClass = 4\n", 86 | "samNum = 100000 * nClass\n", 87 | "# load train data\n", 88 | "x_data_mat = sio.loadmat('/content/drive/My Drive/train_data_awgn_100k.mat')\n", 89 | "x_data_complex = x_data_mat['train_data']\n", 90 | "x_data_real = x_data_complex.real\n", 91 | "x_data_imag = x_data_complex.imag\n", 92 | "x_data_real = x_data_real.reshape((x_data_real.shape[0], seqLen))\n", 93 | "x_data_imag = x_data_imag.reshape((x_data_imag.shape[0], seqLen))\n", 94 | "x_train = np.stack((x_data_real, x_data_imag), axis=2)\n", 95 | "y_data_mat = sio.loadmat('/content/drive/My Drive/train_label_awgn_100k.mat')\n", 96 | "y_data = y_data_mat['train_label'][:,0]\n", 97 | "y_snrs = y_data_mat['train_label'][:,1]\n", 98 | "y_train = np_utils.to_categorical(y_data, nClass)\n", 99 | "# train data shuffle\n", 100 | "index = np.arange(y_train.shape[0])\n", 101 | "np.random.shuffle(index)\n", 102 | "x_train = x_train[index,:]\n", 103 | "y_train = y_train[index]\n", 104 | "\n", 105 | "_in_ = Input(shape = (x_train.shape[1], x_train.shape[2]))\n", 106 | "ot = CuDNNLSTM(16, return_sequences=False)(_in_)\n", 107 | "#ot = Flatten()(ot)\n", 108 | "ot = BatchNormalization(axis=-1, momentum=0.99, epsilon=0.001, center=True, scale=True)(ot)\n", 109 | "ot = Dense(64, use_bias=True, activation='relu')(ot)\n", 110 | "ot = Dense(16, use_bias=True, activation='relu')(ot)\n", 111 | "_out_ = Dense(nClass, activation='softmax')(ot)\n", 112 | "model = Model(_in_, _out_)\n", 113 | "\n", 114 | "tensor_board = TensorBoard(log_dir='./tensorboard_log', histogram_freq=0, write_graph=True, write_images=False,\n", 115 | " embeddings_freq=0, embeddings_layer_names=None, embeddings_metadata=None)\n", 116 | "early_stopping = EarlyStopping(monitor='val_loss', patience=15)\n", 117 | "adam = optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08)\n", 118 | "model.compile(loss='categorical_crossentropy',\n", 119 | " optimizer=adam, \n", 120 | " metrics=['categorical_accuracy'])\n", 121 | "model.fit(x_train,\n", 122 | " y_train, \n", 123 | " epochs=100, \n", 124 | " batch_size=128,\n", 125 | " validation_split=0.1,\n", 126 | " shuffle=True,callbacks=[early_stopping])\n", 127 | " #callbacks=[])\n", 128 | " #callbacks=[tensor_board])\n", 129 | " #callbacks=[early_stopping])\n", 130 | " #callbacks=[tensor_board, early_stopping])\n", 131 | "model.summary()\n", 132 | "\n" 133 | ], 134 | "execution_count": null, 135 | "outputs": [ 136 | { 137 | "output_type": "stream", 138 | "text": [ 139 | "Train on 360000 samples, validate on 40000 samples\n", 140 | "Epoch 1/100\n", 141 | "360000/360000 [==============================] - 39s 108us/step - loss: 0.6170 - categorical_accuracy: 0.6561 - val_loss: 0.4683 - val_categorical_accuracy: 0.7419\n", 142 | "Epoch 2/100\n", 143 | "360000/360000 [==============================] - 38s 107us/step - loss: 0.4615 - categorical_accuracy: 0.7554 - val_loss: 0.4499 - val_categorical_accuracy: 0.7629\n", 144 | "Epoch 3/100\n", 145 | "360000/360000 [==============================] - 38s 107us/step - loss: 0.4442 - categorical_accuracy: 0.7658 - val_loss: 0.4338 - val_categorical_accuracy: 0.7713\n", 146 | "Epoch 4/100\n", 147 | "360000/360000 [==============================] - 38s 107us/step - loss: 0.4337 - categorical_accuracy: 0.7714 - val_loss: 0.4223 - val_categorical_accuracy: 0.7797\n", 148 | "Epoch 5/100\n", 149 | "360000/360000 [==============================] - 39s 108us/step - loss: 0.4246 - categorical_accuracy: 0.7775 - val_loss: 0.4428 - val_categorical_accuracy: 0.7682\n", 150 | "Epoch 6/100\n", 151 | "360000/360000 [==============================] - 39s 108us/step - loss: 0.4190 - categorical_accuracy: 0.7809 - val_loss: 0.4089 - val_categorical_accuracy: 0.7887\n", 152 | "Epoch 7/100\n", 153 | "360000/360000 [==============================] - 39s 108us/step - loss: 0.4144 - categorical_accuracy: 0.7835 - val_loss: 0.4254 - val_categorical_accuracy: 0.7841\n", 154 | "Epoch 8/100\n", 155 | "360000/360000 [==============================] - 39s 108us/step - loss: 0.4106 - categorical_accuracy: 0.7860 - val_loss: 0.4034 - val_categorical_accuracy: 0.7900\n", 156 | "Epoch 9/100\n", 157 | "360000/360000 [==============================] - 39s 107us/step - loss: 0.4079 - categorical_accuracy: 0.7872 - val_loss: 0.4030 - val_categorical_accuracy: 0.7910\n", 158 | "Epoch 10/100\n", 159 | "360000/360000 [==============================] - 39s 108us/step - loss: 0.4064 - categorical_accuracy: 0.7881 - val_loss: 0.4154 - val_categorical_accuracy: 0.7862\n", 160 | "Epoch 11/100\n", 161 | "360000/360000 [==============================] - 39s 107us/step - loss: 0.4040 - categorical_accuracy: 0.7897 - val_loss: 0.4075 - val_categorical_accuracy: 0.7911\n", 162 | "Epoch 12/100\n", 163 | "360000/360000 [==============================] - 39s 108us/step - loss: 0.4019 - categorical_accuracy: 0.7907 - val_loss: 0.4053 - val_categorical_accuracy: 0.7847\n", 164 | "Epoch 13/100\n", 165 | "360000/360000 [==============================] - 39s 108us/step - loss: 0.4011 - categorical_accuracy: 0.7909 - val_loss: 0.3977 - val_categorical_accuracy: 0.7916\n", 166 | "Epoch 14/100\n", 167 | "360000/360000 [==============================] - 39s 107us/step - loss: 0.3994 - categorical_accuracy: 0.7919 - val_loss: 0.4425 - val_categorical_accuracy: 0.7801\n", 168 | "Epoch 15/100\n", 169 | "360000/360000 [==============================] - 39s 107us/step - loss: 0.3982 - categorical_accuracy: 0.7928 - val_loss: 0.4089 - val_categorical_accuracy: 0.7856\n", 170 | "Epoch 16/100\n", 171 | "360000/360000 [==============================] - 39s 108us/step - loss: 0.3969 - categorical_accuracy: 0.7938 - val_loss: 0.4040 - val_categorical_accuracy: 0.7893\n", 172 | "Epoch 17/100\n", 173 | "360000/360000 [==============================] - 38s 107us/step - loss: 0.3965 - categorical_accuracy: 0.7936 - val_loss: 0.3930 - val_categorical_accuracy: 0.7933\n", 174 | "Epoch 18/100\n", 175 | "360000/360000 [==============================] - 39s 107us/step - loss: 0.3946 - categorical_accuracy: 0.7952 - val_loss: 0.4046 - val_categorical_accuracy: 0.7913\n", 176 | "Epoch 19/100\n", 177 | "360000/360000 [==============================] - 38s 107us/step - loss: 0.3940 - categorical_accuracy: 0.7956 - val_loss: 0.4036 - val_categorical_accuracy: 0.7915\n", 178 | "Epoch 20/100\n", 179 | "360000/360000 [==============================] - 39s 107us/step - loss: 0.3930 - categorical_accuracy: 0.7962 - val_loss: 0.4012 - val_categorical_accuracy: 0.7914\n", 180 | "Epoch 21/100\n", 181 | "360000/360000 [==============================] - 39s 107us/step - loss: 0.3929 - categorical_accuracy: 0.7963 - val_loss: 0.4138 - val_categorical_accuracy: 0.7846\n", 182 | "Epoch 22/100\n", 183 | "360000/360000 [==============================] - 38s 107us/step - loss: 0.3918 - categorical_accuracy: 0.7966 - val_loss: 0.4012 - val_categorical_accuracy: 0.7896\n", 184 | "Epoch 23/100\n", 185 | "360000/360000 [==============================] - 39s 107us/step - loss: 0.3911 - categorical_accuracy: 0.7969 - val_loss: 0.3948 - val_categorical_accuracy: 0.7951\n", 186 | "Epoch 24/100\n", 187 | "360000/360000 [==============================] - 39s 109us/step - loss: 0.3909 - categorical_accuracy: 0.7963 - val_loss: 0.3948 - val_categorical_accuracy: 0.7959\n", 188 | "Epoch 25/100\n", 189 | "360000/360000 [==============================] - 38s 106us/step - loss: 0.3903 - categorical_accuracy: 0.7972 - val_loss: 0.3948 - val_categorical_accuracy: 0.7947\n", 190 | "Epoch 26/100\n", 191 | "360000/360000 [==============================] - 38s 106us/step - loss: 0.3900 - categorical_accuracy: 0.7982 - val_loss: 0.3889 - val_categorical_accuracy: 0.7977\n", 192 | "Epoch 27/100\n", 193 | "360000/360000 [==============================] - 37s 104us/step - loss: 0.3894 - categorical_accuracy: 0.7983 - val_loss: 0.3916 - val_categorical_accuracy: 0.7984\n", 194 | "Epoch 28/100\n", 195 | "360000/360000 [==============================] - 38s 106us/step - loss: 0.3888 - categorical_accuracy: 0.7979 - val_loss: 0.3958 - val_categorical_accuracy: 0.7933\n", 196 | "Epoch 29/100\n", 197 | "360000/360000 [==============================] - 39s 107us/step - loss: 0.3883 - categorical_accuracy: 0.7984 - val_loss: 0.3918 - val_categorical_accuracy: 0.7954\n", 198 | "Epoch 30/100\n", 199 | "360000/360000 [==============================] - 38s 106us/step - loss: 0.3878 - categorical_accuracy: 0.7985 - val_loss: 0.3963 - val_categorical_accuracy: 0.7957\n", 200 | "Epoch 31/100\n", 201 | "360000/360000 [==============================] - 38s 107us/step - loss: 0.3878 - categorical_accuracy: 0.7989 - val_loss: 0.3931 - val_categorical_accuracy: 0.7962\n", 202 | "Epoch 32/100\n", 203 | "360000/360000 [==============================] - 39s 108us/step - loss: 0.3878 - categorical_accuracy: 0.7985 - val_loss: 0.3934 - val_categorical_accuracy: 0.7969\n", 204 | "Epoch 33/100\n", 205 | "360000/360000 [==============================] - 38s 106us/step - loss: 0.3879 - categorical_accuracy: 0.7987 - val_loss: 0.3876 - val_categorical_accuracy: 0.7989\n", 206 | "Epoch 34/100\n", 207 | "360000/360000 [==============================] - 39s 107us/step - loss: 0.3870 - categorical_accuracy: 0.7992 - val_loss: 0.3928 - val_categorical_accuracy: 0.7974\n", 208 | "Epoch 35/100\n", 209 | "360000/360000 [==============================] - 38s 107us/step - loss: 0.3868 - categorical_accuracy: 0.7993 - val_loss: 0.4006 - val_categorical_accuracy: 0.7931\n", 210 | "Epoch 36/100\n", 211 | "360000/360000 [==============================] - 38s 107us/step - loss: 0.3868 - categorical_accuracy: 0.7990 - val_loss: 0.3883 - val_categorical_accuracy: 0.7982\n", 212 | "Epoch 37/100\n", 213 | "360000/360000 [==============================] - 38s 107us/step - loss: 0.3866 - categorical_accuracy: 0.7997 - val_loss: 0.3989 - val_categorical_accuracy: 0.7953\n", 214 | "Epoch 38/100\n", 215 | "360000/360000 [==============================] - 38s 107us/step - loss: 0.3865 - categorical_accuracy: 0.7999 - val_loss: 0.3928 - val_categorical_accuracy: 0.7987\n", 216 | "Epoch 39/100\n", 217 | "360000/360000 [==============================] - 38s 107us/step - loss: 0.3862 - categorical_accuracy: 0.7998 - val_loss: 0.3921 - val_categorical_accuracy: 0.7951\n", 218 | "Epoch 40/100\n", 219 | "360000/360000 [==============================] - 39s 108us/step - loss: 0.3859 - categorical_accuracy: 0.7996 - val_loss: 0.3994 - val_categorical_accuracy: 0.7933\n", 220 | "Epoch 41/100\n", 221 | "360000/360000 [==============================] - 38s 106us/step - loss: 0.3858 - categorical_accuracy: 0.7996 - val_loss: 0.3918 - val_categorical_accuracy: 0.7973\n", 222 | "Epoch 42/100\n", 223 | "360000/360000 [==============================] - 38s 106us/step - loss: 0.3853 - categorical_accuracy: 0.8000 - val_loss: 0.3978 - val_categorical_accuracy: 0.7923\n", 224 | "Epoch 43/100\n", 225 | "360000/360000 [==============================] - 38s 106us/step - loss: 0.3857 - categorical_accuracy: 0.7993 - val_loss: 0.3878 - val_categorical_accuracy: 0.8000\n", 226 | "Epoch 44/100\n", 227 | "360000/360000 [==============================] - 38s 106us/step - loss: 0.3853 - categorical_accuracy: 0.7998 - val_loss: 0.3934 - val_categorical_accuracy: 0.7971\n", 228 | "Epoch 45/100\n", 229 | "360000/360000 [==============================] - 39s 107us/step - loss: 0.3852 - categorical_accuracy: 0.8003 - val_loss: 0.3862 - val_categorical_accuracy: 0.8004\n", 230 | "Epoch 46/100\n", 231 | "360000/360000 [==============================] - 38s 106us/step - loss: 0.3849 - categorical_accuracy: 0.8004 - val_loss: 0.3867 - val_categorical_accuracy: 0.7994\n", 232 | "Epoch 47/100\n", 233 | "360000/360000 [==============================] - 38s 107us/step - loss: 0.3847 - categorical_accuracy: 0.7998 - val_loss: 0.3880 - val_categorical_accuracy: 0.7994\n", 234 | "Epoch 48/100\n", 235 | "360000/360000 [==============================] - 39s 108us/step - loss: 0.3847 - categorical_accuracy: 0.8002 - val_loss: 0.3866 - val_categorical_accuracy: 0.8004\n", 236 | "Epoch 49/100\n", 237 | "360000/360000 [==============================] - 38s 107us/step - loss: 0.3847 - categorical_accuracy: 0.8000 - val_loss: 0.3920 - val_categorical_accuracy: 0.7966\n", 238 | "Epoch 50/100\n", 239 | "360000/360000 [==============================] - 39s 107us/step - loss: 0.3845 - categorical_accuracy: 0.8005 - val_loss: 0.3989 - val_categorical_accuracy: 0.7937\n", 240 | "Epoch 51/100\n", 241 | "360000/360000 [==============================] - 39s 107us/step - loss: 0.3844 - categorical_accuracy: 0.8005 - val_loss: 0.3878 - val_categorical_accuracy: 0.7970\n", 242 | "Epoch 52/100\n", 243 | "360000/360000 [==============================] - 38s 106us/step - loss: 0.3842 - categorical_accuracy: 0.8004 - val_loss: 0.3983 - val_categorical_accuracy: 0.7893\n", 244 | "Epoch 53/100\n", 245 | "360000/360000 [==============================] - 38s 107us/step - loss: 0.3841 - categorical_accuracy: 0.8011 - val_loss: 0.3902 - val_categorical_accuracy: 0.7982\n", 246 | "Epoch 54/100\n", 247 | "360000/360000 [==============================] - 38s 106us/step - loss: 0.3842 - categorical_accuracy: 0.8005 - val_loss: 0.3905 - val_categorical_accuracy: 0.7994\n", 248 | "Epoch 55/100\n", 249 | "360000/360000 [==============================] - 38s 106us/step - loss: 0.3842 - categorical_accuracy: 0.8011 - val_loss: 0.3879 - val_categorical_accuracy: 0.7983\n", 250 | "Epoch 56/100\n", 251 | "360000/360000 [==============================] - 39s 108us/step - loss: 0.3837 - categorical_accuracy: 0.8004 - val_loss: 0.3904 - val_categorical_accuracy: 0.7951\n", 252 | "Epoch 57/100\n", 253 | "360000/360000 [==============================] - 38s 107us/step - loss: 0.3838 - categorical_accuracy: 0.8003 - val_loss: 0.4016 - val_categorical_accuracy: 0.7934\n", 254 | "Epoch 58/100\n", 255 | "360000/360000 [==============================] - 38s 106us/step - loss: 0.3838 - categorical_accuracy: 0.8004 - val_loss: 0.3866 - val_categorical_accuracy: 0.8013\n", 256 | "Epoch 59/100\n", 257 | "360000/360000 [==============================] - 38s 106us/step - loss: 0.3837 - categorical_accuracy: 0.8010 - val_loss: 0.3924 - val_categorical_accuracy: 0.7950\n", 258 | "Epoch 60/100\n", 259 | "360000/360000 [==============================] - 38s 106us/step - loss: 0.3836 - categorical_accuracy: 0.8008 - val_loss: 0.3894 - val_categorical_accuracy: 0.7966\n", 260 | "Model: \"model_2\"\n", 261 | "_________________________________________________________________\n", 262 | "Layer (type) Output Shape Param # \n", 263 | "=================================================================\n", 264 | "input_3 (InputLayer) (None, 128, 2) 0 \n", 265 | "_________________________________________________________________\n", 266 | "cu_dnnlstm_3 (CuDNNLSTM) (None, 16) 1280 \n", 267 | "_________________________________________________________________\n", 268 | "batch_normalization_2 (Batch (None, 16) 64 \n", 269 | "_________________________________________________________________\n", 270 | "dense_4 (Dense) (None, 64) 1088 \n", 271 | "_________________________________________________________________\n", 272 | "dense_5 (Dense) (None, 16) 1040 \n", 273 | "_________________________________________________________________\n", 274 | "dense_6 (Dense) (None, 4) 68 \n", 275 | "=================================================================\n", 276 | "Total params: 3,540\n", 277 | "Trainable params: 3,508\n", 278 | "Non-trainable params: 32\n", 279 | "_________________________________________________________________\n" 280 | ], 281 | "name": "stdout" 282 | } 283 | ] 284 | }, 285 | { 286 | "cell_type": "code", 287 | "metadata": { 288 | "id": "8u0eO80QwRcw", 289 | "colab_type": "code", 290 | "colab": {} 291 | }, 292 | "source": [ 293 | "model.save_weights('/content/drive/My Drive/model_weights_rnn_lite_awgn.h5')" 294 | ], 295 | "execution_count": null, 296 | "outputs": [] 297 | }, 298 | { 299 | "cell_type": "code", 300 | "metadata": { 301 | "id": "lDaBFdXL05tJ", 302 | "colab_type": "code", 303 | "colab": {} 304 | }, 305 | "source": [ 306 | "acc_array_cumulants_awgn=[0.247500,0.247500,0.267500,0.242500,0.260000,0.315000,0.457500,0.632500,0.845000,0.950000,0.985000,1.000000,1.000000,1.000000,1.000000,1.000000]" 307 | ], 308 | "execution_count": null, 309 | "outputs": [] 310 | }, 311 | { 312 | "cell_type": "code", 313 | "metadata": { 314 | "id": "5MmLdx1kBt2H", 315 | "colab_type": "code", 316 | "colab": {} 317 | }, 318 | "source": [ 319 | "X_test_mat=sio.loadmat('/content/drive/My Drive/train_data_awgn_10k.mat')\n", 320 | "Y_test_mat=sio.loadmat('/content/drive/My Drive/train_label_awgn_10k.mat')\n", 321 | "X_test_complex = X_test_mat['train_data']\n", 322 | "X_test_real = X_test_complex.real\n", 323 | "X_test_imag = X_test_complex.imag\n", 324 | "X_test_real = X_test_real.reshape((X_test_real.shape[0], seqLen))\n", 325 | "X_test_imag = X_test_imag.reshape((X_test_imag.shape[0], seqLen))\n", 326 | "X_test = np.stack((X_test_real, X_test_imag), axis=2)" 327 | ], 328 | "execution_count": null, 329 | "outputs": [] 330 | }, 331 | { 332 | "cell_type": "code", 333 | "metadata": { 334 | "id": "MlUM5J5QXLI6", 335 | "colab_type": "code", 336 | "colab": { 337 | "base_uri": "https://localhost:8080/", 338 | "height": 35 339 | }, 340 | "outputId": "11a6170b-7467-4553-f671-7a504e8ff259" 341 | }, 342 | "source": [ 343 | "fucked=Y_test_mat['train_label']\n", 344 | "Y_test=fucked[:,0]\n", 345 | "Y_test_snrs=fucked[:,1]\n", 346 | "Y_test=np_utils.to_categorical(Y_test,4)\n", 347 | "score = model.evaluate(X_test, Y_test, verbose=0)\n", 348 | "print(score)\n", 349 | "#test_Y_hat = model.predict(X_test)" 350 | ], 351 | "execution_count": null, 352 | "outputs": [ 353 | { 354 | "output_type": "stream", 355 | "text": [ 356 | "[0.38159793635606765, 0.8]\n" 357 | ], 358 | "name": "stdout" 359 | } 360 | ] 361 | }, 362 | { 363 | "cell_type": "code", 364 | "metadata": { 365 | "id": "ux-qEeAHtoNd", 366 | "colab_type": "code", 367 | "colab": {} 368 | }, 369 | "source": [ 370 | "acc_array_cumulants_rayleigh=[0.2500, 0.2458 , 0.2542 , 0.2833 , 0.3167 , 0.3958 , 0.4125 , 0.5875 , 0.6792 , 0.7458 , 0.8167 , 0.8750, 0.9417 , 0.9375 , 0.9708 , 0.9625]" 371 | ], 372 | "execution_count": null, 373 | "outputs": [] 374 | }, 375 | { 376 | "cell_type": "code", 377 | "metadata": { 378 | "id": "_viheZlCuIKN", 379 | "colab_type": "code", 380 | "colab": {} 381 | }, 382 | "source": [ 383 | "snrs=np.arange(-10,21,2)" 384 | ], 385 | "execution_count": null, 386 | "outputs": [] 387 | }, 388 | { 389 | "cell_type": "code", 390 | "metadata": { 391 | "id": "kb1pF5BM4Roq", 392 | "colab_type": "code", 393 | "colab": { 394 | "base_uri": "https://localhost:8080/", 395 | "height": 605 396 | }, 397 | "outputId": "eb4f63fe-be91-4841-d043-14b535facf6c" 398 | }, 399 | "source": [ 400 | "\n", 401 | "acc_lstm_awgn = {}\n", 402 | "for snr in snrs:\n", 403 | " # extract classes @ SNR\n", 404 | " #test_SNRs = list(map(lambda x: lbl[x][1], test_idx))\n", 405 | " test_X_i = X_test[np.where(np.array(Y_test_snrs)==snr)]\n", 406 | " test_Y_i = Y_test[np.where(np.array(Y_test_snrs)==snr)] \n", 407 | " test_Y_i_hat = model.predict(test_X_i.reshape(test_X_i.shape[0],128,2))\n", 408 | " conf = np.zeros([4,4])\n", 409 | " confnorm = np.zeros([4,4])\n", 410 | " for i in range(0,test_X_i.shape[0]):\n", 411 | " j = list(test_Y_i[i,:]).index(1)\n", 412 | " k = int(np.argmax(test_Y_i_hat[i,:]))\n", 413 | " conf[j,k] = conf[j,k] + 1\n", 414 | " for i in range(0,4):\n", 415 | " confnorm[i,:] = conf[i,:] / np.sum(conf[i,:])\n", 416 | " #plt.figure()\n", 417 | " #plot_confusion_matrix(confnorm, labels=classes, title=\"ConvNet Confusion Matrix (SNR=%d)\"%(snr))\n", 418 | " \n", 419 | " cor = np.sum(np.diag(conf))\n", 420 | " ncor = np.sum(conf) - cor\n", 421 | " print(\"Overall Accuracy: \", cor / (cor+ncor))\n", 422 | " print(\"snr=\",snr)\n", 423 | " acc_lstm_awgn[snr] = 1.0*cor/(cor+ncor)" 424 | ], 425 | "execution_count": null, 426 | "outputs": [ 427 | { 428 | "output_type": "stream", 429 | "text": [ 430 | "Overall Accuracy: 0.3460434604346043\n", 431 | "snr= -10\n", 432 | "Overall Accuracy: 0.3839249286005712\n", 433 | "snr= -8\n", 434 | "Overall Accuracy: 0.44208037825059104\n", 435 | "snr= -6\n", 436 | "Overall Accuracy: 0.5149130074565037\n", 437 | "snr= -4\n", 438 | "Overall Accuracy: 0.6153232242617718\n", 439 | "snr= -2\n", 440 | "Overall Accuracy: 0.7004698512137824\n", 441 | "snr= 0\n", 442 | "Overall Accuracy: 0.8527755430410298\n", 443 | "snr= 2\n", 444 | "Overall Accuracy: 0.9338205440519691\n", 445 | "snr= 4\n", 446 | "Overall Accuracy: 0.9813046937151949\n", 447 | "snr= 6\n", 448 | "Overall Accuracy: 0.9988175009854159\n", 449 | "snr= 8\n", 450 | "Overall Accuracy: 1.0\n", 451 | "snr= 10\n", 452 | "Overall Accuracy: 1.0\n", 453 | "snr= 12\n", 454 | "Overall Accuracy: 1.0\n", 455 | "snr= 14\n", 456 | "Overall Accuracy: 1.0\n", 457 | "snr= 16\n", 458 | "Overall Accuracy: 1.0\n", 459 | "snr= 18\n", 460 | "Overall Accuracy: 1.0\n", 461 | "snr= 20\n" 462 | ], 463 | "name": "stdout" 464 | } 465 | ] 466 | }, 467 | { 468 | "cell_type": "code", 469 | "metadata": { 470 | "id": "KI4wf_v_uskI", 471 | "colab_type": "code", 472 | "colab": {} 473 | }, 474 | "source": [ 475 | "import matplotlib.pyplot as plt" 476 | ], 477 | "execution_count": null, 478 | "outputs": [] 479 | }, 480 | { 481 | "cell_type": "code", 482 | "metadata": { 483 | "id": "RNs8gRNnuc4h", 484 | "colab_type": "code", 485 | "colab": { 486 | "base_uri": "https://localhost:8080/", 487 | "height": 279 488 | }, 489 | "outputId": "2744e1a4-9d9c-4f6d-903e-23007bb42530" 490 | }, 491 | "source": [ 492 | "plt.plot(snrs, list(map(lambda x: acc_lstm_awgn[x], snrs)),'k--',label='LSTM')\n", 493 | "plt.plot(snrs, acc_array_cumulants_awgn,'k-',label='Cumulants')\n", 494 | "plt.xlabel(\"Signal to Noise Ratio\")\n", 495 | "plt.ylabel(\"Accuracy\")\n", 496 | "plt.legend()\n", 497 | "plt.savefig('/content/drive/My Drive/lstm_vs_cum_awgn.png',figsize=(15,7.5), dpi= 100)\t#save image" 498 | ], 499 | "execution_count": null, 500 | "outputs": [ 501 | { 502 | "output_type": "display_data", 503 | "data": { 504 | "image/png": "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\n", 505 | "text/plain": [ 506 | "
" 507 | ] 508 | }, 509 | "metadata": { 510 | "tags": [] 511 | } 512 | } 513 | ] 514 | }, 515 | { 516 | "cell_type": "code", 517 | "metadata": { 518 | "id": "EMH0ExVguqZ_", 519 | "colab_type": "code", 520 | "colab": { 521 | "base_uri": "https://localhost:8080/", 522 | "height": 311 523 | }, 524 | "outputId": "c621ff38-6c9a-4d3b-acce-83dc8b4bb603" 525 | }, 526 | "source": [ 527 | "list(map(lambda x: acc_lstm_awgn[x], snrs))" 528 | ], 529 | "execution_count": null, 530 | "outputs": [ 531 | { 532 | "output_type": "execute_result", 533 | "data": { 534 | "text/plain": [ 535 | "[0.3460434604346043,\n", 536 | " 0.3839249286005712,\n", 537 | " 0.44208037825059104,\n", 538 | " 0.5149130074565037,\n", 539 | " 0.6153232242617718,\n", 540 | " 0.7004698512137824,\n", 541 | " 0.8527755430410298,\n", 542 | " 0.9338205440519691,\n", 543 | " 0.9813046937151949,\n", 544 | " 0.9988175009854159,\n", 545 | " 1.0,\n", 546 | " 1.0,\n", 547 | " 1.0,\n", 548 | " 1.0,\n", 549 | " 1.0,\n", 550 | " 1.0]" 551 | ] 552 | }, 553 | "metadata": { 554 | "tags": [] 555 | }, 556 | "execution_count": 31 557 | } 558 | ] 559 | }, 560 | { 561 | "cell_type": "code", 562 | "metadata": { 563 | "id": "Ql0AwtHa_Y5d", 564 | "colab_type": "code", 565 | "colab": { 566 | "base_uri": "https://localhost:8080/", 567 | "height": 311 568 | }, 569 | "outputId": "7b5fe643-01a4-4567-e1f0-f09e77232b07" 570 | }, 571 | "source": [ 572 | "list(map(lambda x: acc_lstm_rayleigh[x], snrs))" 573 | ], 574 | "execution_count": null, 575 | "outputs": [ 576 | { 577 | "output_type": "execute_result", 578 | "data": { 579 | "text/plain": [ 580 | "[0.2826534816646065,\n", 581 | " 0.3249370277078086,\n", 582 | " 0.3669579030976966,\n", 583 | " 0.4213217938630999,\n", 584 | " 0.47513812154696133,\n", 585 | " 0.5663430420711975,\n", 586 | " 0.6441368078175895,\n", 587 | " 0.7141104294478527,\n", 588 | " 0.7864,\n", 589 | " 0.8565815324165029,\n", 590 | " 0.8978790259230165,\n", 591 | " 0.9360675512665863,\n", 592 | " 0.9613259668508287,\n", 593 | " 0.9721459395841506,\n", 594 | " 0.9842368319876971,\n", 595 | " 0.991876523151909]" 596 | ] 597 | }, 598 | "metadata": { 599 | "tags": [] 600 | }, 601 | "execution_count": 32 602 | } 603 | ] 604 | }, 605 | { 606 | "cell_type": "code", 607 | "metadata": { 608 | "id": "ibX-LuVdAOJF", 609 | "colab_type": "code", 610 | "colab": { 611 | "base_uri": "https://localhost:8080/", 612 | "height": 311 613 | }, 614 | "outputId": "ef845bd1-7c4c-4b0f-dc0a-9985bcbfe458" 615 | }, 616 | "source": [ 617 | "acc_array_cumulants_awgn" 618 | ], 619 | "execution_count": null, 620 | "outputs": [ 621 | { 622 | "output_type": "execute_result", 623 | "data": { 624 | "text/plain": [ 625 | "[0.2475,\n", 626 | " 0.2475,\n", 627 | " 0.2675,\n", 628 | " 0.2425,\n", 629 | " 0.26,\n", 630 | " 0.315,\n", 631 | " 0.4575,\n", 632 | " 0.6325,\n", 633 | " 0.845,\n", 634 | " 0.95,\n", 635 | " 0.985,\n", 636 | " 1.0,\n", 637 | " 1.0,\n", 638 | " 1.0,\n", 639 | " 1.0,\n", 640 | " 1.0]" 641 | ] 642 | }, 643 | "metadata": { 644 | "tags": [] 645 | }, 646 | "execution_count": 29 647 | } 648 | ] 649 | }, 650 | { 651 | "cell_type": "code", 652 | "metadata": { 653 | "id": "FMZA2lyZ_oyH", 654 | "colab_type": "code", 655 | "colab": { 656 | "base_uri": "https://localhost:8080/", 657 | "height": 311 658 | }, 659 | "outputId": "d3c7a473-f81e-49d1-8cab-48f3397f0c33" 660 | }, 661 | "source": [ 662 | "acc_array_cumulants_rayleigh" 663 | ], 664 | "execution_count": null, 665 | "outputs": [ 666 | { 667 | "output_type": "execute_result", 668 | "data": { 669 | "text/plain": [ 670 | "[0.25,\n", 671 | " 0.2458,\n", 672 | " 0.2542,\n", 673 | " 0.2833,\n", 674 | " 0.3167,\n", 675 | " 0.3958,\n", 676 | " 0.4125,\n", 677 | " 0.5875,\n", 678 | " 0.6792,\n", 679 | " 0.7458,\n", 680 | " 0.8167,\n", 681 | " 0.875,\n", 682 | " 0.9417,\n", 683 | " 0.9375,\n", 684 | " 0.9708,\n", 685 | " 0.9625]" 686 | ] 687 | }, 688 | "metadata": { 689 | "tags": [] 690 | }, 691 | "execution_count": 30 692 | } 693 | ] 694 | }, 695 | { 696 | "cell_type": "code", 697 | "metadata": { 698 | "id": "Y8NfjLZhAdbW", 699 | "colab_type": "code", 700 | "colab": {} 701 | }, 702 | "source": [ 703 | "" 704 | ], 705 | "execution_count": null, 706 | "outputs": [] 707 | } 708 | ] 709 | } 710 | -------------------------------------------------------------------------------- /Plots/Accuracy_Curve_CLDNN_RML.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaushikYenni/Deep-Learning-based-Modulation-Classification/a9c0e97f438f0ef5cda8e2951b0d5d9b37b28b60/Plots/Accuracy_Curve_CLDNN_RML.png -------------------------------------------------------------------------------- /Plots/Accuracy_Curve_CNN2_RML.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaushikYenni/Deep-Learning-based-Modulation-Classification/a9c0e97f438f0ef5cda8e2951b0d5d9b37b28b60/Plots/Accuracy_Curve_CNN2_RML.png -------------------------------------------------------------------------------- /Plots/Accuracy_Curve_CNN4_RML.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaushikYenni/Deep-Learning-based-Modulation-Classification/a9c0e97f438f0ef5cda8e2951b0d5d9b37b28b60/Plots/Accuracy_Curve_CNN4_RML.png -------------------------------------------------------------------------------- /Plots/Accuracy_Curve_RNN_RML.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaushikYenni/Deep-Learning-based-Modulation-Classification/a9c0e97f438f0ef5cda8e2951b0d5d9b37b28b60/Plots/Accuracy_Curve_RNN_RML.png -------------------------------------------------------------------------------- /Plots/all_awgn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaushikYenni/Deep-Learning-based-Modulation-Classification/a9c0e97f438f0ef5cda8e2951b0d5d9b37b28b60/Plots/all_awgn.jpg -------------------------------------------------------------------------------- /Plots/all_rayleigh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaushikYenni/Deep-Learning-based-Modulation-Classification/a9c0e97f438f0ef5cda8e2951b0d5d9b37b28b60/Plots/all_rayleigh.jpg -------------------------------------------------------------------------------- /Plots/cldnn_vs_cum_awgn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaushikYenni/Deep-Learning-based-Modulation-Classification/a9c0e97f438f0ef5cda8e2951b0d5d9b37b28b60/Plots/cldnn_vs_cum_awgn.jpg -------------------------------------------------------------------------------- /Plots/cldnn_vs_cum_rayleigh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaushikYenni/Deep-Learning-based-Modulation-Classification/a9c0e97f438f0ef5cda8e2951b0d5d9b37b28b60/Plots/cldnn_vs_cum_rayleigh.jpg -------------------------------------------------------------------------------- /Plots/cnn2_vs_cum_awgn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaushikYenni/Deep-Learning-based-Modulation-Classification/a9c0e97f438f0ef5cda8e2951b0d5d9b37b28b60/Plots/cnn2_vs_cum_awgn.jpg -------------------------------------------------------------------------------- /Plots/cnn2_vs_cum_rayleigh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaushikYenni/Deep-Learning-based-Modulation-Classification/a9c0e97f438f0ef5cda8e2951b0d5d9b37b28b60/Plots/cnn2_vs_cum_rayleigh.jpg -------------------------------------------------------------------------------- /Plots/cnn4_vs_cum_awgn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaushikYenni/Deep-Learning-based-Modulation-Classification/a9c0e97f438f0ef5cda8e2951b0d5d9b37b28b60/Plots/cnn4_vs_cum_awgn.jpg -------------------------------------------------------------------------------- /Plots/cnn4_vs_cum_rayleigh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaushikYenni/Deep-Learning-based-Modulation-Classification/a9c0e97f438f0ef5cda8e2951b0d5d9b37b28b60/Plots/cnn4_vs_cum_rayleigh.jpg -------------------------------------------------------------------------------- /Plots/lstm_vs_cum_awgn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaushikYenni/Deep-Learning-based-Modulation-Classification/a9c0e97f438f0ef5cda8e2951b0d5d9b37b28b60/Plots/lstm_vs_cum_awgn.jpg -------------------------------------------------------------------------------- /Plots/lstm_vs_cum_rayleigh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaushikYenni/Deep-Learning-based-Modulation-Classification/a9c0e97f438f0ef5cda8e2951b0d5d9b37b28b60/Plots/lstm_vs_cum_rayleigh.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deep-Learning-based-Modulation-Classification 2 | 3 | In this work, we investigate the value of employing deep learning for the task of wireless signal modulation classification. We generate two data sets which simulate an AWGN channel and a Rayleigh channel. We consider a baseline method using cumulants and compare it with the deep learning approach across a varying range of signal-tonoise ratios . We use a convolutional neural network (CNN) architecture, a recurrent neural network (RNN) architecture and a Convolutional Long Short-term Deep Neural Network (CLDNN) architecure for the purpose of classification. Finally we conclude with an evalution of the performance of the architectures on the RadioML 2016 dataset. 4 | --------------------------------------------------------------------------------