From 29c0bb32aed55ab4c353113d622c77d0b8541247 Mon Sep 17 00:00:00 2001 From: scimax Date: Sat, 1 Aug 2020 16:32:50 +0200 Subject: [PATCH 01/29] Phase unwrapping generalized Phase unwrapping generalized to arbitrary interval size, such as 360 for phase in degree instead of radian. Also integer unwrapping is supported, but the return values are floats. --- numpy/lib/function_base.py | 51 ++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 42ea8c7a785d..804f7bef3028 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1487,37 +1487,44 @@ def _unwrap_dispatcher(p, discont=None, axis=None): @array_function_dispatch(_unwrap_dispatcher) -def unwrap(p, discont=pi, axis=-1): - """ - Unwrap by changing deltas between values to 2*pi complement. +# def _unwrap_dispatcher(p, discont=None, axis=None, *, min_val=None, max_val=None): +# return (p,) - Unwrap radian phase `p` by changing absolute jumps greater than - `discont` to their 2*pi complement along the given axis. +# @array_function_dispatch(_unwrap_dispatcher) +def unwrap(p, interval_size= 2*pi, discont=None, axis=-1): + """ + Unwrap by changing deltas between values to complement. + + For the default case where `interval_size= 2*pi`, `discont=pi`, + It unwraps radian phase `p` by changing absolute jumps greater + than `discont` to their 2*pi complement along the given axis. + + In general it unwrapps a signal `p` by changing absolute jumps + greater than `discont` to their `interval_size` complementary values. + Parameters ---------- p : array_like Input array. + interval_size: float, optional + size of the range over which the input wraps. discont : float, optional - Maximum discontinuity between values, default is ``pi``. + Maximum discontinuity between values, default is ``interval_size/2``. axis : int, optional Axis along which unwrap will operate, default is the last axis. - Returns ------- out : ndarray Output array. - See Also -------- rad2deg, deg2rad - Notes ----- - If the discontinuity in `p` is smaller than ``pi``, but larger than - `discont`, no unwrapping is done because taking the 2*pi complement - would only make the discontinuity larger. - + If the discontinuity in `p` is smaller than ``interval_size/2``, + but larger than `discont`, no unwrapping is done because taking + the complement would only make the discontinuity larger. Examples -------- >>> phase = np.linspace(0, np.pi, num=5) @@ -1526,16 +1533,28 @@ def unwrap(p, discont=pi, axis=-1): array([ 0. , 0.78539816, 1.57079633, 5.49778714, 6.28318531]) # may vary >>> np.unwrap(phase) array([ 0. , 0.78539816, 1.57079633, -0.78539816, 0. ]) # may vary - + >>> unwrap([0, 1, 2, -1, 0], interval_size=4) + array([0., 1., 2., 3., 4.]) + >>> unwrap([ 1, 2, 3, 4, 5, 6, 1, 2, 3], interval_size=6) + array([1., 2., 3., 4., 5., 6., 7., 8., 9.]) + >>> unwrap([2, 3, 4, 5, 2, 3, 4, 5], interval_size=4) + array([2., 3., 4., 5., 6., 7., 8., 9.]) + >>> phase_deg = np.mod(np.linspace(0,720,19), 360) - 180 + >>> unwrap(phase_deg, interval_size=360) + array([-180., -140., -100., -60., -20., 20., 60., 100., 140., + 180., 220., 260., 300., 340., 380., 420., 460., 500., + 540.]) """ + if discont is None: + discont = interval_size/2 p = asarray(p) nd = p.ndim dd = diff(p, axis=axis) slice1 = [slice(None, None)]*nd # full slices slice1[axis] = slice(1, None) slice1 = tuple(slice1) - ddmod = mod(dd + pi, 2*pi) - pi - _nx.copyto(ddmod, pi, where=(ddmod == -pi) & (dd > 0)) + ddmod = mod(dd + interval_size/2, interval_size) - interval_size/2 + _nx.copyto(ddmod, interval_size/2, where=(ddmod == -interval_size/2) & (dd > 0)) ph_correct = ddmod - dd _nx.copyto(ph_correct, 0, where=abs(dd) < discont) up = array(p, copy=True, dtype='d') From f08059353890eff34c993d8bd5a8291f629f8fc7 Mon Sep 17 00:00:00 2001 From: scimax Date: Sun, 2 Aug 2020 17:31:25 +0200 Subject: [PATCH 02/29] Update numpy/lib/function_base.py unwrap function signature compatible Co-authored-by: Eric Wieser --- numpy/lib/function_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 804f7bef3028..cc8e1a191da0 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1492,7 +1492,7 @@ def _unwrap_dispatcher(p, discont=None, axis=None): # @array_function_dispatch(_unwrap_dispatcher) -def unwrap(p, interval_size= 2*pi, discont=None, axis=-1): +def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi): """ Unwrap by changing deltas between values to complement. From dfee8851c65276907eedd084ff40334ea7d46865 Mon Sep 17 00:00:00 2001 From: Max Kellermeier Date: Sun, 2 Aug 2020 18:10:01 +0200 Subject: [PATCH 03/29] Tests added according to #14877, obsolete comments removed. --- numpy/lib/function_base.py | 5 ----- numpy/lib/tests/test_function_base.py | 18 +++++++++++++++++- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index cc8e1a191da0..16453ffbe7cd 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1487,11 +1487,6 @@ def _unwrap_dispatcher(p, discont=None, axis=None): @array_function_dispatch(_unwrap_dispatcher) -# def _unwrap_dispatcher(p, discont=None, axis=None, *, min_val=None, max_val=None): -# return (p,) - - -# @array_function_dispatch(_unwrap_dispatcher) def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi): """ Unwrap by changing deltas between values to complement. diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index eb2fc3311aca..878fb3de1070 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -1756,7 +1756,23 @@ def test_simple(self): assert_array_equal(unwrap([1, 1 + 2 * np.pi]), [1, 1]) # check that unwrap maintains continuity assert_(np.all(diff(unwrap(rand(10) * 100)) < np.pi)) - + + def test_minmax(self): + # check that unwrap removes jumps greater that 255 + assert_array_equal(unwrap([1, 1 + 256], interval_size=255), [1, 2]) + # check that unwrap maintains continuity + assert_(np.all(diff(unwrap(rand(10) * 1000, interval_size=255)) < 255)) + # check simple case + simple_seq = np.array([0, 75, 150, 225, 300]) + wrap_seq = np.mod(simple_seq, 255) + assert_array_equal(unwrap(wrap_seq, interval_size=255), simple_seq) + # check custom discont value + uneven_seq = np.array([0, 75, 150, 225, 300, 430]) + wrap_uneven = np.mod(uneven_seq, 250) + no_discont = unwrap(wrap_uneven, interval_size=250) + assert_array_equal(no_discont, [0, 75, 150, 225, 300, 180]) + sm_discont = unwrap(wrap_uneven, interval_size=250, discont=140) + assert_array_equal(sm_discont, [0, 75, 150, 225, 300, 430]) class TestFilterwindows: From 6131310089d6eaca6e52db0e2a1406f6f5a77096 Mon Sep 17 00:00:00 2001 From: Max Kellermeier Date: Mon, 3 Aug 2020 09:11:44 +0200 Subject: [PATCH 04/29] Release Note --- doc/release/upcoming_changes/16987.improvement.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 doc/release/upcoming_changes/16987.improvement.rst diff --git a/doc/release/upcoming_changes/16987.improvement.rst b/doc/release/upcoming_changes/16987.improvement.rst new file mode 100644 index 000000000000..28acc1ce2fa5 --- /dev/null +++ b/doc/release/upcoming_changes/16987.improvement.rst @@ -0,0 +1,14 @@ +Arbitrary `interval_size` option for ``numpy.unwrap`` +----------------------------------------------------- +The size of the interval, over which phases are unwraped, is not restricted to `2 * pi` +anymore. This is especially useful for unwrapping degrees but can also be used for other +intervals. + +.. code:: python + + >>> phase_deg = np.mod(np.linspace(0,720,19), 360) - 180 + >>> unwrap(phase_deg, interval_size=360) + array([-180., -140., -100., -60., -20., 20., 60., 100., 140., + 180., 220., 260., 300., 340., 380., 420., 460., 500., + 540.]) + From 0b7ad2c5185aaea651181ac3815def7e1c2f6247 Mon Sep 17 00:00:00 2001 From: Max Kellermeier Date: Mon, 3 Aug 2020 09:25:37 +0200 Subject: [PATCH 05/29] dispatcher fixed --- numpy/lib/function_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 16453ffbe7cd..c5541cc862b2 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1482,7 +1482,7 @@ def angle(z, deg=False): return a -def _unwrap_dispatcher(p, discont=None, axis=None): +def _unwrap_dispatcher(p, discont=None, axis=None, *, interval_size=2*pi): return (p,) From 2c0d4b8e4411ca046cbf92aaabe3e860499f0e21 Mon Sep 17 00:00:00 2001 From: Max Kellermeier Date: Mon, 3 Aug 2020 16:54:26 +0200 Subject: [PATCH 06/29] Hybrid solution including interval boundaries, and keeping backward compatibility without boundary --- numpy/lib/function_base.py | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index c5541cc862b2..772f44fcf264 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1482,12 +1482,12 @@ def angle(z, deg=False): return a -def _unwrap_dispatcher(p, discont=None, axis=None, *, interval_size=2*pi): +def _unwrap_dispatcher(p, discont=None, axis=None, *, interval_size=2*pi, min_val=None, max_val=None): return (p,) @array_function_dispatch(_unwrap_dispatcher) -def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi): +def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi, min_val=None, max_val=None): """ Unwrap by changing deltas between values to complement. @@ -1502,12 +1502,25 @@ def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi): ---------- p : array_like Input array. - interval_size: float, optional - size of the range over which the input wraps. discont : float, optional Maximum discontinuity between values, default is ``interval_size/2``. axis : int, optional Axis along which unwrap will operate, default is the last axis. + interval_size: float, optional + Size of the range over which the input wraps. By default, it is 2 pi. + If ``min_val`` and ``max_val`` are given, ``interval_size`` is ignored + and the interval size is ``max_val - min_val``. + min_val, max_val: float, optional + Boundaries of the interval over which the input array is expected to + wrap. By default, they are ``None`` and the interval is considered as + ``[-interval_size, interval_size]``. In case the first value of the + phase input array, ``p[0]``, is outside of the interval + ``[min_val, max_val]`` it will be corrected by an integral multiple of + the interval size such that it will be within the + boundaries. + Both boundaries require each other. If only one boundary is + provided without the other, it will be ignored. + Returns ------- out : ndarray @@ -1540,11 +1553,20 @@ def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi): 180., 220., 260., 300., 340., 380., 420., 460., 500., 540.]) """ - if discont is None: - discont = interval_size/2 p = asarray(p) nd = p.ndim dd = diff(p, axis=axis) + offset = 0 + if (not min_val is None) and (not max_val is None): + interval_size = max_val - min_val + slice0list = [slice(None, None)]*nd # full slices + slice0list[axis] = 0 + slice0 = tuple(slice0list) + offset_mul = (p[slice0] - min_val)//interval_size + slice0list[axis] = None + offset = -offset_mul[tuple(slice0list)]*interval_size + if discont is None: + discont = interval_size/2 slice1 = [slice(None, None)]*nd # full slices slice1[axis] = slice(1, None) slice1 = tuple(slice1) @@ -1552,8 +1574,9 @@ def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi): _nx.copyto(ddmod, interval_size/2, where=(ddmod == -interval_size/2) & (dd > 0)) ph_correct = ddmod - dd _nx.copyto(ph_correct, 0, where=abs(dd) < discont) + p += offset up = array(p, copy=True, dtype='d') - up[slice1] = p[slice1] + ph_correct.cumsum(axis) + up[slice1] = p[slice1] + ph_correct.cumsum(axis) return up From 24afdab04507d92b47c7fba48f71b0ba0b012e28 Mon Sep 17 00:00:00 2001 From: scimax Date: Mon, 17 Aug 2020 22:19:46 +0200 Subject: [PATCH 07/29] shorter slice Co-authored-by: Eric Wieser --- numpy/lib/function_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 772f44fcf264..88926ff5bf06 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1559,7 +1559,7 @@ def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi, min_val=None, max_va offset = 0 if (not min_val is None) and (not max_val is None): interval_size = max_val - min_val - slice0list = [slice(None, None)]*nd # full slices + slice0list = [slice(None)]*nd # full slices slice0list[axis] = 0 slice0 = tuple(slice0list) offset_mul = (p[slice0] - min_val)//interval_size From 16e3bec1744c39915e7ec3e490529c01e2cbde7a Mon Sep 17 00:00:00 2001 From: Max Kellermeier Date: Thu, 20 Aug 2020 11:06:58 +0200 Subject: [PATCH 08/29] Rolling back to only. Improved documentation --- numpy/lib/function_base.py | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 88926ff5bf06..910c2bc43d86 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1482,18 +1482,19 @@ def angle(z, deg=False): return a -def _unwrap_dispatcher(p, discont=None, axis=None, *, interval_size=2*pi, min_val=None, max_val=None): +def _unwrap_dispatcher(p, discont=None, axis=None, *, interval_size=2*pi): return (p,) @array_function_dispatch(_unwrap_dispatcher) -def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi, min_val=None, max_val=None): +def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi): """ Unwrap by changing deltas between values to complement. For the default case where `interval_size= 2*pi`, `discont=pi`, It unwraps radian phase `p` by changing absolute jumps greater - than `discont` to their 2*pi complement along the given axis. + than `discont` to their 2*pi complement along the given axis. Jumps equal + to `discont` are not changed. In general it unwrapps a signal `p` by changing absolute jumps greater than `discont` to their `interval_size` complementary values. @@ -1507,19 +1508,7 @@ def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi, min_val=None, max_va axis : int, optional Axis along which unwrap will operate, default is the last axis. interval_size: float, optional - Size of the range over which the input wraps. By default, it is 2 pi. - If ``min_val`` and ``max_val`` are given, ``interval_size`` is ignored - and the interval size is ``max_val - min_val``. - min_val, max_val: float, optional - Boundaries of the interval over which the input array is expected to - wrap. By default, they are ``None`` and the interval is considered as - ``[-interval_size, interval_size]``. In case the first value of the - phase input array, ``p[0]``, is outside of the interval - ``[min_val, max_val]`` it will be corrected by an integral multiple of - the interval size such that it will be within the - boundaries. - Both boundaries require each other. If only one boundary is - provided without the other, it will be ignored. + Size of the range over which the input wraps. By default, it is ``2 pi``. Returns ------- @@ -1556,15 +1545,6 @@ def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi, min_val=None, max_va p = asarray(p) nd = p.ndim dd = diff(p, axis=axis) - offset = 0 - if (not min_val is None) and (not max_val is None): - interval_size = max_val - min_val - slice0list = [slice(None)]*nd # full slices - slice0list[axis] = 0 - slice0 = tuple(slice0list) - offset_mul = (p[slice0] - min_val)//interval_size - slice0list[axis] = None - offset = -offset_mul[tuple(slice0list)]*interval_size if discont is None: discont = interval_size/2 slice1 = [slice(None, None)]*nd # full slices @@ -1574,7 +1554,6 @@ def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi, min_val=None, max_va _nx.copyto(ddmod, interval_size/2, where=(ddmod == -interval_size/2) & (dd > 0)) ph_correct = ddmod - dd _nx.copyto(ph_correct, 0, where=abs(dd) < discont) - p += offset up = array(p, copy=True, dtype='d') up[slice1] = p[slice1] + ph_correct.cumsum(axis) return up From de7aa73c56d8128e3fa5cca1e99ff352fffdf0c5 Mon Sep 17 00:00:00 2001 From: scimax Date: Thu, 20 Aug 2020 11:49:22 +0200 Subject: [PATCH 09/29] Minor code clean up Co-authored-by: Eric Wieser --- doc/release/upcoming_changes/16987.improvement.rst | 5 ++--- numpy/lib/function_base.py | 6 ++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/release/upcoming_changes/16987.improvement.rst b/doc/release/upcoming_changes/16987.improvement.rst index 28acc1ce2fa5..9ff81380afed 100644 --- a/doc/release/upcoming_changes/16987.improvement.rst +++ b/doc/release/upcoming_changes/16987.improvement.rst @@ -9,6 +9,5 @@ intervals. >>> phase_deg = np.mod(np.linspace(0,720,19), 360) - 180 >>> unwrap(phase_deg, interval_size=360) array([-180., -140., -100., -60., -20., 20., 60., 100., 140., - 180., 220., 260., 300., 340., 380., 420., 460., 500., - 540.]) - + 180., 220., 260., 300., 340., 380., 420., 460., 500., + 540.]) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 910c2bc43d86..3115f7a80664 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1482,7 +1482,7 @@ def angle(z, deg=False): return a -def _unwrap_dispatcher(p, discont=None, axis=None, *, interval_size=2*pi): +def _unwrap_dispatcher(p, discont=None, axis=None, *, interval_size=None): return (p,) @@ -1551,11 +1551,13 @@ def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi): slice1[axis] = slice(1, None) slice1 = tuple(slice1) ddmod = mod(dd + interval_size/2, interval_size) - interval_size/2 + # the above line made `ddmod[abs(dd) == interval_size/2] == -interval_size/2`. + # correct these such that `ddmod[abs(dd) == interval_size/2] == sign(dd)*interval_size/2`. _nx.copyto(ddmod, interval_size/2, where=(ddmod == -interval_size/2) & (dd > 0)) ph_correct = ddmod - dd _nx.copyto(ph_correct, 0, where=abs(dd) < discont) up = array(p, copy=True, dtype='d') - up[slice1] = p[slice1] + ph_correct.cumsum(axis) + up[slice1] = p[slice1] + ph_correct.cumsum(axis) return up From 11ae4340173c644768368755bba93ced112b4505 Mon Sep 17 00:00:00 2001 From: Max Kellermeier Date: Thu, 20 Aug 2020 11:59:52 +0200 Subject: [PATCH 10/29] Renamed new argument for unwraping. Extended release note --- .../upcoming_changes/16987.improvement.rst | 9 ++++-- numpy/lib/function_base.py | 32 +++++++++---------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/doc/release/upcoming_changes/16987.improvement.rst b/doc/release/upcoming_changes/16987.improvement.rst index 9ff81380afed..e85fbda915a5 100644 --- a/doc/release/upcoming_changes/16987.improvement.rst +++ b/doc/release/upcoming_changes/16987.improvement.rst @@ -1,4 +1,4 @@ -Arbitrary `interval_size` option for ``numpy.unwrap`` +Arbitrary `period` option for ``numpy.unwrap`` ----------------------------------------------------- The size of the interval, over which phases are unwraped, is not restricted to `2 * pi` anymore. This is especially useful for unwrapping degrees but can also be used for other @@ -7,7 +7,12 @@ intervals. .. code:: python >>> phase_deg = np.mod(np.linspace(0,720,19), 360) - 180 - >>> unwrap(phase_deg, interval_size=360) + >>> phase_deg + array([-180., -140., -100., -60., -20., 20., 60., 100., 140., + -180., -140., -100., -60., -20., 20., 60., 100., 140., + -180.]) + + >>> unwrap(phase_deg, period=360) array([-180., -140., -100., -60., -20., 20., 60., 100., 140., 180., 220., 260., 300., 340., 380., 420., 460., 500., 540.]) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 3115f7a80664..ceea92849903 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1482,32 +1482,32 @@ def angle(z, deg=False): return a -def _unwrap_dispatcher(p, discont=None, axis=None, *, interval_size=None): +def _unwrap_dispatcher(p, discont=None, axis=None, *, period=None): return (p,) @array_function_dispatch(_unwrap_dispatcher) -def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi): +def unwrap(p, discont=None, axis=-1, *, period=2*pi): """ Unwrap by changing deltas between values to complement. - For the default case where `interval_size= 2*pi`, `discont=pi`, + For the default case where `period= 2*pi`, `discont=pi`, It unwraps radian phase `p` by changing absolute jumps greater than `discont` to their 2*pi complement along the given axis. Jumps equal to `discont` are not changed. In general it unwrapps a signal `p` by changing absolute jumps - greater than `discont` to their `interval_size` complementary values. + greater than `discont` to their `period` complementary values. Parameters ---------- p : array_like Input array. discont : float, optional - Maximum discontinuity between values, default is ``interval_size/2``. + Maximum discontinuity between values, default is ``period/2``. axis : int, optional Axis along which unwrap will operate, default is the last axis. - interval_size: float, optional + period: float, optional Size of the range over which the input wraps. By default, it is ``2 pi``. Returns @@ -1519,7 +1519,7 @@ def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi): rad2deg, deg2rad Notes ----- - If the discontinuity in `p` is smaller than ``interval_size/2``, + If the discontinuity in `p` is smaller than ``period/2``, but larger than `discont`, no unwrapping is done because taking the complement would only make the discontinuity larger. Examples @@ -1530,14 +1530,14 @@ def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi): array([ 0. , 0.78539816, 1.57079633, 5.49778714, 6.28318531]) # may vary >>> np.unwrap(phase) array([ 0. , 0.78539816, 1.57079633, -0.78539816, 0. ]) # may vary - >>> unwrap([0, 1, 2, -1, 0], interval_size=4) + >>> unwrap([0, 1, 2, -1, 0], period=4) array([0., 1., 2., 3., 4.]) - >>> unwrap([ 1, 2, 3, 4, 5, 6, 1, 2, 3], interval_size=6) + >>> unwrap([ 1, 2, 3, 4, 5, 6, 1, 2, 3], period=6) array([1., 2., 3., 4., 5., 6., 7., 8., 9.]) - >>> unwrap([2, 3, 4, 5, 2, 3, 4, 5], interval_size=4) + >>> unwrap([2, 3, 4, 5, 2, 3, 4, 5], period=4) array([2., 3., 4., 5., 6., 7., 8., 9.]) >>> phase_deg = np.mod(np.linspace(0,720,19), 360) - 180 - >>> unwrap(phase_deg, interval_size=360) + >>> unwrap(phase_deg, period=360) array([-180., -140., -100., -60., -20., 20., 60., 100., 140., 180., 220., 260., 300., 340., 380., 420., 460., 500., 540.]) @@ -1546,14 +1546,14 @@ def unwrap(p, discont=None, axis=-1, *, interval_size=2*pi): nd = p.ndim dd = diff(p, axis=axis) if discont is None: - discont = interval_size/2 + discont = period/2 slice1 = [slice(None, None)]*nd # full slices slice1[axis] = slice(1, None) slice1 = tuple(slice1) - ddmod = mod(dd + interval_size/2, interval_size) - interval_size/2 - # the above line made `ddmod[abs(dd) == interval_size/2] == -interval_size/2`. - # correct these such that `ddmod[abs(dd) == interval_size/2] == sign(dd)*interval_size/2`. - _nx.copyto(ddmod, interval_size/2, where=(ddmod == -interval_size/2) & (dd > 0)) + ddmod = mod(dd + period/2, period) - period/2 + # for `mask = (abs(dd) == period/2)`, the above line made `ddmod[mask] == -period/2`. + # correct these such that `ddmod[mask] == sign(dd[mask])*period/2`. + _nx.copyto(ddmod, period/2, where=(ddmod == -period/2) & (dd > 0)) ph_correct = ddmod - dd _nx.copyto(ph_correct, 0, where=abs(dd) < discont) up = array(p, copy=True, dtype='d') From 8cf0872290fa05b6adc18d53e45e121ef9f74bd3 Mon Sep 17 00:00:00 2001 From: scimax Date: Thu, 20 Aug 2020 12:01:53 +0200 Subject: [PATCH 11/29] Update numpy/lib/tests/test_function_base.py Co-authored-by: Eric Wieser --- numpy/lib/tests/test_function_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 878fb3de1070..44ff7ea81dad 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -1757,7 +1757,7 @@ def test_simple(self): # check that unwrap maintains continuity assert_(np.all(diff(unwrap(rand(10) * 100)) < np.pi)) - def test_minmax(self): + def test_period(self): # check that unwrap removes jumps greater that 255 assert_array_equal(unwrap([1, 1 + 256], interval_size=255), [1, 2]) # check that unwrap maintains continuity From c3ea9b680e458a91e0a7e97ce61d6853c379385f Mon Sep 17 00:00:00 2001 From: Max Kellermeier Date: Thu, 20 Aug 2020 14:34:22 +0200 Subject: [PATCH 12/29] Integer input returning integer output Co-authored-by: Eric Wieser --- numpy/lib/function_base.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index ceea92849903..491b259150e5 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1550,13 +1550,21 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): slice1 = [slice(None, None)]*nd # full slices slice1[axis] = slice(1, None) slice1 = tuple(slice1) - ddmod = mod(dd + period/2, period) - period/2 - # for `mask = (abs(dd) == period/2)`, the above line made `ddmod[mask] == -period/2`. - # correct these such that `ddmod[mask] == sign(dd[mask])*period/2`. - _nx.copyto(ddmod, period/2, where=(ddmod == -period/2) & (dd > 0)) + dtype = np.result_type(dd, period) + if _nx.issubdtype(dtype, _nx.integer): + interval_low = -(period // 2) + interval_high = -interval_low + else: + interval_low = -period / 2 + interval_high = -interval_low + ddmod = mod(dd - interval_low, period) + interval_low + if period % 2 == 0: + # for `mask = (abs(dd) == period/2)`, the above line made `ddmod[mask] == -period/2`. + # correct these such that `ddmod[mask] == sign(dd[mask])*period/2`. + _nx.copyto(ddmod, interval_high, where=(ddmod == interval_low) & (dd > 0)) ph_correct = ddmod - dd _nx.copyto(ph_correct, 0, where=abs(dd) < discont) - up = array(p, copy=True, dtype='d') + up = array(p, copy=True, dtype=dtype) up[slice1] = p[slice1] + ph_correct.cumsum(axis) return up From 00dcda244bc1eb58cb3b4f30c7b18a71a8569194 Mon Sep 17 00:00:00 2001 From: Max Kellermeier Date: Fri, 21 Aug 2020 22:55:29 +0200 Subject: [PATCH 13/29] Updated incorrect argument in tests. boundary correction for int and float. Co-authored-by: Eric Wieser --- numpy/lib/function_base.py | 4 +++- numpy/lib/tests/test_function_base.py | 11 ++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 491b259150e5..2a942a13a572 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1554,11 +1554,13 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): if _nx.issubdtype(dtype, _nx.integer): interval_low = -(period // 2) interval_high = -interval_low + boundary_ambiguous = (period % 2 == 0) else: interval_low = -period / 2 interval_high = -interval_low + boundary_ambiguous = True ddmod = mod(dd - interval_low, period) + interval_low - if period % 2 == 0: + if boundary_ambiguous: # for `mask = (abs(dd) == period/2)`, the above line made `ddmod[mask] == -period/2`. # correct these such that `ddmod[mask] == sign(dd[mask])*period/2`. _nx.copyto(ddmod, interval_high, where=(ddmod == interval_low) & (dd > 0)) diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 44ff7ea81dad..2ebde9aec6d9 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -1759,20 +1759,21 @@ def test_simple(self): def test_period(self): # check that unwrap removes jumps greater that 255 - assert_array_equal(unwrap([1, 1 + 256], interval_size=255), [1, 2]) + assert_array_equal(unwrap([1, 1 + 256], period=255), [1, 2]) # check that unwrap maintains continuity - assert_(np.all(diff(unwrap(rand(10) * 1000, interval_size=255)) < 255)) + assert_(np.all(diff(unwrap(rand(10) * 1000, period=255)) < 255)) # check simple case simple_seq = np.array([0, 75, 150, 225, 300]) wrap_seq = np.mod(simple_seq, 255) - assert_array_equal(unwrap(wrap_seq, interval_size=255), simple_seq) + assert_array_equal(unwrap(wrap_seq, period=255), simple_seq) # check custom discont value uneven_seq = np.array([0, 75, 150, 225, 300, 430]) wrap_uneven = np.mod(uneven_seq, 250) - no_discont = unwrap(wrap_uneven, interval_size=250) + no_discont = unwrap(wrap_uneven, period=250) assert_array_equal(no_discont, [0, 75, 150, 225, 300, 180]) - sm_discont = unwrap(wrap_uneven, interval_size=250, discont=140) + sm_discont = unwrap(wrap_uneven, period=250, discont=140) assert_array_equal(sm_discont, [0, 75, 150, 225, 300, 430]) + assert sm_discont.dtype == wrap_uneven.dtype class TestFilterwindows: From 8755c7f102363bee2572a08a5d9f83671af7957d Mon Sep 17 00:00:00 2001 From: scimax Date: Fri, 21 Aug 2020 23:08:14 +0200 Subject: [PATCH 14/29] Code cleanup Co-authored-by: Eric Wieser --- numpy/lib/function_base.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 2a942a13a572..4f0377efec2d 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1552,13 +1552,12 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): slice1 = tuple(slice1) dtype = np.result_type(dd, period) if _nx.issubdtype(dtype, _nx.integer): - interval_low = -(period // 2) - interval_high = -interval_low - boundary_ambiguous = (period % 2 == 0) + interval_high, rem = divmod(period, 2) + boundary_ambiguous = rem == 0 else: - interval_low = -period / 2 - interval_high = -interval_low + interval_high = period / 2 boundary_ambiguous = True + interval_low = -interval_high ddmod = mod(dd - interval_low, period) + interval_low if boundary_ambiguous: # for `mask = (abs(dd) == period/2)`, the above line made `ddmod[mask] == -period/2`. From fde3fdb05eda00a4c84d6e52184c43928b320035 Mon Sep 17 00:00:00 2001 From: Max Kellermeier Date: Sun, 23 Aug 2020 17:19:02 +0200 Subject: [PATCH 15/29] Minor corrections in unwrapping docstrings Co-authored-by: Eric Wieser --- doc/release/upcoming_changes/16987.improvement.rst | 4 ++-- numpy/lib/function_base.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/release/upcoming_changes/16987.improvement.rst b/doc/release/upcoming_changes/16987.improvement.rst index e85fbda915a5..e25b2832fa2a 100644 --- a/doc/release/upcoming_changes/16987.improvement.rst +++ b/doc/release/upcoming_changes/16987.improvement.rst @@ -9,8 +9,8 @@ intervals. >>> phase_deg = np.mod(np.linspace(0,720,19), 360) - 180 >>> phase_deg array([-180., -140., -100., -60., -20., 20., 60., 100., 140., - -180., -140., -100., -60., -20., 20., 60., 100., 140., - -180.]) + -180., -140., -100., -60., -20., 20., 60., 100., 140., + -180.]) >>> unwrap(phase_deg, period=360) array([-180., -140., -100., -60., -20., 20., 60., 100., 140., diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 4f0377efec2d..7c819eaf38df 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1531,11 +1531,11 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): >>> np.unwrap(phase) array([ 0. , 0.78539816, 1.57079633, -0.78539816, 0. ]) # may vary >>> unwrap([0, 1, 2, -1, 0], period=4) - array([0., 1., 2., 3., 4.]) + array([0, 1, 2, 3, 4]) >>> unwrap([ 1, 2, 3, 4, 5, 6, 1, 2, 3], period=6) - array([1., 2., 3., 4., 5., 6., 7., 8., 9.]) + array([1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> unwrap([2, 3, 4, 5, 2, 3, 4, 5], period=4) - array([2., 3., 4., 5., 6., 7., 8., 9.]) + array([2, 3, 4, 5, 6, 7, 8, 9]) >>> phase_deg = np.mod(np.linspace(0,720,19), 360) - 180 >>> unwrap(phase_deg, period=360) array([-180., -140., -100., -60., -20., 20., 60., 100., 140., From 7c56c83d39677deb00fc42e31a96a7118fe255a0 Mon Sep 17 00:00:00 2001 From: scimax Date: Sun, 23 Aug 2020 21:55:48 +0200 Subject: [PATCH 16/29] Apply suggestions from code review Co-authored-by: Eric Wieser --- .../upcoming_changes/16987.improvement.rst | 5 ++--- numpy/lib/function_base.py | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/doc/release/upcoming_changes/16987.improvement.rst b/doc/release/upcoming_changes/16987.improvement.rst index e25b2832fa2a..04a17e98f0a3 100644 --- a/doc/release/upcoming_changes/16987.improvement.rst +++ b/doc/release/upcoming_changes/16987.improvement.rst @@ -1,8 +1,7 @@ Arbitrary `period` option for ``numpy.unwrap`` ----------------------------------------------------- -The size of the interval, over which phases are unwraped, is not restricted to `2 * pi` -anymore. This is especially useful for unwrapping degrees but can also be used for other -intervals. +The size of the interval over which phases are unwrapped is no longer restricted to `2 * pi`. +This is especially useful for unwrapping degrees, but can also be used for other intervals. .. code:: python diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 7c819eaf38df..41dec5e80919 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1489,15 +1489,15 @@ def _unwrap_dispatcher(p, discont=None, axis=None, *, period=None): @array_function_dispatch(_unwrap_dispatcher) def unwrap(p, discont=None, axis=-1, *, period=2*pi): """ - Unwrap by changing deltas between values to complement. - - For the default case where `period= 2*pi`, `discont=pi`, - It unwraps radian phase `p` by changing absolute jumps greater - than `discont` to their 2*pi complement along the given axis. Jumps equal - to `discont` are not changed. - - In general it unwrapps a signal `p` by changing absolute jumps - greater than `discont` to their `period` complementary values. + Unwrap by taking the complement of large deltas with respect to the period. + + This unwraps a signal `p` by changing elements which have an absolute + difference from their predecessor of more than ``max(discont, period/2)`` + to their `period`-complementary values. + + For the default case where `period` is :math:`2\pi` and is `discont` is :math:`\pi`, + this unwraps a radian phase `p` such that adjacent differences are never + greater than :math:`\pi` by adding :math:`2k\pi` for some integer :math:`k`. Parameters ---------- @@ -1505,6 +1505,7 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): Input array. discont : float, optional Maximum discontinuity between values, default is ``period/2``. + Values below ``period/2`` are treated as if they were ``period/2``. axis : int, optional Axis along which unwrap will operate, default is the last axis. period: float, optional From a84b28afb9fdd0547148ba186d59fcaba9e82a8d Mon Sep 17 00:00:00 2001 From: Max Kellermeier Date: Sun, 23 Aug 2020 22:05:12 +0200 Subject: [PATCH 17/29] Comment in docs on discontinuity in unwrap --- numpy/lib/function_base.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 41dec5e80919..04b051973b57 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1504,8 +1504,9 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): p : array_like Input array. discont : float, optional - Maximum discontinuity between values, default is ``period/2``. - Values below ``period/2`` are treated as if they were ``period/2``. + Maximum discontinuity between values, default is ``period/2``. + Values below ``period/2`` are treated as if they were ``period/2``. To have an effect + different from the default, `discont` should be larger than ``period/2``. axis : int, optional Axis along which unwrap will operate, default is the last axis. period: float, optional From d31cc73b3e8772550d551931a8b0a5d8f3aae9c9 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Wed, 2 Sep 2020 12:40:27 +0100 Subject: [PATCH 18/29] Update numpy/lib/function_base.py --- numpy/lib/function_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 04b051973b57..ebfba1af19fd 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1488,7 +1488,7 @@ def _unwrap_dispatcher(p, discont=None, axis=None, *, period=None): @array_function_dispatch(_unwrap_dispatcher) def unwrap(p, discont=None, axis=-1, *, period=2*pi): - """ + r""" Unwrap by taking the complement of large deltas with respect to the period. This unwraps a signal `p` by changing elements which have an absolute From dbb347295ac7414818ab5068abe31dc19a63563c Mon Sep 17 00:00:00 2001 From: Max Kellermeier Date: Fri, 11 Sep 2020 17:57:30 +0200 Subject: [PATCH 19/29] fix CI fails by blank lines --- numpy/lib/function_base.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index ebfba1af19fd..d6dc7e5b95a4 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1516,14 +1516,17 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): ------- out : ndarray Output array. + See Also -------- rad2deg, deg2rad + Notes ----- If the discontinuity in `p` is smaller than ``period/2``, but larger than `discont`, no unwrapping is done because taking the complement would only make the discontinuity larger. + Examples -------- >>> phase = np.linspace(0, np.pi, num=5) From e6bea5f79c127a53a9252d8d3f51108815c60267 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 14 Sep 2020 10:16:37 +0100 Subject: [PATCH 20/29] Apply suggestions from code review Cleanup whitespace --- numpy/lib/function_base.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index d6dc7e5b95a4..ceb6148c5b03 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1526,7 +1526,6 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): If the discontinuity in `p` is smaller than ``period/2``, but larger than `discont`, no unwrapping is done because taking the complement would only make the discontinuity larger. - Examples -------- >>> phase = np.linspace(0, np.pi, num=5) @@ -1544,8 +1543,8 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): >>> phase_deg = np.mod(np.linspace(0,720,19), 360) - 180 >>> unwrap(phase_deg, period=360) array([-180., -140., -100., -60., -20., 20., 60., 100., 140., - 180., 220., 260., 300., 340., 380., 420., 460., 500., - 540.]) + 180., 220., 260., 300., 340., 380., 420., 460., 500., + 540.]) """ p = asarray(p) nd = p.ndim From ba6fc3ae7594f599ba3f561efb2697427da8a3f5 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 14 Sep 2020 10:17:03 +0100 Subject: [PATCH 21/29] Cleanup whitespace --- numpy/lib/function_base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index ceb6148c5b03..87929d696b9a 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1511,7 +1511,6 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): Axis along which unwrap will operate, default is the last axis. period: float, optional Size of the range over which the input wraps. By default, it is ``2 pi``. - Returns ------- out : ndarray From 985c2a64b46885ef22942df8350517a6163dfd9a Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 14 Sep 2020 10:17:34 +0100 Subject: [PATCH 22/29] Add missing newline --- numpy/lib/function_base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 87929d696b9a..d1afdf96a059 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1525,6 +1525,7 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): If the discontinuity in `p` is smaller than ``period/2``, but larger than `discont`, no unwrapping is done because taking the complement would only make the discontinuity larger. + Examples -------- >>> phase = np.linspace(0, np.pi, num=5) From d7322c71f1dcd4b8defea12dba6bf35f28aa2b56 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 14 Sep 2020 10:18:06 +0100 Subject: [PATCH 23/29] Cleanup whitespace --- numpy/lib/function_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index d1afdf96a059..dde0217cd587 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1498,7 +1498,7 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): For the default case where `period` is :math:`2\pi` and is `discont` is :math:`\pi`, this unwraps a radian phase `p` such that adjacent differences are never greater than :math:`\pi` by adding :math:`2k\pi` for some integer :math:`k`. - + Parameters ---------- p : array_like From e54a06ca81dd93cfda4570ae03740711092e08d3 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Mon, 14 Sep 2020 10:18:55 +0100 Subject: [PATCH 24/29] Add missing whitespace --- numpy/lib/tests/test_function_base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 2ebde9aec6d9..f881ddf00792 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -1775,6 +1775,7 @@ def test_period(self): assert_array_equal(sm_discont, [0, 75, 150, 225, 300, 430]) assert sm_discont.dtype == wrap_uneven.dtype + class TestFilterwindows: def test_hanning(self): From fa7f79d05936164cf5907880e68a8929bee074a5 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Tue, 16 Feb 2021 09:22:50 +0000 Subject: [PATCH 25/29] Update numpy/lib/function_base.py --- numpy/lib/function_base.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index dde0217cd587..4276a010e859 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1511,6 +1511,9 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): Axis along which unwrap will operate, default is the last axis. period: float, optional Size of the range over which the input wraps. By default, it is ``2 pi``. + + .. versionadded:: 1.21.0 + Returns ------- out : ndarray From f80fe629ea371914492e78a48994ed3ce2f2da48 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Tue, 16 Feb 2021 09:23:43 +0000 Subject: [PATCH 26/29] Update numpy/lib/function_base.py --- numpy/lib/function_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 4276a010e859..83786adfd334 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1543,7 +1543,7 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): array([1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> unwrap([2, 3, 4, 5, 2, 3, 4, 5], period=4) array([2, 3, 4, 5, 6, 7, 8, 9]) - >>> phase_deg = np.mod(np.linspace(0,720,19), 360) - 180 + >>> phase_deg = np.mod(np.linspace(0 ,720, 19), 360) - 180 >>> unwrap(phase_deg, period=360) array([-180., -140., -100., -60., -20., 20., 60., 100., 140., 180., 220., 260., 300., 340., 380., 420., 460., 500., From f4c2d090045004a28a7776e5eb2a156a1295f3be Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Tue, 16 Feb 2021 09:25:43 +0000 Subject: [PATCH 27/29] Apply suggestions from code review --- doc/release/upcoming_changes/16987.improvement.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/release/upcoming_changes/16987.improvement.rst b/doc/release/upcoming_changes/16987.improvement.rst index 04a17e98f0a3..dc592a068401 100644 --- a/doc/release/upcoming_changes/16987.improvement.rst +++ b/doc/release/upcoming_changes/16987.improvement.rst @@ -1,6 +1,6 @@ -Arbitrary `period` option for ``numpy.unwrap`` ------------------------------------------------------ -The size of the interval over which phases are unwrapped is no longer restricted to `2 * pi`. +Arbitrary ``period`` option for `numpy.unwrap` +---------------------------------------------- +The size of the interval over which phases are unwrapped is no longer restricted to ``2 * pi``. This is especially useful for unwrapping degrees, but can also be used for other intervals. .. code:: python From 5bc6926d063866731cbe568366137f9e12182648 Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Wed, 19 May 2021 13:17:21 -0600 Subject: [PATCH 28/29] STY: Break long lines --- numpy/lib/function_base.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 83786adfd334..d1d33b321501 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1495,9 +1495,10 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): difference from their predecessor of more than ``max(discont, period/2)`` to their `period`-complementary values. - For the default case where `period` is :math:`2\pi` and is `discont` is :math:`\pi`, - this unwraps a radian phase `p` such that adjacent differences are never - greater than :math:`\pi` by adding :math:`2k\pi` for some integer :math:`k`. + For the default case where `period` is :math:`2\pi` and is `discont` is + :math:`\pi`, this unwraps a radian phase `p` such that adjacent differences + are never greater than :math:`\pi` by adding :math:`2k\pi` for some + integer :math:`k`. Parameters ---------- @@ -1505,12 +1506,14 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): Input array. discont : float, optional Maximum discontinuity between values, default is ``period/2``. - Values below ``period/2`` are treated as if they were ``period/2``. To have an effect - different from the default, `discont` should be larger than ``period/2``. + Values below ``period/2`` are treated as if they were ``period/2``. + To have an effect different from the default, `discont` should be + larger than ``period/2``. axis : int, optional Axis along which unwrap will operate, default is the last axis. period: float, optional - Size of the range over which the input wraps. By default, it is ``2 pi``. + Size of the range over which the input wraps. By default, it is + ``2 pi``. .. versionadded:: 1.21.0 @@ -1567,9 +1570,11 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): interval_low = -interval_high ddmod = mod(dd - interval_low, period) + interval_low if boundary_ambiguous: - # for `mask = (abs(dd) == period/2)`, the above line made `ddmod[mask] == -period/2`. - # correct these such that `ddmod[mask] == sign(dd[mask])*period/2`. - _nx.copyto(ddmod, interval_high, where=(ddmod == interval_low) & (dd > 0)) + # for `mask = (abs(dd) == period/2)`, the above line made + # `ddmod[mask] == -period/2`. correct these such that + # `ddmod[mask] == sign(dd[mask])*period/2`. + _nx.copyto(ddmod, interval_high, + where=(ddmod == interval_low) & (dd > 0)) ph_correct = ddmod - dd _nx.copyto(ph_correct, 0, where=abs(dd) < discont) up = array(p, copy=True, dtype=dtype) From 8bdeaebe0c82590a135d5b815fa41ffda0b9a9dd Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Wed, 19 May 2021 13:52:28 -0600 Subject: [PATCH 29/29] BUG: Fix missing "np." in docstring examples. --- numpy/lib/function_base.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index d1d33b321501..651343a2c2e4 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1540,14 +1540,14 @@ def unwrap(p, discont=None, axis=-1, *, period=2*pi): array([ 0. , 0.78539816, 1.57079633, 5.49778714, 6.28318531]) # may vary >>> np.unwrap(phase) array([ 0. , 0.78539816, 1.57079633, -0.78539816, 0. ]) # may vary - >>> unwrap([0, 1, 2, -1, 0], period=4) + >>> np.unwrap([0, 1, 2, -1, 0], period=4) array([0, 1, 2, 3, 4]) - >>> unwrap([ 1, 2, 3, 4, 5, 6, 1, 2, 3], period=6) + >>> np.unwrap([ 1, 2, 3, 4, 5, 6, 1, 2, 3], period=6) array([1, 2, 3, 4, 5, 6, 7, 8, 9]) - >>> unwrap([2, 3, 4, 5, 2, 3, 4, 5], period=4) + >>> np.unwrap([2, 3, 4, 5, 2, 3, 4, 5], period=4) array([2, 3, 4, 5, 6, 7, 8, 9]) >>> phase_deg = np.mod(np.linspace(0 ,720, 19), 360) - 180 - >>> unwrap(phase_deg, period=360) + >>> np.unwrap(phase_deg, period=360) array([-180., -140., -100., -60., -20., 20., 60., 100., 140., 180., 220., 260., 300., 340., 380., 420., 460., 500., 540.])