File indexing completed on 2024-05-12 03:47:50
0001 /* 0002 File : nsl_dft.c 0003 Project : LabPlot 0004 Description : NSL discrete Fourier transform 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_dft.h" 0011 #include "nsl_common.h" 0012 #include <gsl/gsl_fft_halfcomplex.h> 0013 #include <gsl/gsl_fft_real.h> 0014 #ifdef HAVE_FFTW3 0015 #include <fftw3.h> 0016 #endif 0017 0018 const char* nsl_dft_result_type_name[] = {i18n("Magnitude"), 0019 i18n("Amplitude"), 0020 i18n("Real Part"), 0021 i18n("Imaginary Part"), 0022 i18n("Power"), 0023 i18n("Phase"), 0024 i18n("Amplitude in dB"), 0025 i18n("Normalized Amplitude in dB"), 0026 i18n("Magnitude Squared"), 0027 i18n("Amplitude Squared"), 0028 i18n("Raw")}; 0029 const char* nsl_dft_xscale_name[] = {i18n("Frequency"), i18n("Index"), i18n("Period")}; 0030 0031 int nsl_dft_transform_window(double data[], size_t stride, size_t n, int two_sided, nsl_dft_result_type type, nsl_sf_window_type window_type) { 0032 /* apply window function */ 0033 if (window_type != nsl_sf_window_uniform) 0034 nsl_sf_apply_window(data, n, window_type); 0035 0036 /* transform */ 0037 int status = nsl_dft_transform(data, stride, n, two_sided, type); 0038 0039 return status; 0040 } 0041 0042 int nsl_dft_transform(double data[], size_t stride, size_t n, int two_sided, nsl_dft_result_type type) { 0043 if (n < 2) // we need at least 2 points 0044 return 1; 0045 size_t i; 0046 double* result = (double*)malloc(2 * n * sizeof(double)); 0047 size_t N = n / 2; /* number of resulting data points */ 0048 if (two_sided) 0049 N = n; 0050 #ifdef HAVE_FFTW3 0051 /* stride ignored */ 0052 (void)stride; 0053 0054 fftw_plan plan = fftw_plan_dft_r2c_1d((int)n, data, (fftw_complex*)result, FFTW_ESTIMATE); 0055 fftw_execute(plan); 0056 fftw_destroy_plan(plan); 0057 0058 /* 2. unpack data */ 0059 if (two_sided) { 0060 for (i = 1; i < n - i; i++) { 0061 result[2 * (n - i)] = result[2 * i]; 0062 result[2 * (n - i) + 1] = -result[2 * i + 1]; 0063 } 0064 if (i == n - i) { 0065 result[2 * i] = result[2 * (n - 1)]; 0066 result[2 * i + 1] = 0; 0067 } 0068 } 0069 #else 0070 /* 1. transform */ 0071 gsl_fft_real_wavetable* real = gsl_fft_real_wavetable_alloc(n); 0072 gsl_fft_real_workspace* work = gsl_fft_real_workspace_alloc(n); 0073 0074 gsl_fft_real_transform(data, stride, n, real, work); 0075 gsl_fft_real_wavetable_free(real); 0076 gsl_fft_real_workspace_free(work); 0077 0078 /* 2. unpack data */ 0079 gsl_fft_halfcomplex_unpack(data, result, stride, n); 0080 #endif 0081 0082 /* 3. write result */ 0083 switch (type) { 0084 case nsl_dft_result_magnitude: 0085 for (i = 0; i < N; i++) 0086 data[i] = sqrt(gsl_pow_2(result[2 * i]) + gsl_pow_2(result[2 * i + 1])); 0087 break; 0088 case nsl_dft_result_amplitude: 0089 for (i = 0; i < N; i++) { 0090 data[i] = sqrt(gsl_pow_2(result[2 * i]) + gsl_pow_2(result[2 * i + 1])) / n; 0091 if (i > 0) 0092 data[i] *= 2.; 0093 } 0094 break; 0095 case nsl_dft_result_real: 0096 for (i = 0; i < N; i++) 0097 data[i] = result[2 * i]; 0098 break; 0099 case nsl_dft_result_imag: 0100 for (i = 0; i < N; i++) 0101 data[i] = result[2 * i + 1]; 0102 break; 0103 case nsl_dft_result_power: 0104 for (i = 0; i < N; i++) { 0105 data[i] = (gsl_pow_2(result[2 * i]) + gsl_pow_2(result[2 * i + 1])) / n; 0106 if (i > 0) 0107 data[i] *= 2.; 0108 } 0109 break; 0110 case nsl_dft_result_phase: 0111 for (i = 0; i < N; i++) 0112 data[i] = -atan2(result[2 * i + 1], result[2 * i]); 0113 break; 0114 case nsl_dft_result_dB: 0115 for (i = 0; i < N; i++) { 0116 if (i == 0) 0117 data[i] = 20. * log10(sqrt(gsl_pow_2(result[2 * i]) + gsl_pow_2(result[2 * i + 1])) / (double)n); 0118 else 0119 data[i] = 20. * log10(2. * sqrt(gsl_pow_2(result[2 * i]) + gsl_pow_2(result[2 * i + 1])) / (double)n); 0120 } 0121 break; 0122 case nsl_dft_result_normdB: { 0123 double maxdB = 0; 0124 for (i = 0; i < N; i++) { 0125 if (i == 0) 0126 data[i] = 20. * log10(sqrt(gsl_pow_2(result[2 * i]) + gsl_pow_2(result[2 * i + 1])) / (double)n); 0127 else 0128 data[i] = 20. * log10(2. * sqrt(gsl_pow_2(result[2 * i]) + gsl_pow_2(result[2 * i + 1])) / (double)n); 0129 0130 if (i == 0 || maxdB < data[i]) 0131 maxdB = data[i]; 0132 } 0133 for (i = 0; i < N; i++) 0134 data[i] -= maxdB; 0135 break; 0136 } 0137 case nsl_dft_result_squaremagnitude: 0138 for (i = 0; i < N; i++) 0139 data[i] = gsl_pow_2(result[2 * i]) + gsl_pow_2(result[2 * i + 1]); 0140 break; 0141 case nsl_dft_result_squareamplitude: 0142 for (i = 0; i < N; i++) { 0143 data[i] = (gsl_pow_2(result[2 * i]) + gsl_pow_2(result[2 * i + 1])) / gsl_pow_2((double)n); 0144 if (i > 0) 0145 data[i] *= 4.; 0146 } 0147 break; 0148 case nsl_dft_result_raw: 0149 #ifdef HAVE_FFTW3 0150 // write gsl_halfcomplex data 0151 data[0] = result[0]; 0152 for (i = 1; i < N; i++) 0153 data[i] = result[i + 1]; 0154 #endif 0155 break; 0156 } 0157 0158 free(result); 0159 0160 return 0; 0161 }