qub_filter.cpp.html |
mathcode2html
|
Source file: qub_filter.cpp
|
Converted: Wed Jan 6 2016 at 15:24:07
|
This documentation file will
not reflect any later changes in the source file.
|
$$\phantom{******** If you see this on the webpage then the
browser could not locate *********}$$
$$\phantom{******** jsMath/easy/load.js or the variable root
is set wrong in this file *********}$$
$$\newcommand{\vector}[1]{\left[\begin{array}{c} #1 \end{array}\right]}$$
$$\newenvironment{matrix}{\left[\begin{array}{cccccccccc}} {\end{array}\right]}$$
$$\newcommand{\A}{{\cal A}}$$
$$\newcommand{\W}{{\cal W}}$$
/* Copyright 1998-2014 Research Foundation State University of New York */
/* This file is part of QUB Express. */
/* QUB Express is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation, either version 3 of the License, or */
/* (at your option) any later version. */
/* QUB Express is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* You should have received a copy of the GNU General Public License, */
/* named LICENSE.txt, in the QUB Express program directory. If not, see */
/* <http://www.gnu.org/licenses/>. */
/*
*/
#ifdef _WIN32
#include <windows.h>
#include <time.h>
#include <float.h>
#define sleep Sleep
#else
#include <stdlib.h>
#define BOOL int
#define TRUE 1
#define FALSE 0
#endif
#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
#include <math.h>
#include <string.h>
#include <vector>
#include <map>
using std::vector;
using std::map;
using std::pair;
#include "qub_filter.h"
void errexit(QUBFAST_VAR_NOT_USED
const char *msg) {
//fprintf(stderr,"\n%s\n",msg);
//exit(1);
}
#define sqr(x) ((x)*(x))
//===== Magic numbers
const double PI = 3.14159265358979;
const double PI2 = 6.28318530717959;
#define EXIT_ERROR /*fprintf(stderr,"Memory allocation error\n"); exit(1);*/return NULL;
double* dalloc1(int size) {
double * ptr = (double *)malloc(size*sizeof(double));
if (ptr==NULL)
EXIT_ERROR
return ptr;
}
template<class T>
T* talloc1(int size) {
T * ptr = (T*) malloc(size*sizeof(T));
if (ptr == NULL)
EXIT_ERROR
return ptr;
}
//----- local functions
//void four1_0(double *data, long nn, int isign);
//void twofft0(double *data1, double *data2, double *fft1, double *fft2, long n);
//void realft0(double *data, long n, int isign);
// -----------------------------------------------------------------------------------
// Fast fourier transform :
// Replaces data [0..2*nn-1] with ...
// isign=1 : its discrete fourier transform
// isign=-1: nn * its inverse discrete fourier transform
// Data is a complex array of length nn or a real array of length nn
// nn must be an integer power of 2 !!!
#define SWAP(a, b) tempswap = (a); (a) = (b); (b) = tempswap
template<class T>
void four1_0(T *data, long nn, int isign){
long n, mmax, m, j, istep, i;
double wtemp, wr, wpr, wpi, wi, theta;
double tempr, tempi;
T tempswap;
n = nn << 1;
j = 1;
for( i=1; i<n; i+=2 ) { // This is the bit reversal section of the routine
if (j > i) { // Exchange the two complex numbers
SWAP( data[j-1], data[i-1]);
SWAP( data[j], data[i]);
}
m = n >> 1;
while (m >= 2 && j > m) {
j -= m;
m >>= 1;
}
j += m;
}
//----- Danielson Lanczos
mmax = 2;
while( n>mmax ) { // outer loop executed log2(nn) times
istep = mmax << 1;
theta = ((T)isign) * ( PI2 / ((T)mmax)); // initialize the trigonometric occurrence
wtemp = sin(0.5 * theta);
wpr = -2.0 * wtemp * wtemp;
wpi = sin(theta);
wr = 1.0;
wi = 0.0;
for( m=1; m<mmax; m+=2) {
for( i=m; i<=n; i+=istep ) {
j = i + mmax; // Danielson Lanczos formula
tempr = wr*data[j-1] - wi*data[j];
tempi = wr*data[j] + wi*data[j-1];
data[j-1] = (T) (data[i-1] - tempr);
data[j] = (T) (data[i] - tempi);
data[i-1] += (T) tempr;
data[i] += (T) tempi;
}
wr = (wtemp=wr)*wpr - wi*wpi + wr; // Trigonometric recurrence
wi = wi*wpr + wtemp*wpi + wi;
}
mmax = istep;
}
}
#undef SWAP
// -----------------------------------------------------------------------------------
// Simultaneous four1() of two real arrays using real and imag of complex numbers alg.
// Given data1[0..n-1] data2[0..n-1], call four1 and return fft1[0..2n-1],fft2[0..2n-1]
// complex arrays of FFT's
// n must be an integer power of 2 !!
template<class T>
void twofft0(T *data1, T *data2, T *fft1, T *fft2, long n){
T rep, rem, aip, aim;
long j, nn=n+n;
// pack the two real arrays into one complex array
for( j=0; j<n; ++j) {
fft1[j+j] = data1[j];
fft1[j+j+1] = data2[j];
}
// transform the complex array
four1_0(fft1, n, 1);
fft2[0] = fft1[1];
fft1[1] = fft2[1] = 0.0;
for( j=2; j<=n; j+=2 ) { // Use symmetries to separate the two transforms
rep = (T) (0.5 * (fft1[j] + fft1[nn-j]));
rem = (T) (0.5 * (fft1[j] - fft1[nn-j]));
aip = (T) (0.5 * (fft1[j+1] + fft1[nn+1-j]));
aim = (T) (0.5 * (fft1[j+1] - fft1[nn+1-j]));
fft1[j] = rep; // Ship them out in two complex arrays
fft1[j+1] = aim;
fft1[nn-j] = rep;
fft1[nn+1-j] = -aim;
fft2[j] = aip;
fft2[j+1] = -rem;
fft2[nn-j] = aip;
fft2[nn+1-j] = rem;
}
}
// -----------------------------------------------------------------------------------
// FFT a single real data set: data1(0:n-1)
template<class T>
void realft0(T *data, long n, int isign){
long i, ii;
T c1 = 0.5, c2, h1r, h1i, h2r, h2i;
T wr, wi, wpr, wpi, wtemp, theta;
theta = (T) (PI / (double) (n >> 1));
if (isign == 1) {
c2 = -0.5;
four1_0(data, n >> 1, 1);
}
else {
c2 = 0.5;
theta = -theta;
}
wtemp = (T) sin(0.5*theta);
wpr = (T) (-2.0*wtemp*wtemp);
wpi = (T) sin(theta);
wr = (T) (1.0 + wpr);
wi = wpi;
for( i=2; i<=(n>>2); i++) {
ii=i+i;
h1r = c1*( data[ii-2] + data[n+2-ii] );
h1i = c1*( data[ii-1] - data[n+3-ii] );
h2r =-c2*( data[ii-1] + data[n+3-ii] );
h2i = c2*( data[ii-2] - data[n+2-ii] );
data[ii-2] = h1r + wr*h2r - wi*h2i;
data[ii-1] = h1i + wr*h2i + wi*h2r;
data[n+2-ii] = h1r - wr*h2r + wi*h2i;
data[n+3-ii] =-h1i + wr*h2i + wi*h2r;
wr = (wtemp = wr)*wpr - wi*wpi + wr;
wi = wi*wpr + wtemp*wpi + wi;
}
if (isign == 1) {
data[0] = (h1r = data[0]) + data[1];
data[1] = h1r - data[1];
}
else {
data[0] = c1*( (h1r=data[0]) + data[1] );
data[1] = c1*( h1r-data[1] );
four1_0(data, n >> 1, -1);
}
}
/*
* Convolve or deconvolve a real data set data[0..n-1] with a response
* function respns[0..n-1].
* 1. n must be an integer power of two.
* 2. data[] must be padded with zeros (at the end) in the calling
* program, and the number of zeros should not be less than the
* positive duration of the response function (not including t=0).
* 3. m must be an odd integer.
* 4. The response function must be stored in wrap-around order in
* the first m elements of respons[].
* 5. The result is returned in the first n components of ans[].
* However, ans[] must be supplied in the calling program with
* dimensions [0..2*n-1].
*/
template<class T>
void convlv0(T *data, long n, T *respns, long m, int isign, T *ans){
long i, no2;
T dum, mag2, *fft;
fft = talloc1<T>(2*(int)n);
for( i=1; i<=(m-1)/2; i++)
respns[n-i] = respns[m-i];
for( i=(m+3)/2; i<=n-(m-1)/2; i++)
respns[i-1]=0.0;
twofft0(data, respns, fft, ans, n);
no2 = n >> 1;
for( i=0; i<=n; i+=2) {
if (isign == 1) {
dum = ans[i];
ans[i] = (T) ((fft[i] * dum - fft[i+1] * ans[i+1]) / ((T)no2));
ans[i+1]= (T) ((fft[i+1] * dum + fft[i+1] * ans[i+1]) / ((T)no2));
}
else if (isign == - 1) {
if ((mag2 = sqr(ans[i]) + sqr(ans[i+1])) == 0.0)
errexit("Deconvolving at response zero in convlv.");
dum = ans[i];
ans[i] = (T) ((fft[i] * dum + fft[i+1] * ans[i+1]) / mag2 / ((T)no2));
ans[i+1]= (T) ((fft[i+1] * dum - fft[i] * ans[i+1]) / mag2 / ((T)no2));
}
}
ans[1] = ans[n];
realft0(ans, n, -1);
free(fft);
}
// -----------------------------------------------------------------------------------
template<class T>
T *gsfir(double fc, int *nfir){
int k, n;
T tmp, sigma, *h;
sigma = (T) (0.1325/fc);
n = (int)(4*sigma);
*nfir = 2*n + 1;
h = talloc1<T>(*nfir + 3);
if (sigma < 0.6) {
*nfir = 3;
h[0] = h[2] = (T) (sqr(sigma)/2.0);
h[1] = (T) (1.0f - h[0] - h[2]);
}
else {
h[n] = (T) (1.0/(sqrt(2.0*PI)*sigma));
for (k = 1; k <= n; k++) {
tmp = (T) (((T)k)/sigma);
tmp = (T) sqr(tmp);
h[n+k] = h[n-k] = (T) (h[n]*exp(-tmp/2.0));
}
}
return h;
}
// -----------------------------------------------------------------------------------
// nh must be an odd integer
// This is a strange function. Used in filtering ?
// Example output : wrap( [1,2,3,4,5,6,7] ) -> [4,5,6,7,6,5,4]
template<class T>
void wrap(int nh, T *h) {
int i, m = (nh-1)/2;
for( i=0; i<=m; i++)
h[i] = h[m+i];
for( i=1; i<=m; i++)
h[m+i] = h[m-i+1];
}
template<class T>
void ovrlap(T *data, long ndata, T *respns, long m, T *ans, int nfft){
long i, nd, np;
T *s, *r, *y;
nd = nfft - (m - 1);
s = talloc1<T>(nfft);
r = talloc1<T>(nfft);
y = talloc1<T>(2*nfft);
memset( ans, 0, ndata*sizeof(T)); // for( i=0; i<ndata; i++) ans[i]=0.0;
for( np=0; np<ndata; np+=nd) {
for( i=1; i<=nfft; i++)
s[i-1] = 0.0;
for( i=0; i<nd; i++)
if( np+i < ndata )
s[(m-1)/2+i] = data[np+i];
for( i=0; i<m; i++)
r[i]=respns[i];
try {
convlv0(s, nfft, r, m, 1, y);
}
catch (...) {
}
for( i=0; i<(m-1)/2; i++)
if (np-i>=1)
ans[np-i-1] += y[(m-1)/2 - i - 1];
for( i=1; i<=nd+(m-1)/2; i++)
if (np+i<=ndata)
ans[np+i-1] += y[(m-1)/2 + i - 1];
}
free(s);
free(r);
free(y);
}
// -----------------------------------------------------------------------------------
extern "C" QUBFAST_API int qub_filterdatad(double *data, double *fdata, int ndata, double dt, double freq) {
int nh;
double * h = NULL;
int rtnVal = 0;
int fft_count = 1024;
try {
h = gsfir<double>(freq*dt, &nh);
wrap(nh, h);
while ( fft_count < nh )
fft_count *= 2;
ovrlap(data, ndata, h, nh, fdata, fft_count);
}
catch (...) {
rtnVal = 1;
}
#if defined(_WIN32)
unsigned int fstat = _clearfp(); // just in case
_fpreset();
#endif
free(h);
return rtnVal;
}
extern "C" QUBFAST_API int qub_filterdataf(float *data, float *fdata, int ndata, float dt, float freq) {
int nh;
float * h = NULL;
int rtnVal = 0;
int fft_count = 1024;
try {
h = gsfir<float>(freq*dt, &nh);
wrap(nh, h);
while ( fft_count < nh )
fft_count *= 2;
ovrlap(data, ndata, h, nh, fdata, fft_count);
}
catch (...) {
rtnVal = 1;
}
#if defined(_WIN32)
unsigned int fstat = _clearfp(); // just in case
_fpreset();
#endif
free(h);
return rtnVal;
}