Source code for mesh2hrtf.Output2HRTF.reference_hrtfs

import numpy as np
import sofar as sf


[docs]def reference_hrtfs(sofa, sourceType, sourceArea, speedOfSound, densityOfAir, mode="min"): """ Reference HRTFs to the sound pressure in the center of the head. After referencing the sound pressure approaches 1 (0 dB) for low frequencies. Parameters ---------- sofa : sofar Sofa object, str Sofa object containing the sound pressure or filename of a SOFA file to be loaded. SOFA object/file must be of the convention SimpleFreeFieldHRTF or GeneralTF sourceType : str The referencing depends on the source type used for simulating the sound pressure. Can be "Both ears", "Left ear", "Right ear", "Point source", or "Plane wave" sourceArea : array like The area of the source is required if `sourceType` is "Both ears" in which case `sourceAre` is a list with two values or if `sourceType` is "Left ear" or "Right ear" in which case `sourceArea` is a list with one value. speedOfSound : number The speed of sound in m/s densityOfAir : number The density of air in kg / m**3 mode : str, optional Pass "min", "max", or "mean" to reference to the minmum, maximum, or mean radius in `sofa.SourcePosition`. Pass "all" to normalize each HRTF to the radius of the corresponding source. Returns ------- sofa : sofar Sofa.object A copy of the input data with referenced sound pressure """ if isinstance(sofa, str): sofa = sf.read_sofa(sofa) else: sofa = sofa.copy() if sofa.GLOBAL_SOFAConventions not in ["SimpleFreeFieldHRTF", "GeneralTF"]: raise ValueError(("Sofa object must have the conventions " "SimpleFreeFieldHRTF or GeneralTF")) if sofa.SourcePosition_Type == "spherical": radius = sofa.SourcePosition[:, 2] else: radius = np.sqrt(sofa.SourcePosition[:, 0]**2 + sofa.SourcePosition[:, 1]**2 + sofa.SourcePosition[:, 2]**2) pressure = sofa.Data_Real + 1j * sofa.Data_Imag frequencies = sofa.N # distance of source positions from the origin if mode == "min": r = np.min(radius) elif mode == "mean": r = np.mean(radius) elif mode == "max": r = np.max(radius) else: r = radius[..., np.newaxis, np.newaxis] if sourceType in {'Both ears', 'Left ear', 'Right ear'}: volumeFlow = 0.1 * np.ones(pressure.shape) if 'sourceArea': # has to be fixed for both ears.... for nn in range(len(sourceArea)): volumeFlow[:, nn, :] = \ volumeFlow[:, nn, :] * sourceArea[nn] # point source in the origin evaluated at r # eq. (6.71) in: Williams, E. G. (1999). Fourier Acoustics. ps = -1j * densityOfAir * 2 * np.pi * frequencies * \ volumeFlow / (4 * np.pi) * \ np.exp(1j * 2 * np.pi * frequencies / speedOfSound * r) / r elif sourceType == 'Point source': amplitude = 0.1 # hard coded in Mesh2HRTF ps = amplitude * \ np.exp(1j * 2 * np.pi * frequencies / speedOfSound * r) / (4 * np.pi * r) elif sourceType == 'Plane wave': raise ValueError( ("Plane wave not implemented yet.")) else: raise ValueError( ("Referencing is currently only implemented for " "sourceType 'Both ears', 'Left ear', 'Right ear'," "'Point source' and 'Plane wave'.")) # here we go... pressure /= ps sofa.Data_Real = np.real(pressure) sofa.Data_Imag = np.imag(pressure) return sofa