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 
35 namespace itpp
36 {
37 void 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
48  int nb_bits = apriori_data.length();
49  int Nc = scrambler_pattern.length();
50  //implementation
51  extrinsic_data.set_size(nb_bits);
52  extrinsic_coded.set_size(nb_bits*Nc);
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 
69 void 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 
96 void 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 
193 void 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 
333 void 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 
415 void 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
SourceForge Logo

Generated on Sat May 25 2013 16:32:22 for IT++ by Doxygen 1.8.2