-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathOptimizePrecoderMimo.m
301 lines (266 loc) · 15 KB
/
OptimizePrecoderMimo.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
% =========================================================================
%
% Deep-learning based MIMO precoding for finite-alphabet signaling
%
% Low-complexity linear precoding for MIMO channels with discrete inputs
% Precoder optimization
%
% Max Girnyk
% Stockholm, 2014-10-01
%
% =========================================================================
%
% This Matlab script produces results used in the following paper:
%
% M. A. Girnyk, "Deep-learning based linear precoding for MIMO channels
% with finite-alphabet signaling," Physical Communication 48(2021) 101402
%
% Paper URL: https://arxiv.org/abs/2111.03504
%
% Version: 1.0 (modified 2021-11-14)
%
% License: This code is licensed under the Apache-2.0 license.
% If you use this code in any way for research that
% results in a publication, please cite the above paper
%
% =========================================================================
function OptimizePrecoderMimo
% % Shuffle random number generator
% rng('shuffle');
% % Or this way
% rand('state', sum(100*clock));
% Or set the seed manually
rand('state', 1);
% Clear and close everything
clear all; clc; close all;
% Add all the subfolders to the path.
currentFilePath = fileparts(which(mfilename));
addpath(genpath(currentFilePath));
% % Add an optional message for future reference
% disp('What is this sim about? Add a comment (e.g., test):');
% comment = input('', 's');
comment = 'Debugging';
% Create default sim param structure
defaultSimParamStruct = createDefaultSimParamStruct;
% Operation type, should be one of {'OPTIMIZATION', 'EVALUATION', 'COMPUTATION'}
operationType = 'OPTIMIZATION';
% =========================================================================
% Define common simulation params =========================================
% (how we want to run sims)
simMode = 'QUICK'; % short/long sim for debugging/full-blown solution: {'QUICK', 'FULL'}
% Cluster-related params --------------------------------------------------
runOnCluster = 0; % flag for running on the cluster/locally
stepThresholdPercent = 1e-1;
evaluateTrueMiMeanwhile = 0; % compute true QAM MI during/after? optimization
nOrderCasesMax = 3; % Max order of the number of cases allowed (how many 9s, e.g., 999)
status = 'STARTED'; % status of the sim: {'STARTED', 'COMPLETED', 'EVALUATED'}
createDataset = 0; % Create dataset for further analysis?
% Channel-related params --------------------------------------------------
channelFadingTag = 'PalomarVerdu'; %{'PalomarVerdu', 'ComplexRayleighIid', 'RealRayleighIid'}
channelMat = generateFadingChannel(channelFadingTag, 2, 2);
[nRx, nTx] = size(channelMat); % sizes of the channel matrix
channelTag = [num2str(nTx), 'x', num2str(nRx), channelFadingTag];
snrDbMin = -20; % lower SNR in dB
snrDbMax = 20; % higher SNR in dB
nSnrPoints = 7; % number of SNR points in dB
snrDbVec = linspace(snrDbMin, snrDbMax, nSnrPoints);
% Optimization-related params ---------------------------------------------
if strcmp(simMode, 'QUICK')
nItersMax = 10; % max number of outer-loop iters for the precoder optimization loop
nNoImprovementsMax = 5; % max number of allowed outer-loop iters w/o improvement of MI value
nBackOffsMax = 2; % max number of allowed back-offs when stuck w/o improvement of MI value
backOffSize = 1; % back-off size
nItersSignalMi = 10; % size of the inner loop for MI computation
nItersNoiseMi = 10; % size of the outer loop for MI computation
nItersSignalMmse = 10; % size of the inner loop for MMSE computation
nItersNoiseMmse = 10; % size of the outer loop for MMSE computation
elseif strcmp(simMode, 'FULL')
nItersMax = 100; % max number of outer-loop iters for the precoder optimization loop
nNoImprovementsMax = 2; % max number of allowed outer-loop iters w/o improvement of MI value
nBackOffsMax = 2; % max number of allowed back-offs when stuck w/o improvement of MI value
backOffSize = 2; % back-off size
nItersSignalMi = 1e3; % size of the inner loop for MI computation
nItersNoiseMi = 1e3; % size of the outer loop for MI computation
nItersSignalMmse = 1e3; % size of the inner loop for MMSE computation
nItersNoiseMmse = 1e3; % size of the outer loop for MMSE computation
else
error('ERROR! Unknown sim mode!');
end
% Setup default sim param structure ---------------------------------------
% (Default sim case)
defaultSimParamStruct.channel.channelMatReal = real(channelMat);
defaultSimParamStruct.channel.channelMatImag = imag(channelMat);
defaultSimParamStruct.channel.nTxAntennas = nTx;
defaultSimParamStruct.channel.nRxAntennas = nRx;
defaultSimParamStruct.channel.channelTag = channelTag;
defaultSimParamStruct.channel.snrDbVec = snrDbVec;
defaultSimParamStruct.optimization.nItersMax = nItersMax;
defaultSimParamStruct.optimization.nNoImprovementsMax = nNoImprovementsMax;
defaultSimParamStruct.optimization.nBackOffsMax = nBackOffsMax;
defaultSimParamStruct.optimization.backOffSize = backOffSize;
defaultSimParamStruct.computation.nItersSignalMi = nItersSignalMi;
defaultSimParamStruct.computation.nItersNoiseMi = nItersNoiseMi;
defaultSimParamStruct.computation.nItersSignalMmse = nItersSignalMmse;
defaultSimParamStruct.computation.nItersNoiseMmse = nItersNoiseMmse;
defaultSimParamStruct.signaling.typeModulation = 'QPSK';
defaultSimParamStruct.cluster.runOnCluster = runOnCluster;
defaultSimParamStruct.cluster.simMode = simMode;
defaultSimParamStruct.cluster.comment = comment;
defaultSimParamStruct.cluster.nOrderCasesMax = nOrderCasesMax;
defaultSimParamStruct.cluster.evaluateTrueMiMeanwhile = evaluateTrueMiMeanwhile;
defaultSimParamStruct.cluster.status = status;
defaultSimParamStruct.cluster.createDataset = createDataset;
defaultSimParamStruct.cluster.stepThresholdPercent = stepThresholdPercent;
% =========================================================================
% Define simulation cases #################################################
% (uncomment and configure setups for which we want to run optimization)
simCaseParamStructs = {};
% %
% % Case #1
% % MI computation via Gaussian signaling
% simCaseParamStructs{end+1} = {};
% simCaseParamStructs{end}.plotting.legendEntry = 'Capacity';
% simCaseParamStructs{end}.plotting.lineType = '--';
% simCaseParamStructs{end}.plotting.lineMarker = 'none';
% simCaseParamStructs{end}.plotting.lineColor = [0, 0, 0];
% simCaseParamStructs{end}.signaling.typeModulation = 'GAUSS';
% simCaseParamStructs{end}.computation.methodComputationMi = 'GAUSS';
% simCaseParamStructs{end}.computation.methodComputationMmse = 'GAUSS';
% simCaseParamStructs{end}.cluster.runOnCluster = 0;
% nSnrPoints = 41;
% simCaseParamStructs{end}.channel.snrDbVec = linspace(snrDbMin, snrDbMax, nSnrPoints);
% Case #2
% MI computation w/o precoding
simCaseParamStructs{end+1} = {};
simCaseParamStructs{end}.plotting.legendEntry = 'No precoder';
simCaseParamStructs{end}.plotting.lineType = '-.';
simCaseParamStructs{end}.plotting.lineMarker = 'none';
simCaseParamStructs{end}.plotting.lineColor = [0, 0, 1];
simCaseParamStructs{end}.computation.methodComputationMi = 'NONE';
nSnrPoints = 25;
simCaseParamStructs{end}.channel.snrDbVec = linspace(snrDbMin, snrDbMax, nSnrPoints);
% % Case #3
% % MI computation via Gaussian signaling
% simCaseParamStructs{end+1} = {};
% simCaseParamStructs{end}.plotting.legendEntry = 'Water filling';
% simCaseParamStructs{end}.plotting.lineType = '-';
% simCaseParamStructs{end}.plotting.lineMarker = 'none';
% simCaseParamStructs{end}.plotting.lineColor = [0.5, 0.5, 0.5];
% % simCaseParamStructs{end}.signaling.typeModulation = 'GAUSS';
% simCaseParamStructs{end}.computation.methodComputationMi = 'GAUSS_OPT';
% nSnrPoints = 41;
% simCaseParamStructs{end}.channel.snrDbVec = linspace(snrDbMin, snrDbMax, nSnrPoints);
% % Case #3
% % MI computation via true exhaustive averaging
% simCaseParamStructs{end+1} = {};
% simCaseParamStructs{end}.plotting.legendEntry = 'True optimum';
% simCaseParamStructs{end}.plotting.lineType = '-';
% simCaseParamStructs{end}.plotting.lineMarker = 'o';
% simCaseParamStructs{end}.plotting.lineColor = [0.5273, 0.8047, 0.9180];
% simCaseParamStructs{end}.computation.methodComputationMi = 'TRUE';
% simCaseParamStructs{end}.computation.methodComputationMmse = 'TRUE';
% nSnrPoints = 13;
% simCaseParamStructs{end}.channel.snrDbVec = linspace(snrDbMin, snrDbMax, nSnrPoints);
% simCaseParamStructs{end}.cluster.evaluateTrueMiMeanwhile = 1;
% % Case #3.5
% % Create dataset
% nRuns = 1000;
% for iRun = 1:nRuns
% % MI computation via Gaussian signaling
% simCaseParamStructs{end+1} = {};
% H = generateFadingChannel(channelFadingTag, 2, 2);
% simCaseParamStructs{end}.channel.channelMatReal = real(H);
% simCaseParamStructs{end}.channel.channelMatImag = imag(H);
% simCaseParamStructs{end}.plotting.legendEntry = ['TRUE_', num2str(iRun)] ;
% simCaseParamStructs{end}.plotting.lineType = '-';
% simCaseParamStructs{end}.plotting.lineMarker = 'o';
% simCaseParamStructs{end}.plotting.lineColor = [0.5273, 0.8047, 0.9180];
% simCaseParamStructs{end}.computation.methodComputationMi = 'TRUE';
% simCaseParamStructs{end}.computation.methodComputationMmse = 'TRUE';
% simCaseParamStructs{end}.signaling.typeModulation = 'BPSK';
% nSnrPoints = 7;
% simCaseParamStructs{end}.channel.snrDbVec = linspace(snrDbMin, snrDbMax, nSnrPoints);
% simCaseParamStructs{end}.cluster.createDataset = 1;
% end
% % Case #4
% % MI computation via Zhu et al.
% simCaseParamStructs{end+1} = {};
% simCaseParamStructs{end}.plotting.legendEntry = 'Zhu et al. [10]';
% simCaseParamStructs{end}.plotting.lineType = '-';
% simCaseParamStructs{end}.plotting.lineMarker = 'x';
% simCaseParamStructs{end}.plotting.lineColor = [1, 0.6445, 0];
% simCaseParamStructs{end}.computation.methodComputationMi = 'ZHU_SHI_FARHANG';
% simCaseParamStructs{end}.computation.methodComputationMmse = 'TRUE';
% nSnrPoints = 13;
% simCaseParamStructs{end}.channel.snrDbVec = linspace(snrDbMin, snrDbMax, nSnrPoints);
%
% % Case #5
% % MI computation via integral approx
% simCaseParamStructs{end+1} = {};
% simCaseParamStructs{end}.plotting.legendEntry = 'Zeng et al. [11]';
% simCaseParamStructs{end}.plotting.lineType = '--';
% simCaseParamStructs{end}.plotting.lineMarker = '+';
% simCaseParamStructs{end}.plotting.lineColor = [0.5, 0, 0.5];
% simCaseParamStructs{end}.computation.methodComputationMi = 'ZENG_XIAO_LU';
% simCaseParamStructs{end}.computation.methodComputationMmse = 'TRUE';
% nSnrPoints = 13;
% simCaseParamStructs{end}.channel.snrDbVec = linspace(snrDbMin, snrDbMax, nSnrPoints);
% Case #6
% MI computation via ML-model predicted
simCaseParamStructs{end+1} = {};
simCaseParamStructs{end}.plotting.legendEntry = 'DL-based';
simCaseParamStructs{end}.plotting.lineType = '--';
simCaseParamStructs{end}.plotting.lineMarker = 's';
simCaseParamStructs{end}.plotting.lineColor = [1, 0, 0];
simCaseParamStructs{end}.computation.methodComputationMi = 'ML_PREDICTED';
nSnrPoints = 13;
simCaseParamStructs{end}.channel.snrDbVec = linspace(snrDbMin, snrDbMax, nSnrPoints);
% #########################################################################
% =========================================================================
% Run simulations ---------------------------------------------------------
% Create sim folder if it does not exist
simName = defaultSimParamStruct.cluster.simName;
simDataPath = defaultSimParamStruct.cluster.simDataPath;
simFolderPath = defaultSimParamStruct.cluster.simFolderPath;
simParamFileName = ['params_', simName, '.mat'];
simParamFilePath = [simFolderPath, '\', simParamFileName];
if (~exist(simFolderPath))
mkdir(simFolderPath);
end
% Fill in param structs for picked sim cases
nSimCases = length(simCaseParamStructs);
for iSimCase = 1:nSimCases
simCaseParamStructs{iSimCase}.cluster.caseIdx = iSimCase;
simCaseParamStructs{iSimCase} =...
overrideStruct(defaultSimParamStruct, simCaseParamStructs{iSimCase});
end % for iSimCase = 1:nSimCases
% Save all params to mat-file
save(simParamFilePath, 'simCaseParamStructs');
% Dispatch simulations
for iSimCase = 1:nSimCases
if strcmp(simCaseParamStructs{iSimCase}.signaling.typeModulation, 'GAUSS')
% Waterfilling computation
fprintf('\nRun water-filling locally... \n\n');
optimizePrecoderMimoGauss(simCaseParamStructs{iSimCase});
fprintf('DONE!\n');
elseif strcmp(simCaseParamStructs{iSimCase}.computation.methodComputationMi, 'ML_PREDICTED')
% ML predicted precoder based on a trained neural net
fprintf('\nPredict precoder locally... \n\n');
optimizePrecoderMimoMl(simCaseParamStructs{iSimCase});
fprintf('DONE!\n');
elseif strcmp(simCaseParamStructs{iSimCase}.computation.methodComputationMi, 'NONE')
% No precoding at all
fprintf('\nSet omni precoder locally... \n\n');
setOmniPrecoderMimo(simCaseParamStructs{iSimCase});
fprintf('DONE!\n');
elseif (simCaseParamStructs{iSimCase}.cluster.runOnCluster)
% Running sim on cluster
error('\nERROR! Functionality not supported!\n\n');
else
% Local running of all other types of sims
fprintf('\nRun new simulation locally... \n\n');
runSimsLocally(simCaseParamStructs{iSimCase}, operationType);
fprintf('DONE!\n');
end
end % for iSimCase = 1:nSimCases
end