IT++ Logo
channel.cpp
Go to the documentation of this file.
1 
30 #include <itpp/comm/channel.h>
31 #include <itpp/base/math/error.h>
33 #include <itpp/base/bessel.h>
34 #include <itpp/base/matfunc.h>
35 #include <itpp/base/specmat.h>
36 #include <itpp/signal/resampling.h>
37 #include <itpp/signal/transforms.h>
38 #include <itpp/signal/window.h>
39 #include <itpp/base/math/min_max.h>
40 #include <itpp/stat/misc_stat.h>
41 
42 
43 namespace itpp
44 {
45 
46 
47 // --------------------------------------------------------------------------
48 // Fading_Generator class
49 // --------------------------------------------------------------------------
50 
52 {
53  // no default LOS component
54  set_LOS_power(0.0);
55 }
56 
57 void Fading_Generator::set_LOS_power(double relative_power)
58 {
59  it_assert(relative_power >= 0.0,
60  "Fading_Generator::set_LOS_power(): Relative_power can not be negative");
61  los_power = relative_power;
62  los_diffuse = std::sqrt(1.0 / (1.0 + los_power));
64 }
65 
67 {
68  it_warning("Fading_Generator::set_LOS_doppler(): This function has no effect on this kind of generator");
69 }
70 
72 {
73  it_warning("Fading_Generator::set_time_offset(): This function has no effect on this kind of generator");
74 }
75 
77 {
78  it_warning("Fading_Generator::set_norm_doppler(): This function has no effect on this kind of generator");
79 }
80 
82 {
83  it_warning("Fading_Generator::set_filter_length(): This function has no effect on this kind of generator");
84 }
85 
87 {
88  it_warning("Fading_Generator::set_doppler_spectrum(): This function has no effect on this kind of generator");
89 }
90 
92 {
93  it_warning("Fading_Generator::set_no_frequencies(): This function has no effect on this kind of generator");
94 }
95 
97 {
98  it_warning("Fading_Generator::set_rice_method(): This function has no effect on this kind of generator");
99 }
100 
102 {
103  it_warning("Fading_Generator::get_LOS_doppler(): This function has no effect on this kind of generator");
104  return 0;
105 }
106 
108 {
109  it_warning("Fading_Generator::get_time_offset(): This function has no effect on this kind of generator");
110  return 0;
111 }
112 
114 {
115  it_warning("Fading_Generator::get_filter_length(): This function has no effect on this kind of generator");
116  return 0;
117 }
118 
120 {
121  it_warning("Fading_Generator::get_norm_doppler(): This function has no effect on this kind of generator");
122  return 0;
123 }
124 
126 {
127  it_warning("Fading_Generator::get_doppler_spectrum(): This function has no effect on this kind of generator");
128  return Jakes;
129 }
130 
132 {
133  it_warning("Fading_Generator::get_no_frequencies(): This function has no effect on this kind of generator");
134  return 0;
135 }
136 
138 {
139  it_warning("Fading_Generator::get_rice_method(): This function has no effect on this kind of generator");
140  return MEDS;
141 }
142 
144 {
145  it_warning("Fading_Generator::shift_time_offset(): This function has no effect on this kind of generator");
146 }
147 
148 cvec Fading_Generator::generate(int no_samples)
149 {
150  cvec output;
151  this->generate(no_samples, output);
152  return output;
153 }
154 
155 
156 // --------------------------------------------------------------------------
157 // Independent_Fading_Generator class
158 // --------------------------------------------------------------------------
159 
160 void Independent_Fading_Generator::generate(int no_samples, cvec& output)
161 {
162  output.set_size(no_samples, false);
163  if (los_power > 0.0) {
164  for (int i = 0; i < no_samples; ++i) {
165  output(i) = los_diffuse * randn_c() + los_direct;
166  }
167  }
168  else {
169  output = randn_c(no_samples);
170  }
171 }
172 
173 
174 // --------------------------------------------------------------------------
175 // Static_Fading_Generator class
176 // --------------------------------------------------------------------------
177 
179 {
180  std::complex<double> static_sample = randn_c();
181  if (los_power > 0.0) {
182  static_sample *= los_diffuse;
183  static_sample += los_direct;
184  }
185  static_sample_re = static_sample.real();
186  static_sample_im = static_sample.imag();
187  init_flag = true;
188 }
189 
190 void Static_Fading_Generator::generate(int no_samples, cvec& output)
191 {
192  if (init_flag == false)
193  init();
194 
195  output.set_size(no_samples, false);
196  output = std::complex<double>(static_sample_re,static_sample_im);
197 }
198 
199 
200 // --------------------------------------------------------------------------
201 // Correlated_Fading_Generator class
202 // --------------------------------------------------------------------------
203 
205  Fading_Generator(), los_dopp(0.7), time_offset(0.0)
206 {
207  set_norm_doppler(norm_doppler);
208 }
209 
211 {
212  it_assert((norm_doppler > 0) && (norm_doppler <= 1.0),
213  "Correlated_Fading_Generator: Normalized Doppler out of range");
214  n_dopp = norm_doppler;
215  init_flag = false;
216 }
217 
218 void Correlated_Fading_Generator::set_LOS_doppler(double relative_doppler)
219 {
220  it_assert((relative_doppler >= 0) && (relative_doppler <= 1.0),
221  "Correlated_Fading_Generator::set_LOS_doppler(): Relative Doppler out of range");
222  los_dopp = relative_doppler;
223 }
224 
226 {
227  time_offset = static_cast<double>(offset);
228 }
229 
231 {
232  time_offset += static_cast<double>(no_samples);
233 }
234 
235 void Correlated_Fading_Generator::add_LOS(int idx, std::complex<double>& sample)
236 {
237  double tmp_arg = m_2pi * los_dopp * n_dopp * (idx + time_offset);
238  sample *= los_diffuse;
239  sample += los_direct * std::complex<double>(std::cos(tmp_arg),
240  std::sin(tmp_arg));
241 }
242 
243 
244 // --------------------------------------------------------------------------
245 // Rice_Fading_Generator class
246 // --------------------------------------------------------------------------
247 
250  int no_freq, RICE_METHOD method) :
251  Correlated_Fading_Generator(norm_doppler)
252 {
254  set_no_frequencies(no_freq);
255  set_rice_method(method);
256 }
257 
259 {
261  init_flag = false;
262 }
263 
265 {
266  it_assert(no_freq >= 7,
267  "Rice_Fading_Generator::set_no_frequencies(): Too low number of Doppler frequencies");
268  Ni = no_freq;
269  init_flag = false;
270 }
271 
273 {
274  // check if this method works for the given spectrum
275  rice_method = method;
276  init_flag = false;
277 }
278 
280 {
281  switch (rice_method) {
282  case MEDS: // Method of Exact Doppler Spread (MEDS)
283  init_MEDS();
284  break;
285  default:
286  it_error("Rice_Fading_Generator::init(): Wrong Rice method for this fading generator");
287  };
288 
289  init_flag = true; // generator ready to use
290 }
291 
292 void Rice_Fading_Generator::generate(int no_samples, cvec &output)
293 {
294  if (init_flag == false)
295  init();
296 
297  output.set_size(no_samples, false);
298 
299  switch (dopp_spectrum) {
300  case Jakes: {
301  double tmp_re, tmp_im;
302  if (los_power > 0.0) { // LOS component exists
303  for (int i = 0; i < no_samples; i++) {
304  tmp_re = sum(elem_mult(c1, cos(m_2pi * f1 * n_dopp * (i + time_offset) + th1)));
305  tmp_im = sum(elem_mult(c2, cos(m_2pi * f2 * n_dopp * (i + time_offset) + th2)));
306  output(i) = std::complex<double>(tmp_re, tmp_im);
307  add_LOS(i, output(i));
308  }
309  }
310  else {
311  for (int i = 0; i < no_samples; i++) {
312  tmp_re = sum(elem_mult(c1, cos(m_2pi * f1 * n_dopp * (i + time_offset) + th1)));
313  tmp_im = sum(elem_mult(c2, cos(m_2pi * f2 * n_dopp * (i + time_offset) + th2)));
314  output(i) = std::complex<double>(tmp_re, tmp_im);
315  }
316  }
317  break;
318  }
319  case GaussI:
320  case GaussII: {
321  double tmp;
322  for (int i = 0; i < no_samples; i++) {
323  tmp = m_2pi * n_dopp * (i + time_offset);
324  output(i) = sum(elem_mult(c1, cos(f1 * tmp + th1)))
325  * std::complex<double>(std::cos(f01 * tmp), -std::sin(f01 * tmp))
326  + sum(elem_mult(c2, cos(f2 * tmp + th2)))
327  * std::complex<double>(std::cos(f02 * tmp), -std::sin(f02 * tmp));
328  }
329  break;
330  }
331  }
332 
333  time_offset += no_samples;
334 }
335 
337 {
338  vec n;
339  double sgm_0_2;
340 
341  switch (dopp_spectrum) {
342  case Jakes:
343  n = linspace(1, Ni, Ni);
344  f1 = sin(pi / (2 * Ni) * (n - 0.5));
345  c1 = std::sqrt(1.0 / Ni) * ones(Ni);
346  th1 = randu(Ni) * 2 * pi;
347  n = linspace(1, Ni + 1, Ni + 1);
348  f2 = sin(pi / (2 * (Ni + 1)) * (n - 0.5));
349  c2 = std::sqrt(1.0 / (Ni + 1)) * ones(Ni + 1);
350  th2 = randu(Ni + 1) * 2 * pi;
351  f01 = f02 = 0;
352  break;
353  case GaussI:
354  n = linspace(1, Ni, Ni);
355  sgm_0_2 = 5.0 / 6.0;
356  c1 = std::sqrt(sgm_0_2 * 2.0 / Ni) * ones(Ni);
357  f1 = std::sqrt(2.0) * 0.05 * erfinv((2 * n - 1) / (2 * Ni));
358  th1 = randu(Ni) * 2 * pi;
359  sgm_0_2 = 1.0 / 6.0;
360  c2 = std::sqrt(sgm_0_2 * 2.0 / Ni) * ones(Ni);
361  f2 = std::sqrt(2.0) * 0.1 * erfinv((2 * n - 1) / (2 * Ni));
362  th2 = randu(Ni) * 2 * pi;
363  f01 = 0.8;
364  f02 = -0.4;
365  break;
366  case GaussII:
367  n = linspace(1, Ni, Ni);
368  sgm_0_2 = std::sqrt(10.0) / (std::sqrt(10.0) + 0.15);
369  c1 = std::sqrt(sgm_0_2 * 2.0 / Ni) * ones(Ni);
370  f1 = std::sqrt(2.0) * 0.1 * erfinv((2 * n - 1) / (2 * Ni));
371  th1 = randu(Ni) * 2 * pi;
372  sgm_0_2 = 0.15 / (std::sqrt(10.0) + 0.15);
373  c2 = std::sqrt(sgm_0_2 * 2.0 / Ni) * ones(Ni);
374  f2 = std::sqrt(2.0) * 0.15 * erfinv((2 * n - 1) / (2 * Ni));
375  th2 = randu(Ni) * 2 * pi;
376  f01 = -0.7;
377  f02 = 0.4;
378  break;
379  default:
380  it_error("Rice_Fading_Generator::init_MEDS(): Wrong spectrum method for this fading generator");
381  };
382 }
383 
384 
385 // --------------------------------------------------------------------------
386 // FIR_Fading_Generator class methods
387 // --------------------------------------------------------------------------
388 
390  int filter_length) :
391  Correlated_Fading_Generator(norm_doppler)
392 {
393  set_filter_length(filter_length);
394 }
395 
397 {
398  it_assert(filter_length >= 50,
399  "FIR_Fading_Generator::set_filter_length(): Filter length should be at least 50");
400  fir_length = filter_length;
401  init_flag = false;
402 }
403 
405 {
406  // calculate a reasonable upsample rate so that normalized doppler is > 0.1
407  double norm_dopp = n_dopp;
408  upsample_rate = 1;
409  while (norm_dopp < 0.1) {
410  norm_dopp *= 2;
411  upsample_rate *= 2;
412  }
414 
415  // fill filter with dummy data
416  cvec dummy = fir_filter(randn_c(fir_length));
417 
418  left_overs.set_size(0, false);
419 
420  init_flag = true; // generator ready to use
421 }
422 
423 void FIR_Fading_Generator::generate(int no_samples, cvec &output)
424 {
425  if (init_flag == false)
426  init();
427 
428  // calculate number of samples before upsampling
429  int no_upsamples = ceil_i(static_cast<double>(no_samples - left_overs.size())
430  / upsample_rate) + 1;
431 
432  // should make a smarter interpolation here!!!
433  lininterp(fir_filter(randn_c(no_upsamples)), upsample_rate, output);
434  output = concat(left_overs, output); // add left-overs from previous filtering
435  left_overs = output.right(output.size() - no_samples); // save left-overs for next round of filtering
436  output.set_size(no_samples, true);
437 
438  if (los_power > 0.0) { // LOS component exist
439  for (int i = 0; i < no_samples; i++) {
440  add_LOS(i, output(i));
441  }
442  }
443 
444  time_offset += no_samples;
445 }
446 
447 vec FIR_Fading_Generator::Jakes_filter(double norm_dopp, int order)
448 {
449  int L = order / 2;
450  vec x_pos(L), x_neg(L), x(2*L + 1), h(2*L + 1);
451  for (int i = 1; i <= L; i++) {
452  x_pos(i - 1) = besselj(0.25, m_2pi * norm_dopp * i) / std::pow(i, 0.25);
453  // / std::sqrt(std::sqrt(static_cast<double>(i)));
454  }
455  double x0 = 1.468813 * std::pow(norm_dopp, 0.25); // std::sqrt(std::sqrt(norm_dopp));
456  x_neg = reverse(x_pos);
457  x = concat(concat(x_neg, x0), x_pos);
458  h = elem_mult(hamming(2 * L + 1), x);
459  h /= norm(h);
460  return h;
461 }
462 
463 
464 // --------------------------------------------------------------------------
465 // IFFT_Fading_Generator class methods
466 // --------------------------------------------------------------------------
467 
468 void IFFT_Fading_Generator::generate(int no_samples, cvec &output)
469 {
470  if (init_flag == false)
471  init();
472 
473  generate_Jakes(no_samples, output);
474 
475  if (los_power > 0.0) { // LOS component exist
476  for (int i = 0; i < no_samples; i++) {
477  add_LOS(i, output(i));
478  }
479  }
480 
481  time_offset += no_samples;
482 }
483 
484 void IFFT_Fading_Generator::generate_Jakes(int no_samples, cvec &output)
485 {
486  int Nfft = pow2i(levels2bits(no_samples));
487  double df = 1.0 / Nfft;
488  int noisesamp = ceil_i(n_dopp / df);
489  int no_upsample = 1;
490 
491  while (noisesamp <= 10) { // if too few samples, increase the FFT size
492  Nfft *= 2;
493  no_upsample *= 2;
494  df = 1.0 / Nfft;
495  noisesamp = ceil_i(n_dopp / df);
496  it_assert(no_upsample < 128,
497  "IFFT_Fading_Generator::generate_Jakes(): Too low normalized doppler or too small blocks of data. Results in an inefficient algorithm with lots of zero-padding");
498  }
499 
500  vec Fpos = linspace(0, 0.5, Nfft / 2 + 1);
501  vec F = concat(Fpos, reverse(-Fpos(1, Nfft / 2 - 1)));
502  vec S = zeros(Nfft);
503 
504  for (int i = 0; i < F.size(); i++) {
505  if (std::fabs(F(i)) < n_dopp)
506  S(i) = std::sqrt(1.5 / (pi * n_dopp * std::sqrt(1 - std::pow(F(i) / n_dopp, 2))));
507  else if (std::fabs(F(i)) == n_dopp)
508  S(i) = 1000000;
509  }
510 
511  S /= norm(S, 2);
512  S *= Nfft;
513 
514  cvec x = zeros_c(Nfft);
515 
516  for (int i = 0; i < noisesamp; ++i) {
517  x(i) = S(i) * randn_c();
518  x(Nfft - 1 - i) = S(Nfft - 1 - i) * randn_c();
519  }
520 
521  x = ifft(x);
522 
523  output = x.mid(0, no_samples);
524 }
525 
526 
527 // --------------------------------------------------------------------------
528 // Channel_Specification class methods
529 // --------------------------------------------------------------------------
530 
532  const vec &delay_prof)
533 {
534  set_channel_profile(avg_power_dB, delay_prof);
535 }
536 
538 {
539  set_channel_profile(profile);
540 }
541 
542 void Channel_Specification::set_channel_profile(const vec &avg_power_dB, const vec &delay_prof)
543 {
544  it_assert(min(delay_prof) == 0,
545  "Channel_Specification::set_channel_profile(): Minimum relative delay must be 0");
546  it_assert(avg_power_dB.size() == delay_prof.size(),
547  "Channel_Specification::set_channel_profile(): Power and delay vectors must be of equal length");
548  it_assert(delay_prof(0) == 0,
549  "Channel_Specification::set_channel_profile(): First tap must be at zero delay");
550  for (int i = 1; i < delay_prof.size(); i++) {
551  it_assert(delay_prof(i) > delay_prof(i - 1),
552  "Channel_Specification::set_channel_profile(): Delays should be sorted and unique");
553  }
554 
555  N_taps = delay_prof.size();
556  a_prof_dB = avg_power_dB;
557  d_prof = delay_prof;
558 
559  // set doppler spectrum to Jakes per default
561  tap_doppler_spectrum = Jakes;
562 
563  // set LOS parameters to zeros per default
564  set_LOS(zeros(N_taps));
565 }
566 
568 {
569  switch (profile) {
570  // -------------- ITU Channel models -----------------
571  case ITU_Vehicular_A:
572  set_channel_profile(vec("0 -1 -9 -10 -15 -20"),
573  vec("0 310 710 1090 1730 2510") * 1e-9);
574  break;
575 
576  case ITU_Vehicular_B:
577  set_channel_profile(vec("-2.5 0 -12.8 -10 -25.2 -16"),
578  vec("0 300 8900 12900 17100 20000") * 1e-9);
579  break;
580 
581  case ITU_Pedestrian_A:
582  set_channel_profile(vec("0 -9.7 -19.2 -22.8"),
583  vec("0 110 190 410") * 1e-9);
584  break;
585 
586  case ITU_Pedestrian_B:
587  set_channel_profile(vec("0 -0.9 -4.9 -8 -7.8 -23.9"),
588  vec("0 200 800 1200 2300 3700") * 1e-9);
589  break;
590 
591  // -------------- COST259 Channel models -----------------
592  case COST259_TUx:
593  set_channel_profile(vec("-5.7 -7.6 -10.1 -10.2 -10.2 -11.5 -13.4 -16.3 -16.9 -17.1 -17.4 -19 -19 -19.8 -21.5 -21.6 -22.1 -22.6 -23.5 -24.3"),
594  vec("0 217 512 514 517 674 882 1230 1287 1311 1349 1533 1535 1622 1818 1836 1884 1943 2048 2140") * 1e-9);
595  break;
596 
597  case COST259_RAx:
598  set_channel_profile(vec("-5.2 -6.4 -8.4 -9.3 -10 -13.1 -15.3 -18.5 -20.4 -22.4"),
599  vec("0 42 101 129 149 245 312 410 469 528") * 1e-9);
600  set_LOS(0, sqr(0.91 / 0.41), 0.7);
601  break;
602 
603  case COST259_HTx:
604  set_channel_profile(vec("-3.6 -8.9 -10.2 -11.5 -11.8 -12.7 -13.0 -16.2 -17.3 -17.7 -17.6 -22.7 -24.1 -25.8 -25.8 -26.2 -29 -29.9 -30 -30.7"),
605  vec("0 356 441 528 546 609 625 842 916 941 15000 16172 16492 16876 16882 16978 17615 17827 17849 18016") * 1e-9);
606  break;
607 
608  // -------------- COST207 Channel models -----------------
609  case COST207_RA:
610  set_channel_profile(vec("0 -2 -10 -20"),
611  vec("0 200 400 600") * 1e-9);
612  set_LOS(0, sqr(0.91 / 0.41), 0.7);
613  break;
614 
615  case COST207_RA6:
616  set_channel_profile(vec("0 -4 -8 -12 -16 -20"),
617  vec("0 100 200 300 400 500") * 1e-9);
618  set_LOS(0, sqr(0.91 / 0.41), 0.7);
619  break;
620 
621  case COST207_TU:
622  set_channel_profile(vec("-3 0 -2 -6 -8 -10"),
623  vec("0 200 600 1600 2400 5000") * 1e-9);
624  set_doppler_spectrum(2, GaussI);
625  set_doppler_spectrum(3, GaussI);
626  set_doppler_spectrum(4, GaussII);
627  set_doppler_spectrum(5, GaussII);
628  break;
629 
630  case COST207_TU6alt:
631  set_channel_profile(vec("-3 0 -2 -6 -8 -10"),
632  vec("0 200 500 1600 2300 5000") * 1e-9);
633  set_doppler_spectrum(3, GaussI);
634  set_doppler_spectrum(4, GaussII);
635  set_doppler_spectrum(5, GaussII);
636  break;
637 
638  case COST207_TU12:
639  set_channel_profile(vec("-4 -3 0 -2 -3 -5 -7 -5 -6 -9 -11 -10"),
640  vec("0 200 400 600 800 1200 1400 1800 2400 3000 3200 5000") * 1e-9);
641  set_doppler_spectrum(3, GaussI);
642  set_doppler_spectrum(4, GaussI);
643  set_doppler_spectrum(5, GaussI);
644  set_doppler_spectrum(6, GaussI);
645  set_doppler_spectrum(7, GaussI);
646  set_doppler_spectrum(8, GaussII);
647  set_doppler_spectrum(9, GaussII);
648  set_doppler_spectrum(10, GaussII);
649  set_doppler_spectrum(11, GaussII);
650  break;
651 
652  case COST207_TU12alt:
653  set_channel_profile(vec("-4 -3 0 -2.6 -3 -5 -7 -5 -6.5 -8.6 -11 -10"),
654  vec("0 200 400 600 800 1200 1400 1800 2400 3000 3200 5000") * 1e-9);
655  set_doppler_spectrum(4, GaussI);
656  set_doppler_spectrum(5, GaussI);
657  set_doppler_spectrum(6, GaussI);
658  set_doppler_spectrum(7, GaussI);
659  set_doppler_spectrum(8, GaussII);
660  set_doppler_spectrum(9, GaussII);
661  set_doppler_spectrum(10, GaussII);
662  set_doppler_spectrum(11, GaussII);
663  break;
664 
665  case COST207_BU:
666  set_channel_profile(vec("-3 0 -3 -5 -2 -4"),
667  vec("0 400 1000 1600 5000 6600") * 1e-9);
668  set_doppler_spectrum(2, GaussI);
669  set_doppler_spectrum(3, GaussI);
670  set_doppler_spectrum(4, GaussII);
671  set_doppler_spectrum(5, GaussII);
672  break;
673 
674  case COST207_BU6alt:
675  set_channel_profile(vec("-2.5 0 -3 -5 -2 -4"),
676  vec("0 300 1000 1600 5000 6600") * 1e-9);
677  set_doppler_spectrum(2, GaussI);
678  set_doppler_spectrum(3, GaussI);
679  set_doppler_spectrum(4, GaussII);
680  set_doppler_spectrum(5, GaussII);
681  break;
682 
683  case COST207_BU12:
684  set_channel_profile(vec("-7 -3 -1 0 -2 -6 -7 -1 -2 -7 -10 -15"),
685  vec("0 200 400 800 1600 2200 3200 5000 6000 7200 8200 10000") * 1e-9);
686  set_doppler_spectrum(3, GaussI);
687  set_doppler_spectrum(4, GaussI);
688  set_doppler_spectrum(5, GaussII);
689  set_doppler_spectrum(6, GaussII);
690  set_doppler_spectrum(7, GaussII);
691  set_doppler_spectrum(8, GaussII);
692  set_doppler_spectrum(9, GaussII);
693  set_doppler_spectrum(10, GaussII);
694  set_doppler_spectrum(11, GaussII);
695  break;
696 
697  case COST207_BU12alt:
698  set_channel_profile(vec("-7.7 -3.4 -1.3 0 -2.3 -5.6 -7.4 -1.4 -1.6 -6.7 -9.8 -15.1"),
699  vec("0 100 300 700 1600 2200 3100 5000 6000 7200 8100 10000") * 1e-9);
700  set_doppler_spectrum(3, GaussI);
701  set_doppler_spectrum(4, GaussI);
702  set_doppler_spectrum(5, GaussII);
703  set_doppler_spectrum(6, GaussII);
704  set_doppler_spectrum(7, GaussII);
705  set_doppler_spectrum(8, GaussII);
706  set_doppler_spectrum(9, GaussII);
707  set_doppler_spectrum(10, GaussII);
708  set_doppler_spectrum(11, GaussII);
709  break;
710 
711 
712  case COST207_HT:
713  set_channel_profile(vec("0 -2 -4 -7 -6 -12"),
714  vec("0 200 400 600 15000 17200") * 1e-9);
715  set_doppler_spectrum(4, GaussII);
716  set_doppler_spectrum(5, GaussII);
717  break;
718 
719  case COST207_HT6alt:
720  set_channel_profile(vec("0 -1.5 -4.5 -7.5 -8 -17.7"),
721  vec("0 100 300 500 15000 17200") * 1e-9);
722  set_doppler_spectrum(4, GaussII);
723  set_doppler_spectrum(5, GaussII);
724  break;
725 
726  case COST207_HT12:
727  set_channel_profile(vec("-10 -8 -6 -4 0 0 -4 -8 -9 -10 -12 -14"),
728  vec("0 200 400 600 800 2000 2400 15000 15200 15800 17200 20000") * 1e-9);
729  set_doppler_spectrum(3, GaussI);
730  set_doppler_spectrum(4, GaussI);
731  set_doppler_spectrum(5, GaussI);
732  set_doppler_spectrum(6, GaussII);
733  set_doppler_spectrum(7, GaussII);
734  set_doppler_spectrum(8, GaussII);
735  set_doppler_spectrum(9, GaussII);
736  set_doppler_spectrum(10, GaussII);
737  set_doppler_spectrum(11, GaussII);
738  break;
739 
740  case COST207_HT12alt:
741  set_channel_profile(vec("-10 -8 -6 -4 0 0 -4 -8 -9 -10 -12 -14"),
742  vec("0 100 300 500 700 1000 1300 15000 15200 15700 17200 20000") * 1e-9);
743  set_doppler_spectrum(4, GaussI);
744  set_doppler_spectrum(5, GaussI);
745  set_doppler_spectrum(6, GaussI);
746  set_doppler_spectrum(7, GaussII);
747  set_doppler_spectrum(8, GaussII);
748  set_doppler_spectrum(9, GaussII);
749  set_doppler_spectrum(10, GaussII);
750  set_doppler_spectrum(11, GaussII);
751  break;
752  };
753 }
754 
755 
757 {
758  for (int i = 0; i < N_taps; i++)
759  tap_doppler_spectrum(i) = tap_spectrum[i];
760 }
761 
763 {
764  tap_doppler_spectrum(tap_number) = tap_spectrum;
765 }
766 
767 void Channel_Specification::set_LOS(int tap_number, double relative_power,
768  double relative_doppler)
769 {
770  it_assert(N_taps >= 1,
771  "Channel_Specification::set_LOS(): Cannot set LOS component if not set channel profile");
772  it_assert((tap_number >= 0) && (tap_number < N_taps),
773  "Channel_Specification::set_LOS(): Tap number out of range");
774  it_assert((relative_doppler >= 0) && (relative_doppler <= 1.0),
775  "Channel_Specification::set_LOS(): Normalized Doppler out of range");
776  it_assert(relative_power >= 0.0,
777  "Channel_Specification::set_LOS(): Rice factor out of range");
778 
779  los_power.set_size(N_taps, true);
780  los_dopp.set_size(N_taps, true);
781  los_power(tap_number) = relative_power;
782  los_dopp(tap_number) = relative_doppler;
783 }
784 
785 void Channel_Specification::set_LOS(const vec& relative_power,
786  const vec& relative_doppler)
787 {
788  it_assert((relative_power.size() == N_taps),
789  "Channel_Specification::set_LOS(): Improper size of input vectors");
790 
791  if (relative_doppler.size() == 0) {
792  los_power.set_size(relative_power.size());
793  los_dopp.set_size(relative_power.size());
794  for (int i = 0; i < relative_power.size(); i++) {
795  it_assert(relative_power(i) >= 0.0,
796  "Channel_Specification::set_LOS(): Rice factor out of range");
797  los_power(i) = relative_power(i);
798  los_dopp(i) = 0.7;
799  }
800  }
801  else {
802  it_assert(relative_doppler.size() == N_taps,
803  "Channel_Specification::set_LOS(): Improper size of input vectors");
804  los_power.set_size(relative_power.size());
805  los_dopp.set_size(relative_power.size());
806  for (int i = 0; i < relative_power.size(); i++) {
807  it_assert((relative_doppler(i) >= 0) && (relative_doppler(i) <= 1.0),
808  "Channel_Specification::set_LOS(): Normalized Doppler out of range");
809  it_assert(relative_power(i) >= 0.0,
810  "Channel_Specification::set_LOS(): Rice factor out of range");
811  los_power(i) = relative_power(i);
812  los_dopp(i) = relative_doppler(i);
813  }
814  }
815 }
816 
818  vec &delay_prof) const
819 {
820  avg_power_dB = a_prof_dB;
821  delay_prof = d_prof;
822 }
823 
825 {
826  it_assert((index >= 0) && (index < N_taps),
827  "Channel_Specification::get_doppler_spectrum(): Index of of range");
828  return tap_doppler_spectrum(index);
829 }
830 
832 {
833  vec a_prof = inv_dB(a_prof_dB);
834  return (a_prof * d_prof / sum(a_prof));
835 }
836 
838 {
839  vec a_prof = inv_dB(a_prof_dB);
840  double a = a_prof * d_prof / sum(a_prof);
841  double b = a_prof * sqr(d_prof) / sum(a_prof);
842 
843  return std::sqrt(b - a*a);
844 }
845 
846 
847 // --------------------------------------------------------------------------
848 // TDL_Channel class methods
849 // --------------------------------------------------------------------------
850 
851 TDL_Channel::TDL_Channel(const vec &avg_power_dB, const ivec &delay_prof):
852  init_flag(false), n_dopp(0.0), fading_type(Independent), method(Rice_MEDS),
853  filter_length(0), nrof_freq(16), discrete_Ts(0.0)
854 {
855  set_channel_profile(avg_power_dB, delay_prof);
856 
857  // initialize LOS parameters to all zeros
858  set_LOS(zeros(delay_prof.size()));
859 
860  // initialize Doppler spectra
861  tap_doppler_spectrum.set_size(delay_prof.size());
862  tap_doppler_spectrum = Jakes;
863 }
864 
865 TDL_Channel::TDL_Channel(const Channel_Specification &channel_spec, double sampling_time):
866  init_flag(false), n_dopp(0.0), fading_type(Independent), method(Rice_MEDS),
867  filter_length(0), nrof_freq(16), discrete_Ts(sampling_time)
868 {
869  set_channel_profile(channel_spec, sampling_time);
870 
871  // set Doppler spectrum
873 }
874 
876 {
877  if (fading_gen.size() > 0) { // delete all old generators
878  for (int i = 0; i < fading_gen.size(); i++) {
879  if (fading_gen(i) != NULL) {
880  delete fading_gen(i);
881  fading_gen(i) = NULL;
882  }
883  }
884  }
885 }
886 
887 void TDL_Channel::set_channel_profile(const vec &avg_power_dB,
888  const ivec &delay_prof)
889 {
890  it_assert(min(delay_prof) == 0,
891  "TDL_Channel::set_channel_profile(): Minimum relative delay must be 0.");
892  it_assert(avg_power_dB.size() == delay_prof.size(),
893  "TDL_Channel::set_channel_profile(): Power and delay vectors must be of equal length!");
894  it_assert(delay_prof(0) == 0,
895  "TDL_Channel::set_channel_profile(): First tap must be at zero delay");
896  for (int i = 1; i < delay_prof.size(); i++) {
897  it_assert(delay_prof(i) > delay_prof(i - 1),
898  "TDL_Channel::set_channel_profile(): Delays should be sorted and unique");
899  }
900 
901  N_taps = delay_prof.size();
902  a_prof = pow(10.0, avg_power_dB / 20.0); // Convert power profile to amplitude profile
903  a_prof /= norm(a_prof); // Normalize amplitude profile
904  d_prof = delay_prof;
905 
906  // initialize Doppler spectra
908  tap_doppler_spectrum = Jakes;
909 
910  // set size of Rice parameters according to the new channel profile
911  set_LOS(zeros(N_taps));
912 
913  // changes in PDP require initialisation
914  init_flag = false;
915 }
916 
918 {
919  it_assert(no_taps >= 1, "TDL_Channel::set_channel_profile_uniform(): Minimum number of taps is 1.");
920 
921  vec avg_power_dB = zeros(no_taps);
922  ivec delay_prof(no_taps);
923  for (int i = 0; i < no_taps; i++)
924  delay_prof(i) = i;
925 
926  set_channel_profile(avg_power_dB, delay_prof);
927 }
928 
930 {
931  it_assert(no_taps >= 1, "TDL_Channel::set_channel_profile_exponential(): Minimum number of taps is 1.");
932 
933  vec avg_power_dB(no_taps);
934  ivec delay_prof(no_taps);
935  for (int i = 0; i < no_taps; i++) {
936  delay_prof(i) = i;
937  // p(i*ts) = exp(-i*ts), k = 0...no_taps-1
938  avg_power_dB(i) = dB(std::exp(static_cast<double>(-i)));
939  }
940 
941  set_channel_profile(avg_power_dB, delay_prof);
942 }
943 
944 void TDL_Channel::set_channel_profile(const Channel_Specification &channel_spec, double sampling_time)
945 {
946  vec avg_power_dB;
947  vec delay_profile;
948 
949  // set power profile and delays
950  channel_spec.get_channel_profile(avg_power_dB, delay_profile);
951  discrete_Ts = sampling_time;
952  N_taps = avg_power_dB.size();
953  a_prof = pow(10.0, avg_power_dB / 20.0); // Convert power profile to amplitude profile
954  a_prof /= norm(a_prof); // Normalize amplitude profile
955 
956  // set size of Rice parameters according to the new channel profile
957  set_LOS(channel_spec.get_LOS_power(), channel_spec.get_LOS_doppler());
958 
959  // set Doppler spectrum
961 
962  // sets discretized delay profile
963  discretize(delay_profile);
964 
965  init_flag = false;
966 }
967 
968 
970 {
971  fading_type = Correlated;
972  method = correlated_method;
973  init_flag = false;
974 }
975 
977 {
978  fading_type = fading_type_in;
979  init_flag = false;
980 }
981 
982 
983 void TDL_Channel::set_norm_doppler(double norm_doppler)
984 {
985  it_assert((norm_doppler > 0) && (norm_doppler <= 1.0),
986  "TDL_Channel::set_norm_doppler(): Normalized Doppler out of range");
987  n_dopp = norm_doppler;
988  // if normalized Doppler is set, we have correlated fading
989  fading_type = Correlated;
990  init_flag = false;
991 }
992 
993 
994 void TDL_Channel::set_LOS(const vec& relative_power, const vec& relative_doppler)
995 {
996  it_assert((relative_power.size() == N_taps),
997  "TDL_Channel::set_LOS(): Improper size of input vectors");
998 
999  if (relative_doppler.size() == 0) {
1000  los_power.set_size(relative_power.size());
1001  los_dopp.set_size(relative_power.size());
1002  for (int i = 0; i < relative_power.size(); i++) {
1003  it_assert(relative_power(i) >= 0.0,
1004  "TDL_Channel::set_LOS(): Rice factor out of range");
1005  los_power(i) = relative_power(i);
1006  los_dopp(i) = (relative_power(i) > 0) ? 0.7 : 0.0;
1007  }
1008  }
1009  else {
1010  it_assert(relative_doppler.size() == N_taps,
1011  "TDL_Channel::set_LOS(): Improper size of input vectors");
1012  los_power.set_size(relative_power.size());
1013  los_dopp.set_size(relative_power.size());
1014  for (int i = 0; i < relative_power.size(); i++) {
1015  it_assert((relative_doppler(i) >= 0) && (relative_doppler(i) <= 1.0),
1016  "TDL_Channel::set_LOS(): Normalized Doppler out of range");
1017  it_assert(relative_power(i) >= 0.0,
1018  "TDL_Channel::set_LOS(): Rice factor out of range");
1019  los_power(i) = relative_power(i);
1020  los_dopp(i) = relative_doppler(i);
1021  }
1022  }
1023 }
1024 
1025 void TDL_Channel::set_LOS_power(const vec& relative_power)
1026 {
1027  it_assert(relative_power.size() == N_taps,
1028  "TDL_Channel::set_LOS_power(): Improper size of input vector");
1029 
1030  los_power.set_size(relative_power.size());
1031  los_dopp.set_size(relative_power.size());
1032  for (int i = 0; i < los_power.size(); ++i) {
1033  los_power(i) = relative_power(i);
1034  los_dopp(i) = (relative_power(i) > 0) ? 0.7 : 0.0;
1035  }
1036  init_flag = false;
1037 }
1038 
1039 void TDL_Channel::set_LOS_doppler(const vec& relative_doppler)
1040 {
1041  it_assert(relative_doppler.size() == los_power.size(),
1042  "TDL_Channel::set_LOS_doppler(): Improper size of input vector");
1043 
1044  it_assert(n_dopp > 0, "TDL_Channel::set_LOS_doppler(): Normalized Doppler needs to be non zero to set the LOS Doppler in a Correlated fading generator");
1045 
1046  los_dopp.set_size(relative_doppler.size());
1047  for (int i = 0; i < relative_doppler.size(); ++i) {
1048  it_assert((relative_doppler(i) >= 0) && (relative_doppler(i) <= 1.0),
1049  "TDL_Channel::set_LOS_doppler(): Normalized Doppler out of range");
1050  los_dopp(i) = relative_doppler(i);
1051  }
1052 
1053  init_flag = false;
1054 }
1055 
1056 
1058 {
1059  it_assert(N_taps > 0, "TDL_Channel::set_doppler_spectrum(): Channel profile not defined yet");
1060 
1061  it_assert(n_dopp > 0, "TDL_Channel::set_doppler_spectrum(): Normalized Doppler needs to be non zero to set the Doppler spectrum in the Correlated Rice MEDS fading generator");
1062 
1063  if (method != Rice_MEDS)
1064  method = Rice_MEDS;
1065 
1067  for (int i = 0; i < N_taps; i++)
1068  tap_doppler_spectrum(i) = tap_spectrum[i];
1069 
1070  init_flag = false;
1071 }
1072 
1073 void TDL_Channel::set_doppler_spectrum(int tap_number, DOPPLER_SPECTRUM tap_spectrum)
1074 {
1075  it_assert((tap_number >= 0) && (tap_number < N_taps),
1076  "TDL_Channel::set_doppler_spectrum(): Improper tap number");
1077 
1078  it_assert(n_dopp > 0, "TDL_Channel::set_doppler_spectrum(): Normalized Doppler needs to be non zero to set the Doppler spectrum in the Correlated Rice MEDS fading generator");
1079 
1080  if (method != Rice_MEDS)
1081  method = Rice_MEDS;
1082 
1084  tap_doppler_spectrum(tap_number) = tap_spectrum;
1085 
1086  init_flag = false;
1087 }
1088 
1090 {
1091  it_assert(n_dopp > 0, "TDL_Channel::set_no_frequencies(): Normalized Doppler needs to be non zero to set the number of frequencies in the Correlated Rice MEDS fading generator");
1092  nrof_freq = no_freq;
1093  if (method != Rice_MEDS)
1094  method = Rice_MEDS;
1095 
1096  init_flag = false;
1097 }
1098 
1099 
1101 {
1102  it_assert(n_dopp > 0, "TDL_Channel::set_filter_length(): Normalized Doppler needs to be non zero to use the Correlated FIR fading generator");
1103 
1104  filter_length = fir_length;
1105  if (method != FIR)
1106  method = FIR;
1107 
1108  init_flag = false;
1109 }
1110 
1111 
1113 {
1114  it_assert(n_dopp > 0, "TDL_Channel::set_time_offset(): Normalized Doppler needs to be non zero to set time offset in a Correlated fading generator");
1115 
1116  if (init_flag == false)
1117  init();
1118 
1119  for (int i = 0; i < N_taps; i++) {
1120  fading_gen(i)->set_time_offset(offset);
1121  }
1122 }
1123 
1124 
1126 {
1127  it_assert(n_dopp > 0, "TDL_Channel::shift_time_offset(): Normalized Doppler needs to be non zero to shift time offset in a Correlated fading generator");
1128 
1129  if (init_flag == false)
1130  init();
1131 
1132  for (int i = 0; i < N_taps; i++) {
1133  fading_gen(i)->shift_time_offset(no_samples);
1134  }
1135 }
1136 
1137 
1138 void TDL_Channel::get_channel_profile(vec &avg_power_dB,
1139  ivec &delay_prof) const
1140 {
1141  avg_power_dB = 20 * log10(a_prof);
1142  delay_prof = d_prof;
1143 }
1144 
1146 {
1147  return (20 * log10(a_prof));
1148 }
1149 
1151 {
1152  if (fading_gen(0) != NULL)
1153  return fading_gen(0)->get_time_offset();
1154  else
1155  return -1.0;
1156 }
1157 
1159 {
1160  return (sqr(a_prof)*d_prof / sum_sqr(a_prof));
1161 }
1162 
1164 {
1165  double a = (sqr(a_prof) * d_prof / sum_sqr(a_prof));
1166  double b = (sqr(a_prof) * sqr(to_vec(d_prof)) / sum_sqr(a_prof));
1167 
1168  return (std::sqrt(b - a*a));
1169 }
1170 
1172 {
1173  it_assert(N_taps > 0, "TDL_Channel::init(): Channel profile not defined yet");
1174  it_assert(N_taps == los_power.size(),
1175  "TDL_Channel::init(): LOS profile does not mach the channel profile");
1176 
1177  if (fading_gen.size() > 0) { // delete all old generators
1178  for (int i = 0; i < fading_gen.size(); i++) {
1179  if (fading_gen(i) != NULL) {
1180  delete fading_gen(i);
1181  fading_gen(i) = NULL;
1182  }
1183  }
1184  }
1185 
1186  // create all generators and set the parameters
1187  fading_gen.set_size(N_taps, false);
1188  switch (fading_type) {
1189 
1190  case Independent:
1191  for (int i = 0; i < N_taps; ++i) {
1193  if (los_power(i) > 0)
1194  fading_gen(i)->set_LOS_power(los_power(i));
1195  fading_gen(i)->init();
1196  }
1197  break;
1198 
1199  case Static:
1200  for (int i = 0; i < N_taps; ++i) {
1202  if (los_power(i) > 0)
1203  fading_gen(i)->set_LOS_power(los_power(i));
1204  fading_gen(i)->init();
1205  }
1206  break;
1207 
1208  case Correlated:
1209  it_assert(n_dopp > 0,
1210  "TDL_Channel::init(): Correlated fading requires non zero normalized Doppler");
1211 
1212  switch (method) {
1213  case Rice_MEDS:
1214  // The third parameter is the number of sine waveforms that create the
1215  // fading process. It is increased by 2 for each tap to make taps
1216  // uncorrelated. Minimum number of waveforms set explicitly to 16.
1217  for (int i = 0; i < N_taps; ++i) {
1219  nrof_freq + 2*i, MEDS);
1220  if (los_power(i) > 0) {
1221  fading_gen(i)->set_LOS_power(los_power(i));
1222  fading_gen(i)->set_LOS_doppler(los_dopp(i));
1223  }
1224  fading_gen(i)->init();
1225  }
1226  break;
1227 
1228  case FIR:
1229  for (int i = 0; i < N_taps; ++i) {
1230  it_assert(tap_doppler_spectrum(i) == Jakes,
1231  "TDL_Channel::init(): FIR fading generator can be used with Jakes spectrum only");
1233  if (los_power(i) > 0) {
1234  fading_gen(i)->set_LOS_power(los_power(i));
1235  fading_gen(i)->set_LOS_doppler(los_dopp(i));
1236  }
1237  if (filter_length > 0)
1238  fading_gen(i)->set_filter_length(filter_length);
1239  fading_gen(i)->init();
1240  }
1241  break;
1242 
1243  case IFFT:
1244  for (int i = 0; i < N_taps; ++i) {
1245  it_assert(tap_doppler_spectrum(i) == Jakes,
1246  "TDL_Channel::init(): IFFT fading generator can be used with Jakes spectrum only");
1248  if (los_power(i) > 0) {
1249  fading_gen(i)->set_LOS_power(los_power(i));
1250  fading_gen(i)->set_LOS_doppler(los_dopp(i));
1251  }
1252  fading_gen(i)->init();
1253  }
1254  break;
1255 
1256  default:
1257  it_error("TDL_Channel::init(): No such fading generation method");
1258  }
1259  break;
1260 
1261  default:
1262  it_error("TDL_Channel::init(): No such fading type");
1263  };
1264 
1265  init_flag = true;
1266 }
1267 
1268 void TDL_Channel::generate(int no_samples, Array<cvec> &channel_coeff)
1269 {
1270  if (init_flag == false)
1271  init();
1272 
1273  channel_coeff.set_size(N_taps, false);
1274  for (int i = 0; i < N_taps; i++)
1275  channel_coeff(i) = a_prof(i) * fading_gen(i)->generate(no_samples);
1276 }
1277 
1278 void TDL_Channel::generate(int no_samples, cmat &channel_coeff)
1279 {
1280  if (init_flag == false)
1281  init();
1282 
1283  channel_coeff.set_size(no_samples, N_taps, false);
1284  for (int i = 0; i < N_taps; i++)
1285  channel_coeff.set_col(i, a_prof(i) * fading_gen(i)->generate(no_samples));
1286 }
1287 
1288 
1289 void TDL_Channel::filter_known_channel(const cvec &input, cvec &output, const Array<cvec> &channel_coeff)
1290 {
1291  int maxdelay = max(d_prof);
1292 
1293  output.set_size(input.size() + maxdelay, false);
1294  output.zeros();
1295 
1296  for (int i = 0; i < N_taps; i++)
1297  output += concat(zeros_c(d_prof(i)), elem_mult(input, channel_coeff(i)), zeros_c(maxdelay - d_prof(i)));
1298 }
1299 
1300 void TDL_Channel::filter_known_channel(const cvec &input, cvec &output, const cmat &channel_coeff)
1301 {
1302  int maxdelay = max(d_prof);
1303 
1304  output.set_size(input.size() + maxdelay, false);
1305  output.zeros();
1306 
1307  for (int i = 0; i < N_taps; i++)
1308  output += concat(zeros_c(d_prof(i)), elem_mult(input, channel_coeff.get_col(i)), zeros_c(maxdelay - d_prof(i)));
1309 }
1310 
1311 void TDL_Channel::filter(const cvec &input, cvec &output, Array<cvec> &channel_coeff)
1312 {
1313  generate(input.size(), channel_coeff);
1314  filter_known_channel(input, output, channel_coeff);
1315 }
1316 
1317 void TDL_Channel::filter(const cvec &input, cvec &output, cmat &channel_coeff)
1318 {
1319  generate(input.size(), channel_coeff);
1320  filter_known_channel(input, output, channel_coeff);
1321 }
1322 
1323 cvec TDL_Channel::filter(const cvec &input, Array<cvec> &channel_coeff)
1324 {
1325  cvec output;
1326  filter(input, output, channel_coeff);
1327  return output;
1328 }
1329 
1330 cvec TDL_Channel::filter(const cvec &input, cmat &channel_coeff)
1331 {
1332  cvec output;
1333  filter(input, output, channel_coeff);
1334  return output;
1335 }
1336 
1337 void TDL_Channel::filter(const cvec &input, cvec &output)
1338 {
1339  Array<cvec> channel_coeff;
1340  filter(input, output, channel_coeff);
1341 }
1342 
1343 cvec TDL_Channel::filter(const cvec &input)
1344 {
1345  cvec output;
1346  filter(input, output);
1347  return output;
1348 }
1349 
1350 
1351 void TDL_Channel::operator()(const cvec &input, cvec &output, Array<cvec> &channel_coeff)
1352 {
1353  filter(input, output, channel_coeff);
1354 }
1355 
1356 void TDL_Channel::operator()(const cvec &input, cvec &output, cmat &channel_coeff)
1357 {
1358  filter(input, output, channel_coeff);
1359 }
1360 
1361 
1362 cvec TDL_Channel::operator()(const cvec &input, Array<cvec> &channel_coeff)
1363 {
1364  return filter(input, channel_coeff);
1365 }
1366 
1367 cvec TDL_Channel::operator()(const cvec &input, cmat &channel_coeff)
1368 {
1369  return filter(input, channel_coeff);
1370 }
1371 
1372 cvec TDL_Channel::operator()(const cvec &input)
1373 {
1374  return filter(input);
1375 }
1376 
1377 
1378 void TDL_Channel::calc_impulse_response(const Array<cvec> &channel_coeff, Array<cvec> &impulse_response)
1379 {
1380  it_assert(init_flag == true, "calc_impulse_response: TDL_Channel is not initialized");
1381  it_assert(N_taps == channel_coeff.size(), "calc_impulse_response: number of channel taps do not match");
1382 
1383  int no_samples = channel_coeff(0).size();
1384  it_assert(no_samples > 0, "calc_impulse_response: channel_coeff must contain samples");
1385 
1386  impulse_response.set_size(no_samples);
1387 
1388  for (int i = 0; i < no_samples; i++) {
1389  impulse_response(i).set_size(d_prof(N_taps - 1) + 1, false);
1390  impulse_response(i).zeros();
1391 
1392  for (int j = 0; j < N_taps; j++)
1393  impulse_response(i)(d_prof(j)) = channel_coeff(j)(i);
1394 
1395  }
1396 }
1397 
1398 void TDL_Channel::calc_frequency_response(const Array<cvec> &channel_coeff, Array<cvec> &frequency_response, const int fft_size)
1399 {
1400  it_assert(init_flag == true, "calc_frequency_response: TDL_Channel is not initialized");
1401  it_assert(N_taps == channel_coeff.size(), "calc_frequency_response: number of channel taps do not match");
1402 
1403  int no_samples = channel_coeff(0).size();
1404  it_assert(no_samples > 0, "calc_frequency_response: channel_coeff must contain samples");
1405 
1406  frequency_response.set_size(no_samples);
1407 
1408  it_assert(fft_size > d_prof(N_taps - 1), "calc_frequency_response: fft_size must be larger than the maximum delay in samples");
1409  cvec impulse_response(fft_size);
1410 
1411  for (int i = 0; i < no_samples; i++) {
1412  impulse_response.zeros();
1413 
1414  for (int j = 0; j < N_taps; j++)
1415  impulse_response(d_prof(j)) = channel_coeff(j)(i);
1416 
1417  fft(impulse_response, frequency_response(i));
1418 
1419  }
1420 }
1421 
1422 void TDL_Channel::calc_frequency_response(const cmat &channel_coeff, cmat &frequency_response, const int fft_size)
1423 {
1424  it_assert(init_flag == true, "calc_frequency_response: TDL_Channel is not initialized");
1425  it_assert(N_taps == channel_coeff.cols(), "calc_frequency_response: number of channel taps do not match");
1426 
1427  int no_samples = channel_coeff.rows();
1428  it_assert(no_samples > 0, "calc_frequency_response: channel_coeff must contain samples");
1429 
1430  frequency_response.set_size(fft_size, no_samples, false);
1431 
1432  it_assert(fft_size > d_prof(N_taps - 1), "calc_frequency_response: fft_size must be larger than the maximum delay in samples");
1433  cvec impulse_response(fft_size);
1434  cvec freq;
1435 
1436  for (int i = 0; i < no_samples; i++) {
1437  impulse_response.zeros();
1438 
1439  for (int j = 0; j < N_taps; j++)
1440  impulse_response(d_prof(j)) = channel_coeff(i, j);
1441 
1442  fft(impulse_response, freq);
1443  frequency_response.set_col(i, freq);
1444  }
1445 }
1446 
1447 void TDL_Channel::discretize(const vec &delay_profile)
1448 {
1449  it_assert(N_taps > 0, "TDL_Channel::discretize(): No channel profile specified");
1450  it_assert(delay_profile(0) == 0, "TDL_Channel::discretize(): First tap should be at zero delay");
1451  it_assert(discrete_Ts > 0, "TDL_Channel::discretize(): Incorrect sampling time");
1452  it_assert((a_prof.size() == N_taps) && (delay_profile.size() == N_taps)
1453  && (los_power.size() == N_taps) && (tap_doppler_spectrum.size() == N_taps),
1454  "TDL_Channel:: discretize(): Channel profile lenghts must be equal to the number of taps");
1455 
1456  vec p_prof = sqr(a_prof); // Power profile
1457  ivec delay_prof(N_taps);
1458  vec power(N_taps);
1459  double spower;
1460  vec scattered(N_taps), direct(N_taps);
1461  vec los_doppler(N_taps);
1462  Array <DOPPLER_SPECTRUM> tap_spectrum(N_taps);
1463 
1464  delay_prof(0) = round_i(delay_profile(0) / discrete_Ts); // should be at zero delay anyway
1465  power(0) = p_prof(0);
1466  spower = p_prof(0) / (1 + los_power(0));
1467  scattered(0) = spower;
1468  direct(0) = los_power(0) * spower;
1469  los_doppler(0) = los_dopp(0);
1470  tap_spectrum(0) = tap_doppler_spectrum(0);
1471 
1472  // taps within ((j-0.5)Ts,(j+0.5)Ts] are included in the j-th tap
1473  int j = 0, j_delay = 0;
1474  for (int i = 1; i < N_taps; i++) {
1475  if (delay_profile(i) > (j_delay + 0.5)*discrete_Ts) {
1476  // first skip empty taps
1477  while (delay_profile(i) > (j_delay + 0.5)*discrete_Ts) { j_delay++; }
1478  // create a new tap at (j+1)Ts
1479  j++;
1480  delay_prof(j) = j_delay;
1481  power(j) = p_prof(i);
1482  spower = p_prof(i) / (1 + los_power(i));
1483  scattered(j) = spower;
1484  direct(j) = los_power(i) * spower;
1485  los_doppler(j) = los_dopp(i);
1486  tap_spectrum(j) = tap_doppler_spectrum(i);
1487  }
1488  else {
1489  // add to the previously created tap
1490  power(j) += p_prof(i);
1491  spower = p_prof(i) / (1 + los_power(i));
1492  scattered(j) += spower;
1493  direct(j) += los_power(i) * spower;
1494  it_assert(tap_spectrum(j) == tap_doppler_spectrum(i),
1495  "TDL_Channel::discretize(): Sampling frequency too low. Can not discretize the channel with different Doppler spectra on merged taps.");
1496  it_warning("TDL_Channel::discretize(): Sampling frequency too low. Merging original tap " << i << " with new tap " << j << ".");
1497  if (los_doppler(j) != los_dopp(i)) {
1498  los_doppler(j) = 0.7;
1499  it_warning("TDL_Channel::discretize(): LOS Doppler value reset to 0.7 for tap " << j << " due to the merging process.");
1500  }
1501  }
1502  }
1503 
1504  int no_taps = j + 1; // number of taps found
1505  if (no_taps < N_taps) {
1506  delay_prof.set_size(no_taps, true);
1507  power.set_size(no_taps, true);
1508  direct.set_size(no_taps, true);
1509  scattered.set_size(no_taps, true);
1510  los_doppler.set_size(no_taps, true);
1511  tap_spectrum.set_size(no_taps, true);
1512 
1513  // write over the existing channel profile with its new version
1514  N_taps = no_taps;
1515  a_prof = sqrt(power);
1516  los_power = elem_div(direct, scattered);
1517  los_dopp = los_doppler;
1518  tap_doppler_spectrum = tap_spectrum;
1519  }
1520  // new discretized path's delays
1521  d_prof = delay_prof; // in samples
1522 }
1523 
1524 
1525 // --------------------------------------------------------------------------
1526 // Binary Symetric Channel class methods
1527 // --------------------------------------------------------------------------
1528 
1529 bvec BSC::operator()(const bvec &input)
1530 {
1531  int i, length = input.length();
1532  bvec output(length);
1533 
1534  for (i = 0; i < length; i++) {
1535  if (u() <= p) {
1536  output(i) = input(i) + bin(1);
1537  }
1538  else {
1539  output(i) = input(i);
1540  }
1541  }
1542  return output;
1543 }
1544 
1545 
1546 // --------------------------------------------------------------------------
1547 // AWGN_Channel class methods
1548 // --------------------------------------------------------------------------
1549 
1550 cvec AWGN_Channel::operator()(const cvec &input)
1551 {
1552  int n = input.size();
1553  cvec noise(n);
1554  rng_cn.sample_vector(n, noise);
1555  noise *= sigma;
1556  noise += input;
1557  return noise;
1558 }
1559 
1560 vec AWGN_Channel::operator()(const vec &input)
1561 {
1562  int n = input.size();
1563  vec noise(n);
1564  rng_n.sample_vector(n, noise);
1565  noise *= sigma;
1566  noise += input;
1567  return noise;
1568 }
1569 
1570 
1571 } // namespace itpp
vec los_dopp
Relative LOS Doppler for each Rice component.
Definition: channel.h:997
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
void sample_vector(int size, vec &out)
Get a Normal distributed (0,1) vector.
Definition: random.h:475
void set_channel_profile(const vec &avg_power_dB, const vec &delay_prof)
Set both average power profile in dB and power delay profile in seconds.
Definition: channel.cpp:542
CHANNEL_PROFILE
Predefined channel profiles. Includes LOS and Doppler spectrum settings.
Definition: channel.h:193
Various functions on vectors and matrices - header file.
virtual void init()
Initialize the generator.
Definition: channel.cpp:404
Rice_Fading_Generator(double norm_doppler, DOPPLER_SPECTRUM spectrum=Jakes, int no_freq=16, RICE_METHOD method=MEDS)
Default constructor.
Definition: channel.cpp:248
General specification of a time-domain multipath channel.
Definition: channel.h:696
const double m_2pi
Constant 2*Pi.
Definition: misc.h:106
void calc_frequency_response(const Array< cvec > &channel_coeff, Array< cvec > &frequency_response, const int fft_size)
Calculate frequency-response on the supplied channel coefficients (produced by the generate() functio...
Definition: channel.cpp:1398
RICE_METHOD rice_method
Rice process generation method.
Definition: channel.h:503
void set_coeffs(const Vec< T2 > &b)
Set the filter coefficients.
Definition: filter.h:343
ITPP_EXPORT int round_i(double x)
Round to nearest integer.
RICE_METHOD
Rice fading generation methods: MEDS.
Definition: channel.h:209
virtual void init()
Initialize the generator.
Definition: channel.h:612
vec hamming(int n)
Hamming window.
Definition: window.cpp:43
int size() const
Returns the number of data elements in the array object.
Definition: array.h:155
bool init_flag
signals if generator is initialized or not
Definition: channel.h:282
Definitions of window functions.
double randu(void)
Generates a random uniform (0,1) number.
Definition: random.h:804
virtual void set_norm_doppler(double norm_doppler)
Set normalized Doppler (for correlated fading generators)
Definition: channel.cpp:76
virtual void set_time_offset(int offset)
Set time offset in samples (for correlated fading generators)
Definition: channel.cpp:71
Vec< T > reverse(const Vec< T > &in)
Reverse the input vector.
Definition: matfunc.h:777
virtual DOPPLER_SPECTRUM get_doppler_spectrum() const
Return Doppler spectrum (for Rice fading generator)
Definition: channel.cpp:125
virtual void init()
Initialize the generator.
Definition: channel.cpp:279
virtual double get_time_offset() const
Get time offset in samples (for correlated fading generators)
Definition: channel.cpp:107
cvec operator()(const cvec &input)
Feed the complex input input through the complex-valued AWGN channel.
Definition: channel.cpp:1550
void shift_time_offset(int no_samples)
Shift fading generators&#39; time offset. A Correlated fading type will be used.
Definition: channel.cpp:1125
void set_correlated_method(CORRELATED_METHOD method)
Set the fading generation method to method.
Definition: channel.cpp:969
virtual void set_no_frequencies(int no_freq)
Set number of Doppler frequencies.
Definition: channel.cpp:264
MA_Filter< std::complex< double >, double, std::complex< double > > fir_filter
Filter used for fading generation.
Definition: channel.h:561
int ceil_i(double x)
The nearest larger integer.
Definition: converters.h:339
Channel_Specification(const vec &avg_power_dB="0", const vec &delay_prof="0")
Default constructor (power profile in dB, delay profile in seconds)
Definition: channel.cpp:531
void get_channel_profile(vec &avg_power_dB, ivec &delay_prof) const
Get both average power profile in dB and power delay profile in samples.
Definition: channel.cpp:1138
cvec left_overs
Left-overs from upsampling.
Definition: channel.h:562
virtual void set_LOS_doppler(double relative_doppler)
Set relative Doppler of the LOS component (for correlated fading generators)
Definition: channel.cpp:66
Correlated_Fading_Generator(double norm_doppler)
Default constructor.
Definition: channel.cpp:204
double discrete_Ts
Sampling time of discretization.
Definition: channel.h:1006
double norm(const cvec &v)
Calculate the 2-norm: norm(v)=sqrt(sum(abs(v).^2))
Definition: misc_stat.cpp:77
DOPPLER_SPECTRUM dopp_spectrum
Definition: channel.h:499
Mat< Num_T > elem_mult(const Mat< Num_T > &m1, const Mat< Num_T > &m2)
Element wise multiplication of two matrices.
Definition: mat.h:1582
vec log10(const vec &x)
log-10 of the elements
Definition: log_exp.h:271
Rice type fading generator class.
Definition: channel.h:467
vec d_prof
Delay profile in seconds.
Definition: channel.h:750
double los_direct
Direct component: sqrt(los_power / (1 + los_power))
Definition: channel.h:285
double erfinv(double P)
Inverse of error function.
Definition: error.cpp:169
double time_offset
Time offset in samples (time state in the generator)
Definition: channel.h:426
ITPP_EXPORT void ifft(const cvec &in, cvec &out)
Inverse Fast Fourier Transform.
void set_channel_profile(const vec &avg_power_dB, const ivec &delay_prof)
Set both average power profile in dB and power delay profile in samples.
Definition: channel.cpp:887
Definitions of Bessel functions.
Fading generator class.
Definition: channel.h:228
T sum(const Vec< T > &v)
Sum of all elements in the vector.
Definition: matfunc.h:59
Fading_Generator()
Default constructor.
Definition: channel.cpp:51
void generate(int no_samples, Array< cvec > &channel_coeff)
Generate no_samples values of the channel.
Definition: channel.cpp:1268
Correlated (random) fading generator class.
Definition: channel.h:390
vec a_prof_dB
Power profile in dB.
Definition: channel.h:749
DOPPLER_SPECTRUM
Predefined Doppler spectra.
Definition: channel.h:212
ITPP_EXPORT void fft(const cvec &in, cvec &out)
Fast Fourier Transform.
double calc_rms_delay_spread() const
Calculate RMS delay spread in samples.
Definition: channel.cpp:1163
double get_time_offset() const
Get fading generators&#39; time ofset.
Definition: channel.cpp:1150
virtual RICE_METHOD get_rice_method() const
Get calculation method of Doppler frequencies and amplitudes (for Rice fading generator) ...
Definition: channel.cpp:137
#define it_assert(t, s)
Abort if t is not true.
Definition: itassert.h:94
int length(const Vec< T > &v)
Length of vector.
Definition: matfunc.h:51
FADING_TYPE
Fading generator type: Independent (default), Static or Correlated.
Definition: channel.h:203
void set_filter_length(int filter_length)
Set fading generator filter length. FIR method will be used.
Definition: channel.cpp:1100
double dB(double x)
Decibel of x (10*log10(x))
Definition: log_exp.h:71
virtual void generate(int no_samples, cvec &output)
Generate no_samples values from the fading process.
Definition: channel.cpp:160
Minimum and maximum functions on vectors and matrices.
CORRELATED_METHOD
Correlated fading generation methods: Rice_MEDS (default), IFFT or FIR.
Definition: channel.h:206
virtual void set_no_frequencies(int no_freq)
Set number of sine frequencies (for Rice fading generator)
Definition: channel.cpp:91
Error functions - header file.
void add_LOS(int idx, std::complex< double > &sample)
add LOS component to the sample with index idx
Definition: channel.cpp:235
void set_size(int n, bool copy=false)
Resizing an Array<T>.
Definition: array.h:257
vec get_LOS_power() const
Get relative power (Rice factor) for each tap.
Definition: channel.h:732
double calc_mean_excess_delay() const
Calculate mean excess delay in samples.
Definition: channel.cpp:1158
virtual ~TDL_Channel()
Destructor.
Definition: channel.cpp:875
void init()
Initialize all fading generators. Automatically invoked in generate() or filter() functions...
Definition: channel.cpp:1171
ITPP_EXPORT cvec zeros_c(int size)
A Double Complex vector of zeros.
vec sin(const vec &x)
Sine function.
Definition: trig_hyp.h:54
ITPP_EXPORT vec zeros(int size)
A Double vector of zeros.
Static fading generator class.
Definition: channel.h:355
T sum_sqr(const Vec< T > &v)
Sum of square of the elements in a vector.
Definition: matfunc.h:116
Communication channels&#39; classes - header file.
vec los_power
Relative power for each Rice component.
Definition: channel.h:753
vec a_prof
Average amplitude of each tap.
Definition: channel.h:994
T min(const Vec< T > &in)
Minimum value of vector.
Definition: min_max.h:125
Fourier, Hadamard, Walsh-Hadamard, and 2D Hadamard transforms - header file.
void set_doppler_spectrum(DOPPLER_SPECTRUM *tap_spectrum)
Set doppler spectrum for each tap in the channel profile.
Definition: channel.cpp:756
virtual double get_norm_doppler() const
Return normalized Doppler (for correlated fading generators)
Definition: channel.cpp:119
int nrof_freq
Number of sine frequencies in the Rice MEDS fading generator.
Definition: channel.h:1005
const double pi
Constant Pi.
Definition: misc.h:103
virtual void set_doppler_spectrum(DOPPLER_SPECTRUM spectrum)
Set Doppler spectrum.
Definition: channel.cpp:258
Array< DOPPLER_SPECTRUM > get_doppler_spectrum() const
Get doppler spectrum for tap index.
Definition: channel.h:728
double los_power
Relative power of LOS component compared to diffuse component (K factor)
Definition: channel.h:283
vec exp(const vec &x)
Exp of the elements of a vector x.
Definition: log_exp.h:155
ivec d_prof
Delay in samples for each tap.
Definition: channel.h:995
vec los_power
Relative power for each Rice component.
Definition: channel.h:996
virtual void set_norm_doppler(double norm_doppler)
Set normalized Doppler.
Definition: channel.cpp:210
virtual void generate(int no_samples, cvec &output)
Generate no_samples values from the fading process.
Definition: channel.cpp:468
T max(const Vec< T > &v)
Maximum value of vector.
Definition: min_max.h:45
Trigonometric and hyperbolic functions - header file.
int pow2i(int x)
Calculate two to the power of x (2^x); x is integer.
Definition: log_exp.h:53
void set_channel_profile_uniform(int no_taps)
Set channel profile to uniform with no_taps taps.
Definition: channel.cpp:917
void operator()(const cvec &input, cvec &output, Array< cvec > &channel_coeff)
Generate channel coefficients and filter the input. Return output and channel coefficients.
Definition: channel.cpp:1351
double inv_dB(double x)
Inverse of decibel of x.
Definition: log_exp.h:73
void calc_impulse_response(const Array< cvec > &channel_coeff, Array< cvec > &impulse_response)
Calculate impulse-response on the supplied channel coefficients (produced by the generate() function)...
Definition: channel.cpp:1378
int filter_length
Filter length of FIR fading generator.
Definition: channel.h:1004
virtual void shift_time_offset(int no_samples)
Shift generator time offset by a number of samples.
Definition: channel.cpp:230
void set_LOS_power(const vec &relative_power)
Set LOS power for each tap. LOS Doppler will be set to 0.7 by default.
Definition: channel.cpp:1025
vec pow(const double x, const vec &y)
Calculates x to the power of y (x^y)
Definition: log_exp.h:176
vec to_vec(const Vec< T > &v)
Converts a Vec<T> to vec.
Definition: converters.h:93
int Ni
Number of sine waves in a Gaussian process.
Definition: channel.h:501
virtual void set_rice_method(RICE_METHOD method)
Set calculation method of Doppler frequencies and amplitudes (for Rice fading generator) ...
Definition: channel.cpp:96
FIR type Fading generator class.
Definition: channel.h:536
void set_fading_type(FADING_TYPE fading_type)
Set fading type to one of Independent, Static or Correlated.
Definition: channel.cpp:976
bool init_flag
Channel ready to produce data.
Definition: channel.h:993
void filter(const cvec &input, cvec &output, Array< cvec > &channel_coeff)
Generate channel coefficients and filter the input. Return output and channel coefficients.
Definition: channel.cpp:1311
void set_LOS(int tap_number, double relative_power, double relative_doppler=0.7)
Set LOS (Rice) components for tap tap_number.
Definition: channel.cpp:767
vec spectrum(const vec &v, int nfft, int noverlap)
Power spectrum calculation.
Definition: sigfun.cpp:267
itpp namespace
Definition: itmex.h:36
void set_LOS_power(double relative_power)
Set relative LOS power.
Definition: channel.cpp:57
virtual void set_filter_length(int filter_length)
Set FIR filter length.
Definition: channel.cpp:396
vec get_LOS_doppler() const
Get relative Doppler for each tap.
Definition: channel.h:734
void set_time_offset(int offset)
Set fading generators&#39; time offset in samples. A Correlated fading type will be used.
Definition: channel.cpp:1112
IFFT type Fading generator class.
Definition: channel.h:602
virtual void generate(int no_samples, cvec &output)=0
Generate no_samples values from the fading process.
ITPP_EXPORT vec ones(int size)
A float vector of ones.
Resampling functions - header file.
Miscellaneous statistics functions and classes - header file.
FIR_Fading_Generator(double norm_doppler, int filter_length=500)
Default constructor.
Definition: channel.cpp:389
void set_doppler_spectrum(const DOPPLER_SPECTRUM *tap_spectrum)
Set doppler spectrum for each tap in the channel profile. Rice_MEDS method will be used...
Definition: channel.cpp:1057
virtual int get_filter_length() const
Set FIR filter length (for FIR fading generator)
Definition: channel.cpp:113
void set_channel_profile_exponential(int no_taps)
Set channel profile to exponential with no_taps taps.
Definition: channel.cpp:929
virtual void set_filter_length(int filter_length)
Set FIR filter length (for FIR fading generator)
Definition: channel.cpp:81
virtual void shift_time_offset(int no_samples)
Shift generator time offset by a number of samples (for correlated fading generators) ...
Definition: channel.cpp:143
void set_no_frequencies(int no_freq)
Set number of sine frequencies. Rice_MEDS method will be used.
Definition: channel.cpp:1089
void filter_known_channel(const cvec &input, cvec &output, const Array< cvec > &channel_coeff)
Filter the input with the known channel values channel_coeff (e.g. from the generate function) ...
Definition: channel.cpp:1289
void init_MEDS()
Init function for MEDS method.
Definition: channel.cpp:336
void discretize(const vec &delay_profile)
Discretize the delay profile with discrete_Ts (Ts). All taps within ((i-0.5)Ts,(i+0.5)Ts] belong to the ith discrete tap.
Definition: channel.cpp:1447
Array< DOPPLER_SPECTRUM > tap_doppler_spectrum
Doppler spectrum for each tap.
Definition: channel.h:751
void set_norm_doppler(double norm_doppler)
Set normalized Doppler rate. A Correlated fading type will be used.
Definition: channel.cpp:983
virtual void init()
Initialize the generator.
Definition: channel.cpp:178
vec sqr(const cvec &data)
Absolute square of elements.
Definition: elem_math.cpp:36
virtual void set_LOS_doppler(double relative_doppler)
Set relative Doppler (compared to the maximum Doppler) for the LOS component.
Definition: channel.cpp:218
Definitions of special vectors and matrices.
double los_dopp
Relative Doppler on LOS component (0.7 by default)
Definition: channel.h:425
#define it_warning(s)
Display a warning message.
Definition: itassert.h:173
virtual int get_no_frequencies() const
Get number of sine frequencies (for Rice fading generator)
Definition: channel.cpp:131
vec linspace(double from, double to, int points)
linspace (works in the same way as the MATLAB version)
Definition: specmat.cpp:106
void sample_vector(int size, cvec &out)
Get a Complex Normal (0,1) distributed vector.
Definition: random.h:626
void set_LOS_doppler(const vec &relative_doppler)
Set LOS doppler for each tap. A Correlated fading type will be used.
Definition: channel.cpp:1039
virtual double get_LOS_doppler() const
Get relative Doppler of the LOS component (for correlated fading generators)
Definition: channel.cpp:101
vec los_dopp
Relative Rice Doppler for each Rice component.
Definition: channel.h:754
vec get_avg_power_dB() const
Return power profile in dB.
Definition: channel.cpp:1145
Independent (random) fading generator class.
Definition: channel.h:328
Binary arithmetic (boolean) class.
Definition: binary.h:56
TDL_Channel(const vec &avg_power_dB="0", const ivec &delay_prof="0")
Default constructor.
Definition: channel.cpp:851
#define it_error(s)
Abort unconditionally.
Definition: itassert.h:126
void generate_Jakes(int no_samples, cvec &output)
Generator for Jakes spectrum.
Definition: channel.cpp:484
virtual void set_time_offset(int offset)
Set time offset in samples.
Definition: channel.cpp:225
int N_taps
Number of taps.
Definition: channel.h:752
double n_dopp
Normalized Doppler of the correlated fading.
Definition: channel.h:999
vec sqrt(const vec &x)
Square root of the elements.
Definition: elem_math.h:123
virtual void generate(int no_samples, cvec &output)
Generate no_samples values from the fading process.
Definition: channel.cpp:423
Array< DOPPLER_SPECTRUM > tap_doppler_spectrum
Doppler spectrum for each tap.
Definition: channel.h:1002
void get_channel_profile(vec &avg_power_dB, vec &delay_prof) const
Get both average power profile in dB and power delay profile in seconds.
Definition: channel.cpp:817
double calc_mean_excess_delay() const
Calculate mean excess delay in samples.
Definition: channel.cpp:831
double calc_rms_delay_spread() const
Calculate RMS delay spread in samples.
Definition: channel.cpp:837
bvec operator()(const bvec &input)
Feed input through the BSC channel.
Definition: channel.cpp:1529
virtual void generate(int no_samples, cvec &output)
Generate no_samples values from the fading process.
Definition: channel.cpp:292
int N_taps
Number of taps.
Definition: channel.h:998
vec cos(const vec &x)
Cosine function.
Definition: trig_hyp.h:58
Array< Fading_Generator * > fading_gen
Fading generators for each tap.
Definition: channel.h:1003
double besselj(int nu, double x)
Bessel function of first kind of order nu for nu integer.
Definition: bessel.cpp:44
virtual void set_doppler_spectrum(DOPPLER_SPECTRUM spectrum)
Set Doppler spectrum (for Rice fading generator)
Definition: channel.cpp:86
double n_dopp
Normalized maximum Doppler frequency.
Definition: channel.h:424
virtual void generate(int no_samples, cvec &output)
Generate no_samples values from the fading process.
Definition: channel.cpp:190
double static_sample_re
Static Rayleigh distributed sample.
Definition: channel.h:373
void set_LOS(const vec &relative_power, const vec &relative_doppler="")
Set LOS parameters for each tap. LOS Doppler will be set to 0.7 by default.
Definition: channel.cpp:994
FADING_TYPE fading_type
Fading type: Independent (default), Static or Correlated.
Definition: channel.h:1000
CORRELATED_METHOD method
Correlated fading generation method: Rice_MEDS (default), IFFT or FIR.
Definition: channel.h:1001
int levels2bits(int n)
Calculate the number of bits needed to represent n different values (levels).
Definition: log_exp.h:92
double los_diffuse
Diffuse component: sqrt(1 / (1 + los_power))
Definition: channel.h:284
virtual void set_rice_method(RICE_METHOD method)
Set calculation method of Doppler frequencies and amplitudes.
Definition: channel.cpp:272
vec Jakes_filter(double norm_dopp, int order=100)
Jakes spectrum filter.
Definition: channel.cpp:447
int fir_length
Size of FIR filter.
Definition: channel.h:558
std::complex< double > randn_c(void)
Generates a random complex Gaussian (0,1) variable.
Definition: random.h:845
const Array< T > concat(const Array< T > &a, const T &e)
Append element e to the end of the Array a.
Definition: array.h:486
SourceForge Logo

Generated on Sun Apr 10 2022 12:00:00 for IT++ by Doxygen 1.8.14