# noiselevel.py - Noise level estimator# -----------------------------------------------# This file is a part of DeerLab. License is MIT (see LICENSE.md).# Copyright(c) 2019-2023: Luis Fabregas, Stefan Stoll and other contributors.fromnumpyimportisreal,std,mean,shape,atleast_1dfromdeerlab.utilsimportmovmean,der_snrfromdeerlab.correctphaseimportcorrectphasefromscipy.signalimportsavgol_filterimportwarnings
[docs]defnoiselevel(V,mode='der',*args):r""" Estimate the noise level in a dataset. Returns the standard deviation estimation of the noise in a given signal using different methods: * ``sigma = noiselevel(V,'der')``: Employs the DER_SNR [1] method for estimating the noise standard deviation. * ``sigma = noiselevel(V,'scans')``: If ``V`` is a 2D-dataset of different scans, the noise standard deviation is estimated from the deviations between scans. The second dimension of ``V2D`` must contain the different scans. The function returns the standard deviation of the averaged signal not of the individual scans. * ``sigma = noiselevel(V,'movmean',winsize)``: The noise level is estimated via filtering of the signal with a moving mean filter. The size ``winsize`` of the moving mean window must be specified as well. * ``sigma = noiselevel(V,'movmean',winsize,order)``: The noise level is estimated via filtering of the signal with a Savitzky-Golay filter. The window size ``winsize`` and polynomial order ``order`` must be specified as well. * ``sigma = noiselevel(V,'reference',Vref)``: If a reference model signal ``Vref`` is given, the noise level is estimated from the difference between both signals. * ``sigma = noiselevel(V,'complex')``: If the input signal ``V`` contains an imaginary component, the noise level is estimated form the imaginary component after phase optimization. Parameters ---------- V : array_like Input signal. Must be a real-valued 2D-matrix for the ``'scans'`` method. Otherwise it must be a real-valued 1D-array. method : string * ``'der'`` - Estimation via the DER_SNR method [1]. * ``'scans'`` - Estimation from deviations between scans. * ``'movmean'`` - Estimation from a moving mean filtered signal. * ``'savgol'`` - Estimation from a Savitzky-Golay filtered signal. * ``'reference'`` - Estimation from comparison with a reference signal. * ``'complex'`` - Estimation from phase-corrected imaginary part of a complex signal. The default is ``'der'``. winsize : scalar integer Filter window size order : scalar integer Savitzky-Golay polynomial order. Vref : array_like Reference dipolar signal. Vco : array_like Complex-valued dipolar signal. Returns ------- sigma : scalar Estimated noise standard deviation References ---------- .. [1] S. Czesla, T. Molle and J. H. M. M. Schmitt A posteriori noise estimation in variable data sets - With applications to spectra and light curves, A&A, 609 (2018) A39 """V=atleast_1d(V)ifmode=='scans':ifargs:raiseKeyError("For the 'der' method, no additional inputs are required.")ifV.ndim!=2:raiseKeyError("For the 'scans' method, the input signal must be a 2D-matrix.")# Estimate standard deviations for all time point, and average over scansifshape(V)[1]<10:raiseWarning('Only a few scans are given. Noise standard deviation estimate will be inaccurate.')sigma=std(V,1)sigma=mean(sigma)elifmode=='movmean':# Filter the noise in the signal ifargs:iflen(args)!=1:raiseKeyError("For the 'movmean' method, only the windows size can be specified.")winsize=argselse:raiseKeyError("For the 'movmean' method, the windows size must be specified.")Vfilt=movmean(V,winsize)sigma=std(V-Vfilt)elifmode=='savgol':# Filter the noise in the signal ifargs:iflen(args)!=2:raiseKeyError("For the 'savgol' method, only the size and order can be specified.")winsize,order=argselse:raiseKeyError("For the 'savgol' method, the size and order must be specified.")withwarnings.catch_warnings():warnings.simplefilter('ignore')Vfilt=savgol_filter(V,winsize,order)sigma=std(V-Vfilt)elifmode=='complex':ifall(isreal(V)):raiseTypeError("For the 'complex' method, the input signal must be complex-valued.")# Optimize the phase of the signal_,Vim,_=correctphase(V,full_output=True)# And estimate the noiselevel from the imaginary partsigma=std(Vim)elifmode=='reference':ifargs:Vref=args[0]else:raiseKeyError("For the 'reference' method, a reference signal must be provided.")iflen(V)!=len(Vref):raiseTypeError('The input and reference signal must have the same number of elements.')sigma=std(V-Vref)elifmode=='der':ifargs:raiseKeyError("For the 'der' method, no additional inputs are required.")sigma=der_snr(V)returnsigma