Source code for towerpy.eclass.snr

"""Towerpy: an open-source toolbox for processing polarimetric radar data."""

import warnings
import numpy as np
from ..datavis import rad_display


warnings.filterwarnings("ignore", category=RuntimeWarning)


[docs] class SNR_Classif: r""" A class to compute the Signal-to-Noise Ratio on radar data. Attributes ---------- elev_angle : float Elevation angle at which the scan was taken, in deg. file_name : str Name of the file containing radar data. scandatetime : datetime Date and time of scan. site_name : str Name of the radar site. min_snr : float Reference noise value. snr_class : dict Results of the SNR method. vars : dict Radar variables with noise removed. """ def __init__(self, radobj=None):
[docs] self.elev_angle = getattr(radobj, 'elev_angle', None) if radobj else None
[docs] self.file_name = getattr(radobj, 'file_name', None) if radobj else None
[docs] self.scandatetime = getattr(radobj, 'scandatetime', None) if radobj else None
[docs] self.site_name = getattr(radobj, 'site_name', None) if radobj else None
[docs] def signalnoiseratio(self, rad_georef, rad_params, rad_vars, min_snr=0, rad_cst=None, snr_linu=False, data2correct=None, classid=None, plot_method=False): """ Compute the SNR and discard data using a reference noise value. Parameters ---------- rad_georef : dict Georeferenced data containing descriptors of the azimuth, gates and beam height, amongst others. rad_params : dict Radar technical details. rad_vars : dict Radar variables used to compute the SNR. min_snr : float64, optional Reference noise value. The default is 0. data2correct : dict, optional Variables into which noise is removed. The default is None. plot_method : Bool, optional Plot the SNR classification method. The default is False. """ self.echoesID = {'pcpn': 0, 'noise': 3} if classid is not None: self.echoesID.update(classid) if rad_cst: rc = rad_cst else: rc = rad_params['radar constant [dB]'] rh, _ = np.meshgrid(rad_georef['range [m]']/1000, rad_georef['azim [rad]']) snrc = rad_vars['ZH [dBZ]'] - 20*np.log10(rh) + rc idx = np.nonzero(snrc >= min_snr) snrclass = np.full(snrc.shape, np.nan) snrclass[idx] = 1 snr = {'snrclass': snrclass, 'snr [dB]': snrc} if snr_linu is True: snrlu = 10 ** (0.1*snrc) snr['snr [linear]'] = snrlu if data2correct is not None: rdatsnr = data2correct.copy() for key in rdatsnr: rdatsnr[key] = rdatsnr[key]*snrclass self.vars = rdatsnr snr['snrclass'][np.isnan(snr['snrclass'])] = self.echoesID['noise'] snr['snrclass'][snr['snrclass'] == 1] = self.echoesID['pcpn'] if plot_method: rad_display.plot_snr(rad_georef, rad_params, snr, min_snr) self.min_snr = min_snr self.snr_class = snr
@staticmethod
[docs] def static_signalnoiseratio(rad_georef, rad_params, rad_vars, min_snr=0, rad_cst=None, snr_linu=False, data2correct=None, plot_method=False): """ Compute the SNR (in dB) and discard data using a reference noise value. Parameters ---------- rad_georef : dict Georeferenced data containing descriptors of the azimuth, gates and beam height, amongst others. rad_params : dict Radar technical details. rad_vars : dict Radar variables used to compute the SNR.. min_snr : float64, optional Reference noise value. The default is 0. data2correct : dict, optional Variables into which noise is removed. The default is None. plot_method : Bool, optional Plot the SNR classification method. The default is False. Returns ------- Object containing the signal/noise classification. """ if rad_cst: rc = rad_cst else: rc = rad_params['radar constant [dB]'] rh, _ = np.meshgrid(rad_georef['range [m]']/1000, rad_georef['azim [rad]']) snrc = rad_vars['ZH [dBZ]'] - 20*np.log10(rh) + rc idx = np.nonzero(snrc >= min_snr) snrclass = np.full(snrc.shape, np.nan) snrclass[idx] = 1 snr = {'snrclass': snrclass, 'snr [dB]': snrc} if snr_linu is True: snrlu = 10 ** (0.1*snrc) snr['snr [linear]'] = snrlu if data2correct is not None: rdatsnr = data2correct.copy() for key in rdatsnr: rdatsnr[key] = rdatsnr[key]*snrclass return snr, rdatsnr return snr
# ============================================================================= # %% xarray implementation # =============================================================================
[docs] def signal2noiseratio(Z, rng_km, rc, scale="db"): """ Compute signal-to-noise ratio (SNR). Parameters ---------- Z : array_like or xarray.DataArray Reflectivity factor [dBZ]. rng_km : array_like or xarray.DataArray Range [km]. rc : float Radar constant [dB]. scale : {"db", "lin", "both"}, optional Output format: - "db" : return SNR in dB (default) - "lin" : return SNR in linear scale - "both" : return dict with both Returns ------- snr : ndarray, DataArray, or dict Depending on `scale`: - "db" → snr_db - "lin" → snr_lin - "both" → {"snr_db": snr_db, "snr_lin": snr_lin} """ if scale == "db": return Z - 20.0 * np.log10(rng_km) + rc elif scale == "lin": snr_db = Z - 20.0 * np.log10(rng_km) + rc return 10.0 ** (snr_db / 10.0) elif scale == "both": snr_db = Z - 20.0 * np.log10(rng_km) + rc snr_lin = 10.0 ** (snr_db / 10.0) return {"snr_db": snr_db, "snr_lin": snr_lin} else: raise ValueError(f"Unknown scale '{scale}'," " expected 'db', 'lin', or 'both'.")