|
| 1 | +% Soft QPSK demodulator using natural mapping |
| 2 | +% Copyright (C) 2010 Robert G. Maunder |
| 3 | + |
| 4 | +% This program is free software: you can redistribute it and/or modify it |
| 5 | +% under the terms of the GNU General Public License as published by the |
| 6 | +% Free Software Foundation, either version 3 of the License, or (at your |
| 7 | +% option) any later version. |
| 8 | + |
| 9 | +% This program is distributed in the hope that it will be useful, but |
| 10 | +% WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
| 12 | +% Public License for more details. |
| 13 | + |
| 14 | +% The GNU General Public License can be seen at http://www.gnu.org/licenses/. |
| 15 | + |
| 16 | +% apriori_llrs is a 1xk vector of a priori LLRs |
| 17 | +% rx is a complex symbol |
| 18 | +% channel is a complex channel coefficient |
| 19 | +% N0 is the noise power spectral density |
| 20 | +% extrinsic_llrs is a 1xk vector of extrinsic LLRs |
| 21 | +function extrinsic_llrs = soft_demodulate(rx, channel, N0, apriori_llrs) |
| 22 | + |
| 23 | + % Specify the constellation points and the bit mapping here |
| 24 | + constellation_points = [+1+1i; -1+1i; -1-1i; +1-1i]/sqrt(2); |
| 25 | + bit_labels = [0,0; 0,1; 1,0; 1,1]; |
| 26 | + |
| 27 | + % Determine the number of bits per symbol and the number of constellation points here |
| 28 | + k = size(bit_labels,2); |
| 29 | + M = 2^k; |
| 30 | + N = length(rx); |
| 31 | + |
| 32 | + % Check that all the vectors and matrices have the correct dimensions |
| 33 | + if ~isequal(size(constellation_points),[M,1]) || ~isequal(size(bit_labels),[M,k]) |
| 34 | + error('wrong dimensions'); |
| 35 | + end |
| 36 | + |
| 37 | + if length(channel) ~= length(rx) && length(channel) ~= 1 |
| 38 | + error('wrong dimensions'); |
| 39 | + end |
| 40 | + |
| 41 | + |
| 42 | + |
| 43 | +aposteriori_symbol_LLRs = zeros(M,N); |
| 44 | + |
| 45 | +% Put the influence of the received signals into the symbol LLRs |
| 46 | +for perm_index = 1:M |
| 47 | + aposteriori_symbol_LLRs(perm_index,:) = -abs(rx-channel*constellation_points(perm_index)).^2./N0; |
| 48 | +end |
| 49 | + |
| 50 | +if exist('apriori_llrs','var') |
| 51 | + % Put the influence of the apriori LLRs into the symbol LLRs |
| 52 | + for bit_index = 1:k |
| 53 | +% aposteriori_symbol_LLRs(:,bit_permutations(bit_index,:) == 0) = aposteriori_symbol_LLRs(:,bit_permutations(bit_index,:) == 0) + repmat(apriori_llrs(bit_index:bits_per_symbol:end),[1,permutations/2]); |
| 54 | + |
| 55 | + for perm_index = 1:M |
| 56 | + if bit_labels(perm_index,bit_index) == 0 |
| 57 | + aposteriori_symbol_LLRs(perm_index,:) = aposteriori_symbol_LLRs(perm_index,:) + apriori_llrs(bit_index:k:end); |
| 58 | + end |
| 59 | + end |
| 60 | + end |
| 61 | +end |
| 62 | + |
| 63 | +% Extract the aposteriori LLRs from the symbol LLRs |
| 64 | +aposteriori_llrs = zeros(1,N*k); |
| 65 | +for bit_index = 1:k |
| 66 | + p0 = -inf(1,N); |
| 67 | + p1 = -inf(1,N); |
| 68 | + |
| 69 | + for perm_index = 1:M |
| 70 | + if bit_labels(perm_index,bit_index) == 0 |
| 71 | + p0 = jac(p0, aposteriori_symbol_LLRs(perm_index,:)); |
| 72 | + else |
| 73 | + p1 = jac(p1, aposteriori_symbol_LLRs(perm_index,:)); |
| 74 | + end |
| 75 | + end |
| 76 | + |
| 77 | + aposteriori_llrs(bit_index:k:end) = p0-p1; |
| 78 | +end |
| 79 | + |
| 80 | +if exist('apriori_llrs','var') |
| 81 | + % Remove the apriori from the aposteriori to get the extrinsic |
| 82 | + extrinsic_llrs = aposteriori_llrs - apriori_llrs; |
| 83 | +else |
| 84 | + extrinsic_llrs = aposteriori_llrs; |
| 85 | +end |
| 86 | + |
| 87 | + |
| 88 | + |
| 89 | + |
| 90 | +end |
0 commit comments