Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

the 997hz testing sin signal #21

Open
szuer2018 opened this issue Jul 5, 2022 · 2 comments
Open

the 997hz testing sin signal #21

szuer2018 opened this issue Jul 5, 2022 · 2 comments

Comments

@szuer2018
Copy link

hi, recently, I have been trying the THD and THDN, could you offer the testing wav files?

@endolith
Copy link
Owner

endolith commented Jul 5, 2022

@szuer2018
Copy link
Author

hi, endolith. Thanks for sharing the 997hz tesing sin signals to me. I tried out the codes on your git, but got THDN=0.002146% or -53.37dB (THDN: 0.001404% or -97.05dB when setting weight='A') when setting weight=None in THDN function. Is that correct? Here is the codes:

if name == "main":

test_wav_path = r'.\Audition 997 Hz 16 bit.flac'

analyze_channels(test_wav_path, THDN)

def analyze_channels(filename, function):
"""
Given a filename, run the given analyzer function on each channel of the
file
"""
signal, sample_rate, channels = load(filename)
print('Analyzing "' + filename + '"...')
signal = signal/max(abs(signal))
if channels == 1:
# Monaural
function(signal, sample_rate)
elif channels == 2:
# Stereo
if array_equal(signal[:, 0], signal[:, 1]):
print('-- Left and Right channels are identical --')
function(signal[:, 0], sample_rate)
else:
print('-- Left channel --')
function(signal[:, 0], sample_rate)
print('-- Right channel --')
function(signal[:, 1], sample_rate)
else:
# Multi-channel
for ch_no, channel in enumerate(signal.transpose()):
print('-- Channel %d --' % (ch_no + 1))
function(channel, sample_rate)

def THDN(signal, fs, weight=None):
"""Measure the THD+N for a signal and print the results

Prints the estimated fundamental frequency and the measured THD+N.  This is
calculated from the ratio of the entire signal before and after
notch-filtering.

This notch-filters by nulling out the frequency coefficients ±10% of the
fundamental

TODO: Make R vs F reference a parameter (currently is R)
TODO: Or report all of the above in a dictionary?

"""
# Get rid of DC and window the signal
signal = np.asarray(signal) + 0.0  # Float-like array
# TODO: Do this in the frequency domain, and take any skirts with it?
signal -= mean(signal)

window = general_cosine(len(signal), flattops['HFT248D'])
windowed = signal * window
del signal

# Zero pad to nearest power of two
new_len = next_fast_len(len(windowed))
windowed = concatenate((windowed, zeros(new_len - len(windowed))))

# Measure the total signal before filtering but after windowing
total_rms = rms_flat(windowed)

# Find the peak of the frequency spectrum (fundamental frequency)
f = rfft(windowed)
i = argmax(abs(f))
true_i = parabolic(log(abs(f)), i)[0]
frequency = fs * (true_i / len(windowed))

# Filter out fundamental by throwing away values ±10%
lowermin = int(true_i * 0.9)
uppermin = int(true_i * 1.1)
f[lowermin: uppermin] = 0
# TODO: Zeroing FFT bins is bad

# Transform noise back into the time domain and measure it
noise = irfft(f)
# TODO: RMS and A-weighting in frequency domain?  Parseval?

if weight is None:
    # TODO: Return a dict or list of frequency, THD+N?
    THDN = rms_flat(noise) / total_rms
    print(f'THD: {THDN * 100}% or {dB(THDN*100)}dB')
    return THDN
elif weight == 'A':
    # Apply A-weighting to residual noise (Not normally used for
    # distortion, but used to measure dynamic range with -60 dBFS signal,
    # for instance)
    noise = A_weight(noise, fs)
    # TODO: filtfilt? tail end of filter?
    # TODO: Return a dict or list of frequency, THD+N?
    THDN = rms_flat(noise) / total_rms
    print(f'THD: {THDN * 100}% or {dB(THDN)}dB')
    return THDN
else:
    raise ValueError('Weighting not understood')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants