File indexing completed on 2024-05-12 15:27:06
0001 /*************************************************************************** 0002 File : nsl_corr.c 0003 Project : LabPlot 0004 Description : NSL discrete correlation functions 0005 -------------------------------------------------------------------- 0006 Copyright : (C) 2018 by Stefan Gerlach (stefan.gerlach@uni.kn) 0007 0008 ***************************************************************************/ 0009 0010 /*************************************************************************** 0011 * * 0012 * This program is free software; you can redistribute it and/or modify * 0013 * it under the terms of the GNU General Public License as published by * 0014 * the Free Software Foundation; either version 2 of the License, or * 0015 * (at your option) any later version. * 0016 * * 0017 * This program is distributed in the hope that it will be useful, * 0018 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0020 * GNU General Public License for more details. * 0021 * * 0022 * You should have received a copy of the GNU General Public License * 0023 * along with this program; if not, write to the Free Software * 0024 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0025 * Boston, MA 02110-1301 USA * 0026 * * 0027 ***************************************************************************/ 0028 0029 #include "nsl_corr.h" 0030 #include "nsl_common.h" 0031 #include <gsl/gsl_cblas.h> 0032 #include <gsl/gsl_fft_halfcomplex.h> 0033 #ifdef HAVE_FFTW3 0034 #include <fftw3.h> 0035 #endif 0036 0037 const char* nsl_corr_type_name[] = {i18n("linear (zero-padded)"), i18n("circular")}; 0038 const char* nsl_corr_norm_name[] = {i18n("none"), i18n("biased"), i18n("unbiased"), i18n("coeff")}; 0039 0040 int nsl_corr_correlation(double s[], size_t n, double r[], size_t m, nsl_corr_type_type type, nsl_corr_norm_type normalize, double out[]) { 0041 return nsl_corr_fft_type(s, n, r, m, type, normalize, out); 0042 } 0043 0044 int nsl_corr_fft_type(double s[], size_t n, double r[], size_t m, nsl_corr_type_type type, nsl_corr_norm_type normalize, double out[]) { 0045 size_t i, size, N = GSL_MAX(n, m), maxlag = N - 1; 0046 if (type == nsl_corr_type_linear) 0047 size = maxlag + N; 0048 else // circular 0049 size = N; 0050 0051 size_t oldsize = size; 0052 #ifdef HAVE_FFTW3 0053 // already zero-pad here for FFT method and FFTW r2c 0054 size = 2*(size/2+1); 0055 #endif 0056 0057 // zero-padded arrays 0058 double *stmp = (double*)malloc(size*sizeof(double)); 0059 if (stmp == NULL) { 0060 printf("nsl_corr_fft_type(): ERROR allocating memory for 'stmp'!\n"); 0061 return -1; 0062 } 0063 0064 double *rtmp = (double*)malloc(size*sizeof(double)); 0065 if (rtmp == NULL) { 0066 free(stmp); 0067 printf("nsl_corr_fft_type(): ERROR allocating memory for 'rtmp'!\n"); 0068 return -1; 0069 } 0070 0071 if (type == nsl_corr_type_linear) { 0072 for (i = 0; i < maxlag; i++) 0073 stmp[i] = 0.; 0074 for (i = 0; i < n; i++) 0075 stmp[i+maxlag] = s[i]; 0076 for (i = n+maxlag; i < size; i++) 0077 stmp[i] = 0; 0078 for (i = 0; i < m; i++) 0079 rtmp[i] = r[i]; 0080 for (i = m; i < size; i++) 0081 rtmp[i] = 0; 0082 } else { // circular 0083 for (i = 0; i < n; i++) 0084 stmp[i] = s[i]; 0085 for (i = n; i < N; i++) 0086 stmp[i] = 0.; 0087 for (i = 0; i < m; i++) 0088 rtmp[i] = r[i]; 0089 for (i = m; i < N; i++) 0090 rtmp[i] = 0.; 0091 } 0092 0093 int status; 0094 #ifdef HAVE_FFTW3 // already wraps output 0095 status = nsl_corr_fft_FFTW(stmp, rtmp, oldsize, out); 0096 #else // GSL 0097 status = nsl_corr_fft_GSL(stmp, rtmp, size, out); 0098 #endif 0099 0100 free(stmp); 0101 free(rtmp); 0102 0103 /* normalization */ 0104 switch (normalize) { 0105 case nsl_corr_norm_none: 0106 break; 0107 case nsl_corr_norm_biased: 0108 for (i = 0; i < oldsize; i++) 0109 out[i] = out[i]/N; 0110 break; 0111 case nsl_corr_norm_unbiased: 0112 for (i = 0; i < oldsize; i++) { 0113 size_t norm = i < oldsize/2 ? i+1 : oldsize - i; 0114 out[i] = out[i]/norm; 0115 } 0116 break; 0117 case nsl_corr_norm_coeff: { 0118 double snorm = cblas_dnrm2((int)n, s, 1); 0119 double rnorm = cblas_dnrm2((int)m, r, 1); 0120 for (i = 0; i < oldsize; i++) 0121 out[i] = out[i]/snorm/rnorm; 0122 break; 0123 } 0124 } 0125 0126 // reverse array for circular type 0127 if (type == nsl_corr_type_circular) { 0128 for (i = 0; i < N/2; i++) { 0129 double tmp = out[i]; 0130 out[i] = out[N - i - 1]; 0131 out[N -i - 1] = tmp; 0132 } 0133 } 0134 0135 return status; 0136 } 0137 0138 #ifdef HAVE_FFTW3 0139 int nsl_corr_fft_FFTW(double s[], double r[], size_t n, double out[]) { 0140 if (n <= 0) 0141 return -1; 0142 0143 const size_t size = 2*(n/2+1); 0144 double* in = (double*)malloc(size*sizeof(double)); 0145 fftw_plan rpf = fftw_plan_dft_r2c_1d((int)n, in, (fftw_complex*)in, FFTW_ESTIMATE); 0146 0147 fftw_execute_dft_r2c(rpf, s, (fftw_complex*)s); 0148 fftw_execute_dft_r2c(rpf, r, (fftw_complex*)r); 0149 fftw_destroy_plan(rpf); 0150 0151 size_t i; 0152 0153 // multiply 0154 for (i = 0; i < size; i += 2) { 0155 double re = s[i]*r[i] + s[i+1]*r[i+1]; 0156 double im = s[i+1]*r[i] - s[i]*r[i+1]; 0157 0158 s[i] = re; 0159 s[i+1] = im; 0160 } 0161 0162 // back transform 0163 double* o = (double*)malloc(size*sizeof(double)); 0164 fftw_plan rpb = fftw_plan_dft_c2r_1d((int)n, (fftw_complex*)o, o, FFTW_ESTIMATE); 0165 fftw_execute_dft_c2r(rpb, (fftw_complex*)s, s); 0166 fftw_destroy_plan(rpb); 0167 0168 for (i = 0; i < n; i++) 0169 out[i] = s[i]/n; 0170 0171 free(in); 0172 free(o); 0173 return 0; 0174 } 0175 #endif 0176 0177 int nsl_corr_fft_GSL(double s[], double r[], size_t n, double out[]) { 0178 gsl_fft_real_workspace *work = gsl_fft_real_workspace_alloc(n); 0179 gsl_fft_real_wavetable *real = gsl_fft_real_wavetable_alloc(n); 0180 0181 /* FFT s and r */ 0182 gsl_fft_real_transform(s, 1, n, real, work); 0183 gsl_fft_real_transform(r, 1, n, real, work); 0184 gsl_fft_real_wavetable_free(real); 0185 0186 size_t i; 0187 /* calculate halfcomplex product */ 0188 out[0] = s[0]*r[0]; 0189 for (i = 1; i < n; i++) { 0190 if (i%2) { /* Re */ 0191 out[i] = s[i]*r[i]; 0192 if (i < n-1) /* when n is even last value is real */ 0193 out[i] += s[i+1]*r[i+1]; 0194 } else /* Im */ 0195 out[i] = s[i]*r[i-1] - s[i-1]*r[i]; 0196 } 0197 0198 /* back transform */ 0199 gsl_fft_halfcomplex_wavetable *hc = gsl_fft_halfcomplex_wavetable_alloc(n); 0200 gsl_fft_halfcomplex_inverse(out, 1, n, hc, work); 0201 gsl_fft_halfcomplex_wavetable_free(hc); 0202 gsl_fft_real_workspace_free(work); 0203 0204 return 0; 0205 }