FilterLeastSquaresFIR.cc

Go to the documentation of this file.
00001 
00002 //
00003 //  $Id: FilterLeastSquaresFIR.cc 620 2011-02-10 06:35:10Z weegreenblobbie $
00004 //
00005 //  Copyright (c) 2010 to Present Nick Hilton
00006 //
00007 //  weegreenblobbie_yahoo_com (replace '_' with '@' and '.')
00008 //
00010 
00012 //
00013 //  This program is free software; you can redistribute it and/or modify
00014 //  it under the terms of the GNU General Public License as published by
00015 //  the Free Software Foundation; either version 2 of the License, or
00016 //  (at your option) any later version.
00017 //
00018 //  This program is distributed in the hope that it will be useful,
00019 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00020 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021 //  GNU Library General Public License for more details.
00022 //
00023 //  You should have received a copy of the GNU General Public License
00024 //  along with this program; if not, write to the Free Software
00025 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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     // Create the Kaiser window.
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     // Allocate f & a axis.
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 // This is private and therefor disabled
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     // Create the Kaiser window.
00115     window_ = new float64[kernel_size_];
00116 
00117     // Allocate f & a axis.
00118     f_axis_ = new Buffer(16);
00119     a_axis_ = new Buffer(16);
00120 
00121     // do the rest in the oprator=()
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         // Create the Kaiser window.
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     // Write x to history
00227     *x_ptr_ = x;
00228 
00229     // Increment history pointer
00230     ++x_ptr_;
00231 
00232     // Bounds check.
00233     if(x_ptr_ >= x_end_ptr_)
00234     {
00235         x_ptr_ = x_history_;
00236     }
00237 
00238     // Perform the convolution.
00239 
00240     // y[n] = kernel_[0] * x[n]
00241     //      + kernel_[1] * x[n - 1]
00242     //      + kernel_[2] * x[n - 2]
00243     //      ...
00244     //      + kernel_[N] * x[n - N]
00245 
00246     float64 y = 0.0;
00247     float64 * history = x_ptr_;
00248     for(float64 * b = b_; b != b_ + kernel_size_; ++b)
00249     {
00250         // When we enter this loop, history is pointing at x[n + 1].
00251         --history;
00252 
00253         // Bounds check
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     // Reset the buffers.
00273     *f_axis_ = Buffer(16);
00274     *a_axis_ = Buffer(16);
00275 
00276     float64 max_freq = sample_rate_ / 2.0;
00277 
00278     // Validate freq_axis and amplitude_axis.
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     // Veirfy all samples inf freq_axis are in assending order.
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     // Test all samples are in assending order.
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     // All is okay.
00337 
00338     *f_axis_ << (freq_axis / max_freq);
00339     *a_axis_ << amplitude_axis;
00340 
00341 //~    // Debug
00342 //~    std::cout << "faxis:" << *f_axis_ << std::endl;
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 //~    cout << "N = " << kernel_size_ << endl
00352 //~         << "F = " << endl;
00353 //~
00354 //~    for(uint32 i = 0; i < f.getLength(); ++i)
00355 //~    {
00356 //~        cout << "    " << f[i] << endl;
00357 //~    }
00358 
00359 //~    cout << "M = " << endl;
00360 //~
00361 //~    for(uint32 i = 0; i < a.getLength(); ++i)
00362 //~    {
00363 //~        cout << "    " << a[i] << endl;
00364 //~    }
00365 
00366 //~    cout << "W = " << endl;
00367 //~
00368 //~    for(uint32 i = 0; i < w.getLength(); ++i)
00369 //~    {
00370 //~        cout << "    " << w[i] << endl;
00371 //~    }
00372 
00373     df = f.getDerivative(1);
00374 
00375     // throw out last value
00376     df = df.subbuffer(0, df.getLength() -1);
00377 
00378 //~    cout << "dF = " << endl;
00379 
00380 //~    for(uint32 i = 0; i < df.getLength(); ++i)
00381 //~    {
00382 //~        cout << "    " << df[i] << endl;
00383 //~    }
00384 
00385     // Check for full band
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 //~    cout << "fullband = " << fullband << endl;
00402 
00403     int32 L = (kernel_size_ - 1) / 2;
00404 
00405 //~    cout << "L = " << L << endl;
00406 
00407     boolean is_odd = true;
00408 
00409     if(kernel_size_ % 2 == 0)
00410     {
00411         is_odd = false;
00412     }
00413 
00414 //~    cout << "Nodd = " << is_odd << endl;
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 //~    cout << "length(m) = " << m.getLength() << endl;
00426 //~    cout << "m[0]   = " << m[0] << endl;
00427 //~    cout << "m[end] = " << m[m.getLength()-1] << endl;
00428 
00429     boolean need_matrix = ! fullband;
00430 
00431 //~    cout << "need_matrix = " << need_matrix << endl;
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 //~    cout << "length(k) = " << k.getLength() << endl;
00449 //~    cout << "k[0]   = " << k[0] << endl;
00450 //~    cout << "k[end] = " << k[k.getLength()-1] << endl;
00451 
00452     float64 PI_x_2 = 2.0 * M_PI;
00453 //~    float64 PI_x_4 = 4.0 * M_PI;
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;    // slope
00467         b1 = a[i] - mm * f[i];          // y-intercept
00468 
00469 //~        cout << endl;
00470 //~        cout << "s = " << i+1 << endl;
00471 //~        cout << "m = " << mm << endl;
00472 //~        cout << "b1 = " << b1 << endl;
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 //~        cout << "b0 = " << b0 << endl;
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 //~        cout << "W[" << i << "] = " << w[(i+1)/2] << endl;
00490 //~        cout << "abs(W^2) = " << abs_w2 << endl;
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 //~        ss.str("");
00505 //~        ss << "s = " << (i+1) << ", b1";
00506 //~        b.plot(ss.str());
00507 
00508 //~        cout << "F[" << (i)   << "] = " << fi  << endl;
00509 //~        cout << "F[" << (i+1) << "] = " << fi1 << endl;
00510 
00511 //~        // DEBUG
00512 //~        Buffer SINC;
00513 //~        for(uint32 j = 0; j < b.getLength(); ++j)
00514 //~        {
00515 //~            float64 x = PI_x_2 * k[j] * fi1;
00516 //~
00517 //~            if(x == 0.0) x = M_PI;
00518 //~
00519 //~            SINC << std::sin(x) / x;
00520 //~        }
00521 //~
00522 //~        ss.str("");
00523 //~        ss << "s = " << (i+1) << ", sinc";
00524 //~        SINC.plot(ss.str());
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 //~        ss << "s = " << (i+1) << ", f1";
00551 //~        f1.plot(ss.str());
00552 //~        ss.str("");
00553 //~        ss << "s = " << (i+1) << ", f2";
00554 //~        f2.plot(ss.str());
00555 //~
00556 //~        ss.str("");
00557 //~        ss << "s = " << (i+1) << ", b2";
00558 //~        b.plot(ss.str());
00559 
00560     }
00561 
00562 //~    cout << "below loop" << endl
00563 //~         << "b0 = " << b0 << endl;
00564 
00565 //~    b.plot("below loop: b");
00566 
00567     if(is_odd)
00568     {
00569         Buffer t;
00570         t << b0 << b;
00571         b = t;
00572     }
00573 
00574 //~    b.plot("below loop: b2");
00575 
00576 //~    a = b;
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 //~    h.plot("h");
00608 //~    Plotter::show();
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     // Apply window
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         // Create the Kaiser window.
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     // Make new kernel with window.
00724     Buffer f(*f_axis_);
00725     Buffer a(*a_axis_);
00726 
00727     f *= 0.5 * sample_rate_;
00728 
00729     makeKernel(f, a);
00730 }
Generated on Sun Apr 15 20:10:05 2012 for nsound by  doxygen 1.6.3