def unfold_phi(phidp, rho, width=5, copy=False): """Unfolds differential phase by adjusting values that exceeded maximum \ ambiguous range. Accepts arbitrarily dimensioned arrays, but THE LAST DIMENSION MUST BE THE RANGE. This is the fast Fortran-based implementation (RECOMMENDED). The algorithm is based on the paper of :cite:`Wang2009`. Parameters ---------- phidp : :class:`numpy:numpy.ndarray` array of shape (...,nr) with nr being the number of range bins rho : :class:`numpy:numpy.ndarray` array of same shape as ``phidp`` width : int Width of the analysis window copy : bool Leaves original ``phidp`` array unchanged if set to True (default: False) """ # Check whether fast Fortran implementation is available speedup = util.import_optional("wradlib.speedup") shape = phidp.shape assert rho.shape == shape, "rho and phidp must have the same shape." phidp = phidp.reshape((-1, shape[-1])) if copy: phidp = phidp.copy() rho = rho.reshape((-1, shape[-1])) gradphi = util.gradient_from_smoothed(phidp) beams, rs = phidp.shape # Compute the standard deviation within windows of 9 range bins stdarr = np.zeros(phidp.shape, dtype=np.float32) for r in range(rs - 9): stdarr[..., r] = np.std(phidp[..., r:r + 9], -1) phidp = speedup.f_unfold_phi( phidp=phidp.astype("f4"), rho=rho.astype("f4"), gradphi=gradphi.astype("f4"), stdarr=stdarr.astype("f4"), beams=beams, rs=rs, w=width, ) return phidp.reshape(shape)
def unfold_phi_naive(phidp, rho, width=5, copy=False): """Unfolds differential phase by adjusting values that exceeded maximum \ ambiguous range. Accepts arbitrarily dimensioned arrays, but THE LAST DIMENSION MUST BE THE RANGE. This is the slow Python-based implementation (NOT RECOMMENDED). The algorithm is based on the paper of :cite:`Wang2009`. Parameters ---------- phidp : :class:`numpy:numpy.ndarray` array of shape (...,nr) with nr being the number of range bins rho : :class:`numpy:numpy.ndarray` array of same shape as ``phidp`` width : int Width of the analysis window copy : bool Leaves original ``phidp`` array unchanged if set to True (default: False) """ shape = phidp.shape assert rho.shape == shape, "rho and phidp must have the same shape." phidp = phidp.reshape((-1, shape[-1])) if copy: phidp = phidp.copy() rho = rho.reshape((-1, shape[-1])) gradphi = util.gradient_from_smoothed(phidp) beams, rs = phidp.shape # Compute the standard deviation within windows of 9 range bins stdarr = np.zeros(phidp.shape, dtype=np.float32) for r in range(rs - 9): stdarr[..., r] = np.std(phidp[..., r:r + 9], -1) # phi_corr = np.zeros(phidp.shape) for beam in range(beams): if np.all(phidp[beam] == 0): continue # step 1: determine location where meaningful PhiDP profile begins for j in range(0, rs - width): if (np.sum(stdarr[beam, j:j + width] < 5) == width) and \ (np.sum(rho[beam, j:j + 5] > 0.9) == width): break ref = np.mean(phidp[beam, j:j + width]) for k in range(j + width, rs): if np.sum(stdarr[beam, k - width:k] < 5) and \ np.logical_and(gradphi[beam, k] > -5, gradphi[beam, k] < 20): ref += gradphi[beam, k] * 0.5 if phidp[beam, k] - ref < -80: if phidp[beam, k] < 0: phidp[beam, k] += 360 elif phidp[beam, k] - ref < -80: if phidp[beam, k] < 0: phidp[beam, k] += 360 return phidp
def test_gradient_from_smoothed(self): x = np.arange(10).reshape((2, 5)).astype("f4")**2 result = util.gradient_from_smoothed(x) shouldbe = np.array([[1.0, 2.0, 1.5, 0.0, 0.0], [11.0, 12.0, 6.5, 0.0, 0.0]]) np.testing.assert_allclose(result, shouldbe)
def test_gradient_from_smoothed(self): x = np.arange(10).reshape((2, 5)).astype("f4") ** 2 result = util.gradient_from_smoothed(x) shouldbe = np.array([[1., 11., 2., 1.5, 0., 0.], [1., 11., 12., 6.5, 0., 0.]]) np.testing.assert_allclose(result, shouldbe)