def test_lin2db(fake_nc_file): nc = netCDF4.Dataset(fake_nc_file) test_var = nc.variables['time'] name, units = 'test_name', 'm s-1' obj = CloudnetArray(test_var, name, units) obj.lin2db() assert obj.units == 'dB' assert_array_equal(obj.data, utils.lin2db(test_var[:]))
def calc_errors(self, attenuations: dict, classification: ClassificationResult) -> None: """Calculates uncertainties of radar echo. Calculates and adds `Z_error`, `Z_sensitivity` and `Z_bias` :class:`CloudnetArray` instances to `data` attribute. Args: attenuations: 2-D attenuations due to atmospheric gases. classification: The :class:`ClassificationResult` instance. References: The method is based on Hogan R. and O'Connor E., 2004, https://bit.ly/2Yjz9DZ and the original Cloudnet Matlab implementation. """ def _calc_sensitivity() -> np.ndarray: """Returns sensitivity of radar as function of altitude.""" mean_gas_atten = ma.mean(attenuations['radar_gas_atten'], axis=0) z_sensitivity = z_power_min + log_range + mean_gas_atten zc = ma.median(ma.array(z, mask=~classification.is_clutter), axis=0) z_sensitivity[~zc.mask] = zc[~zc.mask] return z_sensitivity def _calc_error() -> np.ndarray: if 'width' not in self.data: return 0.3 z_precision = 4.343 * (1 / np.sqrt(_number_of_independent_pulses()) + utils.db2lin(z_power_min - z_power) / 3) gas_error = attenuations['radar_gas_atten'] * 0.1 liq_error = attenuations['liquid_atten_err'].filled(0) z_error = utils.l2norm(gas_error, liq_error, z_precision) z_error[attenuations['liquid_uncorrected']] = ma.masked return z_error def _number_of_independent_pulses() -> float: seconds_in_hour = 3600 dwell_time = utils.mdiff(self.time) * seconds_in_hour return (dwell_time * self.radar_frequency * 1e9 * 4 * np.sqrt(math.pi) * self.data['width'][:] / 3e8) def _calc_z_power_min() -> float: if ma.all(z_power.mask): return 0 return np.percentile(z_power.compressed(), 0.1) z = self.data['Z'][:] radar_range = self.km2m(self.dataset.variables['range']) log_range = utils.lin2db(radar_range, scale=20) z_power = z - log_range z_power_min = _calc_z_power_min() self.append_data(_calc_error(), 'Z_error') self.append_data(_calc_sensitivity(), 'Z_sensitivity') self.append_data(1, 'Z_bias')
def test_lin2db(input, result): assert utils.lin2db(*input) == result
def _get_z_factor(self) -> float: """Returns empirical scaling factor for radar echo.""" return float(utils.lin2db(self.coeffs.K2liquid0 / 0.93))
def lin2db(self) -> None: """Converts linear units to log.""" if "db" not in self.units.lower(): self.data = utils.lin2db(self.data) self.units = "dB"
def test_lin2db(self): name, units = "test_name", "m s-1" obj = CloudnetArray(self.time, name, units) obj.lin2db() assert obj.units == "dB" assert_array_equal(obj.data, utils.lin2db(self.time[:]))
def test_lin2db_arrays(input, expected): converted = utils.lin2db(input) assert_array_equal(converted, expected) if ma.isMaskedArray(input): assert_array_equal(converted.mask, expected.mask)
def test_lin2db(self): name, units = 'test_name', 'm s-1' obj = CloudnetArray(self.time, name, units) obj.lin2db() assert obj.units == 'dB' assert_array_equal(obj.data, utils.lin2db(self.time[:]))