def properties(signal, sample_rate):
    """Return a list of some wave properties for a given 1-D signal
    
    """
    # Measurements that include DC component
    DC_offset = mean(signal)
    # Maximum/minimum sample value
    # Estimate of true bit rate
    
    # Remove DC component
    signal -= mean(signal)
    
    # Measurements that don't include DC
    signal_level = rms_flat(signal)
    peak_level = max(absolute(signal))
    crest_factor = peak_level/signal_level
    
    # Apply the A-weighting filter to the signal
    weighted = A_weight(signal, sample_rate)
    weighted_level = rms_flat(weighted)
    
    # TODO: rjust instead of tabs
    
    return [
    'DC offset:\t%f (%.3f%%)' % (DC_offset, DC_offset * 100),
    'Crest factor:\t%.3f (%.3f dB)' % (crest_factor, dB(crest_factor)),
    'Peak level:\t%.3f (%.3f dBFS)' % (peak_level, dB(peak_level)), # Doesn't account for intersample peaks!
    'RMS level:\t%.3f (%.3f dBFS)' % (signal_level, dB(signal_level)),
    'RMS A-weighted:\t%.3f (%.3f dBFS(A), %.3f dB)' % (weighted_level, dB(weighted_level), dB(weighted_level/signal_level)),
    '-----------------',
    ]
Exemple #2
0
def properties(signal, sample_rate):
    """Return a list of some wave properties for a given 1-D signal
    
    """
    # Measurements that include DC component
    DC_offset = mean(signal)
    # Maximum/minimum sample value
    # Estimate of true bit rate

    # Remove DC component
    signal -= mean(signal)

    # Measurements that don't include DC
    signal_level = rms_flat(signal)
    peak_level = max(absolute(signal))
    crest_factor = peak_level / signal_level

    # Apply the A-weighting filter to the signal
    weighted = A_weight(signal, sample_rate)
    weighted_level = rms_flat(weighted)

    # TODO: rjust instead of tabs

    return [
        'DC offset:\t%f (%.3f%%)' % (DC_offset, DC_offset * 100),
        'Crest factor:\t%.3f (%.3f dB)' % (crest_factor, dB(crest_factor)),
        'Peak level:\t%.3f (%.3f dBFS)' %
        (peak_level, dB(peak_level)),  # Doesn't account for intersample peaks!
        'RMS level:\t%.3f (%.3f dBFS)' % (signal_level, dB(signal_level)),
        'RMS A-weighted:\t%.3f (%.3f dBFS(A), %.3f dB)' %
        (weighted_level, dB(weighted_level), dB(
            weighted_level / signal_level)),
        '-----------------',
    ]
def THDN(signal, sample_rate):
    """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

    """
    # Get rid of DC and window the signal
    signal -= mean(
        signal
    )  # TODO: Do this in the frequency domain, and take any skirts with it?
    windowed = signal * kaiser(len(signal), 100)
    del signal

    # Zero pad to nearest power of two
    new_len = 2**ceil(log(len(windowed)) / log(2))
    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]
    print 'Frequency: %f Hz' % (sample_rate * (true_i / len(windowed)))

    # Filter out fundamental by throwing away values ±10%
    lowermin = true_i - 0.1 * true_i
    uppermin = true_i + 0.1 * true_i
    f[lowermin:uppermin] = 0

    # Transform noise back into the time domain and measure it
    noise = irfft(f)
    THDN = rms_flat(noise) / total_rms

    # TODO: RMS and A-weighting in frequency domain?

    # Apply A-weighting to residual noise (Not normally used for distortion,
    # but used to measure dynamic range with -60 dBFS signal, for instance)
    weighted = A_weight(noise, sample_rate)
    THDNA = rms_flat(weighted) / total_rms

    print "THD+N:      %.4f%% or %.1f dB" % (THDN * 100, 20 * log10(THDN))
    print "A-weighted: %.4f%% or %.1f dB(A)" % (THDNA * 100, 20 * log10(THDNA))
Exemple #4
0
def THDN(signal, sample_rate):
    """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

    """
    # Get rid of DC and window the signal
    signal -= mean(signal) # TODO: Do this in the frequency domain, and take any skirts with it?
    windowed = signal * kaiser(len(signal), 100)
    del signal

    # Zero pad to nearest power of two
    new_len = 2**ceil( log(len(windowed)) / log(2) )
    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]
    print 'Frequency: %f Hz' % (sample_rate * (true_i / len(windowed)))

    # Filter out fundamental by throwing away values ±10%
    lowermin = true_i - 0.1 * true_i
    uppermin = true_i + 0.1 * true_i
    f[lowermin: uppermin] = 0

    # Transform noise back into the time domain and measure it
    noise = irfft(f)
    THDN = rms_flat(noise) / total_rms

    # TODO: RMS and A-weighting in frequency domain?

    # Apply A-weighting to residual noise (Not normally used for distortion,
    # but used to measure dynamic range with -60 dBFS signal, for instance)
    weighted = A_weight(noise, sample_rate)
    THDNA = rms_flat(weighted) / total_rms

    print "THD+N:      %.4f%% or %.1f dB"    % (THDN  * 100, 20 * log10(THDN))
    print "A-weighted: %.4f%% or %.1f dB(A)" % (THDNA * 100, 20 * log10(THDNA))