-
Notifications
You must be signed in to change notification settings - Fork 2
/
dect_rx.m
300 lines (244 loc) · 18.2 KB
/
dect_rx.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
299
classdef dect_rx < handle
properties
verbose; % show data during execution: 0 false, 1 only text, 2 text + plots
mac_meta; % data received from MAC layer
phy_4_5; % data from chapter 4 and 5
packet_data; % intermediate results during packet decoding
tx_handle; % handle to tx for debugging
ch_handle; % handle to rf channel for debugging
STF_templates; % for synchronization based on STF, both time and frequency domain
harq_buf_40; % these are the cbsbuffers used by matlab for harq operation, PCC 40 bits
harq_buf_80; % these are the cbsbuffers used by matlab for harq operation, PCC 80 bits
harq_buf; % these are the cbsbuffers used by matlab for harq operation, PDC
wiener; % structure with data about wiener filter for channel estimation, depends on channel environment
end
methods
function obj = dect_rx(verbose_arg, mac_meta_arg)
% if channel estimation type is not specifically defined, use Wiener as a default
if ~isfield(mac_meta_arg, 'active_ch_estim_type')
mac_meta_arg.active_ch_estim_type = 'wiener';
end
% if equalization/detection is not specifically turned off, activate if by default
if ~isfield(mac_meta_arg, 'active_equalization_detection')
mac_meta_arg.active_equalization_detection = true;
end
obj.verbose = verbose_arg;
obj.mac_meta = mac_meta_arg;
obj.phy_4_5 = lib_util.run_chapter_4_5(verbose_arg, mac_meta_arg);
obj.packet_data = [];
obj.tx_handle = [];
obj.ch_handle = [];
% we only load STF templates if they are needed
if mac_meta_arg.synchronization.stf.active == true
obj.STF_templates = lib_rx.sync_STF_template(mac_meta_arg);
end
obj.harq_buf_40 = [];
obj.harq_buf_80 = [];
obj.harq_buf = [];
% init wiener coefficients with reasonable default values
obj.overwrite_wiener(1/10^(30/10), ... % 30dB SNR
20, ... % 20Hz Doppler
363e-9); % 363ns delay spread
end
% Wiener filter interpolates between DRS pilots. Optimal interpolation depends on channel properties.
% We use a static filter which is used regardless of the instantaneous channel.
% For noise, the best case value is assumed, for delay and Doppler spread the worst case value.
% To improve performance, different sets should be precalculated for different SNRs.
function [] = overwrite_wiener(obj, noise_estim, f_d_hertz, tau_rms_sec)
% We estimate the channel for each subcarrier based on the closest DRS pilots in time and frequency.
% This value defines how many of the closest DRS pilots we consider. Ideally, this value should depend on the SNR.
N_closest_DRS_pilots = 8;
obj.wiener = lib_rx.channel_estimation_wiener_weights( obj.phy_4_5.physical_resource_mapping_DRS_cell,...
N_closest_DRS_pilots,...
obj.phy_4_5.numerology.N_b_DFT,...
obj.phy_4_5.N_PACKET_symb,...
obj.phy_4_5.numerology.N_b_CP, ...
obj.phy_4_5.numerology.B_u_b_DFT,...
noise_estim, ...
f_d_hertz, ...
tau_rms_sec);
end
% We pass on the samples as they are received at the antennas and we try to extract the PCC and PDC bits.
% It gets more complicated when using HARQ as calls to this function depend on each other.
function [PCC_user_bits, PDC_user_bits] = demod_decode_packet(obj, samples_antenna_rx)
% for the purpose of readability, extract all variables that are necessary at this stage
verbose_ = obj.verbose;
tx_handle_ = obj.tx_handle;
ch_handle_ = obj.ch_handle;
STF_templates_ = obj.STF_templates;
harq_buf_40_ = obj.harq_buf_40;
harq_buf_80_ = obj.harq_buf_80;
harq_buf_ = obj.harq_buf;
wiener_ = obj.wiener;
mode_0_to_11 = obj.phy_4_5.tm_mode.mode_0_to_11;
N_eff_TX = obj.phy_4_5.tm_mode.N_eff_TX;
modulation0 = obj.phy_4_5.mcs.modulation0;
N_b_DFT = obj.phy_4_5.numerology.N_b_DFT;
N_b_CP = obj.phy_4_5.numerology.N_b_CP;
N_TB_bits = obj.phy_4_5.N_TB_bits;
N_PACKET_symb = obj.phy_4_5.N_PACKET_symb;
k_b_OCC = obj.phy_4_5.k_b_OCC;
n_packet_samples = obj.phy_4_5.n_packet_samples;
u = obj.mac_meta.u;
Z = obj.mac_meta.Z;
network_id = obj.mac_meta.network_id;
PLCF_type = obj.mac_meta.PLCF_type;
rv = obj.mac_meta.rv;
N_RX = obj.mac_meta.N_RX;
oversampling = obj.mac_meta.oversampling;
synchronization = obj.mac_meta.synchronization;
active_ch_estim_type = obj.mac_meta.active_ch_estim_type;
active_equalization_detection = obj.mac_meta.active_equalization_detection;
physical_resource_mapping_PCC_cell = obj.phy_4_5.physical_resource_mapping_PCC_cell;
physical_resource_mapping_PDC_cell = obj.phy_4_5.physical_resource_mapping_PDC_cell;
physical_resource_mapping_STF_cell = obj.phy_4_5.physical_resource_mapping_STF_cell;
physical_resource_mapping_DRS_cell = obj.phy_4_5.physical_resource_mapping_DRS_cell;
%% sync of STO + CFO and extraction of N_eff_TX into STO_CFO_report
if synchronization.stf.active == true
% The number of samples received is larger than the number of samples in a packet.
% In this function, we try to synchronize the packet and extract the exact number of samples in the packet, which we assume to be known.
% In a real receiver, the number of samples is unknown. We would first have to decode the PCC which lies in the first few OFDM symbols and extract that information.
[samples_antenna_rx_sto_cfo, STO_CFO_report] = lib_rx.sync_STF( verbose_,...
u,...
N_b_DFT,...
samples_antenna_rx,...
STF_templates_,...
n_packet_samples,...
oversampling,...
synchronization.stf.sto_config,...
synchronization.stf.cfo_config);
obj.packet_data.STO_CFO_report = STO_CFO_report;
else
% assume the input samples are synchronized and have the correct length
samples_antenna_rx_sto_cfo = samples_antenna_rx;
end
%% OFDM demodulation a.k.a FFT
% Switch back to frequency domain.
% We use one version with subcarriers from oversampling removed and one with them still occupied.
% The second version might be necessary if we have a very large, uncorrected integer CFO.
[antenna_streams_mapped_rev, ~]= lib_6_generic_procedures.ofdm_signal_generation_Cyclic_prefix_insertion_rev( samples_antenna_rx_sto_cfo,...
k_b_OCC,...
N_PACKET_symb,...
N_RX,...
N_eff_TX,...
N_b_DFT,...
u,...
N_b_CP,...
oversampling);
%% PCC decoding and packet data extraction
% Decode PCC and extract all relevant data about the packet.
% We know N_eff_TX from STO sync, so we also know the DRS pattern.
% With STF and DRS known, we can now estimate the channel for PCC, which lies at the beginning of each packet.
% PCC is always transmitted with transmit diversity coding.
% For now it is done down below together with the PDC.
% TODO
%% residual CFO correction post FFT based on averaging DRS symbols
if synchronization.drs.cfo_config.active_residual == true
antenna_streams_mapped_rev = lib_rx.sync_CFO_residual( antenna_streams_mapped_rev,...
physical_resource_mapping_DRS_cell,...
physical_resource_mapping_STF_cell,...
N_RX,...
N_eff_TX,...
synchronization.drs.cfo_config);
end
%% channel estimation
% Now that we know the length of the packet from the PCC, we can determine a channel estimate.
% Output is a cell(N_RX,1), each cell with a matrix of size N_b_DFT x N_PACKET_symb x N_TX.
% For subcarriers which are unused the channel estimate can be NaN or +/- infinity.
if strcmp(active_ch_estim_type,'wiener') == true
% real world channel estimation based on precalculated wiener filter coefficients assuming worst-case channel conditions
ch_estim = lib_rx.channel_estimation_wiener(antenna_streams_mapped_rev, physical_resource_mapping_DRS_cell, wiener_, N_RX, N_eff_TX);
elseif strcmp(active_ch_estim_type,'least squares') == true
% Zero forcing at the pilots and linear interpolation for subcarriers inbetween.
% It works without channel knowledge, but has a fairly large error floor.
% The error floor is comes from only considering the closest neighbours.
ch_estim = lib_rx.channel_estimation_ls(antenna_streams_mapped_rev, physical_resource_mapping_STF_cell, physical_resource_mapping_DRS_cell, N_RX, N_eff_TX);
else
error('Unknown channel estimation type %s.', active_ch_estim_type);
end
%% equalization and detection
% With the known transmission mode and the channel estimate, we can now extract the binary data from the packet.
% Equalization here is understood as the inversion of channel effects at the subcarriers, usually paired with a symbol demapper.
% For MIMO detection with N_SS > 1 and symbol detection, equalization is not performed explicitly but is implicit part of the underlying algorithm.
if active_equalization_detection == true
% SISO
if N_eff_TX == 1 && N_RX ==1
x_PCC_rev = lib_rx.equalization_SISO_zf(antenna_streams_mapped_rev, ch_estim, physical_resource_mapping_PCC_cell);
x_PDC_rev = lib_rx.equalization_SISO_zf(antenna_streams_mapped_rev, ch_estim, physical_resource_mapping_PDC_cell);
% SIMO (Maximum Ratio Combining (MRC))
elseif N_eff_TX == 1 && N_RX > 1
x_PCC_rev = lib_rx.equalization_SIMO_mrc(antenna_streams_mapped_rev, ch_estim, physical_resource_mapping_PCC_cell, N_RX);
x_PDC_rev = lib_rx.equalization_SIMO_mrc(antenna_streams_mapped_rev, ch_estim, physical_resource_mapping_PDC_cell, N_RX);
% MISO (Alamouti) and MIMO (Alamouti + MRC and other modes)
else
% Transmit diversity precoding
if ismember(mode_0_to_11, [1,5,10]) == true
x_PCC_rev = lib_rx.equalization_MISO_MIMO_alamouti_mrc(antenna_streams_mapped_rev, ch_estim, N_RX, N_eff_TX, physical_resource_mapping_PCC_cell);
x_PDC_rev = lib_rx.equalization_MISO_MIMO_alamouti_mrc(antenna_streams_mapped_rev, ch_estim, N_RX, N_eff_TX, physical_resource_mapping_PDC_cell);
% MIMO modes with more than one spatial stream
else
error("MIMO modes with N_SS>1 not implemented yet.");
end
end
% no equalization, a great debugging tool when using awgn channel
else
x_PCC_rev = lib_7_Transmission_modes.subcarrier_unmapping_PCC(antenna_streams_mapped_rev, physical_resource_mapping_PCC_cell);
x_PDC_rev = lib_7_Transmission_modes.subcarrier_unmapping_PDC(antenna_streams_mapped_rev, physical_resource_mapping_PDC_cell);
end
%% PCC and PDC decoding
% decode PCC
[PCC_user_bits, PCC_harq_buf_40_report,...
PCC_harq_buf_80_report,...
CL_report,...
BF_report,...
PCC_report,...
pcc_dec_dbg] = lib_7_Transmission_modes.PCC_decoding( x_PCC_rev, ...
harq_buf_40_,...
harq_buf_80_);
% decode PDC
[PDC_user_bits, PDC_harq_buf_report, pdc_dec_dbg] = lib_7_Transmission_modes.PDC_decoding( x_PDC_rev,...
N_TB_bits,...
Z,...
network_id,...
PLCF_type,...
rv,...
modulation0,...
harq_buf_);
%% HARQ buffers
% save harq buffer for next call
if numel(PCC_harq_buf_40_report) > 0
obj.harq_buf_40 = PCC_harq_buf_40_report;
end
if numel(PCC_harq_buf_80_report) > 0
obj.harq_buf_80 = PCC_harq_buf_80_report;
end
if numel(PDC_harq_buf_report) > 0
obj.harq_buf = PDC_harq_buf_report;
end
%% save packet data for debugging
obj.packet_data.CL_report = CL_report;
obj.packet_data.BF_report = BF_report;
obj.packet_data.PCC_report = PCC_report;
obj.packet_data.pcc_dec_dbg = pcc_dec_dbg;
obj.packet_data.pdc_dec_dbg = pdc_dec_dbg;
% debugging
if verbose_ > 0
disp('##### RX debugging ######');
% compare complex symbols of PCC and PDF
fprintf('Max error distance PCC: %.20f\n', max(abs(x_PCC_rev - tx_handle_.packet_data.x_PCC)));
fprintf('Max error distance PDC: %.20f\n', max(abs(x_PDC_rev - tx_handle_.packet_data.x_PDC)));
% measure the sinr in dB by comparing the complex PDC symbols
tx_power_measurement = tx_handle_.packet_data.x_PDC;
tx_power_measurement = sum(abs(tx_power_measurement).^2)/numel(tx_power_measurement);
noise_power_measurement = x_PDC_rev - tx_handle_.packet_data.x_PDC;
noise_power_measurement = sum(abs(noise_power_measurement).^2)/numel(noise_power_measurement);
sinr = 10*log10(tx_power_measurement/noise_power_measurement);
fprintf('Measured f domain SINR: %f dB\n', sinr);
if verbose_ > 1
lib_dbg.plot_chestim(ch_estim, obj.phy_4_5.numerology.n_guards_bottom, obj.phy_4_5.numerology.n_guards_top);
scatterplot(x_PDC_rev);
end
end
end
end
end