how to calculate signal to noise ratio using python
Asked Answered
S

4

8

Dear experts i have a data set.i just want to calculate signal to noise ratio of the data. data is loaded here https://i.fluffy.cc/jwg9d7nRNDFqdzvg1Qthc0J7CNtKd5CV.html

my code is given below:

import numpy as np
from scipy import signaltonoise
import scipy.io
dat=scipy.io.loadmat('./data.mat')
arr=dat['dn']
snr=scipy.stats.signaltonoise(arr, axis=0, ddof=0) 

but i am getting error like importError: cannot import name 'signaltonoise' from 'scipy' if it doesn't exist how to calculate snr,please suggest some other way to do it with this data set using python.

Sync answered 30/7, 2020 at 16:15 Comment(0)
E
12

scipy.stats.signaltonoise was removed in scipy 1.0.0. You can either downgrade your scipy version or create the function yourself:

def signaltonoise(a, axis=0, ddof=0):
    a = np.asanyarray(a)
    m = a.mean(axis)
    sd = a.std(axis=axis, ddof=ddof)
    return np.where(sd == 0, 0, m/sd)

Source: https://github.com/scipy/scipy/blob/v0.16.0/scipy/stats/stats.py#L1963

See the github link for the docstring.

Edit: the full script would then look as follows

import numpy as np
import scipy.io

def signaltonoise(a, axis=0, ddof=0):
    a = np.asanyarray(a)
    m = a.mean(axis)
    sd = a.std(axis=axis, ddof=ddof)
    return np.where(sd == 0, 0, m/sd)

dat = scipy.io.loadmat('./data.mat')
arr = dat['dn']
snr = signaltonoise(arr)
Euchre answered 30/7, 2020 at 16:25 Comment(4)
But where is the signal to noise ratio can you please help me implementing my data on your script.Sync
Its working...but I need some value in decibel....something like 1db....does it required to calculate some averageSync
Not sure what you mean. If signaltonoise working as expected please accept the answer. If you have another, unrelated question, you might want to start a new question.Euchre
This seems to be a question about the data. Probably best to check with the data provider.Euchre
F
2

More generally speaking, it depends on the application. For many applications, the relation between mean and standard deviation might be sufficient.

As JuliettVictor pointed out, the old scipy implementation's source code can be found online easily and is the most common one. In order to convert this to decibels, one would add . Before that one should calculate the absolute value, in case the signal's mean is negative:

def signaltonoise_dB(a, axis=0, ddof=0):
    a = np.asanyarray(a)
    m = a.mean(axis)
    sd = a.std(axis=axis, ddof=ddof)
    return 20*np.log10(abs(np.where(sd == 0, 0, m/sd)))

This runs into problems though, when the signal of interest contains higher frequencies (e.g. in audio applications, here, DC is often filtered out even).

In matlab's snr() function a kaiser windowed periodogram is used, the peak of the fundamental is detected and its power is computed. The same happens for the harmonics. The rest of the signal is assumed to be noise and their corresponding power levels are calculated. Other approaches involve low-pass filtering of the signal (similar to calculating its mean).
Yet another python based example can be found here. An incomplete overview of methods (including a matlab like periodogram-based one) in python can be found here

Fogy answered 27/4, 2021 at 23:7 Comment(0)
J
1

If someone is interested on moving/rolling Signal to Noise Ratio (SNR). Assume "signal" to be moving average (with specific window size) and the noise to be the fluctuation around the moving average. In this case you can calculate moving SNR like:

import pandas as pd

# Moving SNR = (Moving Average)/(Moving Standard Deviation)
def rolling_snr(signal, window_size: int):
    signal_series = pd.Series(signal)
    rolling_mean = signal_series.rolling(window=window_size).mean()
    rolling_std = signal_series.rolling(window=window_size).std()
    rolling_snr = 10 * np.log10((rolling_mean**2) / (rolling_std**2).replace(0, np.finfo(float).eps)) # type: ignore
    return rolling_snr

Jongjongleur answered 5/1 at 11:51 Comment(0)
C
0

You can use Sox for that:

def add_noise(exp,sig, n_directory, snrdb):
    """     This function calculate the mixture of an audio 
        and an audio file as a noise with a desired SNR in db
Input:
    sig: signal, the output vector of wav.read
    rate: the signal's rate
    n_directory: directory of noise
    snrdb: Desired signal-to-noise ratio in db

Output:
    d = s + n such that SNR = Ps/Pn     """
direc_st = exp + "mixed.wav"

write(exp + 'sig_t.wav', 16000, sig)
s = np.expand_dims(sig, -1)
s = s.astype('float64')

rate, n = wav.read(n_directory)
n = np.expand_dims(n, -1)
n = n.astype('float64')

snr = 10 ** (snrdb * 0.1)
Es = np.sum(s ** 2)
En = np.sum(n ** 2)

snr = 10 ** (snrdb * 0.1)
alpha = np.sqrt(Es / (snr * En))

cmd = "sox -m -v" + str(
    alpha) + " " + n_directory + ' ' + exp + 'sig_t.wav ' + direc_st
os.system(cmd)

rate, d = wav.read(direc_st)

return d
Cataphoresis answered 8/7, 2022 at 9:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.