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 }