5 * Copyright (C) 2006 Laurency Franck
6 * Copyright (C) 2007 Jean Bréfort <jean.brefort@normalesup.org>
7 * Copyright (C) 2009 Andreas Guelzow <aguelzow@pyrshep.ca>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <https://www.gnu.org/licenses/>
24 /***************************************************************
25 * This file contains all declarations of time series analysis
26 * functions and their help functions
27 ****************************************************************/
29 #include <gnumeric-config.h>
32 #include <parse-util.h>
34 #include <rangefunc.h>
35 #include <regression.h>
40 #include <number-match.h>
43 #include <func-builtin.h>
45 #include <goffice/goffice.h>
46 #include <gnm-plugin.h>
47 #include <tools/analysis-tools.h>
54 GNM_PLUGIN_MODULE_HEADER
;
65 INTERPOLATION_LINEAR
= 0,
66 INTERPOLATION_LINEAR_AVG
,
67 INTERPOLATION_STAIRCASE
,
68 INTERPOLATION_STAIRCASE_AVG
,
70 INTERPOLATION_SPLINE_AVG
,
73 #ifdef GNM_WITH_LONG_DOUBLE
74 # define GnmCSpline GOCSplinel
75 # define gnm_cspline_init go_cspline_initl
76 # define gnm_cspline_destroy go_cspline_destroyl
77 # define gnm_cspline_get_value go_cspline_get_valuel
78 # define gnm_cspline_get_values go_cspline_get_valuesl
79 # define gnm_cspline_get_integrals go_cspline_get_integralsl
81 # define GnmCSpline GOCSpline
82 # define gnm_cspline_init go_cspline_init
83 # define gnm_cspline_destroy go_cspline_destroy
84 # define gnm_cspline_get_value go_cspline_get_value
85 # define gnm_cspline_get_values go_cspline_get_values
86 # define gnm_cspline_get_integrals go_cspline_get_integrals
89 #define INTERPOLATIONMETHODS { GNM_FUNC_HELP_DESCRIPTION, F_("Possible interpolation methods are:\n" \
91 "1: linear with averaging;\n" \
93 "3: staircase with averaging;\n" \
94 "4: natural cubic spline;\n" \
95 "5: natural cubic spline with averaging.") }
97 /**************************************************************************/
98 /**************************************************************************/
99 /* CALCULATION FUNCTIONS FOR TOOLS */
100 /**************************************************************************/
101 /**************************************************************************/
104 gnm_fourier_fft (gnm_complex
const *in
, int n
, int skip
, gnm_complex
**fourier
, gboolean inverse
)
106 gnm_complex
*fourier_1
, *fourier_2
;
111 *fourier
= g_new (gnm_complex
, n
);
114 (*fourier
)[0] = in
[0];
118 gnm_fourier_fft (in
, nhalf
, skip
* 2, &fourier_1
, inverse
);
119 gnm_fourier_fft (in
+ skip
, nhalf
, skip
* 2, &fourier_2
, inverse
);
121 argstep
= (inverse
? M_PIgnum
: -M_PIgnum
) / nhalf
;
122 for (i
= 0; i
< nhalf
; i
++) {
123 gnm_complex dir
, tmp
;
125 dir
= GNM_CPOLAR (1, argstep
* i
);
126 tmp
= GNM_CMUL (fourier_2
[i
], dir
);
128 (*fourier
)[i
] = GNM_CSCALE (GNM_CADD (fourier_1
[i
], tmp
), 0.5);
130 (*fourier
)[i
+ nhalf
] = GNM_CSCALE (GNM_CSUB (fourier_1
[i
], tmp
), 0.5);
138 /*******LINEAR INTERPOLATION*******/
141 linear_interpolation (const gnm_float
*absc
, const gnm_float
*ord
, int nb_knots
,
142 const gnm_float
*targets
, int nb_targets
)
144 int i
, j
, k
, jmax
= nb_knots
- 1;
145 gnm_float slope
, *res
;
148 res
= g_new (gnm_float
, nb_targets
);
149 if (gnm_range_increasing (targets
, nb_targets
)) {
152 slope
= (ord
[1] - ord
[0]) / (absc
[1] - absc
[0]);
153 for (i
= 0; i
< nb_targets
; i
++) {
154 while (j
< jmax
&& targets
[i
] > absc
[j
])
158 slope
= (ord
[j
] - ord
[k
]) / (absc
[j
] - absc
[k
]);
160 res
[i
] = (targets
[i
] - absc
[k
]) * slope
+ ord
[k
];
164 for (i
= 0; i
< nb_targets
; i
++) {
166 if (targets
[i
] >= absc
[k
])
167 res
[i
] = (targets
[i
] - absc
[k
]) *
168 (ord
[jmax
] - ord
[k
]) / (absc
[jmax
] - absc
[k
])
170 else if (targets
[i
] <= absc
[1])
171 res
[i
] = (targets
[i
] - absc
[0]) *
172 (ord
[1] - ord
[0]) / (absc
[1] - absc
[0])
178 if (targets
[i
] > absc
[l
])
183 res
[i
] = (targets
[i
] - absc
[j
]) *
184 (ord
[k
] - ord
[j
]) / (absc
[k
] - absc
[j
])
192 /*******LINEAR AVERAGING*******/
195 linear_averaging (const gnm_float
*absc
, const gnm_float
*ord
, int nb_knots
,
196 const gnm_float
*targets
, int nb_targets
)
198 int i
, j
, k
, jmax
= nb_knots
- 1;
199 gnm_float slope
, *res
, x0
, x1
;
200 if (nb_knots
< 2 || !gnm_range_increasing (targets
, nb_targets
+ 1))
202 res
= g_new (gnm_float
, nb_targets
);
204 while (j
< jmax
&& targets
[0] > absc
[j
])
207 slope
= (ord
[j
] - ord
[k
]) / (absc
[j
] - absc
[k
]) / 2.;
208 for (i
= 1; i
<= nb_targets
; i
++) {
209 if (targets
[i
] < absc
[j
] || j
== jmax
) {
210 x0
= targets
[i
- 1] - absc
[k
];
211 x1
= targets
[i
] - absc
[k
];
212 res
[i
- 1] = (x1
* (slope
* x1
+ ord
[k
])
213 - x0
* (slope
* x0
+ ord
[k
]))
217 x0
= targets
[i
- 1] - absc
[k
];
218 x1
= absc
[j
] - absc
[k
];
219 res
[i
- 1] = (x1
* (slope
* x1
+ ord
[k
])
220 - x0
* (slope
* x0
+ ord
[k
]));
221 while (j
< jmax
&& targets
[i
] > absc
[++j
]) {
223 x0
= absc
[j
] - absc
[k
];
224 slope
= (ord
[j
] - ord
[k
]) / x0
/ 2.;
225 res
[i
- 1] += x0
* (slope
* x0
+ ord
[k
]);
229 slope
= (ord
[j
] - ord
[k
]) / (absc
[j
] - absc
[k
]) / 2.;
232 x0
= targets
[i
] - absc
[k
];
233 res
[i
- 1] += x0
* (slope
* x0
+ ord
[k
]);
234 res
[i
- 1] /= (targets
[i
] - targets
[i
- 1]);
239 /*******STAIRCASE INTERPOLATION*******/
242 staircase_interpolation (const gnm_float
*absc
, const gnm_float
*ord
, int nb_knots
,
243 const gnm_float
*targets
, int nb_targets
)
245 int i
, j
, jmax
= nb_knots
- 1;
251 res
= g_new (gnm_float
, nb_targets
);
252 if (gnm_range_increasing (targets
, nb_targets
)) {
254 for (i
= 0; i
< nb_targets
; i
++) {
255 while (j
<= jmax
&& targets
[i
] >= absc
[j
])
261 for (i
= 0; i
< nb_targets
; i
++) {
263 if (targets
[i
] >= absc
[jmax
])
269 if (targets
[i
] >= absc
[l
])
274 if (k
!= j
&& targets
[i
] >= absc
[k
])
283 /*******STAIRCASE AVERAGING*******/
286 staircase_averaging (const gnm_float
*absc
, const gnm_float
*ord
, int nb_knots
,
287 const gnm_float
*targets
, int nb_targets
)
289 int i
, j
, jmax
= nb_knots
- 1;
296 if (!gnm_range_increasing (targets
, nb_targets
+ 1))
298 res
= g_new (gnm_float
, nb_targets
);
300 while (j
<= jmax
&& targets
[0] >= absc
[j
])
302 for (i
= 1; i
<= nb_targets
; i
++) {
303 if (j
> jmax
|| targets
[i
] < absc
[j
]) {
304 res
[i
- 1] = ord
[j
- 1];
307 res
[i
- 1] = (absc
[j
] - targets
[i
- 1]) * ord
[j
- 1];
308 while (j
< jmax
&& targets
[i
] >= absc
[++j
])
309 res
[i
- 1] += (absc
[j
] - absc
[j
- 1]) * ord
[j
- 1];
310 if (targets
[i
] >= absc
[j
])
312 res
[i
- 1] += (targets
[i
] - absc
[j
- 1]) * ord
[j
- 1];
313 res
[i
- 1] /= (targets
[i
] - targets
[i
- 1]);
318 /*******SPLINE INTERPOLATION*******/
321 spline_interpolation (const gnm_float
*absc
, const gnm_float
*ord
, int nb_knots
,
322 const gnm_float
*targets
, int nb_targets
)
326 GnmCSpline
*sp
= gnm_cspline_init (absc
, ord
, nb_knots
,
327 GO_CSPLINE_NATURAL
, 0., 0.);
330 if (gnm_range_increasing (targets
, nb_targets
))
331 res
= gnm_cspline_get_values (sp
, targets
, nb_targets
);
333 res
= g_new (gnm_float
, nb_targets
);
334 for (i
= 0; i
< nb_targets
; i
++)
335 res
[i
] = gnm_cspline_get_value (sp
, targets
[i
]);
337 gnm_cspline_destroy (sp
);
341 /*******SPLINE AVERAGING*******/
344 spline_averaging (const gnm_float
*absc
, const gnm_float
*ord
, int nb_knots
,
345 const gnm_float
*targets
, int nb_targets
)
350 if (!gnm_range_increasing (targets
, nb_targets
+ 1))
352 sp
= gnm_cspline_init (absc
, ord
, nb_knots
,
353 GO_CSPLINE_NATURAL
, 0., 0.);
356 res
= gnm_cspline_get_integrals (sp
, targets
, nb_targets
+ 1);
358 for (i
= 0; i
< imax
; i
++)
359 res
[i
] /= targets
[i
+ 1] - targets
[i
];
360 gnm_cspline_destroy (sp
);
364 /*******Interpolation procedure********/
366 typedef gnm_float
* (*INTERPPROC
) (const gnm_float
*, const gnm_float
*,
367 int, const gnm_float
*, int);
369 /******************************************************************************/
370 /* INTERPOLATION FUNCTION */
371 /******************************************************************************/
373 static GnmFuncHelp
const help_interpolation
[] = {
374 { GNM_FUNC_HELP_NAME
, F_("INTERPOLATION:interpolated values corresponding to the given abscissa targets") },
375 { GNM_FUNC_HELP_ARG
, F_("abscissae:abscissae of the given data points") },
376 { GNM_FUNC_HELP_ARG
, F_("ordinates:ordinates of the given data points") },
377 { GNM_FUNC_HELP_ARG
, F_("targets:abscissae of the interpolated data") },
378 { GNM_FUNC_HELP_ARG
, F_("interpolation:method of interpolation, defaults to 0 (\'linear\')") },
379 { GNM_FUNC_HELP_DESCRIPTION
, F_("The output consists always of one column of numbers.") },
380 INTERPOLATIONMETHODS
,
381 { GNM_FUNC_HELP_NOTE
, F_("The @{abscissae} should be given in increasing order. If the @{abscissae} is not in "
382 "increasing order the INTERPOLATION function is significantly slower.") },
383 { GNM_FUNC_HELP_NOTE
, F_("If any two @{abscissae} values are equal an error is returned.") },
384 { GNM_FUNC_HELP_NOTE
, F_("If any of interpolation methods 1 ('linear with averaging'), 3 "
385 "('staircase with averaging'), and 5 ('natural cubic spline with "
386 "averaging') is used, the number "
387 "of returned values is one less than the number of targets and the target "
388 "values must be given in increasing order. The values returned "
389 "are the average heights of the interpolation function on the intervals "
390 "determined by consecutive target values.") },
391 { GNM_FUNC_HELP_NOTE
, F_("Strings and empty cells in @{abscissae} and @{ordinates} are ignored.") },
392 { GNM_FUNC_HELP_NOTE
, F_("If several target data are provided they must be in the same column in consecutive cells.") },
393 { GNM_FUNC_HELP_EXAMPLES
, "=interpolation(array(1,2,3),array(10,20,20),1.5,0)" },
394 { GNM_FUNC_HELP_EXAMPLES
, "=interpolation(array(1,2,3),array(10,20,20),array(1.5,4),1)" },
395 { GNM_FUNC_HELP_SEEALSO
, "PERIODOGRAM" },
396 { GNM_FUNC_HELP_END
, NULL
}
400 gnumeric_interpolation (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
402 gnm_float
*vals0
, *vals1
, *vals2
, *fres
;
405 GnmValue
*error
= NULL
;
408 GnmEvalPos
const * const ep
= ei
->pos
;
409 GnmValue
const * const PtInterpolation
= argv
[2];
411 GSList
*missing2
= NULL
, *missing
;
412 INTERPPROC interpproc
= NULL
;
413 gboolean constp
= FALSE
;
417 int const cols
= value_area_get_width (PtInterpolation
, ep
);
418 int const rows
= value_area_get_height (PtInterpolation
, ep
);
420 if (rows
== 0 || cols
!= 1) {
421 res
= value_new_error_std (ei
->pos
, GNM_ERROR_VALUE
);
425 flags
= COLLECT_IGNORE_BLANKS
| COLLECT_IGNORE_STRINGS
| COLLECT_IGNORE_BOOLS
| COLLECT_IGNORE_ERRORS
;
426 vals2
= collect_floats_value_with_info (PtInterpolation
, ei
->pos
, flags
,
427 &n2
, &missing2
, &error
);
429 g_slist_free (missing2
);
436 interp
= (int) gnm_floor (value_get_as_float (argv
[3]));
437 if (interp
< 0 || interp
> INTERPOLATION_SPLINE_AVG
) {
438 g_slist_free (missing2
);
440 return value_new_error_VALUE (ei
->pos
);
443 interp
= INTERPOLATION_LINEAR
;
446 case INTERPOLATION_LINEAR
:
447 interpproc
= linear_interpolation
;
449 case INTERPOLATION_LINEAR_AVG
:
450 interpproc
= linear_averaging
;
453 case INTERPOLATION_STAIRCASE
:
454 interpproc
= staircase_interpolation
;
456 case INTERPOLATION_STAIRCASE_AVG
:
457 interpproc
= staircase_averaging
;
460 case INTERPOLATION_SPLINE
:
461 interpproc
= spline_interpolation
;
463 case INTERPOLATION_SPLINE_AVG
:
464 interpproc
= spline_averaging
;
470 g_slist_free (missing2
);
472 return value_new_error_std (ei
->pos
, GNM_ERROR_VALUE
);
475 /* argv[0] & argv[1] */
477 flags
= COLLECT_IGNORE_BLANKS
| COLLECT_IGNORE_STRINGS
| COLLECT_IGNORE_BOOLS
;
478 error
= collect_float_pairs (argv
[0], argv
[1], ei
->pos
, flags
, &vals0
, &vals1
,
482 g_slist_free (missing2
);
487 /* Check whether the abscissae are increasing, if not order them */
488 if (!gnm_range_increasing (vals0
, n0
)) {
489 gboolean switched
= TRUE
;
491 vals0
= g_memdup (vals0
, sizeof(gnm_float
) * n0
);
492 vals1
= g_memdup (vals1
, sizeof(gnm_float
) * n0
);
498 for (i
= 1, val
= vals0
; i
< n0
; i
++, val
++) {
499 if (*val
== *(val
+ 1)) {
500 res
= value_new_error_std (ei
->pos
, GNM_ERROR_VALUE
) ;
503 if (*val
> *(val
+ 1)) {
508 *(vals1
+ i
) = *(vals1
+ i
- 1);
509 *(vals1
+ i
- 1) = v
;
520 gnm_strip_missing (vals2
, &n
, missing2
);
521 res
= value_new_array_non_init (1 , n2
);
524 res
->v_array
.vals
[0] = g_new (GnmValue
*, n2
);
526 fres
= interpproc (vals0
, vals1
, n0
, vals2
, n
);
530 for (r
= 0 ; r
< n2
; ++r
)
531 if (missing
&& r
== GPOINTER_TO_INT (missing
->data
)) {
532 missing
= missing
->next
;
533 res
->v_array
.vals
[0][r
] = value_new_error_std (ei
->pos
, GNM_ERROR_VALUE
);
535 res
->v_array
.vals
[0][r
] = value_new_float (fres
[i
++]);
538 for( r
= 0 ; r
< n2
; ++r
)
539 res
->v_array
.vals
[0][r
] = value_new_error_std (ei
->pos
, GNM_ERROR_VALUE
);
545 g_slist_free (missing2
);
554 /*********************************************************************************************************/
556 /******************************************************************************/
557 /* PERIODOGRAM WITH INTERPOLATION FUNCTION */
558 /******************************************************************************/
560 static GnmFuncHelp
const help_periodogram
[] = {
561 { GNM_FUNC_HELP_NAME
, F_("PERIODOGRAM:periodogram of the given data") },
562 { GNM_FUNC_HELP_ARG
, F_("ordinates:ordinates of the given data") },
563 { GNM_FUNC_HELP_ARG
, F_("filter:windowing function to be used, defaults to no filter") },
564 { GNM_FUNC_HELP_ARG
, F_("abscissae:abscissae of the given data, defaults to regularly spaced abscissae") },
565 { GNM_FUNC_HELP_ARG
, F_("interpolation:method of interpolation, defaults to none") },
566 { GNM_FUNC_HELP_ARG
, F_("number:number of interpolated data points") },
567 { GNM_FUNC_HELP_DESCRIPTION
, F_("If an interpolation method is used, the number of returned values is one less than the number of targets and the targets values must be given in increasing order.") },
568 { GNM_FUNC_HELP_DESCRIPTION
, F_("The output consists always of one column of numbers.") },
569 INTERPOLATIONMETHODS
,
570 { GNM_FUNC_HELP_DESCRIPTION
, F_("Possible window functions are:\n"
571 "0: no filter (rectangular window)\n"
572 "1: Bartlett (triangular window)\n"
573 "2: Hahn (cosine window)\n"
574 "3: Welch (parabolic window)") },
575 { GNM_FUNC_HELP_NOTE
, F_("Strings and empty cells in @{abscissae} and @{ordinates} are ignored.") },
576 { GNM_FUNC_HELP_NOTE
, F_("If several target data are provided they must be in the same column in consecutive cells.") },
577 { GNM_FUNC_HELP_SEEALSO
, "INTERPOLATION" },
578 { GNM_FUNC_HELP_END
, NULL
}
582 gnumeric_periodogram (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
584 gnm_float
*ord
, *absc
;
587 GnmValue
*error
= NULL
;
590 GnmEvalPos
const * const ep
= ei
->pos
;
591 GnmValue
const * const Pt
= argv
[0];
593 GSList
*missing0
= NULL
, *missing1
= NULL
;
594 gnm_complex
*in
, *out
= NULL
;
596 int const cols
= value_area_get_width (Pt
, ep
);
597 int const rows
= value_area_get_height (Pt
, ep
);
609 res
= value_new_error_std (ei
->pos
, GNM_ERROR_VALUE
);
613 flags
=COLLECT_IGNORE_BLANKS
| COLLECT_IGNORE_STRINGS
| COLLECT_IGNORE_BOOLS
;
615 ord
= collect_floats_value_with_info (argv
[0], ei
->pos
, flags
,
616 &n0
, &missing0
, &error
);
618 g_slist_free (missing0
);
623 res
= value_new_error_std (ei
->pos
, GNM_ERROR_VALUE
);
628 filter
= (int) gnm_floor (value_get_as_float (argv
[1]));
629 if (filter
< 0 || filter
> FILTER_WELCH
) {
630 g_slist_free (missing0
);
632 res
= value_new_error_std (ei
->pos
, GNM_ERROR_VALUE
);
636 filter
= FILTER_NONE
;
639 gnm_float
*interpolated
, *new_ord
, start
, incr
;
641 INTERPPROC(interpproc
) = NULL
;
642 absc
= collect_floats_value_with_info (argv
[2], ei
->pos
, flags
,
643 &n1
, &missing1
, &error
);
645 g_slist_free (missing1
);
650 g_slist_free (missing0
);
651 g_slist_free (missing1
);
656 g_slist_free (missing0
);
657 g_slist_free (missing1
);
660 return value_new_error_std (ei
->pos
, GNM_ERROR_VALUE
);
663 interp
= (int) gnm_floor (value_get_as_float (argv
[3]));
664 if (interp
< 0 || interp
> INTERPOLATION_SPLINE_AVG
) {
665 g_slist_free (missing0
);
666 g_slist_free (missing1
);
672 interp
= INTERPOLATION_LINEAR
;
674 if (missing0
|| missing1
) {
675 GSList
*missing
= gnm_slist_sort_merge (missing0
, missing1
);
676 gnm_strip_missing (ord
, &n0
, missing
);
677 gnm_strip_missing (absc
, &n1
, missing
);
678 g_slist_free (missing
);
681 g_warning ("This should not happen. n0=%d n1=%d\n",
684 n0
= n1
= MIN (n0
, n1
);
685 /* here we test if there is abscissas are always increasing, if not,
686 an error is returned */
687 if (n0
< 2 || !gnm_range_increasing (absc
, n0
) || n0
== 0) {
690 return value_new_error_std (ei
->pos
, GNM_ERROR_VALUE
);
693 n1
= (int) gnm_floor (value_get_as_float (argv
[4]));
697 return value_new_error_std (ei
->pos
, GNM_ERROR_VALUE
);
708 incr
= (absc
[n0
- 1] - absc
[0]) / n1
;
710 case INTERPOLATION_LINEAR
:
711 interpproc
= linear_interpolation
;
715 case INTERPOLATION_LINEAR_AVG
:
716 interpproc
= linear_averaging
;
717 start
= absc
[0] - incr
/ 2.;
720 case INTERPOLATION_STAIRCASE
:
721 interpproc
= staircase_interpolation
;
725 case INTERPOLATION_STAIRCASE_AVG
:
726 interpproc
= staircase_averaging
;
727 start
= absc
[0] - incr
/ 2.;
730 case INTERPOLATION_SPLINE
:
731 interpproc
= spline_interpolation
;
735 case INTERPOLATION_SPLINE_AVG
:
736 interpproc
= spline_averaging
;
737 start
= absc
[0] - incr
/ 2.;
743 return value_new_error_std (ei
->pos
, GNM_ERROR_NA
);
745 interpolated
= g_new (gnm_float
, n1
);
746 for (i
= 0; i
< n2
; i
++)
747 interpolated
[i
] = start
+ i
* incr
;
748 new_ord
= interpproc (absc
, ord
, n0
, interpolated
, n1
);
753 g_free (interpolated
);
754 return value_new_error_std (ei
->pos
, GNM_ERROR_NA
);
759 /* we have no interpolation to apply, so just take the values */
761 gnm_strip_missing (ord
, &n0
, missing0
);
762 g_slist_free (missing0
);
769 /* Now apply the filter if any */
770 if (filter
!= FILTER_NONE
) {
773 case FILTER_BARTLETT
:
775 for (i
= 0; i
< n0
; i
++)
776 ord
[i
] *= 1. - gnm_abs ((i
/ factor
- 1));
779 factor
= 2. * M_PIgnum
/ n0
;
780 for (i
= 0; i
< n0
; i
++)
781 ord
[i
] *= 0.5 * (1 - gnm_cos (factor
* i
));
785 for (i
= 0; i
< n0
; i
++)
786 ord
[i
] *= 1. - (i
/ factor
- 1.) * (i
/ factor
- 1.);
791 /* Transform and return the result */
792 in
= g_new0 (gnm_complex
, nb
);
793 for (i
= 0; i
< n0
; i
++){
797 gnm_fourier_fft (in
, nb
, 1, &out
, FALSE
);
801 res
= value_new_array_non_init (1 , nb
);
802 res
->v_array
.vals
[0] = g_new (GnmValue
*, nb
);
803 for (i
= 0; i
< nb
; i
++)
804 res
->v_array
.vals
[0][i
] =
805 value_new_float (gnm_sqrt (
806 out
[i
].re
* out
[i
].re
+
807 out
[i
].im
* out
[i
].im
));
810 res
= value_new_error_std (ei
->pos
, GNM_ERROR_VALUE
);
815 /******************************************************************************/
816 /* Fourier Transform */
817 /******************************************************************************/
819 static GnmFuncHelp
const help_fourier
[] = {
820 { GNM_FUNC_HELP_NAME
, F_("FOURIER:Fourier or inverse Fourier transform") },
821 { GNM_FUNC_HELP_ARG
, F_("Sequence:the data sequence to be transformed") },
822 { GNM_FUNC_HELP_ARG
, F_("Inverse:if true, the inverse Fourier transform is calculated, defaults to false") },
823 { GNM_FUNC_HELP_ARG
, F_("Separate:if true, the real and imaginary parts are given separately, defaults to false") },
824 { GNM_FUNC_HELP_DESCRIPTION
, F_("This array function returns the Fourier or inverse Fourier transform of the given data sequence.") },
825 { GNM_FUNC_HELP_DESCRIPTION
, F_("The output consists of one column of complex numbers if @{Separate} is false and of two columns of real numbers if @{Separate} is true.") },
826 { GNM_FUNC_HELP_DESCRIPTION
, F_("If @{Separate} is true the first output column contains the real parts and the second column the imaginary parts.") },
827 { GNM_FUNC_HELP_NOTE
, F_("If @{Sequence} is neither an n by 1 nor 1 by n array, this function returns #VALUE!") },
828 { GNM_FUNC_HELP_END
, NULL
}
832 gnumeric_fourier (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
835 gboolean inverse
= FALSE
;
836 gboolean sep_columns
= FALSE
;
838 GnmValue
*error
= NULL
;
841 GnmEvalPos
const * const ep
= ei
->pos
;
842 GnmValue
const * const Pt
= argv
[0];
844 GSList
*missing0
= NULL
;
845 gnm_complex
*in
, *out
= NULL
;
847 int const cols
= value_area_get_width (Pt
, ep
);
848 int const rows
= value_area_get_height (Pt
, ep
);
850 if (cols
!= 1 && rows
!= 1) {
851 res
= value_new_error_std (ei
->pos
, GNM_ERROR_VALUE
);
855 flags
=COLLECT_IGNORE_BLANKS
| COLLECT_IGNORE_STRINGS
| COLLECT_IGNORE_BOOLS
;
857 ord
= collect_floats_value_with_info (argv
[0], ei
->pos
, flags
,
858 &n0
, &missing0
, &error
);
860 g_slist_free (missing0
);
865 res
= value_new_error_std (ei
->pos
, GNM_ERROR_VALUE
);
870 inverse
= 0 != (int) gnm_floor (value_get_as_float (argv
[1]));
872 sep_columns
= (0 != (int)
873 gnm_floor (value_get_as_float (argv
[2])));
878 gnm_strip_missing (ord
, &n0
, missing0
);
879 g_slist_free (missing0
);
886 /* Transform and return the result */
887 in
= g_new0 (gnm_complex
, nb
);
888 for (i
= 0; i
< n0
; i
++)
891 gnm_fourier_fft (in
, nb
, 1, &out
, inverse
);
894 if (out
&& !sep_columns
) {
895 res
= value_new_array_empty (1 , nb
);
896 for (i
= 0; i
< nb
; i
++)
897 res
->v_array
.vals
[0][i
] = value_new_string_nocopy
898 (gnm_complex_to_string (&(out
[i
]), 'i'));
900 } else if (out
&& sep_columns
) {
901 res
= value_new_array_empty (2 , nb
);
902 for (i
= 0; i
< nb
; i
++) {
903 res
->v_array
.vals
[0][i
] = value_new_float (out
[i
].re
);
904 res
->v_array
.vals
[1][i
] = value_new_float (out
[i
].im
);
908 res
= value_new_error_std (ei
->pos
, GNM_ERROR_VALUE
);
913 /******************************************************************************/
915 static GnmFuncHelp
const help_hpfilter
[] = {
916 { GNM_FUNC_HELP_NAME
, F_("HPFILTER:Hodrick Prescott Filter") },
917 { GNM_FUNC_HELP_ARG
, F_("Sequence:the data sequence to be transformed") },
918 { GNM_FUNC_HELP_ARG
, F_("\316\273:filter parameter \316\273, defaults to 1600") },
919 { GNM_FUNC_HELP_DESCRIPTION
, F_("This array function returns the trend and cyclical components obtained by applying the Hodrick Prescott Filter with parameter @{\316\273} to the given data sequence.") },
920 { GNM_FUNC_HELP_DESCRIPTION
, F_("The output consists of two columns of numbers, the first containing the trend component, the second the cyclical component.") },
921 { GNM_FUNC_HELP_NOTE
, F_("If @{Sequence} is neither an n by 1 nor 1 by n array, this function returns #VALUE!") },
922 { GNM_FUNC_HELP_NOTE
, F_("If @{Sequence} contains less than 6 numerical values, this function returns #VALUE!") },
923 { GNM_FUNC_HELP_END
, NULL
}
928 gnm_hpfilter (gnm_float
*data
, int n
, gnm_float lambda
, int *err
)
930 gnm_float
*a
, *b
, *c
;
932 gnm_float lambda6
= 6 * lambda
+ 1;
933 gnm_float lambda4
= -4 * lambda
;
934 gnm_float h
[5] = {0,0,0,0,0};
935 gnm_float g
[5] = {0,0,0,0,0};
936 gnm_float j
[2] = {0,0};
937 gnm_float h_b
, h_c
, denom
;
939 g_return_if_fail (n
> 5);
940 g_return_if_fail (data
!= NULL
);
941 g_return_if_fail (err
!= NULL
);
943 /* Initializing arrays a, b, and c */
945 a
= g_new (gnm_float
, n
);
946 b
= g_new (gnm_float
, n
);
947 c
= g_new (gnm_float
, n
);
953 for (i
= 1; i
< n
- 2; i
++) {
959 a
[n
- 2] = a
[1] = lambda6
- lambda
;
967 for (i
= 0; i
< n
; i
++) {
968 denom
= a
[i
]- h
[3]*h
[0] - g
[4]*g
[1];
970 *err
= GNM_ERROR_DIV0
;
976 b
[i
] = h
[0] = (h_b
- h
[3] * h
[1])/denom
;
980 c
[i
] = h
[1] = h_c
/denom
;
982 a
[i
] = (data
[i
] - g
[2]*g
[4] - h
[2]*h
[3])/denom
;
986 h
[3] = h_b
- h
[4] * g
[0];
991 data
[n
- 1] = j
[0] = a
[n
- 1];
994 for (i
= n
- 1; i
> 0; i
--) {
995 data
[i
- 1] = a
[i
- 1] - b
[i
- 1] * j
[0] - c
[i
- 1] * j
[1];
1008 gnumeric_hpfilter (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1010 gnm_float
*raw
, *filtered
;
1013 GnmValue
*error
= NULL
;
1016 GnmEvalPos
const * const ep
= ei
->pos
;
1017 GnmValue
const * const Pt
= argv
[0];
1020 int const cols
= value_area_get_width (Pt
, ep
);
1021 int const rows
= value_area_get_height (Pt
, ep
);
1023 if (cols
!= 1 && rows
!= 1) {
1024 res
= value_new_error_std (ei
->pos
, GNM_ERROR_VALUE
);
1028 flags
=COLLECT_IGNORE_BLANKS
| COLLECT_IGNORE_STRINGS
| COLLECT_IGNORE_BOOLS
;
1030 raw
= collect_floats_value (argv
[0], ei
->pos
, flags
,
1037 res
= value_new_error_std (ei
->pos
, GNM_ERROR_VALUE
);
1042 lambda
= value_get_as_float (argv
[1]);
1047 /* Filter and return the result */
1048 filtered
= g_new0 (gnm_float
, n
);
1049 for (i
= 0; i
< n
; i
++)
1050 filtered
[i
] = raw
[i
];
1051 gnm_hpfilter (filtered
, n
, lambda
, &err
);
1055 res
= value_new_error_std (ei
->pos
, err
);
1059 res
= value_new_array_empty (2 , n
);
1060 for (i
= 0; i
< n
; i
++) {
1061 res
->v_array
.vals
[0][i
] = value_new_float (filtered
[i
]);
1062 res
->v_array
.vals
[1][i
] = value_new_float (raw
[i
] - filtered
[i
]);
1070 const GnmFuncDescriptor TimeSeriesAnalysis_functions
[] = {
1072 { "interpolation", "AAA|f",
1073 help_interpolation
, gnumeric_interpolation
, NULL
,
1074 GNM_FUNC_RETURNS_NON_SCALAR
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1076 { "periodogram", "A|fAff",
1077 help_periodogram
, gnumeric_periodogram
, NULL
,
1078 GNM_FUNC_RETURNS_NON_SCALAR
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1080 { "fourier", "A|bb",
1081 help_fourier
, gnumeric_fourier
, NULL
,
1082 GNM_FUNC_RETURNS_NON_SCALAR
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1084 { "hpfilter", "A|f",
1085 help_hpfilter
, gnumeric_hpfilter
, NULL
,
1086 GNM_FUNC_RETURNS_NON_SCALAR
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},