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
Generated on Sun Sep 14 18:54:54 2008 for IT++ by Doxygen 1.5.6