synr routine to numpy
@@ -112,15 +112,29 @@ def _unwrap_correct(dd, discont):
return ph_correct
-def unwrap(p, discont=numpy.pi, axis=-1):
- """Unwrap by changing deltas between values to 2*pi complement.
+def unwrap(p, discont=None, axis=-1, *, period=2*numpy.pi):
+ """Unwrap by taking the complement of large deltas w.r.t. 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 ``2 * pi`` and is `discont` is
+ ``pi``, this unwraps a radian phase `p` such that adjacent differences
+ are never greater than ``pi`` by adding ``2ki*pi`` for some
+ integer ``k``.
Args:
p (cupy.ndarray): Input array.
discont (float): Maximum discontinuity between values, default is
- ``pi``.
+ ``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): 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:
cupy.ndarray: The result array.
@@ -130,13 +144,27 @@ def unwrap(p, discont=numpy.pi, axis=-1):
p = cupy.asarray(p)
nd = p.ndim
dd = sumprod.diff(p, axis=axis)
+ if discont is None:
+ discont = period/2
slice1 = [slice(None, None)]*nd # full slices
slice1[axis] = slice(1, None)
slice1 = tuple(slice1)
ph_correct = _unwrap_correct(dd, discont)
- dtype = 'd'
- if numpy.dtype(p.dtype).kind == 'f':
- dtype = p.dtype
+ dtype = numpy.result_type(dd.dtype, period)
+ if numpy.core.numeric.issubdtype(dtype, numpy.core.numeric.integer):
+ interval_high, rem = divmod(period, 2)
+ boundary_ambiguous = rem == 0
+ else:
+ interval_high = period / 2
+ boundary_ambiguous = True
+ interval_low = -interval_high
+ ddmod = cupy.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`.
+ ddmod[(ddmod == interval_low) & (dd > 0)] = interval_high
+
up = cupy.array(p, copy=True, dtype=dtype)
up[slice1] = p[slice1] + cupy.cumsum(ph_correct, axis=axis)
return up
