00001
00002
00003
00004
00005
00006
00007
00008
00010
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00028
00029 #include <Nsound/AudioStream.h>
00030 #include <Nsound/Buffer.h>
00031 #include <Nsound/FilterLeastSquaresFIR.h>
00032 #include <Nsound/Generator.h>
00033 #include <Nsound/Plotter.h>
00034
00035 #include <cmath>
00036 #include <cstring>
00037 #include <cstdio>
00038 #include <iostream>
00039 #include <sstream>
00040
00041 using namespace Nsound;
00042
00043 using std::cout;
00044 using std::cerr;
00045 using std::endl;
00046
00047 #define CERR_HEADER __FILE__ << ":" << __LINE__ << ": ***ERROR: "
00048
00050 FilterLeastSquaresFIR::
00051 FilterLeastSquaresFIR(
00052 const float64 & sample_rate,
00053 uint32 kernel_size,
00054 const Buffer & freq_axis,
00055 const Buffer & amplitude_axis,
00056 const float64 & beta)
00057 :
00058 Filter(sample_rate),
00059 b_(NULL),
00060 window_(NULL),
00061 x_history_(NULL),
00062 x_ptr_(NULL),
00063 x_end_ptr_(NULL),
00064 f_axis_(NULL),
00065 a_axis_(NULL)
00066 {
00067 kernel_size_ = kernel_size;
00068
00069 b_ = new float64[kernel_size_];
00070
00071 x_history_ = new float64[kernel_size_ + 1];
00072 x_ptr_ = x_history_;
00073 x_end_ptr_ = x_history_ + kernel_size_ + 1;
00074
00075
00076 window_ = new float64[kernel_size_];
00077
00078 Generator gen(1.0);
00079
00080 Buffer kaiser = gen.drawWindowKaiser(kernel_size_, beta);
00081
00082 memcpy(window_, kaiser.getPointer(), sizeof(float64) * kernel_size_);
00083
00084
00085 f_axis_ = new Buffer(16);
00086 a_axis_ = new Buffer(16);
00087
00088 FilterLeastSquaresFIR::makeKernel(freq_axis, amplitude_axis);
00089 FilterLeastSquaresFIR::reset();
00090 }
00091
00093
00094 FilterLeastSquaresFIR::
00095 FilterLeastSquaresFIR(const FilterLeastSquaresFIR & copy)
00096 :
00097 Filter(copy.sample_rate_),
00098 b_(NULL),
00099 window_(NULL),
00100 x_history_(NULL),
00101 x_ptr_(NULL),
00102 x_end_ptr_(NULL),
00103 f_axis_(NULL),
00104 a_axis_(NULL)
00105 {
00106 kernel_size_ = copy.kernel_size_;
00107
00108 b_ = new float64[kernel_size_];
00109
00110 x_history_ = new float64[kernel_size_ + 1];
00111 x_ptr_ = x_history_;
00112 x_end_ptr_ = x_history_ + kernel_size_ + 1;
00113
00114
00115 window_ = new float64[kernel_size_];
00116
00117
00118 f_axis_ = new Buffer(16);
00119 a_axis_ = new Buffer(16);
00120
00121
00122 *this = copy;
00123 }
00124
00126 FilterLeastSquaresFIR::
00127 ~FilterLeastSquaresFIR()
00128 {
00129 delete [] b_;
00130 delete [] window_;
00131 delete [] x_history_;
00132 delete f_axis_;
00133 delete a_axis_;
00134 }
00135
00137 Buffer
00138 FilterLeastSquaresFIR::
00139 getKernel() const
00140 {
00141 Buffer k(kernel_size_);
00142 for(uint32 i = 0; i < kernel_size_; ++i)
00143 {
00144 k << b_[i];
00145 }
00146
00147 return k;
00148 }
00149
00151 void
00152 FilterLeastSquaresFIR::
00153 setKernel(const Buffer & k)
00154 {
00155 if(k.getLength() != kernel_size_)
00156 {
00157 delete [] b_;
00158 delete [] window_;
00159 delete [] x_history_;
00160
00161 kernel_size_ = k.getLength();
00162
00163 b_ = new float64[kernel_size_];
00164
00165 x_history_ = new float64[kernel_size_ + 1];
00166 x_ptr_ = x_history_;
00167 x_end_ptr_ = x_history_ + kernel_size_ + 1;
00168
00169
00170 window_ = new float64[kernel_size_];
00171
00172 Generator gen(1.0);
00173
00174 Buffer kaiser = gen.drawWindowKaiser(kernel_size_, 5.0);
00175
00176 memcpy(window_, kaiser.getPointer(), sizeof(float64) * kernel_size_);
00177
00178 FilterLeastSquaresFIR::reset();
00179 }
00180
00181 for(uint32 i = 0; i < kernel_size_; ++i)
00182 {
00183 b_[i] = k[i];
00184 }
00185
00186 return;
00187 }
00188
00190 Buffer
00191 FilterLeastSquaresFIR::
00192 getKernelFrequencies()
00193 {
00194 return *f_axis_;
00195 }
00196
00198 Buffer
00199 FilterLeastSquaresFIR::
00200 getKernelAmplitudes()
00201 {
00202 return *a_axis_;
00203 }
00204
00206 AudioStream
00207 FilterLeastSquaresFIR::
00208 filter(const AudioStream & x)
00209 {
00210 return Filter::filter(x);
00211 }
00212
00214 Buffer
00215 FilterLeastSquaresFIR::
00216 filter(const Buffer & x)
00217 {
00218 return Filter::filter(x);
00219 }
00220
00222 float64
00223 FilterLeastSquaresFIR::
00224 filter(const float64 & x)
00225 {
00226
00227 *x_ptr_ = x;
00228
00229
00230 ++x_ptr_;
00231
00232
00233 if(x_ptr_ >= x_end_ptr_)
00234 {
00235 x_ptr_ = x_history_;
00236 }
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246 float64 y = 0.0;
00247 float64 * history = x_ptr_;
00248 for(float64 * b = b_; b != b_ + kernel_size_; ++b)
00249 {
00250
00251 --history;
00252
00253
00254 if(history < x_history_)
00255 {
00256 history = x_end_ptr_ - 1;
00257 }
00258
00259 y += *b * *history;
00260 }
00261
00262 return y;
00263 }
00264
00266 void
00267 FilterLeastSquaresFIR::
00268 makeKernel(
00269 const Buffer & freq_axis,
00270 const Buffer & amplitude_axis)
00271 {
00272
00273 *f_axis_ = Buffer(16);
00274 *a_axis_ = Buffer(16);
00275
00276 float64 max_freq = sample_rate_ / 2.0;
00277
00278
00279 if(freq_axis.getLength() != amplitude_axis.getLength() ||
00280 freq_axis.getLength() % 2 != 0)
00281 {
00282 cerr << CERR_HEADER
00283 << "freq_axis and amplitude_axis must be same length and even!"
00284 << endl;
00285
00286 *f_axis_ << 0.0 << max_freq;
00287 *a_axis_ << 1.0 << 1.0;
00288
00289 FilterLeastSquaresFIR::reset();
00290 return;
00291 }
00292
00293
00294 if(freq_axis[0] != 0.0)
00295 {
00296 cerr << CERR_HEADER
00297 << "freq_axis[0] must be 0.0!"
00298 << endl;
00299
00300 *f_axis_ << 0.0 << max_freq;
00301 *a_axis_ << 1.0 << 1.0;
00302
00303 FilterLeastSquaresFIR::reset();
00304 return;
00305 }
00306
00307 if(freq_axis[freq_axis.getLength() -1 ] != max_freq)
00308 {
00309 cerr << CERR_HEADER
00310 << "freq_axis[end] (" << freq_axis[freq_axis.getLength() -1 ]
00311 << ") must be " << max_freq << "!"
00312 << endl;
00313
00314 *f_axis_ << 0.0 << max_freq;
00315 *a_axis_ << 1.0 << 1.0;
00316
00317 FilterLeastSquaresFIR::reset();
00318 return;
00319 }
00320
00321
00322 Buffer df = freq_axis.getDerivative(1);
00323 if(df.getMin() < 0.0)
00324 {
00325 cerr << CERR_HEADER
00326 << "Frequencies in freq_axis must be increasing!"
00327 << endl;
00328
00329 *f_axis_ << 0.0 << max_freq;
00330 *a_axis_ << 1.0 << 1.0;
00331
00332 FilterLeastSquaresFIR::reset();
00333 return;
00334 }
00335
00336
00337
00338 *f_axis_ << (freq_axis / max_freq);
00339 *a_axis_ << amplitude_axis;
00340
00341
00342
00343
00344 Generator gen(1.0);
00345
00346 Buffer f(*f_axis_/2.0);
00347 Buffer a(*a_axis_);
00348
00349 Buffer w = gen.drawLine(freq_axis.getLength() / 2, 1.0, 1.0);
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373 df = f.getDerivative(1);
00374
00375
00376 df = df.subbuffer(0, df.getLength() -1);
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387 boolean fullband = true;
00388
00389 if(df.getLength() > 1)
00390 {
00391 for(uint32 i = 1; i < df.getLength() - 1; i += 2)
00392 {
00393 if(df[i] != 0.0)
00394 {
00395 fullband = false;
00396 break;
00397 }
00398 }
00399 }
00400
00401
00402
00403 int32 L = (kernel_size_ - 1) / 2;
00404
00405
00406
00407 boolean is_odd = true;
00408
00409 if(kernel_size_ % 2 == 0)
00410 {
00411 is_odd = false;
00412 }
00413
00414
00415
00416 Buffer m = gen.drawLine(L, 0, L);
00417
00418 m << L;
00419
00420 if(!is_odd)
00421 {
00422 m += 0.5;
00423 }
00424
00425
00426
00427
00428
00429 boolean need_matrix = ! fullband;
00430
00431
00432
00433 if(need_matrix)
00434 {
00435 cerr << CERR_HEADER
00436 << "FIXME: need_matix is true!" << endl;
00437 }
00438
00439 Buffer k(m);
00440
00441 float64 b0 = 0.0;
00442
00443 if(is_odd)
00444 {
00445 k = m.subbuffer(1, m.getLength()-1);
00446 }
00447
00448
00449
00450
00451
00452 float64 PI_x_2 = 2.0 * M_PI;
00453
00454 float64 PI_x_PI_x_4 = 4.0 * M_PI * M_PI;
00455
00456 Buffer b = 0.0 * k;
00457 Buffer kk = k * k;
00458
00459 for(uint32 i = 0; i < f.getLength(); i += 2)
00460 {
00461 float64 t_df = f[i+1] - f[i];
00462
00463 float64 mm = 0.0;
00464 float64 b1 = 0.0;
00465
00466 mm = (a[i+1] - a[i]) / t_df;
00467 b1 = a[i] - mm * f[i];
00468
00469
00470
00471
00472
00473
00474 if(is_odd)
00475 {
00476 b0 += (b1 * t_df + mm / 2.0 * (f[i+1] * f[i+1] - f[i]*f[i]))
00477 * w[(i+1)/2] * w[(i+1)/2];
00478 }
00479
00480
00481
00482 Buffer f1 = PI_x_2 * k * f[i+1];
00483 Buffer f2 = PI_x_2 * k * f[i];
00484
00485 std::stringstream ss;
00486
00487 float64 abs_w2 = std::fabs(w[(i+1)/2] * w[(i+1)/2]);
00488
00489
00490
00491
00492
00493 for(uint32 j = 0; j < b.getLength(); ++j)
00494 {
00495 b[j] += (mm / PI_x_PI_x_4
00496 * (std::cos(f1[j]) - std::cos(f2[j]))
00497 / (k[j] * k[j])
00498 ) * abs_w2;
00499 }
00500
00501 float64 fi = f[i];
00502 float64 fi1 = f[i+1];
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526 for(uint32 j = 0; j < b.getLength(); ++j)
00527 {
00528 float64 t = PI_x_2 * k[j];
00529 float64 x = 0.0;
00530 float64 sinc = 0.0;
00531 float64 sinc1 = 0.0;
00532
00533 x = t*fi;
00534
00535 if(x == 0.0) x = M_PI;
00536
00537 sinc = std::sin(x) / x;
00538
00539 x = t*fi1;
00540
00541 if(x == 0.0) x = M_PI;
00542
00543 sinc1 = std::sin(x) / x;
00544
00545 b[j] += ( fi1 * (mm * fi1 + b1) * sinc1
00546 - fi * (mm * fi + b1) * sinc )
00547 * abs_w2;
00548 }
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560 }
00561
00562
00563
00564
00565
00566
00567 if(is_odd)
00568 {
00569 Buffer t;
00570 t << b0 << b;
00571 b = t;
00572 }
00573
00574
00575
00576
00577 Buffer h;
00578
00579 if(need_matrix)
00580 {
00581 cerr << CERR_HEADER
00582 << "FIXME: need_matix is true!" << endl;
00583 }
00584 else
00585 {
00586 a = w[0] * w[0] * 4.0 * b;
00587
00588 if(is_odd)
00589 {
00590 a[0] *= 0.5;
00591 }
00592 }
00593
00594 if(is_odd)
00595 {
00596 float32 a0 = a[0];
00597 Buffer a2 = 0.5 * a.subbuffer(1, a.getLength());
00598 h = a2.getReverse() << a0 << a2;
00599 }
00600 else
00601 {
00602 h = a.getReverse() << a;
00603
00604 h *= 0.5;
00605 }
00606
00607
00608
00609
00610 if(kernel_size_ != h.getLength())
00611 {
00612 cerr << CERR_HEADER
00613 << "kernel_size_ != h.getLength()!" << endl;
00614
00615 for(uint32 i = 0; i < kernel_size_; ++i)
00616 {
00617 b_[i] = 0.0;
00618 }
00619 }
00620 else
00621 {
00622 memcpy(b_, h.getPointer(), sizeof(float64)*kernel_size_);
00623 }
00624
00625
00626 for(uint32 i = 0; i < kernel_size_; ++i)
00627 {
00628 b_[i] *= window_[i];
00629 }
00630 }
00631
00633 FilterLeastSquaresFIR &
00634 FilterLeastSquaresFIR::
00635 operator=(const FilterLeastSquaresFIR & rhs)
00636 {
00637 if(this == &rhs)
00638 {
00639 return *this;
00640 }
00641
00642 if(kernel_size_ != rhs.kernel_size_)
00643 {
00644 delete [] b_;
00645 delete [] window_;
00646 delete [] x_history_;
00647
00648 kernel_size_ = rhs.kernel_size_;
00649
00650 b_ = new float64[kernel_size_];
00651
00652 x_history_ = new float64[kernel_size_ + 1];
00653 x_ptr_ = x_history_;
00654 x_end_ptr_ = x_history_ + kernel_size_ + 1;
00655
00656
00657 window_ = new float64[kernel_size_];
00658 }
00659
00660 sample_rate_ = rhs.sample_rate_;
00661
00662 *f_axis_ = *rhs.f_axis_;
00663 *a_axis_ = *rhs.a_axis_;
00664
00665 memcpy(b_, rhs.b_, sizeof(float64) * kernel_size_);
00666 memcpy(window_, rhs.window_, sizeof(float64) * kernel_size_);
00667
00668 FilterLeastSquaresFIR::reset();
00669
00670 return *this;
00671 }
00672
00674 void
00675 FilterLeastSquaresFIR::
00676 plot(boolean show_fc, boolean show_phase)
00677 {
00678 char title[256];
00679 sprintf(title,
00680 "Least Square FIR Frequency Response\n"
00681 "order = %d, sr = %0.1f Hz",
00682 kernel_size_, sample_rate_);
00683
00684 Filter::plot(show_phase);
00685
00686 Plotter pylab;
00687
00688 int32 topplot = 111;
00689
00690 if(show_phase)
00691 {
00692 topplot = 211;
00693 }
00694
00695 if(show_fc)
00696 {
00697 pylab.subplot(topplot);
00698
00699 pylab.title(title);
00700 }
00701 }
00702
00704 void
00705 FilterLeastSquaresFIR::
00706 reset()
00707 {
00708 memset(x_history_, 0, sizeof(float64) * (kernel_size_ + 1));
00709 x_ptr_ = x_history_;
00710 }
00711
00713 void
00714 FilterLeastSquaresFIR::
00715 setWindow(WindowType type)
00716 {
00717 Generator gen(1.0);
00718
00719 Buffer window = gen.drawWindow(kernel_size_, type);
00720
00721 memcpy(window_, window.getPointer(), sizeof(float64)*kernel_size_);
00722
00723
00724 Buffer f(*f_axis_);
00725 Buffer a(*a_axis_);
00726
00727 f *= 0.5 * sample_rate_;
00728
00729 makeKernel(f, a);
00730 }