54{
55
56}
57
58FilterSavitzkyGolay::FilterSavitzkyGolay(int nL, int nR, int m, int lD, bool convolveWithNr)
59{
60 m_params.nL = nL;
61 m_params.nR = nR;
62 m_params.m = m;
63 m_params.lD = lD;
64 m_params.convolveWithNr = convolveWithNr;
65}
66
67
68FilterSavitzkyGolay::FilterSavitzkyGolay(const SavGolParams sav_gol_params)
69{
70 m_params.nL = sav_gol_params.nL;
71 m_params.nR = sav_gol_params.nR;
72 m_params.m = sav_gol_params.m;
73 m_params.lD = sav_gol_params.lD;
74 m_params.convolveWithNr = sav_gol_params.convolveWithNr;
75}
76
77
78FilterSavitzkyGolay::FilterSavitzkyGolay(const QString ¶meters)
79{
80 buildFilterFromString(parameters);
81}
82
83
84FilterSavitzkyGolay::FilterSavitzkyGolay(const FilterSavitzkyGolay &other)
85{
86
87
88 m_params.nL = other.m_params.nL;
89 m_params.nR = other.m_params.nR;
90 m_params.m = other.m_params.m;
91 m_params.lD = other.m_params.lD;
92 m_params.convolveWithNr = other.m_params.convolveWithNr;
93}
94
95
96FilterSavitzkyGolay::~FilterSavitzkyGolay()
97{
98}
99
100FilterSavitzkyGolay &
101FilterSavitzkyGolay::operator=(const FilterSavitzkyGolay &other)
102{
103 if(&other == this)
104 return *this;
105
106
107
108 m_params.nL = other.m_params.nL;
109 m_params.nR = other.m_params.nR;
110 m_params.m = other.m_params.m;
111 m_params.lD = other.m_params.lD;
112 m_params.convolveWithNr = other.m_params.convolveWithNr;
113
114 return *this;
115}
116
117
118void
119FilterSavitzkyGolay::buildFilterFromString(const QString ¶meters)
120{
121
122 if(parameters.startsWith(QString("%1|").arg(name())))
123 {
124 QStringList params = parameters.split("|").back().split(";");
125
126 m_params.nL = params.at(0).toInt();
127 m_params.nR = params.at(1).toInt();
128 m_params.m = params.at(2).toInt();
129 m_params.lD = params.at(3).toInt();
130 m_params.convolveWithNr = (params.at(4) == "true" ? true : false);
131 }
132 else
133 {
135 QString("Building of FilterSavitzkyGolay from string '%1' failed").arg(parameters));
136 }
137}
138
139
140Trace &
141FilterSavitzkyGolay::filter(Trace &data_points) const
142{
143
144
145
146
147 int data_point_count = data_points.size();
148
150 pappso_double *y_initial_data_p = dvector(1, data_point_count);
152
153 if(m_params.convolveWithNr)
154 y_filtered_data_p = dvector(1, 2 * data_point_count);
155 else
156 y_filtered_data_p = dvector(1, data_point_count);
157
158 for(int iter = 0; iter < data_point_count; ++iter)
159 {
160 x_data_p[iter] = data_points.at(iter).x;
161 y_initial_data_p[iter] = data_points.at(iter).y;
162 }
163
164
165
166 runFilter(y_initial_data_p, y_filtered_data_p, data_point_count);
167
168
169 auto iter_yf = y_filtered_data_p;
170 for(auto &data_point : data_points)
171 {
172 data_point.y = *iter_yf;
173 iter_yf++;
174 }
175
176 return data_points;
177}
178
179
180SavGolParams
181FilterSavitzkyGolay::getParameters() const
182{
183 return SavGolParams(m_params.nL, m_params.nR, m_params.m, m_params.lD, m_params.convolveWithNr);
184}
185
186
187
188QString
189FilterSavitzkyGolay::toString() const
190{
191 return QString("%1|%2").arg(name()).arg(m_params.toString());
192}
193
194
195QString
196FilterSavitzkyGolay::name() const
197{
198 return "Savitzky-Golay";
199}
200
201
202int *
203FilterSavitzkyGolay::ivector(long nl, long nh) const
204{
205 int *v;
206 v = (int *)malloc((size_t)((nh - nl + 2) * sizeof(int)));
207 if(!v)
208 {
209 qFatal("Error: Allocation failure.");
210 }
211 return v - nl + 1;
212}
213
214
216FilterSavitzkyGolay::dvector(long nl, long nh) const
217{
219 long k;
220 v = (
pappso_double *)malloc((
size_t)((nh - nl + 2) *
sizeof(pappso_double)));
221 if(!v)
222 {
223 qFatal("Error: Allocation failure.");
224 }
225 for(k = nl; k <= nh; k++)
226 v[k] = 0.0;
227 return v - nl + 1;
228}
229
230
232FilterSavitzkyGolay::dmatrix(long nrl, long nrh, long ncl, long nch) const
233{
234 long i, nrow = nrh - nrl + 1, ncol = nch - ncl + 1;
236 m = (
pappso_double **)malloc((
size_t)((nrow + 1) *
sizeof(pappso_double *)));
237 if(!m)
238 {
239 qFatal("Error: Allocation failure.");
240 }
241 m += 1;
242 m -= nrl;
243 m[nrl] = (
pappso_double *)malloc((
size_t)((nrow * ncol + 1) *
sizeof(pappso_double)));
244 if(!m[nrl])
245 {
246 qFatal("Error: Allocation failure.");
247 }
248 m[nrl] += 1;
249 m[nrl] -= ncl;
250 for(i = nrl + 1; i <= nrh; i++)
251 m[i] = m[i - 1] + ncol;
252 return m;
253}
254
255
256void
257FilterSavitzkyGolay::free_ivector(int *v, long nl, [[maybe_unused]] long nh) const
258{
259 free((char *)(v + nl - 1));
260}
261
262
263void
264FilterSavitzkyGolay::free_dvector(pappso_double *v, long nl, [[maybe_unused]] long nh) const
265{
266 free((char *)(v + nl - 1));
267}
268
269
270void
271FilterSavitzkyGolay::free_dmatrix(
272 pappso_double **m, long nrl, [[maybe_unused]] long nrh, long ncl, [[maybe_unused]] long nch) const
273{
274 free((char *)(m[nrl] + ncl - 1));
275 free((char *)(m + nrl - 1));
276}
277
278
279void
280FilterSavitzkyGolay::lubksb(pappso_double **a, int n, int *indx, pappso_double b[]) const
281{
282 int i, ii = 0, ip, j;
284
285 for(i = 1; i <= n; i++)
286 {
287 ip = indx[i];
290 if(ii)
291 for(j = ii; j <= i - 1; j++)
292 sum -= a[i][j] * b[j];
293 else if(sum)
294 ii = i;
296 }
297 for(i = n; i >= 1; i--)
298 {
300 for(j = i + 1; j <= n; j++)
301 sum -= a[i][j] * b[j];
302 b[i] =
sum /
a[i][i];
303 }
304}
305
306
307void
308FilterSavitzkyGolay::ludcmp(pappso_double **a, int n, int *indx, pappso_double *d) const
309{
310 int i, imax = 0, j, k;
313
314 vv = dvector(1, n);
316 for(i = 1; i <= n; i++)
317 {
318 big = 0.0;
319 for(j = 1; j <= n; j++)
320 if((temp = fabs(a[i][j])) > big)
321 big = temp;
322 if(big == 0.0)
323 {
324 qFatal("Error: Singular matrix found in routine ludcmp().");
325 }
326 vv[i] = 1.0 / big;
327 }
328 for(j = 1; j <= n; j++)
329 {
330 for(i = 1; i < j; i++)
331 {
333 for(k = 1; k < i; k++)
334 sum -= a[i][k] * a[k][j];
336 }
337 big = 0.0;
338 for(i = j; i <= n; i++)
339 {
341 for(k = 1; k < j; k++)
342 sum -= a[i][k] * a[k][j];
344 if((dum = vv[i] * fabs(sum)) >= big)
345 {
346 big = dum;
347 imax = i;
348 }
349 }
350 if(j != imax)
351 {
352 for(k = 1; k <= n; k++)
353 {
355 a[imax][k] =
a[j][k];
357 }
359 vv[imax] = vv[j];
360 }
361 indx[j] = imax;
362 if(a[j][j] == 0.0)
363 a[j][j] = std::numeric_limits<pappso_double>::epsilon();
364 if(j != n)
365 {
366 dum = 1.0 / (
a[j][j]);
367 for(i = j + 1; i <= n; i++)
368 a[i][j] *= dum;
369 }
370 }
371 free_dvector(vv, 1, n);
372}
373
374
375void
376FilterSavitzkyGolay::four1(pappso_double data[], unsigned long nn, int isign)
377{
378 unsigned long n, mmax, m, j, istep, i;
381
382 n = nn << 1;
383 j = 1;
384 for(i = 1; i < n; i += 2)
385 {
386 if(j > i)
387 {
388 SWAP(data[j], data[i]);
389 SWAP(data[j + 1], data[i + 1]);
390 }
391 m = n >> 1;
392 while(m >= 2 && j > m)
393 {
394 j -= m;
395 m >>= 1;
396 }
397 j += m;
398 }
399 mmax = 2;
400 while(n > mmax)
401 {
402 istep = mmax << 1;
403 theta = isign * (6.28318530717959 / mmax);
404 wtemp = sin(0.5 * theta);
405 wpr = -2.0 * wtemp * wtemp;
406 wpi = sin(theta);
407 wr = 1.0;
408 wi = 0.0;
409 for(m = 1; m < mmax; m += 2)
410 {
411 for(i = m; i <= n; i += istep)
412 {
413 j = i + mmax;
414 tempr = wr * data[j] - wi * data[j + 1];
415 tempi = wr * data[j + 1] + wi * data[j];
416 data[j] = data[i] - tempr;
417 data[j + 1] = data[i + 1] - tempi;
418 data[i] += tempr;
419 data[i + 1] += tempi;
420 }
421 wr = (wtemp = wr) * wpr - wi * wpi + wr;
422 wi = wi * wpr + wtemp * wpi + wi;
423 }
424 mmax = istep;
425 }
426}
427
428
429void
430FilterSavitzkyGolay::twofft(pappso_double data1[],
431 pappso_double data2[],
432 pappso_double fft1[],
433 pappso_double fft2[],
434 unsigned long n)
435{
436 unsigned long nn3, nn2, jj, j;
438
439 nn3 = 1 + (nn2 = 2 + n + n);
440 for(j = 1, jj = 2; j <= n; j++, jj += 2)
441 {
442 fft1[jj - 1] = data1[j];
443 fft1[jj] = data2[j];
444 }
445 four1(fft1, n, 1);
446 fft2[1] = fft1[2];
447 fft1[2] = fft2[2] = 0.0;
448 for(j = 3; j <= n + 1; j += 2)
449 {
450 rep = 0.5 * (fft1[j] + fft1[nn2 - j]);
451 rem = 0.5 * (fft1[j] - fft1[nn2 - j]);
452 aip = 0.5 * (fft1[j + 1] + fft1[nn3 - j]);
453 aim = 0.5 * (fft1[j + 1] - fft1[nn3 - j]);
454 fft1[j] = rep;
455 fft1[j + 1] = aim;
456 fft1[nn2 - j] = rep;
457 fft1[nn3 - j] = -aim;
458 fft2[j] = aip;
459 fft2[j + 1] = -rem;
460 fft2[nn2 - j] = aip;
461 fft2[nn3 - j] = rem;
462 }
463}
464
465
466void
467FilterSavitzkyGolay::realft(pappso_double data[], unsigned long n, int isign)
468{
469 unsigned long i, i1, i2, i3, i4, np3;
472
474 if(isign == 1)
475 {
476 c2 = -0.5;
477 four1(data, n >> 1, 1);
478 }
479 else
480 {
481 c2 = 0.5;
482 theta = -theta;
483 }
484 wtemp = sin(0.5 * theta);
485 wpr = -2.0 * wtemp * wtemp;
486 wpi = sin(theta);
487 wr = 1.0 + wpr;
488 wi = wpi;
489 np3 = n + 3;
490 for(i = 2; i <= (n >> 2); i++)
491 {
492 i4 = 1 + (i3 = np3 - (i2 = 1 + (i1 = i + i - 1)));
493 h1r = c1 * (data[i1] + data[i3]);
494 h1i = c1 * (data[i2] - data[i4]);
495 h2r = -c2 * (data[i2] + data[i4]);
496 h2i = c2 * (data[i1] - data[i3]);
497 data[i1] = h1r + wr * h2r - wi * h2i;
498 data[i2] = h1i + wr * h2i + wi * h2r;
499 data[i3] = h1r - wr * h2r + wi * h2i;
500 data[i4] = -h1i + wr * h2i + wi * h2r;
501 wr = (wtemp = wr) * wpr - wi * wpi + wr;
502 wi = wi * wpr + wtemp * wpi + wi;
503 }
504 if(isign == 1)
505 {
506 data[1] = (h1r = data[1]) + data[2];
507 data[2] = h1r - data[2];
508 }
509 else
510 {
511 data[1] = c1 * ((h1r = data[1]) + data[2]);
512 data[2] = c1 * (h1r - data[2]);
513 four1(data, n >> 1, -1);
514 }
515}
516
517
518char
519FilterSavitzkyGolay::convlv(pappso_double data[],
520 unsigned long n,
521 pappso_double respns[],
522 unsigned long m,
523 int isign,
524 pappso_double ans[])
525{
526 unsigned long i, no2;
528
529 fft = dvector(1, n << 1);
530 for(i = 1; i <= (m - 1) / 2; i++)
531 respns[n + 1 - i] = respns[m + 1 - i];
532 for(i = (m + 3) / 2; i <= n - (m - 1) / 2; i++)
533 respns[i] = 0.0;
534 twofft(data, respns, fft, ans, n);
535 no2 = n >> 1;
536 for(i = 2; i <= n + 2; i += 2)
537 {
538 if(isign == 1)
539 {
540 ans[i - 1] = (fft[i - 1] * (dum = ans[i - 1]) - fft[i] * ans[i]) / no2;
541 ans[i] = (fft[i] * dum + fft[i - 1] * ans[i]) / no2;
542 }
543 else if(isign == -1)
544 {
545 if((mag2 = ans[i - 1] * ans[i - 1] + ans[i] * ans[i]) == 0.0)
546 {
547 qDebug("Attempt of deconvolving at zero response in convlv().");
548 return (1);
549 }
550 ans[i - 1] = (fft[i - 1] * (dum = ans[i - 1]) + fft[i] * ans[i]) / mag2 / no2;
551 ans[i] = (fft[i] * dum - fft[i - 1] * ans[i]) / mag2 / no2;
552 }
553 else
554 {
555 qDebug("No meaning for isign in convlv().");
556 return (1);
557 }
558 }
559 ans[2] = ans[n + 1];
560 realft(ans, n, -1);
561 free_dvector(fft, 1, n << 1);
562 return (0);
563}
564
565
566char
567FilterSavitzkyGolay::sgcoeff(pappso_double c[], int np, int nl, int nr, int ld, int m) const
568{
569 int imj, ipj, j, k, kk, mm, *indx;
571
572 if(np < nl + nr + 1 || nl < 0 || nr < 0 || ld > m || nl + nr < m)
573 {
574 qDebug("Inconsistent arguments detected in routine sgcoeff.");
575 return (1);
576 }
577 indx = ivector(1, m + 1);
578 a = dmatrix(1, m + 1, 1, m + 1);
579 b = dvector(1, m + 1);
580 for(ipj = 0; ipj <= (m << 1); ipj++)
581 {
582 sum = (ipj ? 0.0 : 1.0);
583 for(k = 1; k <= nr; k++)
585 for(k = 1; k <= nl; k++)
587 mm = (ipj < 2 * m - ipj ? ipj : 2 * m - ipj);
588 for(imj = -mm; imj <= mm; imj += 2)
589 a[1 + (ipj + imj) / 2][1 + (ipj - imj) / 2] = sum;
590 }
591 ludcmp(a, m + 1, indx, &d);
592 for(j = 1; j <= m + 1; j++)
593 b[j] = 0.0;
595 lubksb(a, m + 1, indx, b);
596 for(kk = 1; kk <= np; kk++)
597 c[kk] = 0.0;
598 for(k = -nl; k <= nr; k++)
599 {
601 fac = 1.0;
602 for(mm = 1; mm <= m; mm++)
603 sum += b[mm + 1] * (fac *= k);
604 kk = ((np - k) % np) + 1;
606 }
607 free_dvector(b, 1, m + 1);
608 free_dmatrix(a, 1, m + 1, 1, m + 1);
609 free_ivector(indx, 1, m + 1);
610 return (0);
611}
612
613
614
615
616
617
618
619char
620FilterSavitzkyGolay::runFilter(double *y_data_p,
621 double *y_filtered_data_p,
622 int data_point_count) const
623{
624 int np = m_params.nL + 1 + m_params.nR;
626 char retval;
627
628#if CONVOLVE_WITH_NR_CONVLV
629 c = dvector(1, data_point_count);
630 retval = sgcoeff(c, np, m_nL, m_nR, m_lD, m_m);
631 if(retval == 0)
632 convlv(y_data_p, data_point_count, c, np, 1, y_filtered_data_p);
633 free_dvector(c, 1, data_point_count);
634#else
635 int j;
636 long int k;
637 c = dvector(1, m_params.nL + m_params.nR + 1);
638 retval = sgcoeff(c, np, m_params.nL, m_params.nR, m_params.lD, m_params.m);
639 if(retval == 0)
640 {
641 qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
642 << "retval is 0";
643
644 for(k = 1; k <= m_params.nL; k++)
645 {
646 for(y_filtered_data_p[k] = 0.0, j = -m_params.nL; j <= m_params.nR; j++)
647 {
648 if(k + j >= 1)
649 {
650 y_filtered_data_p[k] +=
651 c[(j >= 0 ? j + 1 : m_params.nR + m_params.nL + 2 + j)] * y_data_p[k + j];
652 }
653 }
654 }
655 for(k = m_params.nL + 1; k <= data_point_count - m_params.nR; k++)
656 {
657 for(y_filtered_data_p[k] = 0.0, j = -m_params.nL; j <= m_params.nR; j++)
658 {
659 y_filtered_data_p[k] +=
660 c[(j >= 0 ? j + 1 : m_params.nR + m_params.nL + 2 + j)] * y_data_p[k + j];
661 }
662 }
663 for(k = data_point_count - m_params.nR + 1; k <= data_point_count; k++)
664 {
665 for(y_filtered_data_p[k] = 0.0, j = -m_params.nL; j <= m_params.nR; j++)
666 {
667 if(k + j <= data_point_count)
668 {
669 y_filtered_data_p[k] +=
670 c[(j >= 0 ? j + 1 : m_params.nR + m_params.nL + 2 + j)] * y_data_p[k + j];
671 }
672 }
673 }
674 }
675
676 free_dvector(c, 1, m_params.nR + m_params.nL + 1);
677#endif
678
679 return (retval);
680}
681
682
683}
excetion to use when an item type is not recognized
@ a
peak detected using a single direct MS2 observation
double pappso_double
A type definition for doubles.