changeset 21386:23e8130ed024

unwrap.m: Fix overcompensation for large phase changes (bug #47279) * unwrap.m: Use round instead of ceil for phase change correction, fixes overcompensation when phase change is large relative to tol. Add BIST tests for small tolerances and large phase changes. Clean up existing BIST tests.
author Mike Miller <mtmiller@octave.org>
date Tue, 01 Mar 2016 13:15:08 -0800
parents 89fa0694aa2e
children cd9d95d74403
files scripts/signal/unwrap.m
diffstat 1 files changed, 44 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/signal/unwrap.m	Thu Feb 25 10:37:59 2016 -0800
+++ b/scripts/signal/unwrap.m	Tue Mar 01 13:15:08 2016 -0800
@@ -21,8 +21,8 @@
 ## @deftypefnx {} {@var{b} =} unwrap (@var{x}, @var{tol})
 ## @deftypefnx {} {@var{b} =} unwrap (@var{x}, @var{tol}, @var{dim})
 ##
-## Unwrap radian phases by adding multiples of 2*pi as appropriate to remove
-## jumps greater than @var{tol}.
+## Unwrap radian phases by adding or subtracting multiples of 2*pi as
+## appropriate to remove jumps greater than @var{tol}.
 ##
 ## @var{tol} defaults to pi.
 ##
@@ -80,7 +80,7 @@
   ## Find only the peaks, and multiply them by the appropriate amount
   ## of ranges so that there are kronecker deltas at each wrap point
   ## multiplied by the appropriate amount of range values.
-  p = ceil (abs (d)./rng) .* rng .* (((d > tol) > 0) - ((d < -tol) > 0));
+  p = round (abs (d)./rng) .* rng .* (((d > tol) > 0) - ((d < -tol) > 0));
 
   ## Now need to "integrate" this so that the deltas become steps.
   r = cumsum (p, dim);
@@ -92,53 +92,43 @@
 endfunction
 
 
-%!function t = __xassert (a,b,tol)
-%!  if (nargin == 1)
-%!    t = all (a(:));
-%!  else
-%!    if (nargin == 2)
-%!      tol = 0;
-%!    endif
-%!    if (any (size (a) != size (b)))
-%!      t = 0;
-%!    elseif (any (abs (a(:) - b(:)) > tol))
-%!      t = 0;
-%!    else
-%!      t = 1;
-%!    endif
-%!  endif
-%!endfunction
-%!
-%!test
-%!
+%!shared i, t, r, w, tol
 %! i = 0;
 %! t = [];
-%!
-%! r = [0:100];                        # original vector
-%! w = r - 2*pi*floor ((r+pi)/(2*pi)); # wrapped into [-pi,pi]
-%! tol = 1e3*eps;                      # maximum expected deviation
-%!
-%! t(++i) = __xassert (r, unwrap (w), tol);              #unwrap single row
-%! t(++i) = __xassert (r', unwrap (w'), tol);            #unwrap single column
-%! t(++i) = __xassert ([r',r'], unwrap ([w',w']), tol);  #unwrap 2 columns
-%! t(++i) = __xassert ([r;r], unwrap ([w;w],[],2), tol); #check that dim works
-%! t(++i) = __xassert (r+10, unwrap (10+w), tol);        #check r(1)>pi works
-%!
-%! t(++i) = __xassert (w', unwrap (w',[],2));  #unwrap col by rows should not change it
-%! t(++i) = __xassert (w, unwrap (w,[],1));    #unwrap row by cols should not change it
-%! t(++i) = __xassert ([w;w], unwrap ([w;w])); #unwrap 2 rows by cols should not change them
-%!
-%! ## verify that setting tolerance too low will cause bad results.
-%! t(++i) = __xassert (any (abs (r - unwrap (w,0.8)) > 100));
-%!
-%! assert (all (t));
-%!
+%! r = [0:100];                         ## original vector
+%! w = r - 2*pi*floor ((r+pi)/(2*pi));  ## wrapped into [-pi,pi]
+%! tol = 1e3*eps;
+
+%!assert (r,  unwrap (w),  tol)
+%!assert (r', unwrap (w'), tol)
+%!assert ([r',r'], unwrap ([w',w']), tol)
+%!assert ([r; r ], unwrap ([w; w ], [], 2), tol)
+%!assert (r + 10, unwrap (10 + w), tol)
+
+%!assert (w', unwrap (w', [], 2))
+%!assert (w,  unwrap (w,  [], 1))
+%!assert ([w; w], unwrap ([w; w]))
+
+## Test that small values of tol have the same effect as tol = pi
+%!assert (r, unwrap (w, 0.1), tol)
+%!assert (r, unwrap (w, eps), tol)
+
+## Test that phase changes larger than 2*pi unwrap properly
+%!assert ([0;  1],        unwrap ([0;  1]))
+%!assert ([0;  4 - 2*pi], unwrap ([0;  4]))
+%!assert ([0;  7 - 2*pi], unwrap ([0;  7]))
+%!assert ([0; 10 - 4*pi], unwrap ([0; 10]))
+%!assert ([0; 13 - 4*pi], unwrap ([0; 13]))
+%!assert ([0; 16 - 6*pi], unwrap ([0; 16]))
+%!assert ([0; 19 - 6*pi], unwrap ([0; 19]))
+%!assert (max (abs (diff (unwrap (100*pi * rand (1000, 1))))) < pi)
+
 %!test
 %! A = [pi*(-4), pi*(-2+1/6), pi/4, pi*(2+1/3), pi*(4+1/2), pi*(8+2/3), pi*(16+1), pi*(32+3/2), pi*64];
-%! assert (unwrap (A), unwrap (A, pi));
-%! assert (unwrap (A, pi), unwrap (A, pi, 2));
-%! assert (unwrap (A', pi), unwrap (A', pi, 1));
-%!
+%! assert (unwrap (A), unwrap (A, pi))
+%! assert (unwrap (A, pi), unwrap (A, pi, 2))
+%! assert (unwrap (A', pi), unwrap (A', pi, 1))
+
 %!test
 %! A = [pi*(-4); pi*(2+1/3); pi*(16+1)];
 %! B = [pi*(-2+1/6); pi*(4+1/2); pi*(32+3/2)];
@@ -148,13 +138,16 @@
 %! E(:, :, 2) = [A+B, B+C, C+D, D+A];
 %! F(:, :, 1) = [unwrap(A), unwrap(B), unwrap(C), unwrap(D)];
 %! F(:, :, 2) = [unwrap(A+B), unwrap(B+C), unwrap(C+D), unwrap(D+A)];
-%! assert (unwrap (E), F);
-%!
+%! assert (unwrap (E), F)
+
 %!test
 %! A = [0, 2*pi, 4*pi, 8*pi, 16*pi, 65536*pi];
 %! B = [pi*(-2+1/6), pi/4, pi*(2+1/3), pi*(4+1/2), pi*(8+2/3), pi*(16+1), pi*(32+3/2), pi*64];
-%! assert (unwrap (A), zeros (1, length (A)));
-%! assert (diff (unwrap (B), 1) < 2*pi, true (1, length (B)-1));
+%! assert (unwrap (A), zeros (1, length (A)))
+%! assert (diff (unwrap (B), 1) < 2*pi, true (1, length (B)-1))
 
-%!error unwrap()
+## Test input validation
+%!error unwrap ()
+%!error unwrap (1,2,3,4)
+%!error unwrap ("foo")