Example #1
0
def loudness_zwicker_time(third_octave_levels, field_type):
    """Calculate Zwicker-loudness for time-varying signals

    Calculate the acoustic loudness according to Zwicker method for
    time-varying signals.
    Normatice reference:
        DIN 45631/A1:2010
        ISO 532-1:2017 (method 2)
    The code is based on C program source code published alongside
    with ISO 532-1 standard.
    Note that for reasons of normative continuity, as defined in the
    preceeding standards, the method is in accordance with
    ISO 226:1987 equal loudness contours (instead of ISO 226:2003)

    Parameters
    ----------
    third_octave_levels : numpy.ndarray
        rms acoustic pressure [Pa] per third octave versus time
        (temporal resolution = 0.5ms)
    field_type : str
        Type of soundfield corresponding to signal ("free" by
        default or "diffuse")

    Outputs
    -------
    N : float
        Calculated loudness [sones]
    N_specific : numpy.ndarray
        Specific loudness [sones/bark]
    bark_axis : numpy.ndarray
        Corresponding bark axis
    """

    # Calculate core loudness
    num_sample_level = np.shape(third_octave_levels)[1]
    core_loudness = np.zeros((21, num_sample_level))
    for i in np.arange(num_sample_level - 1):
        core_loudness[:, i] = calc_main_loudness(third_octave_levels[:, i], field_type)
    #
    # Nonlinearity
    core_loudness = calc_nl_loudness(core_loudness)
    #
    # Calculation of specific loudness
    loudness = np.zeros(np.shape(core_loudness)[1])
    spec_loudness = np.zeros((240, np.shape(core_loudness)[1]))
    for i_time in np.arange(np.shape(core_loudness)[1]):
        loudness[i_time], spec_loudness[:, i_time] = calc_slopes(
            core_loudness[:, i_time]
        )
    #
    # temporal weigthing
    filt_loudness = loudness_zwicker_temporal_weighting(loudness)
    #
    # Decimation from temporal resolution 0.5 ms to 2ms and return
    dec_factor = 4
    N = filt_loudness[::dec_factor]
    N_spec = spec_loudness[:, ::dec_factor]
    return N, N_spec
Example #2
0
def loudness_zwicker_stationary(spec_third, third_axis=[], field_type="free"):
    """Zwicker-loudness calculation for stationary signals

    Calculates the acoustic loudness according to Zwicker method for
    stationary signals.
    Normatice reference:
        ISO 532:1975 (method B)
        DIN 45631:1991
        ISO 532-1:2017 (method 1)
    The code is based on BASIC program published in "Program for
    calculating loudness according to DIN 45631 (ISO 532B)", E.Zwicker
    and H.Fastl, J.A.S.J (E) 12, 1 (1991). 
    Note that due to normative continuity, as defined in the
    preceeding standards, the method is in accordance with 
    ISO 226:1987 equal loudness contours (instead of ISO 226:2003)

    Parameters
    ----------
    spec_third : numpy.ndarray
        A third octave band spectrum [dB ref. 2e-5 Pa]
    third_axis : numpy.ndarray
        Normalized center frequency of third octave bands [Hz]
    field_type : str
        Type of soundfield corresponding to spec_third ("free" by 
        default or "diffuse")

    Outputs
    -------
    N : float
        Calculated loudness [sones]
    N_specific : numpy.ndarray
        Specific loudness [sones/bark]
    """
    #
    # Input parameters control and formating
    fr = [
        25,
        31.5,
        40,
        50,
        63,
        80,
        100,
        125,
        160,
        200,
        250,
        315,
        400,
        500,
        630,
        800,
        1000,
        1250,
        1600,
        2000,
        2500,
        3150,
        4000,
        5000,
        6300,
        8000,
        10000,
        12500,
    ]
    if field_type != "diffuse" and field_type != "free":
        raise ValueError(
            "ERROR: field_type should be either 'diffuse' or 'free'")
    if len(spec_third) != 28:
        raise ValueError(
            "ERROR: spectrum must contains 28 third octave bands values")
    if len(third_axis) == 0:
        third_axis = fr
    elif (len(third_axis) == 28
          and np.all(third_axis != fr)) or len(third_axis) < 28:
        raise ValueError(
            """ERROR: third_axis does not contains 1/3 oct between 25 and 
            12.5 kHz. Check the input parameters""")
    else:
        # TODO: manage spectrum and third_axis longer than 28 (extract data
        # between 25 and 12.5 kHz)
        pass
    #    if (min(spec_third) < -60 or max(spec_third) > 120):
    # TODO: replace value below -60 by -60 and raise a warning
    #        raise ValueError(
    #            """ERROR: Third octave levels must be within interval
    #            [-60, 120] dB ref. 2e-5 Pa (for model validity) """
    #        )
    #
    #
    # Calculate main loudness
    Nm = calc_main_loudness(spec_third, field_type)
    #
    # Calculation of specific loudness pattern and integration of overall
    # loudness by attaching slopes towards higher frequencies
    N, N_specific = calc_slopes(Nm)

    return N, N_specific