IT++ Logo

pulse_shape.h

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

Generated on Sun Dec 9 17:38:47 2007 for IT++ by Doxygen 1.5.4