IT++ Logo Newcom Logo

pulse_shape.h

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

Generated on Thu Apr 19 14:14:58 2007 for IT++ by Doxygen 1.5.1