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 }