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
00247
00248
00249
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
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
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
00386
00387
00388
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
00398
00399
00400
00401
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
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
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
00477
00478
00479 #ifdef HAVE_EXTERN_TEMPLATE
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 // HAVE_EXTERN_TEMPLATE
00494
00496
00497 }
00498
00499 #endif // #ifndef PULSE_SHAPE_H