SDDSlib
Loading...
Searching...
No Matches
sddsanalyticsignal.c File Reference

SDDS-format Hilbert transform program. More...

#include "mdb.h"
#include "SDDS.h"
#include "scan.h"
#include "fftpackC.h"
#include "SDDSutils.h"
#include <ctype.h>

Go to the source code of this file.

Enumerations

enum  option_type {
  SET_COLUMN , SET_MAJOR_ORDER , SET_PIPE , SET_UNWRAP_LIMIT ,
  N_OPTIONS
}
 

Functions

long process_data (SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, int64_t rows, char *depenQuantity, double unwrapLimit)
 
long create_fft_columns (SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, char *origName)
 
int main (int argc, char **argv)
 

Variables

char * option [N_OPTIONS]
 
static char * USAGE
 

Detailed Description

SDDS-format Hilbert transform program.

This program computes the analytic signal of a real input signal using a Hilbert transform. The result includes the real part, imaginary part, magnitude, and phase (both wrapped and unwrapped).

Algorithm:

  • Perform a complex FFT (Fast Fourier Transform) on the input signal.
  • Eliminate negative frequencies by setting the second half of the FFT output to zero.
  • Multiply the positive frequencies (except DC and Nyquist) by 2.
  • Perform the inverse FFT to obtain the analytic signal.
  • Compute the magnitude and phase of the resulting complex signal.

Output Columns:

  • Real<signal>: Real part of the analytic signal.
  • Imag<signal>: Imaginary part of the analytic signal.
  • Mag<signal>: Magnitude of the analytic signal.
  • Arg<signal>: Wrapped phase of the analytic signal.
  • UnwrappedArg<signal>: Unwrapped phase of the analytic signal.

Usage:

sddsanalyticsignal [inputfile] [outputfile]
--pipe=<input>,<output>
--columns=<indep-variable>,<depen-quantity>[,...]
--unwrapLimit=<value>
--majorOrder=row|column

Options:

  • --pipe: Use standard input/output pipes for data.
  • --columns: Specify the independent and dependent quantities for analysis.
  • --unwrapLimit: Set the relative magnitude threshold for phase unwrapping.
  • --majorOrder: Define the output file's major order (row or column).
License
This file is distributed under the terms of the Software License Agreement found in the file LICENSE included with this distribution.
Author
H. Shang, R. Soliday

Definition in file sddsanalyticsignal.c.

Enumeration Type Documentation

◆ option_type

enum option_type

Definition at line 56 of file sddsanalyticsignal.c.

56 {
57 SET_COLUMN,
58 SET_MAJOR_ORDER,
59 SET_PIPE,
60 SET_UNWRAP_LIMIT,
61 N_OPTIONS
62};

Function Documentation

◆ create_fft_columns()

long create_fft_columns ( SDDS_DATASET * SDDSout,
SDDS_DATASET * SDDSin,
char * origName )

Definition at line 355 of file sddsanalyticsignal.c.

355 {
356 char s[SDDS_MAXLINE];
357 char *origUnits, *origSymbol;
358 char *description, *name, *symbol;
359
360 if (SDDS_GetColumnInformation(SDDSin, "units", &origUnits, SDDS_GET_BY_NAME, origName) != SDDS_STRING ||
361 SDDS_GetColumnInformation(SDDSin, "symbol", &origSymbol, SDDS_GET_BY_NAME, origName) != SDDS_STRING)
362 return 0;
363
364 /* Define Real column */
365 sprintf(s, "Real%s", origName);
366 SDDS_CopyString(&name, s);
367 if (!origSymbol)
368 SDDS_CopyString(&origSymbol, origName);
369 sprintf(s, "Re[%s]", origSymbol);
370 SDDS_CopyString(&symbol, s);
371 sprintf(s, "Real part of %s", origSymbol);
372 SDDS_CopyString(&description, s);
373
374 if (SDDS_DefineColumn(SDDSout, name, symbol, NULL, description, NULL, SDDS_DOUBLE, 0) < 0)
375 return 0;
376 free(name);
377 free(symbol);
378 free(description);
379
380 /* Define Imaginary column */
381 sprintf(s, "Imag%s", origName);
382 SDDS_CopyString(&name, s);
383 if (!origSymbol)
384 SDDS_CopyString(&origSymbol, origName);
385 sprintf(s, "Im[%s]", origSymbol);
386 SDDS_CopyString(&symbol, s);
387 sprintf(s, "Imaginary part of %s", origSymbol);
388 SDDS_CopyString(&description, s);
389
390 if (SDDS_DefineColumn(SDDSout, name, symbol, NULL, description, NULL, SDDS_DOUBLE, 0) < 0)
391 return 0;
392 free(name);
393 free(symbol);
394 free(description);
395
396 /* Define Magnitude column */
397 sprintf(s, "Mag%s", origName);
398 SDDS_CopyString(&name, s);
399
400 if (!origSymbol)
401 SDDS_CopyString(&origSymbol, origName);
402 sprintf(s, "Mag[%s]", origSymbol);
403 SDDS_CopyString(&symbol, s);
404 sprintf(s, "Magnitude of %s", origSymbol);
405 SDDS_CopyString(&description, s);
406 if (SDDS_DefineColumn(SDDSout, name, symbol, NULL, description, NULL, SDDS_DOUBLE, 0) < 0)
407 return 0;
408 free(name);
409 free(symbol);
410 free(description);
411
412 /* Define Phase (Arg) column */
413 sprintf(s, "Arg%s", origName);
414 SDDS_CopyString(&name, s);
415
416 if (!origSymbol)
417 SDDS_CopyString(&origSymbol, origName);
418 sprintf(s, "Arg[%s]", origSymbol);
419 SDDS_CopyString(&symbol, s);
420 sprintf(s, "Phase of %s", origSymbol);
421 SDDS_CopyString(&description, s);
422 if (SDDS_DefineColumn(SDDSout, name, symbol, "degrees", description, NULL, SDDS_DOUBLE, 0) < 0)
423 return 0;
424 free(name);
425 free(symbol);
426 free(description);
427
428 /* Define Unwrapped Phase column */
429 sprintf(s, "UnwrappedArg%s", origName);
430 SDDS_CopyString(&name, s);
431
432 if (!origSymbol)
433 SDDS_CopyString(&origSymbol, origName);
434 sprintf(s, "UnwrappedArg[%s]", origSymbol);
435 SDDS_CopyString(&symbol, s);
436 sprintf(s, "Unwrapped Phase of %s", origSymbol);
437 SDDS_CopyString(&description, s);
438 if (SDDS_DefineColumn(SDDSout, name, symbol, "degrees", description, NULL, SDDS_DOUBLE, 0) < 0)
439 return 0;
440 free(name);
441 free(symbol);
442 free(description);
443
444 return 1;
445}
int32_t SDDS_GetColumnInformation(SDDS_DATASET *SDDS_dataset, char *field_name, void *memory, int32_t mode,...)
Retrieves information about a specified column in the SDDS dataset.
Definition SDDS_info.c:41
int32_t SDDS_DefineColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, int32_t field_length)
Defines a data column within the SDDS dataset.
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
Definition SDDS_utils.c:856
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37

◆ main()

int main ( int argc,
char ** argv )

Definition at line 95 of file sddsanalyticsignal.c.

95 {
96 int iArg;
97 char *indepQuantity, **depenQuantity, **exclude = NULL;
98 long depenQuantities, excludes = 0;
99 char *input, *output;
100 long i, readCode;
101 int64_t rows;
102 int32_t page = 0;
103 unsigned long pipeFlags, majorOrderFlag;
104 SCANNED_ARG *scanned;
105 SDDS_DATASET SDDSin, SDDSout;
106 short columnMajorOrder = -1;
107 double unwrapLimit = 0;
108
110 argc = scanargs(&scanned, argc, argv);
111 if (argc < 3) {
112 fprintf(stderr, "%s\n", USAGE);
113 exit(EXIT_FAILURE);
114 }
115
116 output = input = NULL;
117 pipeFlags = 0;
118 indepQuantity = NULL;
119 depenQuantity = NULL;
120 depenQuantities = 0;
121
122 for (iArg = 1; iArg < argc; iArg++) {
123 if (scanned[iArg].arg_type == OPTION) {
124 /* Process options here */
125 switch (match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
126 case SET_COLUMN:
127 if (indepQuantity)
128 SDDS_Bomb("Only one -columns option may be given");
129 if (scanned[iArg].n_items < 2)
130 SDDS_Bomb("Invalid -columns syntax");
131 indepQuantity = scanned[iArg].list[1];
132 if (scanned[iArg].n_items >= 2) {
133 depenQuantity = tmalloc(sizeof(*depenQuantity) * (depenQuantities = scanned[iArg].n_items - 2));
134 for (i = 0; i < depenQuantities; i++)
135 depenQuantity[i] = scanned[iArg].list[i + 2];
136 }
137 break;
138
139 case SET_PIPE:
140 if (!processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
141 SDDS_Bomb("Invalid -pipe syntax");
142 break;
143
144 case SET_MAJOR_ORDER:
145 majorOrderFlag = 0;
146 scanned[iArg].n_items--;
147 if (scanned[iArg].n_items > 0 &&
148 !scanItemList(&majorOrderFlag, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
149 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
150 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL))
151 SDDS_Bomb("Invalid -majorOrder syntax/values");
152 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
153 columnMajorOrder = 1;
154 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
155 columnMajorOrder = 0;
156 break;
157
158 case SET_UNWRAP_LIMIT:
159 if (scanned[iArg].n_items != 2)
160 SDDS_Bomb("Invalid -unwrapLimit syntax/values");
161 if (!get_double(&unwrapLimit, scanned[iArg].list[1]))
162 SDDS_Bomb("Invalid -unwrapLimit syntax/values");
163 break;
164
165 default:
166 fprintf(stderr, "Error: Unknown or ambiguous option: %s\n", scanned[iArg].list[0]);
167 exit(EXIT_FAILURE);
168 break;
169 }
170 } else {
171 if (!input)
172 input = scanned[iArg].list[0];
173 else if (!output)
174 output = scanned[iArg].list[0];
175 else
176 SDDS_Bomb("Too many filenames provided");
177 }
178 }
179
180 processFilenames("sddsanalyticsignal", &input, &output, pipeFlags, 0, NULL);
181
182 if (!indepQuantity)
183 SDDS_Bomb("Supply the independent quantity name with the -columns option");
184
185 if (!SDDS_InitializeInput(&SDDSin, input))
186 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
187
188 if (SDDS_CheckColumn(&SDDSin, indepQuantity, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OKAY)
189 exit(EXIT_FAILURE);
190
191 excludes = appendToStringArray(&exclude, excludes, indepQuantity);
192
193 if (!depenQuantities)
194 depenQuantities = appendToStringArray(&depenQuantity, depenQuantities, "*");
195
196 if ((depenQuantities = expandColumnPairNames(&SDDSin, &depenQuantity, NULL, depenQuantities,
197 exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
198 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
199 SDDS_Bomb("No quantities selected to FFT");
200 }
201
202#if 0
203 fprintf(stderr, "%ld dependent quantities:\n", depenQuantities);
204 for (i = 0; i < depenQuantities; i++)
205 fprintf(stderr, " %s\n", depenQuantity[i]);
206#endif
207
208 if (!SDDS_InitializeCopy(&SDDSout, &SDDSin, output, "w"))
209 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
210
211 if (columnMajorOrder != -1)
212 SDDSout.layout.data_mode.column_major = columnMajorOrder;
213 else
214 SDDSout.layout.data_mode.column_major = SDDSin.layout.data_mode.column_major;
215
216 for (i = 0; i < depenQuantities; i++) {
217 if (!create_fft_columns(&SDDSout, &SDDSin, depenQuantity[i])) {
218 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
219 fprintf(stderr, "Error creating output column for %s\n", depenQuantity[i]);
220 exit(EXIT_FAILURE);
221 }
222 }
223
224 if (!SDDS_WriteLayout(&SDDSout))
225 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
226
227 while ((readCode = SDDS_ReadPage(&SDDSin)) > 0) {
228 page++;
229 if ((rows = SDDS_CountRowsOfInterest(&SDDSin)) < 0)
230 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
231 if (rows) {
232 if (!SDDS_StartPage(&SDDSout, rows) || !SDDS_CopyPage(&SDDSout, &SDDSin))
233 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
234 for (i = 0; i < depenQuantities; i++) {
235 if (!process_data(&SDDSout, &SDDSin, rows, depenQuantity[i], unwrapLimit)) {
236 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
237 exit(EXIT_FAILURE);
238 }
239 }
240 } else {
241 if (!SDDS_StartPage(&SDDSout, 0) || !SDDS_CopyParameters(&SDDSout, &SDDSin))
242 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
243 }
244 if (!SDDS_WritePage(&SDDSout))
245 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
246 }
247
248 if (!SDDS_Terminate(&SDDSin)) {
249 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
250 exit(EXIT_FAILURE);
251 }
252
253 if (!SDDS_Terminate(&SDDSout)) {
254 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
255 exit(EXIT_FAILURE);
256 }
257
258 /* free_scanargs(&scanned, argc); */
259
260 return EXIT_SUCCESS;
261}
int32_t SDDS_CopyParameters(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
Definition SDDS_copy.c:286
int32_t SDDS_InitializeCopy(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source, char *filename, char *filemode)
Definition SDDS_copy.c:40
int32_t SDDS_CopyPage(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
Definition SDDS_copy.c:578
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int64_t SDDS_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset)
Counts the number of rows marked as "of interest" in the current data table.
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:49
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_ReadPage(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
int32_t SDDS_CheckColumn(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if a column exists in the SDDS dataset with the specified name, units, and type.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:432
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:288
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:342
#define SDDS_ANY_NUMERIC_TYPE
Special identifier used by SDDS_Check*() routines to accept any numeric type.
Definition SDDStypes.h:157
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
Definition array.c:59
int get_double(double *dptr, char *s)
Parses a double value from the given string.
Definition data_scan.c:40
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
Definition scanargs.c:36
long processPipeOption(char **item, long items, unsigned long *flags)
Definition scanargs.c:356
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:390
long scanItemList(unsigned long *flags, char **item, long *items, unsigned long mode,...)
Scans a list of items and assigns values based on provided keywords and types.

◆ process_data()

long process_data ( SDDS_DATASET * SDDSout,
SDDS_DATASET * SDDSin,
int64_t rows,
char * depenQuantity,
double unwrapLimit )

Definition at line 263 of file sddsanalyticsignal.c.

263 {
264 long index1;
265 int64_t i, n_freq, fftrows, nhalf = 0;
266 double *real, *imag, *real_imag, *data, *magData, *arg, *unwrapped, delta, min, max, phase_correction;
267 char s[256];
268
269 if (!(data = SDDS_GetColumnInDoubles(SDDSin, depenQuantity)))
270 return 0;
271
272 fftrows = rows;
273
274 /* Compute forward FFT */
275 real_imag = tmalloc(sizeof(double) * (2 * fftrows + 2));
276 for (i = 0; i < fftrows; i++) {
277 real_imag[2 * i] = data[i];
278 real_imag[2 * i + 1] = 0;
279 }
280 complexFFT(real_imag, fftrows, 0);
281
282 nhalf = fftrows / 2 + 1;
283
284 /* Remove the second half points by setting them to zero */
285 for (i = nhalf; i < fftrows; i++) {
286 real_imag[2 * i] = 0;
287 real_imag[2 * i + 1] = 0;
288 }
289
290 /* Multiply the first half by 2 except f=0 */
291 for (i = 1; i < nhalf; i++) {
292 if (rows % 2 == 0 && i == rows / 2)
293 continue;
294 real_imag[2 * i] *= 2;
295 real_imag[2 * i + 1] *= 2;
296 }
297
298 /* Compute inverse FFT */
299 complexFFT(real_imag, fftrows, INVERSE_FFT);
300 n_freq = fftrows;
301
302 /* Convert into amplitudes and frequencies, adding phase factor for t[0]!=0 */
303 real = tmalloc(sizeof(double) * n_freq);
304 imag = tmalloc(sizeof(double) * n_freq);
305 magData = tmalloc(sizeof(double) * n_freq);
306 arg = tmalloc(sizeof(*arg) * n_freq);
307 unwrapped = tmalloc(sizeof(*arg) * n_freq);
308 for (i = 0; i < n_freq; i++) {
309 real[i] = real_imag[2 * i];
310 imag[i] = real_imag[2 * i + 1];
311 magData[i] = sqrt(sqr(real[i]) + sqr(imag[i]));
312 if (real[i] || imag[i])
313 arg[i] = 180.0 / PI * atan2(imag[i], real[i]);
314 else
315 arg[i] = 0;
316 }
317
318 /* Find the maximum of magnitude */
319 find_min_max(&min, &max, magData, n_freq);
320
321 /* Compute unwrapped phase using Louis' algorithm */
322 phase_correction = 0;
323 for (i = 0; i < n_freq; i++) {
324 if (i && magData[i] / max > unwrapLimit) {
325 delta = arg[i] - arg[i - 1];
326 if (delta < -180.0)
327 phase_correction += 360.0;
328 else if (delta > 180.0)
329 phase_correction -= 360.0;
330 }
331 unwrapped[i] = arg[i] + phase_correction;
332 }
333
334 sprintf(s, "Real%s", depenQuantity);
335 if ((index1 = SDDS_GetColumnIndex(SDDSout, s)) < 0)
336 return 0;
337
338 if (!SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, real, n_freq, index1) ||
339 !SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, imag, n_freq, index1 + 1) ||
340 !SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, magData, n_freq, index1 + 2) ||
341 !SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, arg, n_freq, index1 + 3) ||
342 !SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, unwrapped, n_freq, index1 + 4))
343 return 0;
344
345 free(data);
346 free(real_imag);
347 free(real);
348 free(imag);
349 free(magData);
350 free(arg);
351 free(unwrapped);
352 return 1;
353}
int32_t SDDS_SetColumn(SDDS_DATASET *SDDS_dataset, int32_t mode, void *data, int64_t rows,...)
Sets the values for one data column in the current data table of an SDDS dataset.
double * SDDS_GetColumnInDoubles(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of doubles, considering only rows mark...
int32_t SDDS_GetColumnIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named column in the SDDS dataset.
int find_min_max(double *min, double *max, double *list, int64_t n)
Finds the minimum and maximum values in a list of doubles.
Definition findMinMax.c:33

Variable Documentation

◆ option

char* option[N_OPTIONS]
Initial value:
= {
"columns",
"majorOrder",
"pipe",
"unwrapLimit",
}

Definition at line 64 of file sddsanalyticsignal.c.

64 {
65 "columns",
66 "majorOrder",
67 "pipe",
68 "unwrapLimit",
69};

◆ USAGE

char* USAGE
static
Initial value:
=
"Usage: sddsanalyticsignal [<inputfile>] [<outputfile>]\n"
" [-pipe=<input>,<output>]\n"
" [-unwrapLimit=<value>]\n"
" [-columns=<indep-variable>,<depen-quantity>[,...]]\n"
" [-majorOrder=row|column]\n\n"
"Options:\n"
" -pipe Use standard SDDS Toolkit pipe with optional input and output.\n"
" -columns Specify the independent variable and dependent quantities to analyze.\n"
" <depen-quantity> entries may include wildcards.\n"
" -unwrapLimit Set the relative magnitude limit for phase unwrapping.\n"
" Phase is only unwrapped when the relative magnitude exceeds this limit.\n"
" -majorOrder Define the output file's major order as either 'row' or 'column'.\n\n"
"Description:\n"
" sddsanalyticsignal computes the complex output of a real signal and generates the following columns:\n"
" Real<signal>, Imag<signal>, Mag<signal>, and Arg<signal>.\n"
" These represent the Real part, Imaginary part, Magnitude, and Phase of the signal, respectively.\n\n"
"Program by Hairong Shang and Louis Emery.\n"
"Compiled on " __DATE__ " at " __TIME__ ", SVN revision: " SVN_VERSION "\n"

Definition at line 71 of file sddsanalyticsignal.c.