1
/***************************************************************************
2
File : SmoothFilter.cpp
4
--------------------------------------------------------------------
5
Copyright : (C) 2007 by Ion Vasilief
6
Email (use @ for *) : ion_vasilief*yahoo.fr
7
Description : Numerical smoothing of data sets
9
***************************************************************************/
11
/***************************************************************************
13
* This program is free software; you can redistribute it and/or modify *
14
* it under the terms of the GNU General Public License as published by *
15
* the Free Software Foundation; either version 2 of the License, or *
16
* (at your option) any later version. *
18
* This program is distributed in the hope that it will be useful, *
19
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
20
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
21
* GNU General Public License for more details. *
23
* You should have received a copy of the GNU General Public License *
24
* along with this program; if not, write to the Free Software *
25
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
26
* Boston, MA 02110-1301 USA *
28
***************************************************************************/
29
#include "SmoothFilter.h"
32
#include <QApplication>
33
#include <QMessageBox>
35
#include <gsl/gsl_fft_halfcomplex.h>
37
SmoothFilter::SmoothFilter(ApplicationWindow *parent, Graph *g, const QString& curveTitle, int m)
40
setDataFromCurve(curveTitle);
44
SmoothFilter::SmoothFilter(ApplicationWindow *parent, Graph *g, const QString& curveTitle,
45
double start, double end, int m)
48
setDataFromCurve(curveTitle, start, end);
52
void SmoothFilter::init (int m)
54
setName(tr("Smoothed"));
63
void SmoothFilter::setMethod(int m)
67
QMessageBox::critical((ApplicationWindow *)parent(), tr("SciDAVis") + " - " + tr("Error"),
68
tr("Unknown smooth filter. Valid values are: 1 - Savitky-Golay, 2 - FFT, 3 - Moving Window Average."));
72
d_method = (SmoothMethod)m;
75
void SmoothFilter::calculateOutputData(double *x, double *y)
77
for (int i = 0; i < d_points; i++)
80
y[i] = d_y[i];//filtering frequencies
86
d_explanation = QString::number(d_smooth_points) + " " + tr("points") + " " + tr("Savitzky-Golay smoothing");
90
d_explanation = QString::number(d_smooth_points) + " " + tr("points") + " " + tr("FFT smoothing");
94
d_explanation = QString::number(d_smooth_points) + " " + tr("points") + " " + tr("average smoothing");
100
void SmoothFilter::smoothFFT(double *x, double *y)
102
gsl_fft_real_workspace *work = gsl_fft_real_workspace_alloc(d_n);
103
gsl_fft_real_wavetable *real = gsl_fft_real_wavetable_alloc(d_n);
104
gsl_fft_real_transform (y, 1, d_n, real, work);//FFT forward
105
gsl_fft_real_wavetable_free (real);
107
double df = 1.0/(double)(x[1] - x[0]);
108
double lf = df/(double)d_smooth_points;//frequency cutoff
109
df = 0.5*df/(double)d_n;
111
for (int i = 0; i < d_n; i++)
114
y[i] = i*df > lf ? 0 : y[i];//filtering frequencies
117
gsl_fft_halfcomplex_wavetable *hc = gsl_fft_halfcomplex_wavetable_alloc (d_n);
118
gsl_fft_halfcomplex_inverse (y, 1, d_n, hc, work);//FFT inverse
119
gsl_fft_halfcomplex_wavetable_free (hc);
120
gsl_fft_real_workspace_free (work);
123
void SmoothFilter::smoothAverage(double *, double *y)
125
int p2 = d_smooth_points/2;
126
double m = double(2*p2+1);
128
double *s = new double[d_n];
131
for (int i=1; i<p2; i++)
134
for (int j=-i; j<=i; j++)
137
s[i] = aux/(double)(2*i+1);
139
for (int i=p2; i<d_n-p2; i++)
142
for (int j=-p2; j<=p2; j++)
147
for (int i=d_n-p2; i<d_n-1; i++)
150
for (int j=d_n-i-1; j>=i-d_n+1; j--)
153
s[i] = aux/(double)(2*(d_n-i-1)+1);
157
for (int i = 0; i<d_n; i++)
163
void SmoothFilter::smoothSavGol(double *, double *y)
165
double *s = new double[d_n];
166
int nl = d_smooth_points;
167
int nr = d_sav_gol_points;
169
double *c = vector(1, np);
171
//seek shift index for given case nl, nr, m (see savgol).
172
int *index = intvector(1, np);
175
for (i=2; i<=nl+1; i++)
176
{// index(2)=-1; index(3)=-2; index(4)=-3; index(5)=-4; index(6)=-5
181
for (i=nl+2; i<=np; i++)
182
{// index(7)= 5; index(8)= 4; index(9)= 3; index(10)=2; index(11)=1
187
//calculate Savitzky-Golay filter coefficients.
188
savgol(c, np, nl, nr, 0, d_polynom_order);
190
for (i=0; i<d_n; i++)
191
{// Apply filter to input data.
193
for (j=1; j<=np; j++)
196
if (it >=0 && it < d_n)//skip left points that do not exist.
197
s[i] += c[j]*y[i+index[j]];
201
for (i = 0; i<d_n; i++)
205
free_vector(c, 1, np);
206
free_intvector(index, 1, np);
209
void SmoothFilter::setSmoothPoints(int points, int left_points)
211
if (points < 0 || left_points < 0)
213
QMessageBox::critical((ApplicationWindow *)parent(), tr("SciDAVis") + " - " + tr("Error"),
214
tr("The number of points must be positive!"));
218
else if (d_polynom_order > points + left_points)
220
QMessageBox::critical((ApplicationWindow *)parent(), tr("SciDAVis") + " - " + tr("Error"),
221
tr("The polynomial order must be lower than the number of left points plus the number of right points!"));
226
d_smooth_points = points;
227
d_sav_gol_points = left_points;
230
void SmoothFilter::setPolynomOrder(int order)
232
if (d_method != SavitzkyGolay)
234
QMessageBox::critical((ApplicationWindow *)parent(), tr("SciDAVis") + " - " + tr("Error"),
235
tr("Setting polynomial order is only available for Savitzky-Golay smooth filters! Ignored option!"));
239
if (order > d_smooth_points + d_sav_gol_points)
241
QMessageBox::critical((ApplicationWindow *)parent(), tr("SciDAVis") + " - " + tr("Error"),
242
tr("The polynomial order must be lower than the number of left points plus the number of right points!"));
246
d_polynom_order = order;