IT++ Logo
pulse_shape.h
Go to the documentation of this file.
00001 
00029 #ifndef PULSE_SHAPE_H
00030 #define PULSE_SHAPE_H
00031 
00032 #include <itpp/base/vec.h>
00033 #include <itpp/base/matfunc.h>
00034 #include <itpp/base/math/trig_hyp.h>
00035 #include <itpp/signal/filter.h>
00036 #include <itpp/signal/resampling.h>
00037 
00038 
00039 namespace itpp
00040 {
00041 
00072 template<class T1, class T2, class T3>
00073 class Pulse_Shape
00074 {
00075 public:
00077   Pulse_Shape();
00079   Pulse_Shape(const Vec<T2> &impulse_response, int upsampling_factor);
00081   virtual ~Pulse_Shape() {}
00089   void set_pulse_shape(const Vec<T2> &impulse_response, int upsampling_factor);
00091   Vec<T2> get_pulse_shape(void) const;
00093   int get_upsampling_factor() const;
00095   int get_pulse_length() const;
00097   int get_filter_length() const;
00098 
00100   void shape_symbols(const Vec<T1> &input, Vec<T3> &output);
00102   Vec<T3> shape_symbols(const Vec<T1> &input);
00103 
00105   void shape_samples(const Vec<T1> &input, Vec<T3> &output);
00107   Vec<T3> shape_samples(const Vec<T1> &input);
00108 
00110   void clear(void);
00111 
00112 protected:
00114   Vec<T2> impulse_response;
00116   MA_Filter<T1, T2, T3> shaping_filter;
00118   int pulse_length;
00120   int upsampling_factor;
00122   bool setup_done;
00123 };
00124 
00161 template<class T1>
00162 class Raised_Cosine : public Pulse_Shape<T1, double, T1>
00163 {
00164 public:
00166   Raised_Cosine() {}
00168   Raised_Cosine(double roll_off, int filter_length = 6, int upsampling_factor = 8);
00170   virtual ~Raised_Cosine() {}
00172   void set_pulse_shape(double roll_off_factor, int filter_length = 6, int upsampling_factor = 8);
00174   double get_roll_off(void) const;
00175 
00176 protected:
00178   double roll_off_factor;
00179 };
00180 
00225 template<class T1>
00226 class Root_Raised_Cosine : public Pulse_Shape<T1, double, T1>
00227 {
00228 public:
00230   Root_Raised_Cosine() {}
00232   Root_Raised_Cosine(double roll_off_factor, int filter_length = 6, int upsampling_factor = 8);
00234   virtual ~Root_Raised_Cosine() {}
00236   void set_pulse_shape(double roll_off_factor, int filter_length = 6, int upsampling_factor = 8);
00238   double get_roll_off(void) const;
00239 
00240 protected:
00242   double roll_off_factor;
00243 };
00244 
00245 //-------------------------------------------------------------------------
00246 // Implementation of templated code starts here
00247 //-------------------------------------------------------------------------
00248 
00249 //---------------------------- Pulse_Shape --------------------------------
00250 
00251 template<class T1, class T2, class T3>
00252 Pulse_Shape<T1, T2, T3>::Pulse_Shape()
00253 {
00254   setup_done = false;
00255   pulse_length = 0;
00256   upsampling_factor = 0;
00257 }
00258 
00259 
00260 template<class T1, class T2, class T3>
00261 Pulse_Shape<T1, T2, T3>::Pulse_Shape(const Vec<T2> &impulse_response, int upsampling_factor)
00262 {
00263   set_pulse_shape(impulse_response, upsampling_factor);
00264 }
00265 
00266 template<class T1, class T2, class T3>
00267 void Pulse_Shape<T1, T2, T3>::set_pulse_shape(const Vec<T2> &impulse_response_in, int upsampling_factor_in)
00268 {
00269   it_error_if(impulse_response_in.size() == 0, "Pulse_Shape: impulse response is zero length");
00270   it_error_if(upsampling_factor_in < 1, "Pulse_Shape: incorrect upsampling factor");
00271 
00272   pulse_length = (impulse_response_in.size() - 1) / upsampling_factor_in;
00273   upsampling_factor = upsampling_factor_in;
00274 
00275   impulse_response = impulse_response_in;
00276   shaping_filter.set_coeffs(impulse_response);
00277   shaping_filter.clear();
00278   setup_done = true;
00279 }
00280 
00281 template<class T1, class T2, class T3>
00282 Vec<T2> Pulse_Shape<T1, T2, T3>::get_pulse_shape(void) const
00283 {
00284   return impulse_response;
00285 }
00286 
00287 template<class T1, class T2, class T3>
00288 int Pulse_Shape<T1, T2, T3>::get_upsampling_factor(void) const
00289 {
00290   return upsampling_factor;
00291 }
00292 
00293 template<class T1, class T2, class T3>
00294 int Pulse_Shape<T1, T2, T3>::get_pulse_length(void) const
00295 {
00296   return pulse_length;
00297 }
00298 
00299 template<class T1, class T2, class T3>
00300 int Pulse_Shape<T1, T2, T3>::get_filter_length(void) const
00301 {
00302   return impulse_response.size();
00303 }
00304 
00305 template<class T1, class T2, class T3>
00306 void Pulse_Shape<T1, T2, T3>::shape_symbols(const Vec<T1>& input, Vec<T3> &output)
00307 {
00308   it_assert(setup_done, "Pulse_Shape must be set up before using");
00309   it_error_if(pulse_length == 0, "Pulse_Shape: impulse response is zero length");
00310   it_error_if(input.size() == 0, "Pulse_Shape: input is zero length");
00311 
00312   if (upsampling_factor > 1)
00313     output = shaping_filter(upsample(input, upsampling_factor));
00314   else
00315     output = input;
00316 }
00317 
00318 template<class T1, class T2, class T3>
00319 Vec<T3> Pulse_Shape<T1, T2, T3>::shape_symbols(const Vec<T1>& input)
00320 {
00321   it_assert(setup_done, "Pulse_Shape must be set up before using");
00322   Vec<T3> temp;
00323   shape_symbols(input, temp);
00324   return temp;
00325 }
00326 
00327 template<class T1, class T2, class T3>
00328 void Pulse_Shape<T1, T2, T3>::shape_samples(const Vec<T1>& input, Vec<T3> &output)
00329 {
00330   it_assert(setup_done, "Pulse_Shape must be set up before using");
00331   it_error_if(pulse_length == 0, "Pulse_Shape: impulse response is zero length");
00332   it_error_if(input.size() == 0, "Pulse_Shape: input is zero length");
00333 
00334   if (upsampling_factor > 1)
00335     output = shaping_filter(input);
00336   else
00337     output = input;
00338 }
00339 
00340 template<class T1, class T2, class T3>
00341 Vec<T3> Pulse_Shape<T1, T2, T3>::shape_samples(const Vec<T1>& input)
00342 {
00343   it_assert(setup_done, "Pulse_Shape must be set up before using");
00344   Vec<T3> temp;
00345   shape_samples(input, temp);
00346   return temp;
00347 }
00348 
00349 template<class T1, class T2, class T3>
00350 void Pulse_Shape<T1, T2, T3>::clear(void)
00351 {
00352   it_assert(setup_done, "Pulse_Shape must be set up before using");
00353   shaping_filter.clear();
00354 }
00355 
00356 //-------------------- Raised_Cosine -----------------------------------
00357 
00358 template<class T1>
00359 Raised_Cosine<T1>::Raised_Cosine(double roll_off_factor, int filter_length, int upsampling_factor)
00360 {
00361   set_pulse_shape(roll_off_factor, filter_length, upsampling_factor);
00362 }
00363 
00364 template<class T1>
00365 void Raised_Cosine<T1>::set_pulse_shape(double roll_off_factor_in, int filter_length, int upsampling_factor_in)
00366 {
00367   it_error_if(roll_off_factor_in < 0 || roll_off_factor_in > 1, "Raised_Cosine: roll-off out of range");
00368   roll_off_factor = roll_off_factor_in;
00369 
00370   it_assert(is_even(filter_length), "Raised_Cosine: Filter length not even");
00371 
00372   int i;
00373   double t, den;
00374   this->upsampling_factor = upsampling_factor_in;
00375   this->pulse_length = filter_length;
00376   this->impulse_response.set_size(filter_length * upsampling_factor_in + 1,
00377                                   false);
00378 
00379   for (i = 0; i < this->impulse_response.size(); i++) {
00380     // delayed to be casual
00381     t = (double)(i - filter_length * upsampling_factor_in / 2)
00382         / upsampling_factor_in;
00383     den = 1 - sqr(2 * roll_off_factor * t);
00384     if (den == 0) {
00385       // exception according to "The Care and feeding of digital,
00386       // pulse-shaping filters" by Ken Gentile,
00387       // the limit of raised cosine impulse responce function,
00388       // as (alpha * t / tau) approaches (+- 0.5) is given as:
00389       this->impulse_response(i) = sinc(t) * pi / 4;
00390     }
00391     else {
00392       this->impulse_response(i) = std::cos(roll_off_factor * pi * t)
00393                                   * sinc(t) / den;
00394     }
00395   }
00396 
00397   // BUGFIX: Commented out to achieve similar results to Matlab
00398   // rcosfil function. Now the concatenation of two root-raised
00399   // cosine filters gives tha same results as a one raised cosine
00400   // shaping function.
00401   // this->impulse_response /= std::sqrt(double(this->upsampling_factor));
00402   this->shaping_filter.set_coeffs(this->impulse_response);
00403   this->shaping_filter.clear();
00404   this->setup_done = true;
00405 }
00406 
00407 template<class T1>
00408 double Raised_Cosine<T1>::get_roll_off(void) const
00409 {
00410   it_assert(this->setup_done, "Pulse_Shape must be set up before using");
00411   return roll_off_factor;
00412 }
00413 
00414 //-------------------- Root_Raised_Cosine -----------------------------------
00415 
00416 template<class T1>
00417 Root_Raised_Cosine<T1>::Root_Raised_Cosine(double roll_off_factor, int filter_length, int upsampling_factor)
00418 {
00419   set_pulse_shape(roll_off_factor, filter_length, upsampling_factor);
00420 }
00421 
00422 template<class T1>
00423 void Root_Raised_Cosine<T1>::set_pulse_shape(double roll_off_factor_in, int filter_length, int upsampling_factor_in)
00424 {
00425   it_error_if(roll_off_factor_in <= 0 || roll_off_factor_in > 1,
00426               "Root_Raised_Cosine: roll-off out of range");
00427   roll_off_factor = roll_off_factor_in;
00428 
00429   it_assert(is_even(filter_length),
00430             "Root_Raised_Cosine: Filter length not even");
00431 
00432   int i;
00433   double t, num, den, tmp_arg;
00434   this->upsampling_factor = upsampling_factor_in;
00435   this->pulse_length = filter_length;
00436   this->impulse_response.set_size(filter_length * upsampling_factor_in + 1,
00437                                   false);
00438 
00439   for (i = 0; i < this->impulse_response.size(); i++) {
00440     // delayed to be casual
00441     t = (double)(i - filter_length * upsampling_factor_in / 2)
00442         / upsampling_factor_in;
00443     den = 1 - sqr(4 * roll_off_factor * t);
00444     if (t == 0) {
00445       this->impulse_response(i) = 1 + (4 * roll_off_factor / pi)
00446                                   - roll_off_factor;
00447     }
00448     else if (den == 0) {
00449       tmp_arg = pi / (4 * roll_off_factor);
00450       this->impulse_response(i) = roll_off_factor / std::sqrt(2.0)
00451                                   * ((1 + 2 / pi) * std::sin(tmp_arg) + (1 - 2 / pi) * std::cos(tmp_arg));
00452     }
00453     else {
00454       num = std::sin(pi * (1 - roll_off_factor) * t)
00455             + std::cos(pi * (1 + roll_off_factor) * t) * 4 * roll_off_factor * t;
00456       this->impulse_response(i) = num / (pi * t * den);
00457     }
00458   }
00459 
00460   this->impulse_response /= std::sqrt(double(upsampling_factor_in));
00461   this->shaping_filter.set_coeffs(this->impulse_response);
00462   this->shaping_filter.clear();
00463   this->setup_done = true;
00464 }
00465 
00466 template<class T1>
00467 double Root_Raised_Cosine<T1>::get_roll_off(void) const
00468 {
00469   it_assert(this->setup_done, "Pulse_Shape must be set up before using");
00470   return roll_off_factor;
00471 }
00472 
00474 
00475 // ----------------------------------------------------------------------
00476 // Instantiations
00477 // ----------------------------------------------------------------------
00478 
00479 #ifndef _MSC_VER
00480 
00481 extern template class Pulse_Shape<double, double, double>;
00482 extern template class Pulse_Shape < std::complex<double>, double,
00483   std::complex<double> >;
00484 extern template class Pulse_Shape < std::complex<double>, std::complex<double>,
00485   std::complex<double> >;
00486 
00487 extern template class Root_Raised_Cosine<double>;
00488 extern template class Root_Raised_Cosine<std::complex<double> >;
00489 
00490 extern template class Raised_Cosine<double>;
00491 extern template class Raised_Cosine<std::complex<double> >;
00492 
00493 #endif // _MSC_VER
00494 
00496 
00497 } // namespace itpp
00498 
00499 #endif // #ifndef PULSE_SHAPE_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
SourceForge Logo

Generated on Sat Jul 9 2011 15:21:31 for IT++ by Doxygen 1.7.4