Instrument Neutral Distributed Interface INDI  2.0.2
fft.c
Go to the documentation of this file.
1 /*
2 * DSP API - a digital signal processing library for astronomy usage
3 * Copyright © 2017-2022 Ilia Platone
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 3 of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19 
20 #include "dsp.h"
21 #include <fftw3.h>
22 
23 static void dsp_fourier_dft_magnitude(dsp_stream_p stream)
24 {
25  if(stream->magnitude)
26  stream->magnitude->buf = dsp_fourier_complex_array_get_magnitude(stream->dft, stream->len);
27 }
28 
29 static void dsp_fourier_dft_phase(dsp_stream_p stream)
30 {
31  if(stream->phase)
32  stream->phase->buf = dsp_fourier_complex_array_get_phase(stream->dft, stream->len);
33 }
34 
36 {
37  int x, y;
38  complex_t *dft = (complex_t*)malloc(sizeof(complex_t) * stream->len);
39  memcpy(dft, stream->dft.pairs, sizeof(complex_t) * stream->len);
40  y = 0;
41  for(x = 0; x < stream->len && y < stream->len; x++) {
42  int *pos = dsp_stream_get_position(stream, x);
43  if(pos[0] <= stream->sizes[0] / 2) {
44  stream->dft.pairs[x][0] = dft[y][0];
45  stream->dft.pairs[x][1] = dft[y][1];
46  stream->dft.pairs[stream->len-1-x][0] = dft[y][0];
47  stream->dft.pairs[stream->len-1-x][1] = dft[y][1];
48  y++;
49  }
50  free(pos);
51  }
52  dsp_fourier_dft_magnitude(stream);
53  dsp_buffer_shift(stream->magnitude);
54  dsp_fourier_dft_phase(stream);
55  dsp_buffer_shift(stream->phase);
56 }
57 
59 {
60  int x, y;
61  if(!stream->phase || !stream->magnitude) return;
62  dsp_buffer_shift(stream->magnitude);
63  dsp_buffer_shift(stream->phase);
64  dsp_fourier_phase_mag_array_get_complex(stream->magnitude->buf, stream->phase->buf, (complex_t*)stream->dft.pairs, stream->len);
65  complex_t *dft = (complex_t*)malloc(sizeof(complex_t) * stream->len);
66  memcpy(dft, stream->dft.pairs, sizeof(complex_t) * stream->len);
67  dsp_buffer_set(stream->dft.buf, stream->len*2, 0);
68  y = 0;
69  for(x = 0; x < stream->len; x++) {
70  int *pos = dsp_stream_get_position(stream, x);
71  if(pos[0] <= stream->sizes[0] / 2) {
72  stream->dft.pairs[y][0] = dft[x][0];
73  stream->dft.pairs[y][1] = dft[x][1];
74  y++;
75  }
76  free(pos);
77  }
78  free(dft);
79 }
80 
82 {
83  int i;
84  double* out = (double*)malloc(sizeof(double) * len);
85  for(i = 0; i < len; i++) {
86  double real = in.complex[i].real;
87  double imaginary = in.complex[i].imaginary;
88  out [i] = sqrt (pow(real, 2)+pow(imaginary, 2));
89  }
90  return out;
91 }
92 
94 {
95  int i;
96  double* out = (double*)malloc(sizeof(double) * len);
97  for(i = 0; i < len; i++) {
98  out [i] = 0;
99  if (in.complex[i].real != 0) {
100  double real = in.complex[i].real;
101  double imaginary = in.complex[i].imaginary;
102  double mag = sqrt(pow(real, 2)+pow(imaginary, 2));
103  double rad = 0.0;
104  if(mag > 0.0) {
105  rad = acos (imaginary / (mag > 0.0 ? mag : 1.0));
106  if(real < 0 && rad != 0)
107  rad = M_PI*2-rad;
108  }
109  out [i] = rad;
110  }
111  }
112  return out;
113 }
114 
115 void dsp_fourier_phase_mag_array_get_complex(double* mag, double* phi, complex_t* out, int len)
116 {
117  int i;
118  for(i = 0; i < len; i++) {
119  double real = sin(phi[i])*mag[i];
120  double imaginary = cos(phi[i])*mag[i];
121  out[i][0] = real;
122  out[i][1] = imaginary;
123  }
124 }
125 
126 static void* dsp_stream_dft_th(void* arg)
127 {
128  struct {
129  int exp;
130  dsp_stream_p stream;
131  } *arguments = arg;
132  dsp_fourier_dft(arguments->stream, arguments->exp);
133  return NULL;
134 }
135 void dsp_fourier_dft(dsp_stream_p stream, int exp)
136 {
137  if(exp < 1)
138  return;
139  double* buf = (double*)malloc(sizeof(double) * stream->len);
140  if(stream->phase == NULL)
141  stream->phase = dsp_stream_copy(stream);
142  if(stream->magnitude == NULL)
143  stream->magnitude = dsp_stream_copy(stream);
144  dsp_buffer_set(stream->dft.buf, stream->len * 2, 0);
145  dsp_buffer_copy(stream->buf, buf, stream->len);
146  int *sizes = (int*)malloc(sizeof(int)*stream->dims);
147  dsp_buffer_reverse(sizes, stream->dims);
148  fftw_plan plan = fftw_plan_dft_r2c(stream->dims, stream->sizes, buf, stream->dft.pairs, FFTW_ESTIMATE_PATIENT);
149  fftw_execute(plan);
150  fftw_free(plan);
151  free(sizes);
152  free(buf);
153  dsp_fourier_2dsp(stream);
154  if(exp > 1) {
155  exp--;
156  pthread_t th[2];
157  struct {
158  int exp;
159  dsp_stream_p stream;
160  } thread_arguments[2];
161  thread_arguments[0].exp = exp;
162  thread_arguments[0].stream = stream->phase;
163  pthread_create(&th[0], NULL, dsp_stream_dft_th, &thread_arguments[0]);
164  thread_arguments[1].exp = exp;
165  thread_arguments[1].stream = stream->magnitude;
166  pthread_create(&th[1], NULL, dsp_stream_dft_th, &thread_arguments[1]);
167  pthread_join(th[0], NULL);
168  pthread_join(th[1], NULL);
169  }
170 }
171 
173 {
174  double *buf = (double*)malloc(sizeof(double)*stream->len);
175  dsp_t mn = dsp_stats_min(stream->buf, stream->len);
176  dsp_t mx = dsp_stats_max(stream->buf, stream->len);
177  dsp_buffer_set(buf, stream->len, 0);
178  dsp_fourier_2complex_t(stream);
179  int *sizes = (int*)malloc(sizeof(int)*stream->dims);
180  dsp_buffer_reverse(sizes, stream->dims);
181  fftw_plan plan = fftw_plan_dft_c2r(stream->dims, stream->sizes, stream->dft.pairs, buf, FFTW_ESTIMATE_PATIENT);
182  fftw_execute(plan);
183  fftw_free(plan);
184  free(sizes);
185  dsp_buffer_stretch(buf, stream->len, mn, mx);
186  dsp_buffer_copy(buf, stream->buf, stream->len);
187  dsp_buffer_shift(stream->magnitude);
188  dsp_buffer_shift(stream->phase);
189  free(buf);
190 }
std::thread th
double dsp_t
Definition: dsp.h:69
double complex_t[2]
Definition: dsp.h:70
struct dsp_stream_t * phase
Fourier transform phase.
Definition: dsp.h:413
double imaginary
Imaginary part of the complex number.
Definition: dsp.h:305
int * sizes
Sizes of each dimension.
Definition: dsp.h:373
dsp_complex dft
Fourier transform.
Definition: dsp.h:377
double * buf
Linear double array containing complex numbers.
Definition: dsp.h:310
struct dsp_stream_t * magnitude
Fourier transform magnitude.
Definition: dsp.h:411
struct dsp_complex::@215 * complex
Complex struct type array.
int dims
Number of dimensions of the buffers.
Definition: dsp.h:371
dsp_t * buf
buffer
Definition: dsp.h:375
int len
The buffers length.
Definition: dsp.h:369
double real
Real part of the complex number.
Definition: dsp.h:303
complex_t * pairs
Complex number type array used with libFFTW.
Definition: dsp.h:308
#define dsp_buffer_copy(in, out, len)
Fill the output buffer with the values of the elements of the input stream by casting them to the out...
Definition: dsp.h:1038
void dsp_buffer_shift(dsp_stream_p stream)
Shift a stream on each dimension.
Definition: buffer.c:24
#define dsp_buffer_set(buf, len, _val)
Fill the buffer with the passed value.
Definition: dsp.h:815
#define dsp_buffer_reverse(buf, len)
Reverse the order of the buffer elements.
Definition: dsp.h:991
#define dsp_buffer_stretch(buf, len, _mn, _mx)
Stretch minimum and maximum values of the input stream.
Definition: dsp.h:792
DLL_EXPORT int * dsp_stream_get_position(dsp_stream_p stream, int index)
Return the multidimensional positional indexes of a DSP stream by specify a linear index.
Definition: stream.c:420
DLL_EXPORT dsp_stream_p dsp_stream_copy(dsp_stream_p stream)
Create a copy of the DSP stream passed as argument.
Definition: stream.c:192
double * dsp_fourier_complex_array_get_phase(dsp_complex in, int len)
Obtain a complex number's array phases.
Definition: fft.c:93
void dsp_fourier_idft(dsp_stream_p stream)
Perform an inverse discrete Fourier Transform of a dsp_stream.
Definition: fft.c:172
void dsp_fourier_2complex_t(dsp_stream_p stream)
Obtain the complex fourier tranform from the current magnitude and phase buffers.
Definition: fft.c:58
double * dsp_fourier_complex_array_get_magnitude(dsp_complex in, int len)
Obtain a complex number's array magnitudes.
Definition: fft.c:81
void dsp_fourier_phase_mag_array_get_complex(double *mag, double *phi, complex_t *out, int len)
Obtain a complex array from phase and magnitude arrays.
Definition: fft.c:115
void dsp_fourier_2dsp(dsp_stream_p stream)
Fill the magnitude and phase buffers with the current data in stream->dft.
Definition: fft.c:35
void dsp_fourier_dft(dsp_stream_p stream, int exp)
Perform a discrete Fourier Transform of a dsp_stream.
Definition: fft.c:135
#define dsp_stats_min(buf, len)
Gets the minimum value of the input stream.
Definition: dsp.h:562
#define dsp_stats_max(buf, len)
Gets the maximum value of the input stream.
Definition: dsp.h:580
Contains a set of informations and data relative to a buffer and how to use it.
Definition: dsp.h:363
Complex number array struct, used in Fourier Transform functions.
Definition: dsp.h:298