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
Generated on Thu Apr 19 14:18:31 2007 for IT++ by Doxygen 1.5.1