IT++ Logo
siso_mud.cpp
Go to the documentation of this file.
1
29#include <itpp/comm/siso.h>
30#include <limits>
31#ifndef INFINITY
32#define INFINITY std::numeric_limits<double>::infinity()
33#endif
34
35namespace itpp
36{
37void SISO::descrambler(itpp::vec &extrinsic_coded, itpp::vec &extrinsic_data, const itpp::vec &intrinsic_coded, const itpp::vec &apriori_data)
38/*
39 inputs:
40 intrinsic_coded - intrinsic information of coded bits (repetition code output)
41 apriori_data - a priori information of informational bits (repetition code input)
42 outputs:
43 extrinsic_coded - extrinsic information of coded bits
44 extrinsic_data - Logarithm of Likelihood Ratio of informational bits
45*/
46{
47 //get parameters
49 int Nc = scrambler_pattern.length();
50 //implementation
53 register int n,k;
54#pragma omp parallel for private(n,k)
55 for (k=0; k<nb_bits; k++)
56 {
57 extrinsic_data[k] = 0;//apriori_data[k];//add a priori info
58 for (n=0; n<Nc; n++)
59 {
60 extrinsic_data[k] += (1-2*double(scrambler_pattern[n]))*intrinsic_coded[n+k*Nc];
61 }
62 for (n=0; n<Nc; n++)
63 {
64 extrinsic_coded[n+k*Nc] = (1-2*double(scrambler_pattern[n]))*extrinsic_data[k]-intrinsic_coded[n+k*Nc];
65 }
66 }
67}
68
69void SISO::zpFIRfilter(itpp::vec &filt, const itpp::vec &h, const itpp::vec &sig)
70//FIR filter for a zero padded signal (L zeros are added at the end of the signal)
71{
72 //get parameters
73 int L = h.length()-1;
74 int N = sig.length();
75 //implementation
76 register int n,l;
77#pragma omp parallel for private(n,l)
78 for (n=0; n<(N+L); n++)
79 {
80 filt[n] = 0;
81 for (l=0; l<=L; l++)
82 {
83 if ((n-l)<0)
84 {
85 break;//channel has state 0 at the beginning
86 }
87 if ((n-l)>=N)
88 {
89 continue;//channel has state 0 in the end
90 }
91 filt[n] += (h[l]*sig[n-l]);
92 }
93 }
94}
95
96void SISO::gen_hyperTrellis(void)
97/* generates channel hyper trellis for binary symbols
98 * the channel is a MISO system
99 * BPSK mapping: 0->+1, 1->-1
100 */
101{
102 //get parameters
103 int nb_usr = impulse_response.rows();
104 int ch_order = impulse_response.cols()-1;
105 int p_order = prec_gen.length()-1;
106 int max_order = std::max(ch_order, p_order);
107
108 //initialize hypertrellis
109 chtrellis.numInputSymbols = itpp::pow2i(nb_usr);
110 int mem_len = nb_usr*max_order;
111 if (mem_len>=(int)(8*sizeof(int)))
112 {
113 std::string msg = "SISO::gen_hyperTrellis: memory length of the hyperchannel should be at most ";
114 msg += itpp::to_str(8*sizeof(int)-1);
115 msg += ". Try to lower the number of users, channel order or the order of the precoding polynomial (if any)";
116 print_err_msg(msg);
117 return;
118 }
119 chtrellis.stateNb = itpp::pow2i(mem_len);
120 try
121 {
122 unsigned int len = static_cast<unsigned int>(chtrellis.stateNb)*static_cast<unsigned int>(chtrellis.numInputSymbols);
123 chtrellis.nextState = new int[len];
124 chtrellis.prevState = new int[len];
125 chtrellis.output = new double[len];
126 chtrellis.input = new int[len];
127 } catch (std::bad_alloc)
128 {
129 std::string msg = "SISO::gen_hyperTrellis: not enough memory for the channel trellis variables. The number of states is ";
130 msg += itpp::to_str(chtrellis.stateNb);
131 msg += " and the number of input symbols ";
132 msg += itpp::to_str(chtrellis.numInputSymbols);
133 print_err_msg(msg);
134 return;
135 }
136 itpp::ivec index(chtrellis.stateNb);
137 index.zeros();
138 itpp::bvec hyper_ch_mem(mem_len);
139 itpp::bvec hyper_ch_in(nb_usr);
140 itpp::bvec hyper_states(mem_len);
141 itpp::bin feedback;
142
143 //create hypertrellis
144 register int n,k,p,r;
145 int buffer;
146 double hyper_ch_out;
147 for (k=0; k<chtrellis.stateNb; k++)
148 {
149 hyper_ch_mem = itpp::dec2bin(mem_len, k);//initial state
150 for (n=0; n<chtrellis.numInputSymbols; n++)
151 {
152 hyper_ch_in = itpp::dec2bin(nb_usr, n);//MISO channel input
153 hyper_ch_out = 0;
154 for (r=0; r<nb_usr; r++)
155 {
156 buffer = r*max_order;
157 //precoder
158 feedback = hyper_ch_in[r];
159 for (p=1; p<=p_order; p++)
160 {
161 if (prec_gen(p))
162 {
163 feedback ^= hyper_ch_mem[p-1+buffer];//xor
164 }
165 }
166 //FIR channel output
167 hyper_ch_out += (1-2*double(feedback))*impulse_response(r,0);
168 for (p=0; p<ch_order; p++)
169 {
170 hyper_ch_out += (1-2*double(hyper_ch_mem[p+buffer]))*impulse_response(r,p+1);//hyper channel output for user r
171 }
172 //(equivalent) channel next state
173 hyper_states[buffer] = feedback;
174 for (p=0; p<(max_order-1); p++)
175 {
176 hyper_states[p+buffer+1] = hyper_ch_mem[p+buffer];//next hyper state for user r
177 }
178 }
179 chtrellis.output[k+n*chtrellis.stateNb] = hyper_ch_out;
180 buffer = itpp::bin2dec(hyper_states);//next state from an initial state and a given input
181 chtrellis.nextState[k+n*chtrellis.stateNb] = buffer;
182 chtrellis.prevState[buffer+index[buffer]*chtrellis.stateNb] = k;
183 chtrellis.input[buffer+index[buffer]*chtrellis.stateNb] = n;
184 index[buffer]++;
185 }
186 }
187}
188
190
193void SISO::mud_maxlogMAP(itpp::mat &extrinsic_data, const itpp::vec &rec_sig, const itpp::mat &apriori_data)
194/* output:
195 * extrinsic_data - extrinsic information for the chips (usr_nb x block_len)
196 * inputs:
197 * rec_sig - received signal (1 x block_len)
198 * apriori_data - a priori information for the chips (usr_nb x block_len)
199 */
200{
201 //get parameters
202 int nb_usr = apriori_data.rows();
203 int block_len = apriori_data.cols();
204
205 //init trellis
206 gen_hyperTrellis();
207
208 //initial conditions for A = log(alpha) and B = log(beta)
209 double *A = NULL,*B = NULL;
210 try
211 {
212 A = new double[chtrellis.stateNb*(block_len+1)];
213 B = new double[chtrellis.stateNb*(block_len+1)];
214 } catch (std::bad_alloc)
215 {
216 std::string msg = "SISO::mud_maxlogMAP: Not enough memory for alphas and betas. The number of states is ";
217 msg += itpp::to_str(chtrellis.stateNb);
218 msg += " and the block length ";
219 msg += itpp::to_str(block_len);
220 print_err_msg(msg);
221 }
222 register int n;
223 A[0] = 0;
224 B[block_len*chtrellis.stateNb] = 0;
225 double buffer = (tail?-INFINITY:0);
226#pragma omp parallel for private(n)
227 for (n=1; n<chtrellis.stateNb; n++)
228 {
229 A[n] = -INFINITY;
230 B[n+block_len*chtrellis.stateNb] = buffer;//if tail==false the final state is not known
231 }
232
233 //compute log(alpha) (forward recursion)
234 register int s,k;
235 int sp,i;
236 itpp::bvec in_chips(nb_usr);
237#pragma omp parallel sections private(n,buffer,s,k,sp,in_chips)
238 {
239 for (n=1; n<=block_len; n++)
240 {
241 buffer = -INFINITY;//normalization factor
242 for (s=0; s<chtrellis.stateNb; s++)
243 {
244 A[s+n*chtrellis.stateNb] = -INFINITY;
245 for (k=0; k<chtrellis.numInputSymbols; k++)
246 {
247 sp = chtrellis.prevState[s+k*chtrellis.stateNb];
248 i = chtrellis.input[s+k*chtrellis.stateNb];
249 in_chips = itpp::dec2bin(nb_usr, i);
250 A[s+n*chtrellis.stateNb] = std::max(A[s+n*chtrellis.stateNb], \
251 A[sp+(n-1)*chtrellis.stateNb]-itpp::sqr(rec_sig[n-1]-chtrellis.output[sp+i*chtrellis.stateNb])/(2*sigma2)+\
252 itpp::to_vec(in_chips)*apriori_data.get_col(n-1));
253 }
254 buffer = std::max(buffer, A[s+n*chtrellis.stateNb]);
255 }
256 //normalization
257 for (s=0; s<chtrellis.stateNb; s++)
258 {
259 A[s+n*chtrellis.stateNb] -= buffer;
260 }
261 }
262
263 //compute log(beta) (backward recursion)
264#pragma omp section
265 for (n=block_len-1; n>=0; n--)
266 {
267 buffer = -INFINITY;//normalization factor
268 for (s=0; s<chtrellis.stateNb; s++)
269 {
270 B[s+n*chtrellis.stateNb] = -INFINITY;
271 for (k=0; k<chtrellis.numInputSymbols; k++)
272 {
273 sp = chtrellis.nextState[s+k*chtrellis.stateNb];
274 in_chips = itpp::dec2bin(nb_usr, k);
275 B[s+n*chtrellis.stateNb] = std::max(B[s+n*chtrellis.stateNb], \
276 B[sp+(n+1)*chtrellis.stateNb]-itpp::sqr(rec_sig[n]-chtrellis.output[s+k*chtrellis.stateNb])/(2*sigma2)+\
277 itpp::to_vec(in_chips)*apriori_data.get_col(n));
278 }
279 buffer = std::max(buffer, B[s+n*chtrellis.stateNb]);
280 }
281 //normalization
282 for (s=0; s<chtrellis.stateNb; s++)
283 {
284 B[s+n*chtrellis.stateNb] -= buffer;
285 }
286 }
287 }
288
289 //compute extrinsic information
290 double nom, denom;
291 extrinsic_data.set_size(nb_usr,block_len);
292 register int u;
293#pragma omp parallel for private(u,n,s,k,nom,denom,in_chips,buffer)
294 for (u=0; u<nb_usr; u++)
295 {
296 for (n=1; n<=block_len; n++)
297 {
298 nom = -INFINITY;
299 denom = -INFINITY;
300 for (s=0; s<chtrellis.stateNb; s++)
301 {
302 for (k=0; k<chtrellis.numInputSymbols; k++)
303 {
304 in_chips = itpp::dec2bin(nb_usr, k);
305 buffer = A[s+(n-1)*chtrellis.stateNb]+B[chtrellis.nextState[s+k*chtrellis.stateNb]+n*chtrellis.stateNb]-\
306 itpp::sqr(rec_sig[n-1]-chtrellis.output[s+k*chtrellis.stateNb])/(2*sigma2)+\
307 itpp::to_vec(in_chips)*apriori_data.get_col(n-1);
308 if (in_chips[u])
309 {
310 nom = std::max(nom, buffer);
311 }
312 else
313 {
314 denom = std::max(denom, buffer);
315 }
316 }
317 }
318 extrinsic_data(u,n-1) = (nom-denom)-apriori_data(u,n-1);
319 }
320 }
321 //free memory
322 delete[] chtrellis.nextState;
323 delete[] chtrellis.prevState;
324 delete[] chtrellis.output;
325 delete[] chtrellis.input;
326 delete[] A;
327 delete[] B;
328}
329
331
333void SISO::GCD(itpp::mat &extrinsic_data, const itpp::vec &rec_sig, const itpp::mat &apriori_data)
334/* Gaussian Chip Detector
335 * output:
336 * extrinsic_data - extrinsic information of emitted chips
337 * inputs:
338 * rec_sig - received signal
339 * apriori_data - a priori information of emitted chips
340 */
341{
342 //get parameters
343 int N = apriori_data.cols();//emitted frames of non-zero samples
344 int K = apriori_data.rows();//number of users
345 int L = impulse_response.cols()-1;//channel order
346 //other parameters
347 register int n,k;
348
349 //mean and variance of each chip (NxK)
350 itpp::mat Ex = -itpp::tanh(apriori_data/2.0);//take into account BPSK mapping
351 itpp::mat Vx = 1.0-sqr(Ex);
352
353 //expectation and variance of the received signal
354 itpp::vec Er(N+L);
355 Er.zeros();
356 itpp::mat Covr;
357 try
358 {
359 Covr.set_size(N+L,N+L);
360 } catch (std::bad_alloc)
361 {
362 std::string msg = "SISO::GCD: not enough memory when allocating space for the covariance matrix. The interleaver length is ";
363 msg += itpp::to_str(N);
364 msg += ". Use sGCD instead or try to reduce the interleaver length";
365 print_err_msg(msg);
366 return;
367 }
368 //create eye function
369 Covr.zeros();
370 for (n=0; n<(N+L); n++)
371 Covr(n,n) = 1;
372 itpp::vec col(N+L);
373 col.zeros();
374 itpp::vec row(N);
375 row.zeros();
376 itpp::mat h_eq(N+L,N);
377 for (k=0; k<K; k++)
378 {
379 col.replace_mid(0, impulse_response.get_row(k));
380 row(0) = impulse_response(k,0);
381 h_eq = itpp::toeplitz(col, row);
382 Er += h_eq*Ex.get_row(k);
383 Covr += (h_eq*itpp::diag(Vx.get_row(k)))*h_eq.T();
384 }
385
386 //extrinsic information
387 double nom,denom;
388 Er = rec_sig-Er;
389 itpp::mat inv_Covr(N+L,N+L);
390 inv_Covr = itpp::inv(Covr);
391 itpp::mat inv_cov_zeta(N+L,N+L);
392 itpp::vec rec_chip(N+L);
393 extrinsic_data.set_size(K,N);
394 for (k=0; k<K; k++)
395 {
396#pragma omp parallel for private(n,inv_cov_zeta,rec_chip,nom,denom) firstprivate(col)
397 for (n=0; n<N; n++)
398 {
399 col.replace_mid(n, impulse_response.get_row(k));
400 inv_cov_zeta = inv_Covr+itpp::outer_product(inv_Covr*col, inv_Covr.T()*(col*Vx(k,0)))/(1-(col*Vx(k,0))*(inv_Covr*col));
401 rec_chip = Er-col*(+1-Ex(k,n));
402 nom = -0.5*rec_chip*(inv_cov_zeta*rec_chip);
403 rec_chip = Er-col*(-1-Ex(k,n));
404 denom = -0.5*rec_chip*(inv_cov_zeta*rec_chip);
405 extrinsic_data(k,n) = denom-nom;//take into account BPSK mapping
406 col(n) = 0;
407 }
408 }
409}
410
412
415void SISO::sGCD(itpp::mat &extrinsic_data, const itpp::vec &rec_sig, const itpp::mat &apriori_data)
416/* simplified GCD
417 * output:
418 * extrinsic_data - extrinsic information of emitted chips
419 * inputs:
420 * rec_sig - received signal
421 * apriori_data - a priori information of emitted chips
422 */
423{
424 //get parameters
425 int N = apriori_data.cols();//emitted frames of non-zero samples
426 int K = apriori_data.rows();//number of users
427 int L = impulse_response.cols()-1;//channel order
428 //other parameters
429 register int n,k;
430
431 //mean and variance of each chip (NxK)
432 itpp::mat Ex = -itpp::tanh(apriori_data/2.0);//take into account BPSK mapping
433 itpp::mat Vx = 1.0-itpp::sqr(Ex);
434
435 //mean and variance for the samples of the received signal
436 itpp::vec Er(N+L);
437 Er.zeros();
438 itpp::vec Vr = sigma2*itpp::ones(N+L);
439 itpp::vec buffer(N+L);
440 for (k=0; k<K; k++)
441 {
442 zpFIRfilter(buffer, impulse_response.get_row(k), Ex.get_row(k));
443 Er += buffer;
444 zpFIRfilter(buffer, itpp::sqr(impulse_response.get_row(k)), Vx.get_row(k));
445 Vr += buffer;
446 }
447
448 //extrinsic information for the samples of the received signal
449 Er = rec_sig-Er;
450 itpp::vec ch(L+1);
451 extrinsic_data.set_size(K,N);
452 for (k=0; k<K; k++)
453 {
454 ch = impulse_response.get_row(k);
455#pragma omp parallel for private(n)
456 for (n=0; n<N; n++)
457 {
458 extrinsic_data(k,n) = -2*itpp::elem_div(ch, Vr.mid(n,L+1)-sqr(ch)*Vx(k,n))*(Er.mid(n,L+1)+ch*Ex(k,n));//take into account BPSK mapping
459 }
460 }
461}
462}//end namespace tr
General array class.
Definition array.h:105
void set_size(int n, bool copy=false)
Resizing an Array<T>.
Definition array.h:257
int length() const
Returns the number of data elements in the array object.
Definition array.h:157
void descrambler(itpp::vec &extrinsic_coded, itpp::vec &extrinsic_data, const itpp::vec &intrinsic_coded, const itpp::vec &apriori_data)
SISO descrambler
Definition siso_mud.cpp:37
Binary arithmetic (boolean) class.
Definition binary.h:57
Mat< T > diag(const Vec< T > &v, const int K=0)
Create a diagonal matrix using vector v as its diagonal.
Definition matfunc.h:557
vec tanh(const vec &x)
Tan hyperbolic function.
Definition trig_hyp.h:97
bool inv(const mat &X, mat &Y)
Inverse of real square matrix.
Definition inv.cpp:87
int pow2i(int x)
Calculate two to the power of x (2^x); x is integer.
Definition log_exp.h:53
vec sqr(const cvec &data)
Absolute square of elements.
Definition elem_math.cpp:36
const cmat toeplitz(const cvec &c)
Generate symmetric Toeplitz matrix from vector c (complex valued)
Definition specmat.cpp:210
ITPP_EXPORT vec ones(int size)
A float vector of ones.
itpp namespace
Definition itmex.h:37
ITPP_EXPORT int bin2dec(const bvec &inbvec, bool msb_first=true)
Convert a bvec to decimal int with the first bit as MSB if msb_first == true.
vec to_vec(const Vec< T > &v)
Converts a Vec<T> to vec.
Definition converters.h:93
std::string to_str(const T &i)
Convert anything to string.
Definition converters.h:444
ITPP_EXPORT bvec dec2bin(int length, int index)
Convert a decimal int index to bvec using length bits in the representation.
Mat< Num_T > elem_div(const Mat< Num_T > &m1, const Mat< Num_T > &m2)
Element wise division of two matrices.
Definition mat.h:1688
Mat< Num_T > outer_product(const Vec< Num_T > &v1, const Vec< Num_T > &v2, bool hermitian=false)
Outer product of two vectors v1 and v2.
Definition vec.h:1021
Definitions for Soft Input Soft Output (SISO) modules class.
SourceForge Logo

Generated on Mon Jun 10 2024 11:49:22 for IT++ by Doxygen 1.9.8