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
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