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