■ ■ ■ ■ ■ ■
unit07_chanest/lab_partial/NRUERxFD.m
| 1 | + | classdef NRUERxFD < matlab.System |
| 2 | + | % 5G NR UR receiver class implemented in frequency domain |
| 3 | + | properties |
| 4 | + | % Configuration |
| 5 | + | carrierConfig; % Carrier configuration |
| 6 | + | pdschConfig; % Default PDSCH config |
| 7 | + | waveformConfig; % Waveform config |
| 8 | + | |
| 9 | + | % OFDM grid |
| 10 | + | rxGrid; |
| 11 | + | |
| 12 | + | % Channel estimation parameters |
| 13 | + | sigFreq = 7; % Channel smoothing in freq |
| 14 | + | sigTime = 3; % Channel smoothing in time |
| 15 | + | lenFreq = 21; % Filter length in freq |
| 16 | + | Wtime; |
| 17 | + | |
| 18 | + | % Test bit parameters |
| 19 | + | bitsPerSym = 2; |
| 20 | + | |
| 21 | + | % Channel and noise estimate |
| 22 | + | chanEstGrid; |
| 23 | + | noiseEst; |
| 24 | + | |
| 25 | + | % RX symbols and estimated channel on the PDSCH |
| 26 | + | pdschChan; |
| 27 | + | pdschSym; |
| 28 | + | |
| 29 | + | |
| 30 | + | % Received data in last slots |
| 31 | + | pdschSymEq; % Equalized PDSCH symbols |
| 32 | + | rxBits; % RX bits |
| 33 | + | |
| 34 | + | end |
| 35 | + | methods |
| 36 | + | function obj = NRUERxFD(carrierConfig, pdschConfig, ... |
| 37 | + | varargin) |
| 38 | + | % Constructor |
| 39 | + | |
| 40 | + | % Save the carrier and PDSCH configuration |
| 41 | + | obj.carrierConfig = carrierConfig; |
| 42 | + | obj.pdschConfig = pdschConfig; |
| 43 | + | |
| 44 | + | % Create the waveform configuration from the carrier |
| 45 | + | % configuration |
| 46 | + | obj.waveformConfig = nrOFDMInfo(obj.carrierConfig); |
| 47 | + | |
| 48 | + | % Set parameters from constructor arguments |
| 49 | + | if nargin >= 1 |
| 50 | + | obj.set(varargin{:}); |
| 51 | + | end |
| 52 | + | |
| 53 | + | |
| 54 | + | end |
| 55 | + | |
| 56 | + | function chanEst(obj, rxGrid) |
| 57 | + | % Computes the channel estimate |
| 58 | + | |
| 59 | + | % TODO: Get the TX DM-RS symbols and indices |
| 60 | + | % dmrsSymTx = ... |
| 61 | + | % dmrsInd = ... |
| 62 | + | |
| 63 | + | % TODO: Get RX symbols on the DM-RS |
| 64 | + | % dmrsSymRx = ... |
| 65 | + | |
| 66 | + | % TODO: Get the raw channel estimate |
| 67 | + | % chanEstRaw = ... |
| 68 | + | |
| 69 | + | % Get the symbol numbers and sub-carrier indices of the |
| 70 | + | % DM-RS symbols from the DM-RS |
| 71 | + | % dmrsSymNum(i) = symbol number for the i-th DM-RS symbol |
| 72 | + | % dmrsScInd(i) = sub-carrier index for the i-th DM-RS symbol |
| 73 | + | |
| 74 | + | % TODO: Get the list of all symbol numbers on which DM-RS was |
| 75 | + | % transmitted. You can use the unique command |
| 76 | + | % dmrsSymNums = unique(...); |
| 77 | + | % ndrmsSym = length(dmrsSymNums); |
| 78 | + | |
| 79 | + | % We first compute the channel and noise |
| 80 | + | % estimate on each of the symbols on which the DM-RS was |
| 81 | + | % transmitted. We will store these in two arrays |
| 82 | + | % chanEstDmrs(k,i) = chan est on sub-carrier k in DM-RS |
| 83 | + | % symbol i |
| 84 | + | % noiseEstDmrs(i) = noise est for DM-RS symbol i |
| 85 | + | chanEstDmrs = zeros(nsc, ndrmsSym); |
| 86 | + | noiseEstDmrs = zeros(ndrmsSym, 1); |
| 87 | + | |
| 88 | + | % Loop over the DM-RS symbols |
| 89 | + | for i = 1:ndrmsSym |
| 90 | + | |
| 91 | + | % TODO: Find the indices, k, in which the DM-RS |
| 92 | + | % dmrsSymNum(k)= dmrsSymNum(i). |
| 93 | + | % I = find(...) |
| 94 | + | |
| 95 | + | % TODO: Get the sub-carrier indices and raw channel |
| 96 | + | % channel estimate for these RS on the symbol |
| 97 | + | % ind = ... |
| 98 | + | % raw = ... |
| 99 | + | |
| 100 | + | % TODO: Use kernelReg to compute the channel estimate |
| 101 | + | % on that DM-RS symbol. Use the lenFreq and sigFreq |
| 102 | + | % for the kernel length and sigma. |
| 103 | + | % chanEstDmrs(:,i) = kernelReg(...) |
| 104 | + | |
| 105 | + | % TODO: Compute the noise estimate on the symbol |
| 106 | + | % using the residual method |
| 107 | + | % noiseEstDmrs(i) = ... |
| 108 | + | |
| 109 | + | end |
| 110 | + | |
| 111 | + | % TODO: Find the noise estimate over the PDSCH by |
| 112 | + | % averaging noiseEstDmrs |
| 113 | + | % obj.noiseEst = mean(...); |
| 114 | + | |
| 115 | + | % TODO: Finally, we interpolate over time. |
| 116 | + | % We will use an estimate of the form |
| 117 | + | % obj.chaneEstGrid = chanEstDrms*W |
| 118 | + | % so that |
| 119 | + | % chanEstGrid(k,j) = \sum_i chanEstDmrs(k,i)*W(i,j) |
| 120 | + | % |
| 121 | + | % We use a kernel estimator |
| 122 | + | % |
| 123 | + | % W(i,j) = W0(i,j) / \sum_k W0(k,j) |
| 124 | + | % W0(k,j) = exp(-D(k,j)^2/(2*obj.sigTime^2)) |
| 125 | + | % D(k,j) = dmrsSymNum(k) - j |
| 126 | + | % |
| 127 | + | |
| 128 | + | % Save the time interpolation matrix |
| 129 | + | obj.Wtime = W; |
| 130 | + | |
| 131 | + | % Create the channel estimate grid |
| 132 | + | obj.chanEstGrid = chanEstDmrs*W; |
| 133 | + | |
| 134 | + | end |
| 135 | + | end |
| 136 | + | methods (Access = protected) |
| 137 | + | |
| 138 | + | |
| 139 | + | function rxBits = stepImpl(obj, rxGrid, chanGrid, noiseVar) |
| 140 | + | % Performs channel estimation, equalization and |
| 141 | + | % symbol demodulation for one slot of data. |
| 142 | + | % |
| 143 | + | % Input |
| 144 | + | % ----- |
| 145 | + | % rxGrid: Received symbols in one slot |
| 146 | + | % chanGrid: Optional true channel estimate. |
| 147 | + | % noiseVar: Optional true noise variance |
| 148 | + | % |
| 149 | + | % If (chanGrid, noiseVar) are supplied the function skips |
| 150 | + | % the channel estimate. This is useful for testing a true |
| 151 | + | % channel estimate without channel estimation error. |
| 152 | + | |
| 153 | + | if nargin >= 3 |
| 154 | + | % Set the estimated channel and noise to the supplied |
| 155 | + | % values if provided. |
| 156 | + | obj.chanEstGrid = chanGrid; |
| 157 | + | obj.noiseEst = noiseVar; |
| 158 | + | else |
| 159 | + | |
| 160 | + | % Compute the channel and noise estimate |
| 161 | + | obj.chanEst(rxGrid); |
| 162 | + | end |
| 163 | + | |
| 164 | + | % Get indices on where the PDSCH is allocated |
| 165 | + | pdschInd = nrPDSCHIndices(obj.carrierConfig, obj.pdschConfig); |
| 166 | + | |
| 167 | + | % TODO: Get the PDSCH symbols and channel on the indicies |
| 168 | + | % obj.pdschSym = ... |
| 169 | + | % obj.pdschChan = ... |
| 170 | + | |
| 171 | + | % TODO: Perform the MMSE equalization |
| 172 | + | % obj.pdschSymEq |
| 173 | + | |
| 174 | + | % Demodulate the symbols |
| 175 | + | M = 2^obj.bitsPerSym; |
| 176 | + | rxBits = qamdemod(obj.pdschSymEq, M, 'OutputType', 'bit',... |
| 177 | + | 'UnitAveragePower', true); |
| 178 | + | end |
| 179 | + | |
| 180 | + | end |
| 181 | + | end |
| 182 | + | |
| 183 | + | |