hrtf_difference¶
- hrtfpykit.hrtf.hrtf_difference(hrtf_reference, hrtfs, metric='rmse', ear='both', plane='all', plane_angle=0.0, positions=None, frequencies=None, frequency_bands=None, reduction_axis=None, reduction_method='mean', epsilon=1e-12)¶
Compute HRTF difference metrics against a reference HRTF.
hrtf_differencecompares one reference HRTF with one or more HRTFs on the same source grid."rmse","mae", and"nrmse"compareIR.values."lsd"comparesTF.values. The function selects the requested sources and ears, computes the selected metric for each compared HRTF, source, and ear, and then applies any requested reduction.metric="rmse",metric="mae", andmetric="nrmse"useIR.valueswith shape(positions, ears, samples). The reference and compared HRTFs must provide matching IR shapes and matching IR sample rates. For each selected source and ear, the sample error is computed ascompared - reference. RMSE returnssqrt(mean(error ** 2))in linear amplitude units. MAE returnsmean(abs(error))in linear amplitude units. NRMSE returnssqrt(sum(error ** 2) / sum(reference ** 2))as a ratio normalized by the reference, applies any requested reduction to that ratio, and finally converts the result to dB with20 * log10.metric="lsd"usesTF.valueswith shape(positions, ears, frequency_bins). The reference and compared HRTFs must provide matching TF shapes, matchingTF.frequency_bins, and matching source positions. Magnitudes are converted to dB, compared as reference minus compared magnitude, and reduced over the selected frequency bins with an RMS operation. The resulting LSD values are in dB before anyreduction_axisreduction is applied.Source selection is resolved against
hrtf_reference.Sourcesin spherical degrees.planeis applied first, then explicitpositionsqueries are intersected with that plane selection. For LSD,frequenciesmaps requested frequencies to the nearest available TF bins and removes duplicate bin selections.frequency_bandsselects inclusive frequency ranges. If neither frequency selector is provided for LSD, the metric uses available bins from 20 Hz to 20000 Hz.Without
reduction_axis, one compared HRTF returns the natural metric array with no leading comparison axis. Several compared HRTFs return a leading difference axis.reduction_axis="differences"reduces the compared HRTF axis,"position"or"positions"reduces selected source positions,"ears"reduces the ear axis, and"global"reduces all available metric axes."source"and"sources"are accepted as aliases for the position axis. Reductions use either arithmetic mean or root mean square, according toreduction_method.- Parameters:
hrtf_reference (HRTF) – Reference HRTF.
"rmse","mae", and"nrmse"requireIR.valuesandIR.sample_rate.metric="lsd"requiresTF.valuesandTF.frequency_bins. All metrics require source positions.hrtfs (HRTF or sequence of HRTF) – HRTF object or objects compared against
hrtf_reference. Compared HRTFs must use the same source grid as the reference."rmse","mae", and"nrmse"also require matching IR shape and sample rate.metric="lsd"also requires matching TF shape and frequency bins.metric ({
"rmse","mae","nrmse","lsd"}, default=``”rmse”``) – Difference metric."rmse"and"mae"return linear amplitude error."nrmse"and"lsd"return dB.ear ({
"left","right","both"}, default=``”both”``) – Ear channel selection."left"uses ear channel 0,"right"uses ear channel 1, and"both"keeps both ears unless the ear axis is reduced.plane ({
"all","horizontal","median"}, default=``”all”``) – Spatial subset used before comparison.plane_angle (float, default=0.0) – Plane coordinate in degrees. For
plane="horizontal"this is spherical elevation. Forplane="median"this is lateral-polar lateral angle.positions (np.ndarray | list | tuple | str | None, default=None) – Optional source-position selector. Queries are resolved on the reference source grid and intersected with the selected plane.
frequencies (float, sequence of float, numpy.ndarray, or None, default=None) – Frequency selector in hertz for
metric="lsd". Each requested frequency is mapped to the nearest available TF bin. Mutually exclusive withfrequency_bands.frequency_bands (pair, sequence of pairs, numpy.ndarray, or None, default=None) – Inclusive frequency band or bands in hertz for
metric="lsd". Mutually exclusive withfrequencies.reduction_axis ({
"differences","positions","ears","global"}, sequence, or None, default=None) – Axis or axes reduced after metric values are computed. None returns the natural metric array."differences"reduces the compared HRTF axis."position"or"positions"reduces source positions."ears"reduces ears and requiresear="both"."global"reduces all axes."source"and"sources"are accepted as aliases for positions. Metric aliases such as"rmses","maes","nrmses", and"lsds"are accepted for the compared HRTF axis.reduction_method ({
"mean","rms"}, default=``”mean”``) – Reduction method applied to selected metric values."mean"computes the arithmetic mean."rms"computes the root mean square.epsilon (float, default=1e-12) – Positive lower bound used for NRMSE reference energy normalization, LSD magnitude flooring, and dB conversion.
- Returns:
Difference values after the requested reduction.
rmseandmaeresults are linear amplitude errors.nrmseandlsdresults are in dB. A full global reduction returns a scalar float.- Return type:
numpy.ndarray or float
- Raises:
ValueError – If any input is not an HRTF object, if
hrtfsis empty, if selected metric data are missing, if source grids or metric shapes differ, if selected data are not arranged as(positions, ears, samples)or(positions, ears, frequency_bins), if option values are unsupported, if epsilon is not finite and positive, or if source or frequency selectors produce no data.
Examples
Compute one RMSE value per position for the left ear:
>>> from hrtfpykit.hrtf import hrtf_difference, load_hrtf >>> reference = load_hrtf("P0001_FreeFieldComp_44kHz.sofa") >>> processed = reference.transform.apply_gain(gain=-1.0, scale="db") >>> values = hrtf_difference(reference, processed, metric="rmse", ear="left") >>> values.shape (793,)
Compute one global NRMSE score in dB:
>>> nrmse_score = hrtf_difference( ... reference, ... processed, ... metric="nrmse", ... reduction_axis="global", ... reduction_method="rms", ... ) >>> isinstance(nrmse_score, float) True
Compute LSD over an explicit frequency band:
>>> lsd_values = hrtf_difference( ... reference, ... processed, ... metric="lsd", ... ear="both", ... frequency_bands=(700.0, 1800.0), ... reduction_axis="ears", ... ) >>> lsd_values.shape (793,)