Qu

sinad

Builtin index · Signal processing

result = snr(x, [tones=|freqs=], [fs=|rate=], [bins=], [leak=0])

Input: x, tones, fs, bins, leak · Output: result

What it is

x: a length-N real vector. With no excitation named, the largest non-DC FFT bin is taken as the fundamental (the single-tone case); tones=/freqs= (a vector, Hz, needs fs=/rate= too) or bins= (a vector of integer bin indices) names a multisine's tone set explicitly — treating a multisine as one tone counts every other tone as noise and reads tens of dB low. leak= (optional number, default 0) widens each named tone by that many bins on each side, for a record that isn't exactly bin-coherent. snr/sfdr each return a single number (dB); sinad(x) (no distinguishing suffix) instead returns the whole breakdown as a record with fields sinad, enob, snr, thd, sfdr (numbers), bins (a vector of the fundamental's bin indices), signal_power, noise_power (numbers).

Overloads

One call shape — this function is not overloaded.

CodeInputOutputDescription
result = snr(x, [tones=|freqs=], [fs=|rate=], [bins=], [leak=0])
x vectorx: a length-N real vector.
tones vector, optional (default |freqs=)tones=/freqs= (a vector, Hz, needs fs=/rate= too) or bins= (a vector of integer bin indices) names a multisine's tone set explicitly — treating a multisine as one tone counts every other tone as noise and reads tens of dB low.
fs vector, optional (default |rate=)tones=/freqs= (a vector, Hz, needs fs=/rate= too) or bins= (a vector of integer bin indices) names a multisine's tone set explicitly — treating a multisine as one tone counts every other tone as noise and reads tens of dB low.
bins vector, optionaltones=/freqs= (a vector, Hz, needs fs=/rate= too) or bins= (a vector of integer bin indices) names a multisine's tone set explicitly — treating a multisine as one tone counts every other tone as noise and reads tens of dB low.
leak number, optional (default 0)leak= (optional number, default 0) widens each named tone by that many bins on each side, for a record that isn't exactly bin-coherent.
result scalar, Num, or Record
Returns a scalar Num in dB for snr and sfdr; sinad returns that eight-field Record instead.

Examples

From the documentation, and run by the build -- the output and the figure below are what the engine actually produced. Simplest first.

fs = 1000
n = 0:1:1023
t = n / fs
f0 = 99 * fs / 1024          # exactly 99 cycles in the record -- coherent sampling

clean = sin(2*pi*f0*t)
x = clean + 0.01 * sin(2*pi*3*f0*t) + 0.001 * randn(1024, seed=3)

r = sinad(x)     # full breakdown: r.sinad, r.enob, r.snr, r.thd, r.sfdr

print("THD  = {thd(x)} dB")
print("SNR  = {snr(x)} dB")
print("SINAD = {r.sinad} dB, ENOB = {r.enob} bits, SFDR = {sfdr(x)} dB")
print("ENOB (from thd/sinad breakdown) = {enob(x)} bits")

# closed-form estimates: what an ideal N-bit converter would show for a

# signal of a given crest factor, no record needed -- the number sinad(x)

# above is checked against. Signature is (bits, crest_factor).

est_sinad = sinad_estimate(12, sqrt(2))    # 12-bit ADC, sine-wave crest factor

est_enob  = enob_estimate(12, sqrt(2))
print("ideal 12-bit ADC: SINAD = {est_sinad} dB, ENOB = {est_enob} bits")
output
THD  = -39.98542 dB
SNR  = 56.858996 dB
SINAD = 39.897111 dB, ENOB = 6.335068 bits, SFDR = 39.986015 dB
ENOB (from thd/sinad breakdown) = 6.335068 bits
ideal 12-bit ADC: SINAD = 74 dB, ENOB = 12 bits

from signal-processing

How it works

Real-optimized half-spectrum FFT (NumPy/MATLAB rfft/irfft convention: a real signal's spectrum is Hermitian-symmetric, so only the non-negative-frequency half is returned/needed). sinad(x) / sinad(x, fs=, tones=, bins=, leak=) -- signal-to-noise-and-distortion of a sampled record, plus the SNR, THD, SFDR and ENOB that come with it. With no excitation named, the largest non-DC bin is taken as the fundamental: the single-tone case. Name the tones for a multisine, in Hz via tones= (with fs=) or directly as bin indices via bins= -- treating a multisine as one tone counts every other tone as noise and reads tens of dB low, which is the whole reason the excitation set is a parameter. leak= widens each tone by that many bins either side, for a record that is not exactly coherent. It defaults to 0 because widening hides close-in noise inside the signal and flatters the answer; that has to be the caller's decision.

From the note above this builtin in the interpreter, where the reasoning was written down as it was built.

See also

snr, sfdr — documented in the same entry.