File indexing completed on 2024-12-22 04:18:10

0001 /***************************************************************************
0002  *                                                                         *
0003  *   copyright : (C) 2007 The University of Toronto                        *
0004  *                   netterfield@astro.utoronto.ca                         *
0005  *   copyright : (C) 2005  University of British Columbia                  *
0006  *                   dscott@phas.ubc.ca                                    *
0007  *                                                                         *
0008  *   This program is free software; you can redistribute it and/or modify  *
0009  *   it under the terms of the GNU General Public License as published by  *
0010  *   the Free Software Foundation; either version 2 of the License, or     *
0011  *   (at your option) any later version.                                   *
0012  *                                                                         *
0013  ***************************************************************************/
0014 
0015 /*
0016  *  Generic pass filter plugin for KST.
0017  *  Released under the terms of the GPL 
0018  */
0019 
0020 #ifndef FILTERS_H
0021 #define FILTERS_H
0022 
0023 #include <stdlib.h>
0024 #include <math.h>
0025 #include <string.h>
0026 #include <gsl/gsl_errno.h>
0027 #include <gsl/gsl_fft_real.h>
0028 #include <gsl/gsl_fft_halfcomplex.h>
0029 
0030 #include "vector.h"
0031 #include "scalar.h"
0032 
0033 double filter_calculate( double dFreqValue, Kst::ScalarList scalars );
0034 int min_pad(Kst::ScalarList scalars);
0035 
0036 void fit_mb(double *y, int n, double &m, double &b) {
0037   if (n<5) {
0038     m = 0.0;
0039     b = y[0];
0040     return;
0041   }
0042 
0043   double Sy=0;
0044   double x_ = 0; // mean of x
0045   double y_ = 0; // mean of y
0046   int i;
0047   double x;
0048   double Sdxdy=0; // sum(x - x_)
0049   double Sdx2=0; // sum((x - x_)^2)
0050 
0051   for (i = 0; i<n; i++) {
0052     Sy += y[i];
0053   }
0054   x_ = double(n)*0.5;
0055   y_ = Sy/n;
0056 
0057   for (i = 0; i<n; i++) {
0058     x = i;
0059     Sdxdy += (x - x_) * (y[i] - y_);
0060     Sdx2 +=  (x - x_) * (x - x_);
0061   }
0062   Sdx2 = qMax(Sdx2,1.0);
0063   m = Sdxdy/Sdx2;
0064   b = y_;
0065 }
0066 
0067 bool kst_pass_filter(
0068   Kst::VectorPtr vector,
0069   Kst::ScalarList scalars,
0070   Kst::VectorPtr outVector) {
0071 
0072   gsl_fft_real_wavetable* real;
0073   gsl_fft_real_workspace* work;
0074   gsl_fft_halfcomplex_wavetable* hc;
0075   double* pPadded;
0076   double dFreqValue;
0077   int iLengthData;
0078   int iLengthDataPadded;
0079   bool bReturn = false;
0080   int iStatus;
0081   int i;
0082   
0083   if( scalars.at(1)->value() > 0.0 ) {
0084     iLengthData = vector->length();
0085     
0086     if( iLengthData > 0 ) {
0087       //
0088       // round up to the nearest power of 2...
0089       //
0090       iLengthDataPadded = (int)pow( 2.0, ceil( log10( (double)iLengthData ) / log10( 2.0 ) ) );
0091       // make sure the padding is long enough - this depends on the type of filter.
0092       if (iLengthDataPadded - iLengthData < min_pad(scalars)) {
0093         //qDebug() << "doubled length" << min_pad(scalars) << iLengthDataPadded - iLengthData << iLengthDataPadded;
0094         iLengthDataPadded *= 2.0;
0095       }
0096       pPadded = (double*)malloc( iLengthDataPadded * sizeof( double ) );
0097       if( pPadded != 0L ) {
0098         outVector->resize(iLengthData);
0099         //outVector->resize(iLengthDataPadded);  // DEBUG ************
0100 
0101         real = gsl_fft_real_wavetable_alloc( iLengthDataPadded );
0102         if( real != NULL ) {
0103           work = gsl_fft_real_workspace_alloc( iLengthDataPadded );
0104           if( work != NULL ) {
0105             memcpy( pPadded, vector->noNanValue(), iLengthData * sizeof( double ) );
0106 
0107             // We are going to do a cubic spline extrapolation on the data
0108             // to improve behavior for high pass filters.
0109             double m1, b1;
0110             double m2, b2;
0111 
0112             int nf = min_pad(scalars)/10.0;
0113             if (nf > iLengthData/5) nf = iLengthData/5;
0114 
0115             fit_mb(pPadded, nf, m2, b2);
0116             fit_mb(pPadded + (iLengthData-nf-1), nf, m1, b1);
0117 
0118             double a = b1;
0119             double b = m1;
0120             double X = double(nf + iLengthDataPadded - iLengthData);
0121             double d = (-2.0*b2 +m2*X + 2.0*b1 + m1*X)/(X*X*X);
0122             double c = (b2 - b1 - m1*X - d*X*X*X)/(X*X);
0123 
0124             //
0125             // polynomial extrapolation on the padded values...
0126             //
0127             for( i=iLengthData; i<iLengthDataPadded; i++ ) {
0128               X = double(i-iLengthData)+nf*0.5;
0129               //pPadded[i] = a + b*X + c*X*X + d*X*X*X;
0130               pPadded[i] = a + X*(b + X*(c + X*d));
0131               //pPadded[i] = vector->value()[iLengthData-1] - (double)( i - iLengthData + 1 ) * ( vector->value()[iLengthData-1] - vector->value()[0] ) / (double)( iLengthDataPadded - iLengthData );
0132             }
0133             
0134             //
0135             // calculate the FFT...
0136             //
0137             iStatus = gsl_fft_real_transform( pPadded, 1, iLengthDataPadded, real, work );
0138 
0139             if( !iStatus ) {
0140               //
0141               // apply the filter...
0142               //
0143               for( i=0; i<iLengthDataPadded; i++ ) {
0144                 dFreqValue = 0.5 * (double)i / (double)iLengthDataPadded;
0145                 pPadded[i] *= filter_calculate( dFreqValue, scalars );
0146               }
0147 
0148               hc = gsl_fft_halfcomplex_wavetable_alloc( iLengthDataPadded );
0149               if( hc != NULL ) {
0150                 //
0151                 // calculate the inverse FFT...
0152                 //
0153                 iStatus = gsl_fft_halfcomplex_inverse( pPadded, 1, iLengthDataPadded, hc, work );
0154                 if( !iStatus ) {
0155                   memcpy( outVector->raw_V_ptr(), pPadded, iLengthData * sizeof( double ) );
0156                   //memcpy( outVector->raw_V_ptr(), pPadded, iLengthDataPadded * sizeof( double ) ); // DEBUG **********************
0157                   bReturn = true;
0158                 }
0159                 gsl_fft_halfcomplex_wavetable_free( hc );
0160               }
0161             }
0162             gsl_fft_real_workspace_free( work );
0163           }
0164           gsl_fft_real_wavetable_free( real );
0165         }
0166         free( pPadded );
0167       }
0168     }
0169   }
0170   return bReturn;
0171 }
0172 
0173 #endif