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>
37
38
39namespace itpp
40{
41
72template<class T1, class T2, class T3>
74{
75public:
81 virtual ~Pulse_Shape() {}
95 int get_pulse_length() const;
97 int get_filter_length() const;
98
100 void shape_symbols(const Vec<T1> &input, Vec<T3> &output);
103
105 void shape_samples(const Vec<T1> &input, Vec<T3> &output);
108
110 void clear(void);
111
112protected:
123};
124
161template<class T1>
162class Raised_Cosine : public Pulse_Shape<T1, double, T1>
163{
164public:
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
176protected:
179};
180
225template<class T1>
226class Root_Raised_Cosine : public Pulse_Shape<T1, double, T1>
227{
228public:
232 Root_Raised_Cosine(double roll_off_factor, int filter_length = 6, int upsampling_factor = 8);
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
240protected:
243};
244
245//-------------------------------------------------------------------------
246// Implementation of templated code starts here
247//-------------------------------------------------------------------------
248
249//---------------------------- Pulse_Shape --------------------------------
250
251template<class T1, class T2, class T3>
253{
254 setup_done = false;
255 pulse_length = 0;
256 upsampling_factor = 0;
257}
258
259
260template<class T1, class T2, class T3>
261Pulse_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
266template<class T1, class T2, class T3>
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
281template<class T1, class T2, class T3>
283{
284 return impulse_response;
285}
286
287template<class T1, class T2, class T3>
289{
290 return upsampling_factor;
291}
292
293template<class T1, class T2, class T3>
295{
296 return pulse_length;
297}
298
299template<class T1, class T2, class T3>
301{
302 return impulse_response.size();
303}
304
305template<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
318template<class T1, class T2, class T3>
320{
321 it_assert(setup_done, "Pulse_Shape must be set up before using");
323 shape_symbols(input, temp);
324 return temp;
325}
326
327template<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
340template<class T1, class T2, class T3>
342{
343 it_assert(setup_done, "Pulse_Shape must be set up before using");
345 shape_samples(input, temp);
346 return temp;
347}
348
349template<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
358template<class T1>
359Raised_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
364template<class T1>
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)
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
407template<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
416template<class T1>
417Root_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
422template<class T1>
424{
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)
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
466template<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
481 std::complex<double> >;
482ITPP_EXPORT_TEMPLATE template class ITPP_EXPORT Pulse_Shape < std::complex<double>, std::complex<double>,
483 std::complex<double> >;
484
487
490
492
493} // namespace itpp
494
495#endif // #ifndef PULSE_SHAPE_H
General array class.
Definition array.h:105
int size() const
Returns the number of data elements in the array object.
Definition array.h:155
void set_size(int n, bool copy=false)
Resizing an Array<T>.
Definition array.h:257
General FIR Pulse Shape.
Definition pulse_shape.h:74
Vec< T3 > shape_samples(const Vec< T1 > &input)
Shape the input symbols already upsampled.
Vec< T2 > get_pulse_shape(void) const
Get the pulse shape.
void set_pulse_shape(const Vec< T2 > &impulse_response, int upsampling_factor)
Set the general impulse response of the FIR filter.
int upsampling_factor
Samples per input symbol.
void shape_samples(const Vec< T1 > &input, Vec< T3 > &output)
Shape the input samples already upsampled.
Pulse_Shape()
Constructor.
int get_filter_length() const
Get the length of the internal FIR filter.
int get_upsampling_factor() const
Get the over sampling factor.
void shape_symbols(const Vec< T1 > &input, Vec< T3 > &output)
Shape the input symbols performing upsampling.
MA_Filter< T1, T2, T3 > shaping_filter
The pulse shaping filter.
int get_pulse_length() const
Get the length of the pulse in number of symbols.
virtual ~Pulse_Shape()
Destructor.
Definition pulse_shape.h:81
Pulse_Shape(const Vec< T2 > &impulse_response, int upsampling_factor)
Constructor.
int pulse_length
Length in symbols.
Vec< T2 > impulse_response
The impulse resounse of the pulse shaping filter.
Vec< T3 > shape_symbols(const Vec< T1 > &input)
Shape the input symbols performing upsampling.
bool setup_done
Ensures that setup is called before any other member function.
void clear(void)
Clear internal states.
Raised Cosine (RC) Pulse Shaper.
Raised_Cosine()
Constructor.
double roll_off_factor
The roll off factor (i.e. alpha)
double get_roll_off(void) const
Get the roll-off factor.
virtual ~Raised_Cosine()
Destructor.
void set_pulse_shape(double roll_off_factor, int filter_length=6, int upsampling_factor=8)
Set pulse shape (roll_off_factor between 0 and 1, filter_length even)
(Square) Root Raised Cosine (RRC) Pulse Shaper
virtual ~Root_Raised_Cosine()
Destructor.
void set_pulse_shape(double roll_off_factor, int filter_length=6, int upsampling_factor=8)
Set pulse_shape, roll_off_factor between 0 and 1, filter_length even.
double roll_off_factor
The roll off factor (i.e. alpha)
double get_roll_off(void) const
Get the Roll-off factor.
Root_Raised_Cosine()
Constructor.
Definitions of Filter classes and functions.
#define it_error_if(t, s)
Abort if t is true.
Definition itassert.h:117
#define it_assert(t, s)
Abort if t is not true.
Definition itassert.h:94
bool is_even(int x)
Return true if x is an even integer.
Definition misc.h:122
vec sqr(const cvec &data)
Absolute square of elements.
Definition elem_math.cpp:36
double sinc(double x)
Sinc function: sinc(x) = sin(pi*x)/pi*x.
Definition trig_hyp.h:42
Various functions on vectors and matrices - header file.
itpp namespace
Definition itmex.h:37
const double pi
Constant Pi.
Definition misc.h:103
Resampling functions - header file.
Trigonometric and hyperbolic functions - header file.
Templated Vector Class Definitions.

Generated on Tue Aug 17 2021 10:59:15 for IT++ by Doxygen 1.9.8