File indexing completed on 2024-05-12 03:47:51

0001 /*
0002     File                 : nsl_filter.c
0003     Project              : LabPlot
0004     Description          : NSL Fourier filter functions
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2016 Stefan Gerlach <stefan.gerlach@uni.kn>
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include "nsl_filter.h"
0011 #include "nsl_common.h"
0012 #include "nsl_sf_poly.h"
0013 #include <gsl/gsl_fft_halfcomplex.h>
0014 #include <gsl/gsl_fft_real.h>
0015 #include <gsl/gsl_sf_pow_int.h>
0016 #ifdef HAVE_FFTW3
0017 #include <fftw3.h>
0018 #endif
0019 
0020 const char* nsl_filter_type_name[] = {i18n("Low Pass"), i18n("High Pass"), i18n("Band Pass"), i18n("Band Reject")};
0021 const char* nsl_filter_form_name[] =
0022     {i18n("Ideal"), i18n("Butterworth"), i18n("Chebyshev Type I"), i18n("Chebyshev Type II"), i18n("Legendre (Optimum L)"), i18n("Bessel (Thomson)")};
0023 const char* nsl_filter_cutoff_unit_name[] = {i18n("Frequency"), i18n("Fraction"), i18n("Index")};
0024 
0025 /* n - order, x = w/w0 */
0026 double nsl_filter_gain_bessel(int n, double x) {
0027     gsl_complex z0 = gsl_complex_rect(0.0, 0.0);
0028     gsl_complex z = gsl_complex_rect(0.0, x);
0029     double norm = gsl_complex_abs(nsl_sf_poly_reversed_bessel_theta(n, z));
0030     double value = GSL_REAL(nsl_sf_poly_reversed_bessel_theta(n, z0));
0031     return value / norm;
0032 }
0033 
0034 /* size of data should be n+2 */
0035 int nsl_filter_apply(double data[], size_t n, nsl_filter_type type, nsl_filter_form form, int order, double cutindex, double bandwidth) {
0036     if (cutindex < 0) {
0037         printf("index for cutoff must be >= 0\n");
0038         return -1;
0039     }
0040     if (cutindex > n / 2 + 1) {
0041         printf("index for cutoff must be <= n/2+1\n");
0042         return -1;
0043     }
0044 
0045     size_t i;
0046     double factor, centerindex = cutindex + bandwidth / 2.;
0047     switch (type) {
0048     case nsl_filter_type_low_pass:
0049         switch (form) {
0050         case nsl_filter_form_ideal:
0051             for (i = (size_t)cutindex; i < n / 2 + 1; i++)
0052                 data[2 * i] = data[2 * i + 1] = 0;
0053             break;
0054         case nsl_filter_form_butterworth:
0055             for (i = 0; i < n / 2 + 1; i++) {
0056                 factor = 1. / sqrt(1. + gsl_sf_pow_int(i / cutindex, 2 * order));
0057                 data[2 * i] *= factor;
0058                 data[2 * i + 1] *= factor;
0059             }
0060             break;
0061         case nsl_filter_form_chebyshev_i:
0062             for (i = 0; i < n / 2 + 1; i++) {
0063                 factor = 1. / sqrt(1. + gsl_sf_pow_int(nsl_sf_poly_chebyshev_T(order, i / cutindex), 2));
0064                 data[2 * i] *= factor;
0065                 data[2 * i + 1] *= factor;
0066             }
0067             break;
0068         case nsl_filter_form_chebyshev_ii:
0069             for (i = 1; i < n / 2 + 1; i++) { /* i==0: factor=1 */
0070                 factor = 1. / sqrt(1. + 1. / gsl_sf_pow_int(nsl_sf_poly_chebyshev_T(order, cutindex / i), 2));
0071                 data[2 * i] *= factor;
0072                 data[2 * i + 1] *= factor;
0073             }
0074             break;
0075         case nsl_filter_form_legendre:
0076             for (i = 0; i < n / 2 + 1; i++) {
0077                 factor = 1. / sqrt(1. + nsl_sf_poly_optimal_legendre_L(order, i * i / (cutindex * cutindex)));
0078                 data[2 * i] *= factor;
0079                 data[2 * i + 1] *= factor;
0080             }
0081             break;
0082         case nsl_filter_form_bessel:
0083             for (i = 0; i < n / 2 + 1; i++) {
0084                 factor = nsl_filter_gain_bessel(order, i / cutindex);
0085                 data[2 * i] *= factor;
0086                 data[2 * i + 1] *= factor;
0087             }
0088             break;
0089         }
0090         break;
0091     case nsl_filter_type_high_pass:
0092         switch (form) {
0093         case nsl_filter_form_ideal:
0094             for (i = 0; i < cutindex; i++)
0095                 data[2 * i] = data[2 * i + 1] = 0;
0096             break;
0097         case nsl_filter_form_butterworth:
0098             data[0] = data[1] = 0;
0099             for (i = 1; i < n / 2 + 1; i++) {
0100                 factor = 1. / sqrt(1. + gsl_sf_pow_int(cutindex / i, 2 * order));
0101                 data[2 * i] *= factor;
0102                 data[2 * i + 1] *= factor;
0103             }
0104             break;
0105         case nsl_filter_form_chebyshev_i:
0106             data[0] = data[1] = 0;
0107             for (i = 1; i < n / 2 + 1; i++) {
0108                 factor = 1. / sqrt(1. + gsl_sf_pow_int(nsl_sf_poly_chebyshev_T(order, cutindex / i), 2));
0109                 data[2 * i] *= factor;
0110                 data[2 * i + 1] *= factor;
0111             }
0112             break;
0113         case nsl_filter_form_chebyshev_ii:
0114             for (i = 0; i < n / 2 + 1; i++) {
0115                 factor = 1. / sqrt(1. + 1. / gsl_sf_pow_int(nsl_sf_poly_chebyshev_T(order, i / cutindex), 2));
0116                 data[2 * i] *= factor;
0117                 data[2 * i + 1] *= factor;
0118             }
0119             break;
0120         case nsl_filter_form_legendre:
0121             data[0] = data[1] = 0;
0122             for (i = 1; i < n / 2 + 1; i++) {
0123                 factor = 1. / sqrt(1. + nsl_sf_poly_optimal_legendre_L(order, cutindex * cutindex / (i * i)));
0124                 data[2 * i] *= factor;
0125                 data[2 * i + 1] *= factor;
0126             }
0127             break;
0128         case nsl_filter_form_bessel:
0129             data[0] = data[1] = 0;
0130             for (i = 1; i < n / 2 + 1; i++) {
0131                 factor = nsl_filter_gain_bessel(order, cutindex / i);
0132                 data[2 * i] *= factor;
0133                 data[2 * i + 1] *= factor;
0134             }
0135             break;
0136         }
0137         break;
0138     case nsl_filter_type_band_pass:
0139         switch (form) {
0140         case nsl_filter_form_ideal:
0141             for (i = 0; i < (size_t)cutindex; i++)
0142                 data[2 * i] = data[2 * i + 1] = 0;
0143             for (i = (size_t)(cutindex + bandwidth); i < n / 2 + 1; i++)
0144                 data[2 * i] = data[2 * i + 1] = 0;
0145             break;
0146         case nsl_filter_form_butterworth:
0147             data[0] = data[1] = 0;
0148             for (i = 1; i < n / 2 + 1; i++) {
0149                 factor = 1. / sqrt(1. + gsl_sf_pow_int((i * i - centerindex * centerindex) / i / bandwidth, 2 * order));
0150                 data[2 * i] *= factor;
0151                 data[2 * i + 1] *= factor;
0152             }
0153             break;
0154         case nsl_filter_form_chebyshev_i:
0155             data[0] = data[1] = 0;
0156             for (i = 1; i < n / 2 + 1; i++) {
0157                 factor = 1. / sqrt(1. + gsl_sf_pow_int(nsl_sf_poly_chebyshev_T(order, (i * i - centerindex * centerindex) / i / bandwidth), 2));
0158                 data[2 * i] *= factor;
0159                 data[2 * i + 1] *= factor;
0160             }
0161             break;
0162         case nsl_filter_form_chebyshev_ii:
0163             for (i = 0; i < n / 2 + 1; i++) {
0164                 factor = 1. / sqrt(1. + 1. / gsl_sf_pow_int(nsl_sf_poly_chebyshev_T(order, i * bandwidth / (i * i - centerindex * centerindex)), 2));
0165                 data[2 * i] *= factor;
0166                 data[2 * i + 1] *= factor;
0167             }
0168             break;
0169         case nsl_filter_form_legendre:
0170             data[0] = data[1] = 0;
0171             for (i = 1; i < n / 2 + 1; i++) {
0172                 factor = 1.
0173                     / sqrt(1.
0174                            + nsl_sf_poly_optimal_legendre_L(order,
0175                                                             (i * i - 2. * centerindex * centerindex + gsl_pow_4(centerindex) / (i * i))
0176                                                                 / gsl_pow_2(bandwidth)));
0177                 data[2 * i] *= factor;
0178                 data[2 * i + 1] *= factor;
0179             }
0180             break;
0181         case nsl_filter_form_bessel:
0182             data[0] = data[1] = 0;
0183             for (i = 1; i < n / 2 + 1; i++) {
0184                 factor = nsl_filter_gain_bessel(order, (i * i - centerindex * centerindex) / i / bandwidth);
0185                 data[2 * i] *= factor;
0186                 data[2 * i + 1] *= factor;
0187             }
0188             break;
0189         }
0190         break;
0191     case nsl_filter_type_band_reject:
0192         switch (form) {
0193         case nsl_filter_form_ideal:
0194             for (i = (size_t)cutindex; i < (size_t)(cutindex + bandwidth); i++)
0195                 data[2 * i] = data[2 * i + 1] = 0;
0196             break;
0197         case nsl_filter_form_butterworth:
0198             for (i = 0; i < n / 2 + 1; i++) {
0199                 factor = 1. / sqrt(1. + gsl_sf_pow_int(i * bandwidth / (i * i - centerindex * centerindex), 2 * order));
0200                 data[2 * i] *= factor;
0201                 data[2 * i + 1] *= factor;
0202             }
0203             break;
0204         case nsl_filter_form_chebyshev_i:
0205             for (i = 0; i < n / 2 + 1; i++) {
0206                 factor = 1. / sqrt(1. + gsl_sf_pow_int(nsl_sf_poly_chebyshev_T(order, i * bandwidth / (i * i - centerindex * centerindex)), 2));
0207                 data[2 * i] *= factor;
0208                 data[2 * i + 1] *= factor;
0209             }
0210             break;
0211         case nsl_filter_form_chebyshev_ii:
0212             for (i = 1; i < n / 2 + 1; i++) { /* i==0: factor=1 */
0213                 factor = 1. / sqrt(1. + 1. / gsl_sf_pow_int(nsl_sf_poly_chebyshev_T(order, (i * i - centerindex * centerindex) / i / bandwidth), 2));
0214                 data[2 * i] *= factor;
0215                 data[2 * i + 1] *= factor;
0216             }
0217             break;
0218         case nsl_filter_form_legendre:
0219             for (i = 0; i < n / 2 + 1; i++) {
0220                 factor = 1. / sqrt(1. + nsl_sf_poly_optimal_legendre_L(order, gsl_pow_2(i * bandwidth) / gsl_pow_2(i * i - centerindex * centerindex)));
0221                 data[2 * i] *= factor;
0222                 data[2 * i + 1] *= factor;
0223             }
0224             break;
0225         case nsl_filter_form_bessel:
0226             for (i = 0; i < n / 2 + 1; i++) {
0227                 if (i == centerindex)
0228                     factor = 0;
0229                 else
0230                     factor = nsl_filter_gain_bessel(order, i * bandwidth / (i * i - centerindex * centerindex));
0231                 data[2 * i] *= factor;
0232                 data[2 * i + 1] *= factor;
0233             }
0234             break;
0235         }
0236         break;
0237     }
0238 
0239     return 0;
0240 }
0241 
0242 void print_fdata(double data[], size_t n) {
0243     size_t i;
0244     for (i = 0; i < 2 * (n / 2 + 1); i++)
0245         printf("%g ", data[i]);
0246     printf("\nreal: ");
0247     for (i = 0; i < n / 2 + 1; i++)
0248         printf("%g ", data[2 * i]);
0249     printf("\nimag: ");
0250     for (i = 0; i < n / 2 + 1; i++)
0251         printf("%g ", data[2 * i + 1]);
0252     puts("");
0253 }
0254 
0255 int nsl_filter_fourier(double data[], size_t n, nsl_filter_type type, nsl_filter_form form, int order, int cutindex, int bandwidth) {
0256     /* 1. transform */
0257     double* fdata = (double*)malloc(2 * n * sizeof(double)); /* contains re0,im0,re1,im1,re2,im2,... */
0258 #ifdef HAVE_FFTW3
0259     fftw_plan plan = fftw_plan_dft_r2c_1d((int)n, data, (fftw_complex*)fdata, FFTW_ESTIMATE);
0260     fftw_execute(plan);
0261     fftw_destroy_plan(plan);
0262 #else
0263     gsl_fft_real_wavetable* real = gsl_fft_real_wavetable_alloc(n);
0264     gsl_fft_real_workspace* work = gsl_fft_real_workspace_alloc(n);
0265 
0266     gsl_fft_real_transform(data, 1, n, real, work);
0267     gsl_fft_real_wavetable_free(real);
0268 
0269     gsl_fft_halfcomplex_unpack(data, fdata, 1, n);
0270 #endif
0271 
0272     /* 2. apply filter */
0273     /*print_fdata(fdata, n);*/
0274     int status = nsl_filter_apply(fdata, n, type, form, order, cutindex, bandwidth);
0275     /*print_fdata(fdata, n);*/
0276 
0277     /* 3. back transform */
0278 #ifdef HAVE_FFTW3
0279     plan = fftw_plan_dft_c2r_1d((int)n, (fftw_complex*)fdata, data, FFTW_ESTIMATE);
0280     fftw_execute(plan);
0281     fftw_destroy_plan(plan);
0282     /* normalize*/
0283     size_t i;
0284     for (i = 0; i < n; i++)
0285         data[i] /= n;
0286 #else
0287     gsl_fft_halfcomplex_wavetable* hc = gsl_fft_halfcomplex_wavetable_alloc(n);
0288     gsl_fft_halfcomplex_inverse(data, 1, n, hc, work);
0289     gsl_fft_halfcomplex_wavetable_free(hc);
0290     gsl_fft_real_workspace_free(work);
0291 #endif
0292     free(fdata);
0293 
0294     return status;
0295 }