IT++ Logo
pulse_shape.h
Go to the documentation of this file.
1 
29 #ifndef PULSE_SHAPE_H
30 #define PULSE_SHAPE_H
31 
32 #include <itpp/base/vec.h>
33 #include <itpp/base/matfunc.h>
35 #include <itpp/signal/filter.h>
36 #include <itpp/signal/resampling.h>
37 
38 
39 namespace itpp
40 {
41 
72 template<class T1, class T2, class T3>
74 {
75 public:
77  Pulse_Shape();
81  virtual ~Pulse_Shape() {}
89  void set_pulse_shape(const Vec<T2> &impulse_response, int upsampling_factor);
91  Vec<T2> get_pulse_shape(void) const;
93  int get_upsampling_factor() const;
95  int get_pulse_length() const;
97  int get_filter_length() const;
98 
100  void shape_symbols(const Vec<T1> &input, Vec<T3> &output);
102  Vec<T3> shape_symbols(const Vec<T1> &input);
103 
105  void shape_samples(const Vec<T1> &input, Vec<T3> &output);
107  Vec<T3> shape_samples(const Vec<T1> &input);
108 
110  void clear(void);
111 
112 protected:
123 };
124 
161 template<class T1>
162 class Raised_Cosine : public Pulse_Shape<T1, double, T1>
163 {
164 public:
168  Raised_Cosine(double roll_off, int filter_length = 6, int upsampling_factor = 8);
170  virtual ~Raised_Cosine() {}
172  void set_pulse_shape(double roll_off_factor, int filter_length = 6, int upsampling_factor = 8);
174  double get_roll_off(void) const;
175 
176 protected:
179 };
180 
225 template<class T1>
226 class Root_Raised_Cosine : public Pulse_Shape<T1, double, T1>
227 {
228 public:
232  Root_Raised_Cosine(double roll_off_factor, int filter_length = 6, int upsampling_factor = 8);
234  virtual ~Root_Raised_Cosine() {}
236  void set_pulse_shape(double roll_off_factor, int filter_length = 6, int upsampling_factor = 8);
238  double get_roll_off(void) const;
239 
240 protected:
243 };
244 
245 //-------------------------------------------------------------------------
246 // Implementation of templated code starts here
247 //-------------------------------------------------------------------------
248 
249 //---------------------------- Pulse_Shape --------------------------------
250 
251 template<class T1, class T2, class T3>
253 {
254  setup_done = false;
255  pulse_length = 0;
256  upsampling_factor = 0;
257 }
258 
259 
260 template<class T1, class T2, class T3>
261 Pulse_Shape<T1, T2, T3>::Pulse_Shape(const Vec<T2> &impulse_response, int upsampling_factor)
262 {
263  set_pulse_shape(impulse_response, upsampling_factor);
264 }
265 
266 template<class T1, class T2, class T3>
267 void Pulse_Shape<T1, T2, T3>::set_pulse_shape(const Vec<T2> &impulse_response_in, int upsampling_factor_in)
268 {
269  it_error_if(impulse_response_in.size() == 0, "Pulse_Shape: impulse response is zero length");
270  it_error_if(upsampling_factor_in < 1, "Pulse_Shape: incorrect upsampling factor");
271 
272  pulse_length = (impulse_response_in.size() - 1) / upsampling_factor_in;
273  upsampling_factor = upsampling_factor_in;
274 
275  impulse_response = impulse_response_in;
276  shaping_filter.set_coeffs(impulse_response);
277  shaping_filter.clear();
278  setup_done = true;
279 }
280 
281 template<class T1, class T2, class T3>
283 {
284  return impulse_response;
285 }
286 
287 template<class T1, class T2, class T3>
289 {
290  return upsampling_factor;
291 }
292 
293 template<class T1, class T2, class T3>
295 {
296  return pulse_length;
297 }
298 
299 template<class T1, class T2, class T3>
301 {
302  return impulse_response.size();
303 }
304 
305 template<class T1, class T2, class T3>
307 {
308  it_assert(setup_done, "Pulse_Shape must be set up before using");
309  it_error_if(pulse_length == 0, "Pulse_Shape: impulse response is zero length");
310  it_error_if(input.size() == 0, "Pulse_Shape: input is zero length");
311 
312  if (upsampling_factor > 1)
313  output = shaping_filter(upsample(input, upsampling_factor));
314  else
315  output = input;
316 }
317 
318 template<class T1, class T2, class T3>
320 {
321  it_assert(setup_done, "Pulse_Shape must be set up before using");
322  Vec<T3> temp;
323  shape_symbols(input, temp);
324  return temp;
325 }
326 
327 template<class T1, class T2, class T3>
329 {
330  it_assert(setup_done, "Pulse_Shape must be set up before using");
331  it_error_if(pulse_length == 0, "Pulse_Shape: impulse response is zero length");
332  it_error_if(input.size() == 0, "Pulse_Shape: input is zero length");
333 
334  if (upsampling_factor > 1)
335  output = shaping_filter(input);
336  else
337  output = input;
338 }
339 
340 template<class T1, class T2, class T3>
342 {
343  it_assert(setup_done, "Pulse_Shape must be set up before using");
344  Vec<T3> temp;
345  shape_samples(input, temp);
346  return temp;
347 }
348 
349 template<class T1, class T2, class T3>
351 {
352  it_assert(setup_done, "Pulse_Shape must be set up before using");
353  shaping_filter.clear();
354 }
355 
356 //-------------------- Raised_Cosine -----------------------------------
357 
358 template<class T1>
359 Raised_Cosine<T1>::Raised_Cosine(double roll_off_factor, int filter_length, int upsampling_factor)
360 {
361  set_pulse_shape(roll_off_factor, filter_length, upsampling_factor);
362 }
363 
364 template<class T1>
365 void Raised_Cosine<T1>::set_pulse_shape(double roll_off_factor_in, int filter_length, int upsampling_factor_in)
366 {
367  it_error_if(roll_off_factor_in < 0 || roll_off_factor_in > 1, "Raised_Cosine: roll-off out of range");
368  roll_off_factor = roll_off_factor_in;
369 
370  it_assert(is_even(filter_length), "Raised_Cosine: Filter length not even");
371 
372  int i;
373  double t, den;
374  this->upsampling_factor = upsampling_factor_in;
375  this->pulse_length = filter_length;
376  this->impulse_response.set_size(filter_length * upsampling_factor_in + 1,
377  false);
378 
379  for (i = 0; i < this->impulse_response.size(); i++) {
380  // delayed to be casual
381  t = (double)(i - filter_length * upsampling_factor_in / 2)
382  / upsampling_factor_in;
383  den = 1 - sqr(2 * roll_off_factor * t);
384  if (den == 0) {
385  // exception according to "The Care and feeding of digital,
386  // pulse-shaping filters" by Ken Gentile,
387  // the limit of raised cosine impulse responce function,
388  // as (alpha * t / tau) approaches (+- 0.5) is given as:
389  this->impulse_response(i) = sinc(t) * pi / 4;
390  }
391  else {
392  this->impulse_response(i) = std::cos(roll_off_factor * pi * t)
393  * sinc(t) / den;
394  }
395  }
396 
397  // BUGFIX: Commented out to achieve similar results to Matlab
398  // rcosfil function. Now the concatenation of two root-raised
399  // cosine filters gives tha same results as a one raised cosine
400  // shaping function.
401  // this->impulse_response /= std::sqrt(double(this->upsampling_factor));
402  this->shaping_filter.set_coeffs(this->impulse_response);
403  this->shaping_filter.clear();
404  this->setup_done = true;
405 }
406 
407 template<class T1>
409 {
410  it_assert(this->setup_done, "Pulse_Shape must be set up before using");
411  return roll_off_factor;
412 }
413 
414 //-------------------- Root_Raised_Cosine -----------------------------------
415 
416 template<class T1>
417 Root_Raised_Cosine<T1>::Root_Raised_Cosine(double roll_off_factor, int filter_length, int upsampling_factor)
418 {
419  set_pulse_shape(roll_off_factor, filter_length, upsampling_factor);
420 }
421 
422 template<class T1>
423 void Root_Raised_Cosine<T1>::set_pulse_shape(double roll_off_factor_in, int filter_length, int upsampling_factor_in)
424 {
425  it_error_if(roll_off_factor_in <= 0 || roll_off_factor_in > 1,
426  "Root_Raised_Cosine: roll-off out of range");
427  roll_off_factor = roll_off_factor_in;
428 
429  it_assert(is_even(filter_length),
430  "Root_Raised_Cosine: Filter length not even");
431 
432  int i;
433  double t, num, den, tmp_arg;
434  this->upsampling_factor = upsampling_factor_in;
435  this->pulse_length = filter_length;
436  this->impulse_response.set_size(filter_length * upsampling_factor_in + 1,
437  false);
438 
439  for (i = 0; i < this->impulse_response.size(); i++) {
440  // delayed to be casual
441  t = (double)(i - filter_length * upsampling_factor_in / 2)
442  / upsampling_factor_in;
443  den = 1 - sqr(4 * roll_off_factor * t);
444  if (t == 0) {
445  this->impulse_response(i) = 1 + (4 * roll_off_factor / pi)
446  - roll_off_factor;
447  }
448  else if (den == 0) {
449  tmp_arg = pi / (4 * roll_off_factor);
450  this->impulse_response(i) = roll_off_factor / std::sqrt(2.0)
451  * ((1 + 2 / pi) * std::sin(tmp_arg) + (1 - 2 / pi) * std::cos(tmp_arg));
452  }
453  else {
454  num = std::sin(pi * (1 - roll_off_factor) * t)
455  + std::cos(pi * (1 + roll_off_factor) * t) * 4 * roll_off_factor * t;
456  this->impulse_response(i) = num / (pi * t * den);
457  }
458  }
459 
460  this->impulse_response /= std::sqrt(double(upsampling_factor_in));
461  this->shaping_filter.set_coeffs(this->impulse_response);
462  this->shaping_filter.clear();
463  this->setup_done = true;
464 }
465 
466 template<class T1>
468 {
469  it_assert(this->setup_done, "Pulse_Shape must be set up before using");
470  return roll_off_factor;
471 }
472 
474 
475 // ----------------------------------------------------------------------
476 // Instantiations
477 // ----------------------------------------------------------------------
478 
479 ITPP_EXPORT_TEMPLATE template class ITPP_EXPORT Pulse_Shape<double, double, double>;
480 ITPP_EXPORT_TEMPLATE template class ITPP_EXPORT Pulse_Shape < std::complex<double>, double,
481  std::complex<double> >;
482 ITPP_EXPORT_TEMPLATE template class ITPP_EXPORT Pulse_Shape < std::complex<double>, std::complex<double>,
483  std::complex<double> >;
484 
485 ITPP_EXPORT_TEMPLATE template class ITPP_EXPORT Root_Raised_Cosine<double>;
486 ITPP_EXPORT_TEMPLATE template class ITPP_EXPORT Root_Raised_Cosine<std::complex<double> >;
487 
488 ITPP_EXPORT_TEMPLATE template class ITPP_EXPORT Raised_Cosine<double>;
489 ITPP_EXPORT_TEMPLATE template class ITPP_EXPORT Raised_Cosine<std::complex<double> >;
490 
492 
493 } // namespace itpp
494 
495 #endif // #ifndef PULSE_SHAPE_H
SourceForge Logo

Generated on Sat Jul 6 2013 10:54:23 for IT++ by Doxygen 1.8.2