Mercurial > forge
changeset 11538:3007c7f11f3d octave-forge
signal: add fwht and ifwht functions
author | mtmiller |
---|---|
date | Mon, 11 Mar 2013 02:25:15 +0000 |
parents | 69f206d4a540 |
children | 3112e99511d8 |
files | main/signal/NEWS main/signal/inst/fwht.m main/signal/inst/ifwht.m main/signal/inst/private/__fwht_opts__.m main/signal/src/Makefile main/signal/src/__fwht__.cc |
diffstat | 6 files changed, 311 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/main/signal/NEWS Sun Mar 10 22:32:12 2013 +0000 +++ b/main/signal/NEWS Mon Mar 11 02:25:15 2013 +0000 @@ -7,6 +7,8 @@ ** The following functions are new: findpeaks + fwht + ifwht ** The function `blackmanharris' was fixed to return a column vector.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/signal/inst/fwht.m Mon Mar 11 02:25:15 2013 +0000 @@ -0,0 +1,79 @@ +## Copyright (C) 2013 Mike Miller <mtmiller@ieee.org> +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} {} fwht (@var{x}) +## @deftypefnx {Function File} {} fwht (@var{x}, @var{n}) +## @deftypefnx {Function File} {} fwht (@var{x}, @var{n}, @var{order}) +## Compute the Walsh-Hadamard transform of @var{x} using the Fast +## Walsh-Hadamard Transform (FWHT) algorithm. If the input is a matrix, +## the FWHT is calculated along the columns of @var{x}. +## +## The number of elements of @var{x} must be a power of 2; if not, the +## input will be extended and filled with zeros. If a second argument +## is given, the input is truncated or extended to have length @var{n}. +## +## The third argument specifies the @var{order} in which the returned +## Walsh-Hadamard transform coefficients should be arranged. The +## @var{order} may be any of the following strings: +## +## @table @asis +## @item "sequency" +## The coefficients are returned in sequency order. This is the default +## if @var{order} is not given. +## +## @item "hadamard" +## The coefficients are returned in Hadamard order. +## +## @item "dyadic" +## The coefficients are returned in Gray code order. +## @end table +## +## @seealso{ifwht} +## @end deftypefn + +## Author: Mike Miller + +function y = fwht (x, n, order) + + if (nargin < 1 || nargin > 3) + print_usage (); + elseif (nargin == 1) + n = order = []; + elseif (nargin == 2) + order = []; + endif + + [y, n] = __fwht_opts__ ("fwht", x, n, order); + y /= n; + +endfunction + +%!assert (isempty (fwht ([]))); +%!assert (fwht (zeros (16)), zeros (16)); +%!assert (fwht (ones (16, 1)), [1; (zeros (15, 1))]); +%!assert (fwht (zeros (17, 1)), zeros (32, 1)); +%!assert (fwht ([1 -1 1 -1 1 -1 1 -1]), [0 0 0 0 0 0 0 1]); + +%!test +%! x = randi (16, 16); +%! assert (ifwht (fwht (x)), x); + +%% Test input validation +%!error fwht (); +%!error fwht (1, 2, 3, 4); +%!error fwht (0, 0); +%!error fwht (0, 5); +%!error fwht (0, [], "invalid");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/signal/inst/ifwht.m Mon Mar 11 02:25:15 2013 +0000 @@ -0,0 +1,74 @@ +## Copyright (C) 2013 Mike Miller <mtmiller@ieee.org> +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} {} ifwht (@var{x}) +## @deftypefnx {Function File} {} ifwht (@var{x}, @var{n}) +## @deftypefnx {Function File} {} ifwht (@var{x}, @var{n}, @var{order}) +## Compute the inverse Walsh-Hadamard transform of @var{x} using the +## Fast Walsh-Hadamard Transform (FWHT) algorithm. If the input is a +## matrix, the inverse FWHT is calculated along the columns of @var{x}. +## +## The number of elements of @var{x} must be a power of 2; if not, the +## input will be extended and filled with zeros. If a second argument +## is given, the input is truncated or extended to have length @var{n}. +## +## The third argument specifies the @var{order} in which the returned +## inverse Walsh-Hadamard transform coefficients should be arranged. +## The @var{order} may be any of the following strings: +## +## @table @asis +## @item "sequency" +## The coefficients are returned in sequency order. This is the default +## if @var{order} is not given. +## +## @item "hadamard" +## The coefficients are returned in Hadamard order. +## +## @item "dyadic" +## The coefficients are returned in Gray code order. +## @end table +## +## @seealso{fwht} +## @end deftypefn + +## Author: Mike Miller + +function y = ifwht (x, n, order) + + if (nargin < 1 || nargin > 3) + print_usage (); + elseif (nargin == 1) + n = order = []; + elseif (nargin == 2) + order = []; + endif + + y = __fwht_opts__ ("ifwht", x, n, order); + +endfunction + +%!assert (isempty (ifwht ([]))); +%!assert (ifwht (zeros (16)), zeros (16)); +%!assert (ifwht ([1; (zeros (15, 1))]), ones (16, 1)); +%!assert (ifwht (zeros (17, 1)), zeros (32, 1)); +%!assert (ifwht ([0 0 0 0 0 0 0 1]), [1 -1 1 -1 1 -1 1 -1]); + +%% Test input validation +%!error ifwht (); +%!error ifwht (1, 2, 3, 4); +%!error ifwht (0, 0); +%!error ifwht (0, 5); +%!error ifwht (0, [], "invalid");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/signal/inst/private/__fwht_opts__.m Mon Mar 11 02:25:15 2013 +0000 @@ -0,0 +1,93 @@ +## Copyright (C) 2013 Mike Miller <mtmiller@ieee.org> +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{y}, @var{len}] =} __fwht_opts__ (@var{caller}, @var{x}, @var{n}, @var{order}) +## Undocumented internal function. +## @end deftypefn + +## Author: Mike Miller + +function [y, len] = __fwht_opts__ (caller, x, n, order) + + if (nargin < 1) + print_usage (); + elseif (nargin != 4) + print_usage (caller); + endif + + [nr, nc] = size (x); + + if (isempty (n)) + if (nr == 1) + n = 2^nextpow2 (nc); + else + n = 2^nextpow2 (nr); + endif + elseif (!(isscalar (n) && n == fix (n) && n > 0)) + error ("%s: N must be a positive scalar", caller); + else + f = log2(n); + if (f != fix (f)) + error ("%s: N must be a power of 2", caller); + endif + endif + + if (isempty (order)) + order = "sequency"; + endif + if (!(strncmp (order, "dyadic", 6) || + strncmp (order, "hadamard", 8) || + strncmp (order, "sequency", 8))) + error ("%s: invalid order option", caller); + endif + + if (nr == 1) + nc = n; + x = x(:); + else + nr = n; + endif + + ## Zero-based index for normal Hadamard ordering + idx = 0:n-1; + + ## Gray code permutation of index for alternate orderings + idx_bin = dec2bin (idx) - "0"; + idx_bin_a = idx_bin(:,1:end-1); + idx_bin_b = idx_bin(:,2:end); + idx_bin(:,2:end) = mod (idx_bin_a + idx_bin_b, 2); + idx_bin = char (idx_bin + "0"); + + if (strncmp (order, "dyadic", 6)) + idx = bin2dec (idx_bin) + 1; + elseif (strncmp (order, "sequency", 8)) + idx = bin2dec (fliplr (idx_bin)) + 1; + else + idx += 1; + endif + + len = n; + x = postpad (x, len); + + if (len < 2) + y = x; + else + y = __fwht__ (x); + endif + + y = reshape (y(idx,:), nr, nc); + +endfunction
--- a/main/signal/src/Makefile Sun Mar 10 22:32:12 2013 +0000 +++ b/main/signal/src/Makefile Mon Mar 11 02:25:15 2013 +0000 @@ -1,6 +1,6 @@ MKOCTFILE ?= mkoctfile -all: cl2bp.oct remez.oct medfilt1.oct sosfilt.oct upfirdn.oct +all: __fwht__.oct cl2bp.oct remez.oct medfilt1.oct sosfilt.oct upfirdn.oct %.oct: %.cc $(MKOCTFILE) -Wall -s $<
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/signal/src/__fwht__.cc Mon Mar 11 02:25:15 2013 +0000 @@ -0,0 +1,62 @@ +// Copyright (C) 2013 Mike Miller <mtmiller@ieee.org> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +#include <octave/oct.h> + +template <typename T> +static void do_fwht (T *x, octave_idx_type n) +{ + double *xa = &x[0]; + double *xb = &x[n/2]; + + // Perform the FWHT butterfly on the input + for (octave_idx_type i = 0; i < n/2; i++) + { + double ya = xa[i] + xb[i]; + double yb = xa[i] - xb[i]; + xa[i] = ya; + xb[i] = yb; + } + + // Divide and conquer + if (n > 2) + { + do_fwht (xa, n/2); + do_fwht (xb, n/2); + } +} + +DEFUN_DLD (__fwht__, args, , + "-*- texinfo -*-\n" +"@deftypefn {Loadable Function} {} __fwht__ (@var{x})\n" +"Undocumented internal function.\n" +"@end deftypefn\n") +{ + int nargin = args.length (); + if (nargin != 1) + print_usage (); + else + { + NDArray x = args(0).array_value (); + octave_idx_type n = x.rows (); + double *data = x.fortran_vec (); + for (octave_idx_type i = 0; i < x.columns (); i++) + { + do_fwht (&data[i*n], n); + } + return octave_value (x); + } + return octave_value (); +}