Source code for snowScatt.instrumentSimulator.radarMoments
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Copyright (C) 2020 Davide Ori
#University of Cologne
# 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 <https://www.gnu.org/licenses/>.
import logging
import numpy as np
from snowScatt import refractiveIndex
from snowScatt._compute import _c
from snowScatt._compute import backscatter
from snowScatt._compute import _convert_to_array
[docs]def dB(x):
"""
Converts from linear units to dB
Parameters
----------
x - ndarray - double (strictly positive >0)
array of values to be converted into dB
Returns
-------
dB(x) - ndarray - double
x array converted to dB
"""
return 10.0*np.log10(x)
[docs]def Bd(x):
"""
Converts from dB to linear units
Parameters
----------
x - ndarray - double
array of values to be converted into linear units
Returns
-------
Bd(x) - ndarray - double
x array converted to linear units
"""
return 10.0**(0.1*x)
[docs]def specific_reflectivity(wl, bck, K2):
"""
Compute radar specific reflectivity
Parameters
----------
wl : scalar - double
electromagnetic wavelength [meters]
bck : array(Nparticles) - double
spectrum of radar backscattering cross section [meters2]
K2 : scalar - double
Rayleigh dielectric factor K**2 (dimensionless)
K = (n2 - 1)/(n2 + 2) for the Clausius Mossotti relation
Returns
-------
eta : ndarray(Nparticles) - double
specific reflectivity in linear units (millimeter6 meters-3)
"""
return 1.0e18*wl**4*bck/(K2*np.pi**5)
[docs]def Ze(diameters, psd, wavelength, properties,
ref_index=None, temperature=None,
mass=None, theta=0.0, bck=None, K2=None):
"""radar reflectivity
Compute radar reflectivity directly from hydrometeor parameters
Parameters
----------
diameters : array(Nparticles) - double
spectrum of diameters of the particles [meters]
psd : callable
size distribution of the particle
concentration [meters^-1 meters^-3]
wavelength : scalar - double
electromagnetic wavelength to be passed to the snowScatt
properties calculator
properties : string
name of the snowflake properties to call from the snowLibrary
ref_index : scalar - complex (default to None)
complex refractive index of ice to be passed to the snowScatt
properties calculator
temperature : scalar - double
absolute temperature, alternative formulation of ref_index when
ref_index is None to be passed to the snowScatt properties
calculator
mass : array(Nparticles) - double (default to None)
mass of the snowflakes to be passed to the snowScatt properties
calculator if left None the mass is derived by the snowLibrary
properties
theta : scalar - double - (default to 0.0 vertical pointing)
zenith incident angle of the electromagnetic radiation, to be passed
to the snowScatt properties calculator
bck : array(Nparticles) - double (default to None)
radar backscattering cross-section [meters**2] override calculation of
bck using particle parameters
K2 : scalar - double
Rayleigh dielectric factor K^2 (dimensionless)
K = (n^2 - 1)/(n^2 + 2) for the Clausius Mossotti relation
override calculation of K2 from dielectric properties (useful for
multirequency radar cross-calibration)
Returns
-------
Z : scalar - double
Radar reflectivity in logaritmic units [dBZ]
"""
freq = _c/wavelength
if bck is None: # compute only if not precalculated
bck = backscatter(diameters, wavelength, properties,
ref_index, temperature, mass, theta)
if K2 is None: # compute only if not precalculated
eps = refractiveIndex.water.eps(temperature, freq, 'Turner')
K2 = refractiveIndex.utilities.K2(eps)
z = specific_reflectivity(wavelength, bck, K2)
Z = dB(np.sum(z*psd*np.gradient(diameters), axis=-1))
return Z
[docs]def calcMoments(spectrum, vel, n=4):
""" calculate moments of spectrum(vel) up to order n.
The maximum order implemented is 4 (kurtosis). The moments available are:
0: reflectivity
1: mean Doppler velocity
2: spectrum width
3: skweness
4: kurtosis
Parameters
----------
spectrum : array(Nvel) - double
specific reflectivity spectrum in linear units
(millimeter6 meters-3) !!! be careful this is already multiplied by dV
so that sum(spectrum)=Z
vel : array(Nvel) - double
vector of velocities upon which spectrum is defined
n : scalar - integer
maximum order of moments to calculate
for any moment n>=1 the 0...n-1 moments have to be calculated anyway
so the computational burden does not increase
Returns
-------
moments : array(n) - double
array of Doppler radar moments ordered from 0 to n
Raises
------
AttributeError : if the order n is larger than the maximum 4
"""
spec = _convert_to_array(spectrum)
v = _convert_to_array(vel)
#if len() # maybe check if the two vectors have equal sizes
if n>4:
raise AttributeError('Only moments up to 4 (kurtosis) are supported')
Z = sum(spec)
MDV = sum(spec*v)/Z
res = v-MDV
diff = res*res # **2
SW = np.sqrt(sum(spec*diff)/Z)
diff *= res # **3
norm = SW*SW*SW # **3
Sk = sum(spec*diff/(Z*norm)) # I guess from this moment on we can potentially iterate
diff *= res # **4
norm *= SW # **4
k = sum(spec*diff/(Z*norm))
moments = np.array([Z, MDV, SW, Sk, k])
return moments[:n]