[gnumeric] Improve Fourier transform tool
- From: Andreas J. Guelzow <guelzow src gnome org>
- To: svn-commits-list gnome org
- Subject: [gnumeric] Improve Fourier transform tool
- Date: Sat, 6 Jun 2009 01:44:14 -0400 (EDT)
commit 565c2b482eeff9477d46d251bdefb1dcb6bd3245
Author: Andreas J. Guelzow <aguelzow pyrshep ca>
Date: Fri Jun 5 23:43:35 2009 -0600
Improve Fourier transform tool
2009-06-05 Andreas J. Guelzow <aguelzow pyrshep ca>
* analysis-tools.h (gnm_fourier_fft): moved to
plugins/fn-tsa/functions.c
* analysis-tools.c (cb_store_data): deleted
(new_data_set): deleted
(destroy_data_set): deleted
(cb_get_data_set_list): deleted
(cb_get_data_set_list): deleted
(new_data_set_list): deleted
(destroy_data_set_list): deleted
(gnm_fourier_fft): moved to
plugins/fn-tsa/functions.c
(analysis_tool_fourier_engine_run): rewritten
(analysis_tool_fourier_calc_length): use analysis_tool_calc_length
(analysis_tool_fourier_engine): adjust required size
2009-06-05 Andreas J. Guelzow <aguelzow pyrshep ca>
* functions.c (gnm_fourier_fft): moved here from
src/tools/analysis-tools.c
(help_interpolation): changed to new form of desription
(help_periodogram): ditto
(help_fourier): new
(gnumeric_fourier): new
(TimeSeriesAnalysis_functions): added fourier function
* plugin.xml.in: added fourier function
---
BUGS | 15 +-
NEWS | 3 +
plugins/fn-tsa/ChangeLog | 11 ++
plugins/fn-tsa/functions.c | 239 ++++++++++++++++++++++--------
plugins/fn-tsa/plugin.xml.in | 1 +
src/tools/ChangeLog | 19 +++-
src/tools/analysis-tools.c | 332 +++++++-----------------------------------
src/tools/analysis-tools.h | 3 -
8 files changed, 271 insertions(+), 352 deletions(-)
diff --git a/BUGS b/BUGS
index 428caf8..e27f47c 100644
--- a/BUGS
+++ b/BUGS
@@ -65,9 +65,6 @@ Misc stuff that should be fixed
correspond to hiding.
: support delete for discontinuous ranges
-- Remove duplication of code between analysis-tools.c and collect.c
- (Many analysis tools may in fact want to follow the consolidate style)
-
Worries
-------
: range_translate in stf.c looks suspecious.
@@ -131,8 +128,8 @@ Architecture Changes
1.1) plugin-manager dialog
1.2) doc meta data
1.2.1) Use GsfDocMetaData {Jody}
- 1.2.1.1) sax-in
- 1.2.1.2) sax-out (DONE)
+ 1.2.1.1) sax-in (DONE)
+ 1.2.1.2) sax-out (DONE)
1.2.2) doc meta data dialog {Trelane and etrunko}
1.3) Insert hyperlink dialog
1.3.1) Integration with evo address book
@@ -321,8 +318,8 @@ Architecture Changes
11.3.1) import
11.3.2) export
11.4) ODF
- 11.4.1) import
- 11.4.2) export
+ 11.4.1) import (conditional number formats DONE)
+ 11.4.2) export (conditional number formats DONE)
11.6) Evaluation
11.6.1) Custom (DONE)
11.6.2) Comparisons
@@ -357,7 +354,7 @@ Architecture Changes
12.3.3) Add to .xsd schema (DONE)
12.6) ODF
12.6.1) import
- 12.6.2) export
+ 12.6.2) export (DONE)
16) Protection limits for selection
16.2) I/O
@@ -721,7 +718,7 @@ Architecture Changes
36.3) Export
36.3.1) We don't handle whitespace correctly. See OpenDocument
format 5.1.1 (DONE)
- 36.4) See 11.4 (Conditionals)
+ 36.4) See 11.4 (Conditionals) (DONE)
36.5) See 12.6 (Input Messages)
36.6) See 21.46 (Autofilters)
36.7) See 22.13 (Validation)
diff --git a/NEWS b/NEWS
index 340dc0a..aa0e50a 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,9 @@ Andreas:
* Add superscipt and subscript buttons. [#583327]
* Improve ODF import.
* Improve 2 factor ANOVA tool
+ * Improve Rank & Percentiles tool
+ * Improve Fourier transform tool
+ * New FOURIER function
Morten:
* Add search-for-number.
diff --git a/plugins/fn-tsa/ChangeLog b/plugins/fn-tsa/ChangeLog
index 8b983f8..cd10283 100644
--- a/plugins/fn-tsa/ChangeLog
+++ b/plugins/fn-tsa/ChangeLog
@@ -1,3 +1,14 @@
+2009-06-05 Andreas J. Guelzow <aguelzow pyrshep ca>
+
+ * functions.c (gnm_fourier_fft): moved here from
+ src/tools/analysis-tools.c
+ (help_interpolation): changed to new form of desription
+ (help_periodogram): ditto
+ (help_fourier): new
+ (gnumeric_fourier): new
+ (TimeSeriesAnalysis_functions): added fourier function
+ * plugin.xml.in: added fourier function
+
2009-05-23 Morten Welinder <terra gnome org>
* Release 1.9.8
diff --git a/plugins/fn-tsa/functions.c b/plugins/fn-tsa/functions.c
index 583714d..b10c11b 100644
--- a/plugins/fn-tsa/functions.c
+++ b/plugins/fn-tsa/functions.c
@@ -5,6 +5,7 @@
*
* Copyright (C) 2006 Laurency Franck
* Copyright (C) 2007 Jean Bréfort <jean brefort normalesup org>
+ * Copyright (C) 2009 Andreas Guelzow <aguelzow pyrshep ca>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -48,6 +49,7 @@
#include <goffice/math/go-cspline.h>
#include <gnm-plugin.h>
#include <tools/analysis-tools.h>
+#include <complex.h>
#include <math.h>
#include <stdlib.h>
@@ -89,12 +91,57 @@ enum {
# define gnm_cspline_get_integrals go_cspline_get_integrals
#endif
+#define INTERPOLATIONMETHODS { GNM_FUNC_HELP_DESCRIPTION, F_("Possible interpolation methods are:\n"\
+ "0: linear;\n"\
+ "1: linear with averaging;\n"\
+ "2: staircase;\n"\
+ "3: staircase with averaging;\n"\
+ "4: natural cubic spline;\n"\
+ "5: natural cubic spline with averaging.") }
+
/**************************************************************************/
/**************************************************************************/
/* CALCULATION FUNCTIONS FOR TOOLS */
/**************************************************************************/
/**************************************************************************/
+static void
+gnm_fourier_fft (complex_t const *in, int n, int skip, complex_t **fourier, gboolean inverse)
+{
+ complex_t *fourier_1, *fourier_2;
+ int i;
+ int nhalf = n / 2;
+ gnm_float argstep;
+
+ *fourier = g_new (complex_t, n);
+
+ if (n == 1) {
+ (*fourier)[0] = in[0];
+ return;
+ }
+
+ gnm_fourier_fft (in, nhalf, skip * 2, &fourier_1, inverse);
+ gnm_fourier_fft (in + skip, nhalf, skip * 2, &fourier_2, inverse);
+
+ argstep = (inverse ? M_PIgnum : -M_PIgnum) / nhalf;
+ for (i = 0; i < nhalf; i++) {
+ complex_t dir, tmp;
+
+ complex_from_polar (&dir, 1, argstep * i);
+ complex_mul (&tmp, &fourier_2[i], &dir);
+
+ complex_add (&((*fourier)[i]), &fourier_1[i], &tmp);
+ complex_scale_real (&((*fourier)[i]), 0.5);
+
+ complex_sub (&((*fourier)[i + nhalf]), &fourier_1[i], &tmp);
+ complex_scale_real (&((*fourier)[i + nhalf]), 0.5);
+ }
+
+ g_free (fourier_1);
+ g_free (fourier_2);
+}
+
+
/*******LINEAR INTERPOLATION*******/
static gnm_float*
@@ -321,36 +368,17 @@ spline_averaging (const gnm_float *absc, const gnm_float *ord, int nb_knots,
/******************************************************************************/
static GnmFuncHelp const help_interpolation[] = {
- { GNM_FUNC_HELP_OLD,
- F_("@FUNCTION=INTERPOLATION\n"
- "@SYNTAX=INTERPOLATION(abscissas,ordinates,targets[,interpolation])\n"
-
- "@DESCRIPTION= \n"
- "INTERPOLATION returns interpolated values corresponding\n"
- "to the given abscissa targets as a one column matrix.\n"
- "\n"
- "@abscissas are the absicssas of the data to interpolate.\n"
- "@ordinates are the ordinates of the data to interpolate.\n"
- "* Strings and empty cells in @abscissas and @ordinates are simply ignored.\n"
- "@targets are the abscissas of the interpolated data. If several data\n"
- "are provided, they must be in the same column, in consecutive cells\n"
- "@interpolation is the method to be used for the interpolation;\n"
- "possible values are:\n"
- "- 0: linear;\n"
- "- 1: linear with averaging;\n"
- "- 2: staircase;\n"
- "- 3: staircase with averaging;\n"
- "- 4: natural cubic spline;\n"
- "- 5: natural cubic spline with averaging.\n"
- "\n"
- "If an averaging method is used, the number of returned values\n"
- "is one less than the number of targets since the evaluation is made by\n"
- "averaging the interpolation over the interval between two consecutive data;\n"
- "in that case, the targets values must be given in increasing order.\n"
- "@EXAMPLES=\n"
- "\n"
- "@SEEALSO=PERIODOGRAM")
- },
+ { GNM_FUNC_HELP_NAME, F_("Interpolation:interpolated values corresponding to the given abscissa targets.") },
+ { GNM_FUNC_HELP_ARG, F_("abscissas:The absicssas of the data to interpolate.") },
+ { GNM_FUNC_HELP_ARG, F_("ordinates:The ordinates of the data to interpolate.") },
+ { GNM_FUNC_HELP_ARG, F_("targets:The abscissas of the interpolated data.") },
+ { GNM_FUNC_HELP_ARG, F_("interpolation:The method of interpolation to be used, defaults to no interpolation") },
+ { 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.") },
+ { GNM_FUNC_HELP_DESCRIPTION, F_("The output consists always of one column of numbers.") },
+ INTERPOLATIONMETHODS,
+ { GNM_FUNC_HELP_NOTE, F_("Strings and empty cells in @{abscissas} and @{ordinates} are ignored.") },
+ { GNM_FUNC_HELP_NOTE, F_("If several target data are provided they must be in the same column in consecutive cells.") },
+ { GNM_FUNC_HELP_SEEALSO, "PERIODOGRAM" },
{ GNM_FUNC_HELP_END }
};
@@ -614,39 +642,23 @@ gnumeric_interpolation (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
/******************************************************************************/
static GnmFuncHelp const help_periodogram[] = {
- { GNM_FUNC_HELP_OLD,
- F_("@FUNCTION=PERIODOGRAM\n"
- "@SYNTAX=PERIODOGRAM(ordinates,[filter,[abscissas,[interpolation,[number]]]])\n"
-
- "@DESCRIPTION= \n"
- "periodogram returns the periodogram of the data\n"
- "as a one column matrix.\n"
- "\n"
- "@ordinates are the ordinates of the data to interpolate.\n"
- "@filter gives the window function to be used. Possible values are:\n"
- "- 0: no filter (rectangular window);\n"
- "- 1: Bartlett (triangular window);\n"
- "- 2: Hahn (cosine window);\n"
- "- 3: Welch (parabolic window);\n"
- "@abscissas are the absicssas of the data to interpolate. If no\n"
- "abscissa is given, it is supposed that the data absicssas are regularly\n"
- "spaced. Otherwise, an interpolation method will be used to evaluate\n"
- "regularly spaced data.\n"
- "* Strings and empty cells in @abscissas and @ordinates are simply ignored.\n"
- "@interpolation is the method to be used for the interpolation;\n"
- "possible values are:\n"
- "- 0: linear;\n"
- "- 1: linear with averaging;\n"
- "- 2: staircase;\n"
- "- 3: staircase with averaging;\n"
- "- 4: natural cubic spline;\n"
- "- 5: natural cubic spline with averaging.\n"
- "@number is the number of interpolated data to be used. If not given,\n"
- "a default number is automatically evaluated.\n"
- "@EXAMPLES=\n"
- "\n"
- "@SEEALSO=INTERPOLATION")
- },
+ { GNM_FUNC_HELP_NAME, F_("PERIODOGRAM: Periodogram of the given data.") },
+ { GNM_FUNC_HELP_ARG, F_("ordinates:The ordinates of the data to interpolate.") },
+ { GNM_FUNC_HELP_ARG, F_("filter:Window function to be used, defaults to no window function.") },
+ { GNM_FUNC_HELP_ARG, F_("abscissas:The abscissas of the data to interpolate, defaults to regularly spaced abscissa.") },
+ { GNM_FUNC_HELP_ARG, F_("interpolation:The method of interpolation to be used, defaults to no interpolation") },
+ { GNM_FUNC_HELP_ARG, F_("number: Number of interpolated data points to be used.") },
+ { 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.") },
+ { GNM_FUNC_HELP_DESCRIPTION, F_("The output consists always of one column of numbers.") },
+ INTERPOLATIONMETHODS,
+ { GNM_FUNC_HELP_DESCRIPTION, F_("Possible window functions are:\n"
+ "0: no filter (rectangular window)\n"
+ "1: Bartlett (triangular window)\n"
+ "2: Hahn (cosine window)\n"
+ "3: Welch (parabolic window)") },
+ { GNM_FUNC_HELP_NOTE, F_("Strings and empty cells in @{abscissas} and @{ordinates} are ignored.") },
+ { GNM_FUNC_HELP_NOTE, F_("If several target data are provided they must be in the same column in consecutive cells.") },
+ { GNM_FUNC_HELP_SEEALSO, "INTERPOLATION" },
{ GNM_FUNC_HELP_END }
};
@@ -892,6 +904,103 @@ gnumeric_periodogram (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
return res;
}
+/******************************************************************************/
+/* Fourier Transform */
+/******************************************************************************/
+
+static GnmFuncHelp const help_fourier[] = {
+ { GNM_FUNC_HELP_NAME, F_("FOURIER:Fourier or inverse Fourier transform.") },
+ { GNM_FUNC_HELP_ARG, F_("Sequence: the data sequence to be transformed") },
+ { GNM_FUNC_HELP_ARG, F_("Inverse:if false, the inverse Fourier transform is calculated. Defaults to false") },
+ { GNM_FUNC_HELP_DESCRIPTION, F_("This array function returns the Fourier or inverse Fourier transform of the given data sequence.") },
+ { GNM_FUNC_HELP_DESCRIPTION, F_("The output consists always of one column of complex numbers.") },
+ { GNM_FUNC_HELP_NOTE, F_("If @{Sequence} is neither an n by 1 nor 1 by n array, this function returns #NUM!") },
+ { GNM_FUNC_HELP_END }
+};
+
+static GnmValue *
+gnumeric_fourier (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
+{
+ gnm_float *ord;
+ gboolean inverse = FALSE;
+ int n0, nb;
+ GnmValue *error = NULL;
+ GnmValue *res;
+ CollectFlags flags;
+ GnmEvalPos const * const ep = ei->pos;
+ GnmValue const * const Pt = argv[0];
+ int i;
+ GSList *missing0 = NULL;
+ complex_t *in, *out = NULL;
+
+ int const cols = value_area_get_width (Pt, ep);
+ int const rows = value_area_get_height (Pt, ep);
+
+ char f[5 + 4 * sizeof (int) + sizeof (GNM_FORMAT_g)];
+
+ if (cols != 1 && rows != 1) {
+ res = value_new_error_std (ei->pos, GNM_ERROR_VALUE);
+ return res;
+ }
+
+ flags=COLLECT_IGNORE_BLANKS | COLLECT_IGNORE_STRINGS | COLLECT_IGNORE_BOOLS;
+
+ ord = collect_floats_value_with_info (argv[0], ei->pos, flags,
+ &n0, &missing0, &error);
+ if (error) {
+ g_slist_free (missing0);
+ return error;
+ }
+
+ if (n0 == 0) {
+ res = value_new_error_std (ei->pos, GNM_ERROR_VALUE);
+ return res;
+ }
+
+ if (argv[1]) {
+ inverse = 0 != (int) gnm_floor (value_get_as_float (argv[1]));
+ }
+
+ if (missing0) {
+ GArray *gval;
+
+ gval = g_array_new (FALSE, FALSE, sizeof (gnm_float));
+ gval = g_array_append_vals (gval, ord, n0);
+ g_free (ord);
+ gnm_strip_missing (gval, missing0);
+ ord = (gnm_float *) gval->data;
+ n0 = gval->len;
+ g_array_free (gval, FALSE);
+
+ g_slist_free (missing0);
+ }
+
+ nb = 1;
+ while (nb < n0)
+ nb *= 2;
+
+ /* Transform and return the result */
+ in = g_new0 (complex_t, nb);
+ for (i = 0; i < n0; i++)
+ in[i].re = ord[i];
+ g_free (ord);
+ gnm_fourier_fft (in, nb, 1, &out, inverse);
+ g_free (in);
+
+ if (out) {
+ res = value_new_array_empty (1 , nb);
+ sprintf (f, "%%.%d" GNM_FORMAT_g, GNM_DIG);
+ for (i = 0; i < nb; i++)
+ res->v_array.vals[0][i] = value_new_string_nocopy
+ (complex_to_string (&(out[i]), f, f, 'i'));
+ g_free (out);
+ } else
+ res = value_new_error_std (ei->pos, GNM_ERROR_VALUE);
+
+ return res;
+}
+
+
const GnmFuncDescriptor TimeSeriesAnalysis_functions[] = {
{ "interpolation", "AAA|f", N_("Abscissas,Ordinates,Targets,Interpolation"),
@@ -902,5 +1011,9 @@ const GnmFuncDescriptor TimeSeriesAnalysis_functions[] = {
help_periodogram, gnumeric_periodogram, NULL, NULL, NULL, NULL,
GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
+ { "fourier", "A|b", N_("Sequence,Inverse"),
+ help_fourier, gnumeric_fourier, NULL, NULL, NULL, NULL,
+ GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
+
{NULL}
};
diff --git a/plugins/fn-tsa/plugin.xml.in b/plugins/fn-tsa/plugin.xml.in
index a944758..6da0bbb 100644
--- a/plugins/fn-tsa/plugin.xml.in
+++ b/plugins/fn-tsa/plugin.xml.in
@@ -14,6 +14,7 @@
<functions>
<function name="interpolation"/>
<function name="periodogram"/>
+ <function name="fourier"/>
</functions>
</service>
</services>
diff --git a/src/tools/ChangeLog b/src/tools/ChangeLog
index 2af4cc2..fcdc9c8 100644
--- a/src/tools/ChangeLog
+++ b/src/tools/ChangeLog
@@ -1,4 +1,21 @@
-2009-06-06 Andreas J. Guelzow <aguelzow pyrshep ca>
+2009-06-05 Andreas J. Guelzow <aguelzow pyrshep ca>
+
+ * analysis-tools.h (gnm_fourier_fft): moved to
+ plugins/fn-tsa/functions.c
+ * analysis-tools.c (cb_store_data): deleted
+ (new_data_set): deleted
+ (destroy_data_set): deleted
+ (cb_get_data_set_list): deleted
+ (cb_get_data_set_list): deleted
+ (new_data_set_list): deleted
+ (destroy_data_set_list): deleted
+ (gnm_fourier_fft): moved to
+ plugins/fn-tsa/functions.c
+ (analysis_tool_fourier_engine_run): rewritten
+ (analysis_tool_fourier_calc_length): use analysis_tool_calc_length
+ (analysis_tool_fourier_engine): adjust required size
+
+2009-06-05 Andreas J. Guelzow <aguelzow pyrshep ca>
* Makefile.am: added analysis-anova.[ch]
* analysis-tools.h (analysis_tool_anova_two_factor_engine):
diff --git a/src/tools/analysis-tools.c b/src/tools/analysis-tools.c
index bfd863e..27e6c5d 100644
--- a/src/tools/analysis-tools.c
+++ b/src/tools/analysis-tools.c
@@ -99,21 +99,6 @@ make_rangeref (int dx0, int dy0, int dx1, int dy1)
}
-/*************************************************************************/
-/*
- * data_set_t: a data set format (optionally) keeping track of missing
- * observations.
- *
- */
-typedef struct {
- GArray *data;
- char *label;
- GSList *missing;
- gboolean complete;
- gboolean read_label;
-} data_set_t;
-
-
static gboolean
gnm_check_input_range_list_homogeneity (GSList *input_range);
@@ -147,166 +132,6 @@ cb_adjust_areas (gpointer data, G_GNUC_UNUSED gpointer user_data)
range->v_range.cell.b.row_relative = 0;
}
-static GnmValue *
-cb_store_data (GnmCellIter const *iter, gpointer user)
-{
- data_set_t *data_set = (data_set_t *)user;
- GnmCell *cell = iter->cell;
- gnm_float the_data;
-
- if (data_set->read_label) {
- if (cell != NULL) {
- data_set->label = cell->value
- ? value_get_as_string (cell->value)
- : NULL;
- if (data_set->label == NULL || strlen (data_set->label) == 0) {
- g_free (data_set->label);
- data_set->label = NULL;
- }
- }
- data_set->read_label = FALSE;
- return NULL;
- }
- if (cell == NULL || !VALUE_IS_NUMBER (cell->value)) {
- if (data_set->complete) {
- data_set->missing = g_slist_prepend (data_set->missing,
- GUINT_TO_POINTER (data_set->data->len));
- the_data = 0;
- g_array_append_val (data_set->data, the_data);
- }
- } else {
- the_data = value_get_as_float (cell->value);
- g_array_append_val (data_set->data, the_data);
- }
- return NULL;
-}
-
-/*
- * new_data_set:
- * @range: GnmValue * the data location, usually a single column or row
- * @ignore_non_num: gboolean whether simply to ignore non-numerical values
- * @read_label: gboolean whether the first entry contains a label
- * @format: char* format string for default label
- * @i: guint index for default label
- */
-static data_set_t *
-new_data_set (GnmValue *range, gboolean ignore_non_num, gboolean read_label,
- char *format, gint i, Sheet* sheet)
-{
- GnmValue *result;
- GnmEvalPos *pos = g_new (GnmEvalPos, 1);
- data_set_t * the_set = g_new (data_set_t, 1);
-
- pos = eval_pos_init_sheet (pos, sheet);
- the_set->data = g_array_new (FALSE, FALSE, sizeof (gnm_float)),
- the_set->missing = NULL;
- the_set->label = NULL;
- the_set->complete = !ignore_non_num;
- the_set->read_label = read_label;
-
- result = workbook_foreach_cell_in_range (pos, range, CELL_ITER_ALL,
- cb_store_data, the_set);
- g_free (pos);
-
- if (result != NULL) value_release (result);
- the_set->missing = g_slist_reverse (the_set->missing);
- if (the_set->label == NULL)
- the_set->label = g_strdup_printf (format, i);
- return the_set;
-}
-
-/*
- * destroy_data_set:
- * @data_set:
- */
-static void
-destroy_data_set (data_set_t *data_set)
-{
-
- if (data_set->data != NULL)
- g_array_free (data_set->data, TRUE);
- g_slist_free (data_set->missing);
- g_free (data_set->label);
- g_free (data_set);
-}
-
-/*
- * cb_get_data_set_list:
- * @data:
- * @user_data:
- */
-static void
-cb_get_data_set_list (gpointer data, gpointer user_data)
-{
- GnmValue * the_range = (GnmValue *) data;
- data_list_specs_t *specs = (data_list_specs_t *)user_data;
-
- specs->length++;
- g_ptr_array_add (specs->data_lists,
- new_data_set (the_range, specs->ignore_non_num,
- specs->read_label, specs->format,
- specs->length, specs->sheet));
-}
-
-
-/*
- * new_data_set_list:
- * @ranges: GSList * the data location
- * @group_by: group_by_t how to group the data
- * @ignore_non_num: gboolean whether simply to ignore non-numerical values
- * @read_label: gboolean whether the first entry contains a label
- */
-static GPtrArray *
-new_data_set_list (GSList *ranges, group_by_t group_by,
- gboolean ignore_non_num, gboolean read_labels, Sheet *sheet)
-{
- data_list_specs_t specs = {NULL, NULL, FALSE, FALSE, 0};
-
- if (ranges == NULL)
- return NULL;
-
- specs.read_label = read_labels;
- specs.data_lists = g_ptr_array_new ();
- specs.ignore_non_num = ignore_non_num;
- specs.sheet = sheet;
-
- switch (group_by) {
- case GROUPED_BY_ROW:
- specs.format = _("Row %i");
- break;
- case GROUPED_BY_COL:
- specs.format = _("Column %i");
- break;
- case GROUPED_BY_BIN:
- specs.format = _("Bin %i");
- break;
- case GROUPED_BY_AREA:
- default:
- specs.format = _("Area %i");
- break;
- }
-
- g_slist_foreach (ranges, cb_get_data_set_list, &specs);
-
- return specs.data_lists;
-}
-
-/*
- * destroy_data_set_list:
- * @the_list:
- */
-static void
-destroy_data_set_list (GPtrArray * the_list)
-{
- guint i;
-
- for (i = 0; i < the_list->len; i++) {
- data_set_t *data = g_ptr_array_index (the_list, i);
- destroy_data_set (data);
- }
- g_ptr_array_free (the_list, TRUE);
-}
-
/*
* analysis_tools_remove_label:
* @val: range to extract label from
@@ -4339,127 +4164,82 @@ analysis_tool_anova_single_engine (data_analysis_output_t *dao, gpointer specs,
* This tool performes a fast fourier transform calculating the fourier
* transform as defined in Weaver: Theory of dis and cont Fouriere Analysis
*
- * If the length of the given sequence is not a power of 2, an appropriate
- * number of 0s are added.
- *
- *
*
**/
-void
-gnm_fourier_fft (complex_t const *in, int n, int skip, complex_t **fourier, gboolean inverse)
+
+static gboolean
+analysis_tool_fourier_engine_run (data_analysis_output_t *dao,
+ analysis_tools_data_fourier_t *info)
{
- complex_t *fourier_1, *fourier_2;
- int i;
- int nhalf = n / 2;
- gnm_float argstep;
+ GSList *data = info->base.input;
+ int col = 0;
- *fourier = g_new (complex_t, n);
+ GnmFunc *fd_fourier;
+ GnmFunc *fd_imaginary;
+ GnmFunc *fd_imreal;
- if (n == 1) {
- (*fourier)[0] = in[0];
- return;
- }
+ fd_fourier = gnm_func_lookup ("FOURIER", NULL);
+ gnm_func_ref (fd_fourier);
+ fd_imaginary = gnm_func_lookup ("IMAGINARY", NULL);
+ gnm_func_ref (fd_imaginary);
+ fd_imreal = gnm_func_lookup ("IMREAL", NULL);
+ gnm_func_ref (fd_imreal);
- gnm_fourier_fft (in, nhalf, skip * 2, &fourier_1, inverse);
- gnm_fourier_fft (in + skip, nhalf, skip * 2, &fourier_2, inverse);
- argstep = (inverse ? M_PIgnum : -M_PIgnum) / nhalf;
- for (i = 0; i < nhalf; i++) {
- complex_t dir, tmp;
+ dao_set_merge (dao, 0, 0, 1, 0);
+ dao_set_italic (dao, 0, 0, 0, 0);
+ dao_set_cell (dao, 0, 0, info->inverse ? _("Inverse Fourier Transform")
+ : _("Fourier Transform"));
- complex_from_polar (&dir, 1, argstep * i);
- complex_mul (&tmp, &fourier_2[i], &dir);
+ for (; data; data = data->next, col++) {
+ GnmValue *val_org = value_dup (data->data);
+ GnmExpr const *expr_fourier;
+ int rows, n;
- complex_add (&((*fourier)[i]), &fourier_1[i], &tmp);
- complex_scale_real (&((*fourier)[i]), 0.5);
+ dao_set_italic (dao, 0, 1, 1, 2);
+ dao_set_cell (dao, 0, 2, _("Real"));
+ dao_set_cell (dao, 1, 2, _("Imaginary"));
+ dao_set_merge (dao, 0, 1, 1, 1);
+ analysis_tools_write_label (val_org, dao, &info->base, 0, 1, col + 1);
- complex_sub (&((*fourier)[i + nhalf]), &fourier_1[i], &tmp);
- complex_scale_real (&((*fourier)[i + nhalf]), 0.5);
+ n = (val_org->v_range.cell.b.row - val_org->v_range.cell.a.row + 1) *
+ (val_org->v_range.cell.b.col - val_org->v_range.cell.a.col + 1);
+ rows = 1;
+ while (rows < n)
+ rows *= 2;
+
+ expr_fourier = gnm_expr_new_funcall2
+ (fd_fourier,
+ gnm_expr_new_constant (val_org),
+ gnm_expr_new_constant (value_new_bool (info->inverse)));
+
+ dao_set_array_expr (dao, 0, 3, 1, rows,
+ gnm_expr_new_funcall1 (fd_imreal,
+ gnm_expr_copy (expr_fourier)));
+ dao_set_array_expr (dao, 1, 3, 1, rows,
+ gnm_expr_new_funcall1 (fd_imaginary,
+ expr_fourier));
+ dao->offset_col += 2;
}
- g_free (fourier_1);
- g_free (fourier_2);
-}
+ gnm_func_unref (fd_fourier);
+ gnm_func_unref (fd_imaginary);
+ gnm_func_unref (fd_imreal);
-static gboolean
-analysis_tool_fourier_engine_run (data_analysis_output_t *dao,
- analysis_tools_data_fourier_t *info)
-{
- GPtrArray *data;
- guint dataset;
- gint col = 0;
-
- data = new_data_set_list (info->base.input, info->base.group_by,
- TRUE, info->base.labels, dao->sheet);
-
- for (dataset = 0; dataset < data->len; dataset++) {
- data_set_t *current;
- complex_t *in, *fourier;
- int row;
- int given_length;
- int desired_length = 1;
- int i;
- gnm_float zero_val = 0.0;
-
- current = g_ptr_array_index (data, dataset);
- given_length = current->data->len;
- while (given_length > desired_length)
- desired_length *= 2;
- for (i = given_length; i < desired_length; i++)
- current->data = g_array_append_val (current->data, zero_val);
-
- dao_set_cell_printf (dao, col, 0, "%s", current->label);
- dao_set_cell_printf (dao, col, 1, _("Real"));
- dao_set_cell_printf (dao, col + 1, 1, _("Imaginary"));
-
- in = g_new (complex_t, desired_length);
- for (i = 0; i < desired_length; i++)
- complex_real (&in[i],
- ((gnm_float const *)current->data->data)[i]);
-
- gnm_fourier_fft (in, desired_length, 1, &fourier, info->inverse);
- g_free (in);
-
- if (fourier) {
- for (row = 0; row < given_length; row++) {
- dao_set_cell_float (dao, col, row + 2,
- fourier[row].re);
- dao_set_cell_float (dao, col + 1, row + 2,
- fourier[row].im);
- }
- g_free (fourier);
- }
-
- col += 2;
- }
- dao_set_italic (dao, 0, 0, col - 1, 1);
-
- destroy_data_set_list (data);
+ dao_redraw_respan (dao);
- return 0;
+ return FALSE;
}
static int
analysis_tool_fourier_calc_length (analysis_tools_data_fourier_t *info)
{
- Sheet *sheet = wb_control_cur_sheet(info->base.wbc);
- GPtrArray *data = new_data_set_list (info->base.input, info->base.group_by,
- TRUE, info->base.labels, sheet);
- int result = 1;
- guint dataset;
-
- for (dataset = 0; dataset < data->len; dataset++) {
- data_set_t *current;
- int given_length;
+ int m = 1, n = analysis_tool_calc_length (&info->base);
- current = g_ptr_array_index (data, dataset);
- given_length = current->data->len;
- if (given_length > result)
- result = given_length;
- }
- destroy_data_set_list (data);
- return result;
+ while (m < n)
+ m *= 2;
+ return m;
}
@@ -4476,7 +4256,7 @@ analysis_tool_fourier_engine (data_analysis_output_t *dao, gpointer specs,
case TOOL_ENGINE_UPDATE_DAO:
prepare_input_range (&info->base.input, info->base.group_by);
dao_adjust (dao, 2 * g_slist_length (info->base.input),
- 2 + analysis_tool_fourier_calc_length (specs));
+ 3 + analysis_tool_fourier_calc_length (specs));
return FALSE;
case TOOL_ENGINE_CLEAN_UP:
return analysis_tool_generic_clean (specs);
diff --git a/src/tools/analysis-tools.h b/src/tools/analysis-tools.h
index f100e3c..29f7bb5 100644
--- a/src/tools/analysis-tools.h
+++ b/src/tools/analysis-tools.h
@@ -217,9 +217,6 @@ const GnmExpr *make_rangeref (int dx0, int dy0, int dx1, int dy1);
gnm_float *range_sort (gnm_float const *xs, int n);
-void gnm_fourier_fft (complex_t const *in, int n, int skip,
- complex_t **fourier, gboolean inverse);
-
void set_cell_text_row (data_analysis_output_t *dao,
int col, int row, const char *text);
void set_cell_text_col (data_analysis_output_t *dao,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]