32 #define INFINITY std::numeric_limits<double>::infinity()
37 void SISO::descrambler(itpp::vec &extrinsic_coded, itpp::vec &extrinsic_data,
const itpp::vec &intrinsic_coded,
const itpp::vec &apriori_data)
48 int nb_bits = apriori_data.length();
49 int Nc = scrambler_pattern.length();
51 extrinsic_data.set_size(nb_bits);
52 extrinsic_coded.set_size(nb_bits*Nc);
54 #pragma omp parallel for private(n,k)
55 for (k=0; k<nb_bits; k++)
57 extrinsic_data[k] = 0;
60 extrinsic_data[k] += (1-2*double(scrambler_pattern[n]))*intrinsic_coded[n+k*Nc];
64 extrinsic_coded[n+k*Nc] = (1-2*double(scrambler_pattern[n]))*extrinsic_data[k]-intrinsic_coded[n+k*Nc];
69 void SISO::zpFIRfilter(itpp::vec &filt,
const itpp::vec &h,
const itpp::vec &sig)
77 #pragma omp parallel for private(n,l)
78 for (n=0; n<(N+L); n++)
91 filt[n] += (h[l]*sig[n-l]);
96 void SISO::gen_hyperTrellis(
void)
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);
110 int mem_len = nb_usr*max_order;
111 if (mem_len>=(
int)(8*
sizeof(
int)))
113 std::string msg =
"SISO::gen_hyperTrellis: memory length of the hyperchannel should be at most ";
115 msg +=
". Try to lower the number of users, channel order or the order of the precoding polynomial (if any)";
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)
129 std::string msg =
"SISO::gen_hyperTrellis: not enough memory for the channel trellis variables. The number of states is ";
131 msg +=
" and the number of input symbols ";
136 itpp::ivec index(chtrellis.stateNb);
138 itpp::bvec hyper_ch_mem(mem_len);
139 itpp::bvec hyper_ch_in(nb_usr);
140 itpp::bvec hyper_states(mem_len);
144 register int n,k,p,r;
147 for (k=0; k<chtrellis.stateNb; k++)
150 for (n=0; n<chtrellis.numInputSymbols; n++)
154 for (r=0; r<nb_usr; r++)
156 buffer = r*max_order;
158 feedback = hyper_ch_in[r];
159 for (p=1; p<=p_order; p++)
163 feedback ^= hyper_ch_mem[p-1+buffer];
167 hyper_ch_out += (1-2*double(feedback))*impulse_response(r,0);
168 for (p=0; p<ch_order; p++)
170 hyper_ch_out += (1-2*double(hyper_ch_mem[p+buffer]))*impulse_response(r,p+1);
173 hyper_states[buffer] = feedback;
174 for (p=0; p<(max_order-1); p++)
176 hyper_states[p+buffer+1] = hyper_ch_mem[p+buffer];
179 chtrellis.output[k+n*chtrellis.stateNb] = hyper_ch_out;
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;
193 void SISO::mud_maxlogMAP(itpp::mat &extrinsic_data,
const itpp::vec &rec_sig,
const itpp::mat &apriori_data)
202 int nb_usr = apriori_data.rows();
203 int block_len = apriori_data.cols();
209 double *A = NULL,*B = NULL;
212 A =
new double[chtrellis.stateNb*(block_len+1)];
213 B =
new double[chtrellis.stateNb*(block_len+1)];
214 }
catch (std::bad_alloc)
216 std::string msg =
"SISO::mud_maxlogMAP: Not enough memory for alphas and betas. The number of states is ";
218 msg +=
" and the block length ";
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++)
230 B[n+block_len*chtrellis.stateNb] = buffer;
236 itpp::bvec in_chips(nb_usr);
237 #pragma omp parallel sections private(n,buffer,s,k,sp,in_chips)
239 for (n=1; n<=block_len; n++)
242 for (s=0; s<chtrellis.stateNb; s++)
244 A[s+n*chtrellis.stateNb] = -INFINITY;
245 for (k=0; k<chtrellis.numInputSymbols; k++)
247 sp = chtrellis.prevState[s+k*chtrellis.stateNb];
248 i = chtrellis.input[s+k*chtrellis.stateNb];
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)+\
254 buffer =
std::max(buffer, A[s+n*chtrellis.stateNb]);
257 for (s=0; s<chtrellis.stateNb; s++)
259 A[s+n*chtrellis.stateNb] -= buffer;
265 for (n=block_len-1; n>=0; n--)
268 for (s=0; s<chtrellis.stateNb; s++)
270 B[s+n*chtrellis.stateNb] = -INFINITY;
271 for (k=0; k<chtrellis.numInputSymbols; k++)
273 sp = chtrellis.nextState[s+k*chtrellis.stateNb];
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)+\
279 buffer =
std::max(buffer, B[s+n*chtrellis.stateNb]);
282 for (s=0; s<chtrellis.stateNb; s++)
284 B[s+n*chtrellis.stateNb] -= buffer;
291 extrinsic_data.set_size(nb_usr,block_len);
293 #pragma omp parallel for private(u,n,s,k,nom,denom,in_chips,buffer)
294 for (u=0; u<nb_usr; u++)
296 for (n=1; n<=block_len; n++)
300 for (s=0; s<chtrellis.stateNb; s++)
302 for (k=0; k<chtrellis.numInputSymbols; 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)+\
318 extrinsic_data(u,n-1) = (nom-denom)-apriori_data(u,n-1);
322 delete[] chtrellis.nextState;
323 delete[] chtrellis.prevState;
324 delete[] chtrellis.output;
325 delete[] chtrellis.input;
333 void SISO::GCD(itpp::mat &extrinsic_data,
const itpp::vec &rec_sig,
const itpp::mat &apriori_data)
343 int N = apriori_data.cols();
344 int K = apriori_data.rows();
345 int L = impulse_response.cols()-1;
351 itpp::mat Vx = 1.0-
sqr(Ex);
359 Covr.set_size(N+L,N+L);
360 }
catch (std::bad_alloc)
362 std::string msg =
"SISO::GCD: not enough memory when allocating space for the covariance matrix. The interleaver length is ";
364 msg +=
". Use sGCD instead or try to reduce the interleaver length";
370 for (n=0; n<(N+L); n++)
376 itpp::mat h_eq(N+L,N);
379 col.replace_mid(0, impulse_response.get_row(k));
380 row(0) = impulse_response(k,0);
382 Er += h_eq*Ex.get_row(k);
383 Covr += (h_eq*
itpp::diag(Vx.get_row(k)))*h_eq.T();
389 itpp::mat inv_Covr(N+L,N+L);
391 itpp::mat inv_cov_zeta(N+L,N+L);
392 itpp::vec rec_chip(N+L);
393 extrinsic_data.set_size(K,N);
396 #pragma omp parallel for private(n,inv_cov_zeta,rec_chip,nom,denom) firstprivate(col)
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;
415 void SISO::sGCD(itpp::mat &extrinsic_data,
const itpp::vec &rec_sig,
const itpp::mat &apriori_data)
425 int N = apriori_data.cols();
426 int K = apriori_data.rows();
427 int L = impulse_response.cols()-1;
439 itpp::vec buffer(N+L);
442 zpFIRfilter(buffer, impulse_response.get_row(k), Ex.get_row(k));
444 zpFIRfilter(buffer,
itpp::sqr(impulse_response.get_row(k)), Vx.get_row(k));
451 extrinsic_data.set_size(K,N);
454 ch = impulse_response.get_row(k);
455 #pragma omp parallel for private(n)
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));