Beispiel #1
0
def strength_factor(Lpe, Lpe_revCh, V_revCh, T_revCh, Lps_revCh, Lps_inSitu):
    S0 = 1  # [m2]

    bands = T_revCh.bands
    nthOct = T_revCh.nthOct
    terms = []
    for bandData in T_revCh.data:
        if bandData == 0:
            terms.append(0)
        else:
            term = (V_revCh * 0.16) / (bandData * S0)
            terms.append(term)
    terms = [10 * np.log10(term) if term != 0 else 0 for term in terms]

    revChTerm = Analysis(anType='mixed',
                         nthOct=nthOct,
                         minBand=float(bands[0]),
                         maxBand=float(bands[-1]),
                         data=terms)
    Lpe.anType = 'mixed'
    Lpe_revCh.anType = 'mixed'
    Lps_revCh.anType = 'mixed'
    Lps_inSitu.anType = 'mixed'
    G = Lpe - Lpe_revCh - revChTerm + 37 \
        + Lps_revCh - Lps_inSitu
    G.anType = 'G'
    return G
Beispiel #2
0
def strength_factor(Lpe, Lpe_revCh, V_revCh, T_revCh, Lps_revCh, Lps_inSitu):
    """
    Reference:
        Christensen, C. L.; Rindel, J. H. APPLYING IN-SITU RECALIBRATION FOR
        SOUND STRENGTH MEASUREMENTS IN AUDITORIA.
    """

    # TO DO: docs
    S0 = 1  # [m2]

    bands = T_revCh.bands
    nthOct = T_revCh.nthOct
    terms = []
    for bandData in T_revCh.data:
        if bandData == 0:
            terms.append(0)
        else:
            term = (V_revCh * 0.16) / (bandData * S0)
            terms.append(term)
    terms = [10 * np.log10(term) if term != 0 else 0 for term in terms]

    revChTerm = Analysis(anType='mixed',
                         nthOct=nthOct,
                         minBand=float(bands[0]),
                         maxBand=float(bands[-1]),
                         data=terms)
    Lpe.anType = 'mixed'
    Lpe_revCh.anType = 'mixed'
    Lps_revCh.anType = 'mixed'
    Lps_inSitu.anType = 'mixed'
    G = Lpe - Lpe_revCh - revChTerm + 37 \
        + Lps_revCh - Lps_inSitu
    G.anType = 'G'
    return G
Beispiel #3
0
def Lp_ST(sigObjList, nthOct, minFreq, maxFreq, IRManualCut=None):
    """
    Calculate from the provided list of one channel SignalObjs the mean
    one-third-octave band time-averaged sound pressure level in the test room
    with the noise source under test in operation, Lp(ST), and the standard
    deviation, Sm, for the preliminary measurements, located at error property
    of the returned pytta.Analysis.

    Correction for background noise not implemented because of the UFSM
    reverberation chamber's good isolation.

    Parameters (default), (type):
    -----------------------------

        * sigObjList (), (list):
            A list containing SignalObjs of each measurement position.

        * nthOct (), (int):
            The number of fractions per octave;

        * minFreq (), (int | float):
            The exact or approximated start band frequency;

        * maxFreq (), (int | float):
            The exact or approximated stop band frequency;

        * IRManualCut (None), (int | float):
            Optional manual IR cut in seconds.

    Returns:
    ---------

        pytta.Analysis object.

    """
    # Code snippet to guarantee that generated object name is
    # the declared at global scope
    # for frame, line in traceback.walk_stack(None):
    for framenline in traceback.walk_stack(None):
        # varnames = frame.f_code.co_varnames
        varnames = framenline[0].f_code.co_varnames
        if varnames == ():
            break
    # creation_file, creation_line, creation_function, \
    #     creation_text = \
    extracted_text = \
        traceback.extract_stack(framenline[0], 1)[0]
        # traceback.extract_stack(frame, 1)[0]
    # creation_name = creation_text.split("=")[0].strip()
    creation_name = extracted_text[3].split("=")[0].strip()

    Leqs = []

    for idx, sigObj in enumerate(sigObjList):
        if not sigObj.channels[firstChNum].calibCheck:
            raise ValueError("SignalObj {} must be calibrated.".format(idx+1))
        # Cutting the IR
        if IRManualCut is not None:
            sigObj.crop(0, IRManualCut)
        # Bands filtering
        hSignal = SignalObj(sigObj.timeSignal[:,0],
                            sigObj.lengthDomain,
                            sigObj.samplingRate)
        hSignal = _filter(signal=hSignal, nthOct=nthOct, minFreq=minFreq,
                        maxFreq=maxFreq)
        bands = FOF(nthOct=nthOct,
                    minFreq=minFreq,
                    maxFreq=maxFreq)[:,1]
        Leq = []
        for chIndex in range(hSignal.numChannels):
            Leq.append(
                10*np.log10(np.mean(hSignal.timeSignal[:,chIndex]**2)/
                            (2e-5**2)))
        Leq = Analysis(anType='mixed', nthOct=nthOct,
                           minBand=float(bands[0]),
                           maxBand=float(bands[-1]), data=Leq,
                           comment='Leq')
        Leqs.append(Leq)

    Leq = 0
    for L in Leqs:
        Leq =  L + Leq
    Lp_ST = Leq / len(sigObjList)
    Lp_ST.anType = 'mixed'
    Lp_ST.unit = 'dB'
    Lp_ST.creation_name = creation_name

    # Statistics for Lp_ST
    data = np.vstack([an.data for an in Leqs])
    Sm = []
    for bandIdx in range(data.shape[1]):
        summing = 0
        for idx in range(data.shape[0]):
            summing += \
            (data[idx, bandIdx] - Lp_ST.data[bandIdx])**2 / (data.shape[0] - 1)
        Sm.append(summing**(1/2))

    Lp_ST.error = Sm
    Lp_ST.errorLabel = "Standard deviation"
    return Lp_ST
Beispiel #4
0
def analyse(obj,
            *params,
            bypassLundeby=False,
            plotLundebyResults=False,
            IREndManualCut=None,
            **kwargs):
    """
    Receives an one channel SignalObj or ImpulsiveResponse and calculate the
    room acoustic parameters especified in the positional input arguments.

    :param obj: one channel impulsive response
    :type obj: SignalObj or ImpulsiveResponse

    Input parameters for reverberation time, 'RT':
        :param RTdecay: decay interval for RT calculation. e.g. 20
        :type RTdecay: int

    Input parameters for clarity, 'C':
        TODO

    Input parameters for definition, 'D':
        TODO

    Input parameters for strength factor, 'G':
        TODO

    :param nthOct: number of fractions per octave
    :type nthOct: int

    :param minFreq: analysis inferior frequency limit
    :type minFreq: float

    :param maxFreq: analysis superior frequency limit
    :type maxFreq: float
    
    :param bypassLundeby: bypass lundeby correction
    to False
    :type bypassLundeby: bool, optional

    :param plotLundebyResults: plot the Lundeby correction parameters, defaults to False
    :type plotLundebyResults: bool, optional

    :return: Analysis object with the calculated parameter
    :rtype: Analysis

    """
    # Code snippet to guarantee that generated object name is
    # the declared at global scope
    # for frame, line in traceback.walk_stack(None):
    for framenline in traceback.walk_stack(None):
        # varnames = frame.f_code.co_varnames
        varnames = framenline[0].f_code.co_varnames
        if varnames is ():
            break
    # creation_file, creation_line, creation_function, \
    #     creation_text = \
    extracted_text = \
        traceback.extract_stack(framenline[0], 1)[0]
    # traceback.extract_stack(frame, 1)[0]
    # creation_name = creation_text.split("=")[0].strip()
    creation_name = extracted_text[3].split("=")[0].strip()

    if not isinstance(obj, SignalObj) and not isinstance(
            obj, ImpulsiveResponse):
        raise TypeError("'obj' must be an one channel SignalObj or" +
                        " ImpulsiveResponse.")
    if isinstance(obj, ImpulsiveResponse):
        SigObj = obj.systemSignal
    else:
        SigObj = obj

    if SigObj.numChannels > 1:
        raise TypeError("'obj' can't contain more than one channel.")
    samplingRate = SigObj.samplingRate

    SigObj = crop_IR(SigObj, IREndManualCut)

    listEDC = cumulative_integration(SigObj, bypassLundeby, plotLundebyResults,
                                     **kwargs)
    for _ in params:
        if 'RT' in params:
            RTdecay = params[params.index('RT') + 1]
            nthOct = kwargs['nthOct']
            RT = reverberation_time(RTdecay, nthOct, samplingRate, listEDC)
            result = Analysis(anType='RT',
                              nthOct=nthOct,
                              minBand=kwargs['minFreq'],
                              maxBand=kwargs['maxFreq'],
                              data=RT)
        # if 'C' in prm:
        #     Ctemp = prm[1]
        # if 'D' in prm:
        #     Dtemp = prm[1]
    result.creation_name = creation_name
    return result
Beispiel #5
0
def G_Lps(IR, nthOct, minFreq, maxFreq):
    """G_Lps 
    
    Calculates the recalibration level, for both in-situ and
    reverberation chamber. Lps is applied for G calculation.

    During the recalibration: source height and mic heigth must be >= 1 [m],
    while the distance between source and mic must be <= 1 [m]. The distances
    must be the same for in-situ and reverberation chamber measurements.

    Reference:
        Christensen, C. L.; Rindel, J. H. APPLYING IN-SITU RECALIBRATION FOR
        SOUND STRENGTH MEASUREMENTS IN AUDITORIA.

    :param IR: one channel impulsive response
    :type IR: ImpulsiveResponse

    :param nthOct: number of fractions per octave
    :type nthOct: int

    :param minFreq: analysis inferior frequency limit
    :type minFreq: float

    :param maxFreq: analysis superior frequency limit
    :type maxFreq: float

    :return: Analysis object with the calculated parameter
    :rtype: Analysis
    """
    # Code snippet to guarantee that generated object name is
    # the declared at global scope
    # for frame, line in traceback.walk_stack(None):
    for framenline in traceback.walk_stack(None):
        # varnames = frame.f_code.co_varnames
        varnames = framenline[0].f_code.co_varnames
        if varnames is ():
            break
    # creation_file, creation_line, creation_function, \
    #     creation_text = \
    extracted_text = \
        traceback.extract_stack(framenline[0], 1)[0]
    # traceback.extract_stack(frame, 1)[0]
    # creation_name = creation_text.split("=")[0].strip()
    creation_name = extracted_text[3].split("=")[0].strip()

    # firstChNum = IR.systemSignal.channels.mapping[0]
    # if not IR.systemSignal.channels[firstChNum].calibCheck:
    #     raise ValueError("'IR' must be a calibrated ImpulsiveResponse")
    if isinstance(IR, SignalObj):
        SigObj = IR
    elif isinstance(IR, ImpulsiveResponse):
        SigObj = IR.systemSignal
    else:
        raise TypeError("'IR' must be an ImpulsiveResponse or SignalObj.")
    # Windowing the IR
    # dBtoOnSet = 20
    # dBIR = 10*np.log10((SigObj.timeSignal[:,0]**2)/((2e-5)**2))
    # windowStart = np.where(dBIR > (max(dBIR) - dBtoOnSet))[0][0]

    broadBandTimeSignal = cp.copy(SigObj.timeSignal[:, 0])
    broadBandTimeSignalNoStart, sampleShift = \
        _circular_time_shift(broadBandTimeSignal)
    windowLength = 0.0032  # [s]
    windowEnd = int(windowLength * SigObj.samplingRate)

    hSignal = SignalObj(
        broadBandTimeSignalNoStart[:windowEnd],
        # hSignal = SignalObj(timeSignal,
        SigObj.lengthDomain,
        SigObj.samplingRate)
    hSignal = _filter(signal=hSignal,
                      nthOct=nthOct,
                      minFreq=minFreq,
                      maxFreq=maxFreq)
    bands = FOF(nthOct=nthOct, freqRange=[minFreq, maxFreq])[:, 1]
    Lps = []
    for chIndex in range(hSignal.numChannels):
        timeSignal = cp.copy(hSignal.timeSignal[:, chIndex])
        # timeSignalNoStart, sampleShift = _circular_time_shift(timeSignal)
        # windowLength = 0.0032 # [s]
        # windowEnd = int(windowLength*SigObj.samplingRate)

        Lps.append(
            # 10*np.log10(np.trapz(y=timeSignalNoStart[:windowEnd]**2/(2e-5**2),
            10 * np.log10(
                np.trapz(
                    y=timeSignal**2 / (2e-5**2),
                    #  x=hSignal.timeVector[sampleShift:sampleShift+windowEnd])))
                    x=hSignal.timeVector)))
    LpsAnal = Analysis(anType='mixed',
                       nthOct=nthOct,
                       minBand=float(bands[0]),
                       maxBand=float(bands[-1]),
                       data=Lps,
                       comment='Source recalibration method IR')
    LpsAnal.creation_name = creation_name
    LpsAnal.windowLimits = ((sampleShift) / SigObj.samplingRate,
                            (sampleShift + windowEnd) / SigObj.samplingRate)
    # Plot IR cutting
    # fig = plt.figure(figsize=(10, 5))
    # ax = fig.add_axes([0.08, 0.15, 0.75, 0.8], polar=False,
    #                         projection='rectilinear', xscale='linear')
    # ax.plot(SigObj.timeVector, 10*np.log10(SigObj.timeSignal**2/2e-5**2))
    # ax.axvline(x=(sampleShift)/SigObj.samplingRate, linewidth=4, color='k')
    # ax.axvline(x=(sampleShift+windowEnd)/SigObj.samplingRate, linewidth=4, color='k')
    # ax.set_xlim([(sampleShift-100)/SigObj.samplingRate, (sampleShift+windowEnd+100)/SigObj.samplingRate])
    return LpsAnal
Beispiel #6
0
def G_Lpe(IR, nthOct, minFreq, maxFreq, IREndManualCut=None):
    """
    Calculate the energy level from the room impulsive response.

    Reference:
        Christensen, C. L.; Rindel, J. H. APPLYING IN-SITU RECALIBRATION FOR
        SOUND STRENGTH MEASUREMENTS IN AUDITORIA.

    :param IR: one channel impulsive response
    :type IR: ImpulsiveResponse

    :param nthOct: number of fractions per octave
    :type nthOct: int

    :param minFreq: analysis inferior frequency limit
    :type minFreq: float

    :param maxFreq: analysis superior frequency limit
    :type maxFreq: float

    :return: Analysis object with the calculated parameter
    :rtype: Analysis
    """
    # Code snippet to guarantee that generated object name is
    # the declared at global scope
    # for frame, line in traceback.walk_stack(None):
    for framenline in traceback.walk_stack(None):
        # varnames = frame.f_code.co_varnames
        varnames = framenline[0].f_code.co_varnames
        if varnames is ():
            break
    # creation_file, creation_line, creation_function, \
    #     creation_text = \
    extracted_text = \
        traceback.extract_stack(framenline[0], 1)[0]
    # traceback.extract_stack(frame, 1)[0]
    # creation_name = creation_text.split("=")[0].strip()
    creation_name = extracted_text[3].split("=")[0].strip()

    # firstChNum = IR.systemSignal.channels.mapping[0]
    # if not IR.systemSignal.channels[firstChNum].calibCheck:
    #     raise ValueError("'IR' must be a calibrated ImpulsiveResponse")
    if isinstance(IR, SignalObj):
        SigObj = cp.copy(IR)
    elif isinstance(IR, ImpulsiveResponse):
        SigObj = cp.copy(IR.systemSignal)
    else:
        raise TypeError("'IR' must be an ImpulsiveResponse or SignalObj.")
    # Cutting the IR
    if IREndManualCut is not None:
        SigObj.crop(0, IREndManualCut)
    timeSignal, _ = _circular_time_shift(SigObj.timeSignal[:, 0])
    # Bands filtering
    # hSignal = SignalObj(SigObj.timeSignal[:,0],
    hSignal = SignalObj(timeSignal, SigObj.lengthDomain, SigObj.samplingRate)
    hSignal = _filter(signal=hSignal,
                      nthOct=nthOct,
                      minFreq=minFreq,
                      maxFreq=maxFreq)
    bands = FOF(nthOct=nthOct, freqRange=[minFreq, maxFreq])[:, 1]
    Lpe = []
    for chIndex in range(hSignal.numChannels):
        Lpe.append(10 * np.log10(
            np.trapz(y=hSignal.timeSignal[:, chIndex]**2 / (2e-5**2),
                     x=hSignal.timeVector)))
    LpeAnal = Analysis(anType='mixed',
                       nthOct=nthOct,
                       minBand=float(bands[0]),
                       maxBand=float(bands[-1]),
                       data=Lpe,
                       comment='h**2 energy level')
    LpeAnal.creation_name = creation_name
    return LpeAnal
Beispiel #7
0
def analyse(obj,
            *params,
            bypassLundeby=False,
            plotLundebyResults=False,
            suppressWarnings=False,
            IREndManualCut=None,
            **kwargs):
    """
    Receives an one channel SignalObj or ImpulsiveResponse and calculate the
    room acoustic parameters especified in the positional input arguments.
    Calculates reverberation time, definition and clarity.
    
    The method for strength factor calculation implies in many input parameters
    and specific procedures, as the sound source's power estimation.
    The pytta.roomir app was designed aiming to support this room parameter
    measurement. For further information check pytta.roomir's and
    pytta.rooms.strength_factor's docstrings.
    
    Input arguments (default), (type):
    -----------------------------------

        * obj (), (SignalObj | ImpulsiveResponse):
            one channel impulsive response

        * non-keyworded argument pairs:
            Pair for 'RT' (reverberation time):
                
                - RTdecay (20), (int):
                    Decay interval for RT calculation. e.g. 20

            Pair for 'C' (clarity):  # TODO
                
                - Cparam (50), (int):
                    ...
                
            Pair for 'D' (definition):  # TODO
                
                - Dparam (50), (int):
                    ...

        * nthOct (), (int): 
            Number of bands per octave;
    
        * minFreq (), (int | float):
            Analysis' inferior frequency limit;
    
        * maxFreq (), (int | float):
            Analysis' superior frequency limit;
        
        * bypassLundeby (false), (bool):
            Bypass lundeby correction
    
        * plotLundebyResults (false), (bool):
            Plot the Lundeby correction parameters;
    
        * suppressWarnings (false), (bool):
            Suppress the warnings from the Lundeby correction;
        
        
    Return (type):
    --------------
    
    
        * Analyses (Analysis | list):
            Analysis object with the calculated parameter or a list of 
            Analyses for more than one parameter.
            
    Usage example:
                
        >>> myRT = pytta.rooms.analyse(IR,
                                       'RT', 20',
                                       'C', 50,
                                       'D', 80,
                                       nthOct=3,
                                       minFreq=100,
                                       maxFreq=10000)
            
    For more tips check the examples folder.

    """
    # Code snippet to guarantee that generated object name is
    # the declared at global scope
    # for frame, line in traceback.walk_stack(None):
    for framenline in traceback.walk_stack(None):
        # varnames = frame.f_code.co_varnames
        varnames = framenline[0].f_code.co_varnames
        if varnames is ():
            break
    # creation_file, creation_line, creation_function, \
    #     creation_text = \
    extracted_text = \
        traceback.extract_stack(framenline[0], 1)[0]
    # traceback.extract_stack(frame, 1)[0]
    # creation_name = creation_text.split("=")[0].strip()
    creation_name = extracted_text[3].split("=")[0].strip()

    if not isinstance(obj, SignalObj) and not isinstance(
            obj, ImpulsiveResponse):
        raise TypeError("'obj' must be an one channel SignalObj or" +
                        " ImpulsiveResponse.")
    if isinstance(obj, ImpulsiveResponse):
        SigObj = obj.systemSignal
    else:
        SigObj = obj

    if SigObj.numChannels > 1:
        raise TypeError("'obj' can't contain more than one channel.")
    samplingRate = SigObj.samplingRate

    SigObj = crop_IR(SigObj, IREndManualCut)

    calcEDC = False
    result = []

    for param in params:
        if param in ['RT']:  # 'C', 'D']:
            calcEDC = True
            break

    if calcEDC:
        listEDC = cumulative_integration(SigObj,
                                         bypassLundeby,
                                         plotLundebyResults,
                                         suppressWarnings=suppressWarnings,
                                         **kwargs)

    if 'RT' in params:
        RTdecay = params[params.index('RT') + 1]
        if not isinstance(RTdecay, (int)):
            RTdecay = 20
        nthOct = kwargs['nthOct']
        RT = reverberation_time(RTdecay, nthOct, samplingRate, listEDC)
        RTtemp = Analysis(anType='RT',
                          nthOct=nthOct,
                          minBand=kwargs['minFreq'],
                          maxBand=kwargs['maxFreq'],
                          data=RT)
        RTtemp.creation_name = creation_name
        result.append(RTtemp)

    # if 'C' in params:
    #     Cparam = params[params.index('C')+1]
    #     if not isinstance(Cparam,(int)):
    #         Cparam = 50
    #     Ctemp = None
    #     result.append(Ctemp)

    # if 'D' in params:
    #     Dparam = params[params.index('D')+1]
    #     if not isinstance(Dparam,(int)):
    #         Dparam = 50
    #     Dtemp = None
    #     result.append(Dtemp)

    if len(result) == 1:
        result = result[0]

    return result