Metrics

Functions for computing localisation metrics and registering custom ones.

Localisation metrics

bayesian_listener.metrics.localization_error(targets, estimations, metric, auxiliary_output=False, degrees=False, **kwargs)[source]

Compute the localization error between two sets of coordinates using the specified metric.

Parameters:
  • targets (pyfar.Coordinates) – The target (reference) coordinates, shape (n_targets,).

  • estimations (pyfar.Coordinates) – The estimated coordinates to compare against. May have an extra repetitions dimension, i.e. shape (n_targets, repetitions); targets is broadcast accordingly and both are flattened to (n_targets * repetitions,) before the metric is applied.

  • metric (str or Callable) –

    The metric to use for error computation.

    • If a string, it must be a registered metric name. Use describe_metrics to list registered names and describe_metrics (name) for details on a specific one.

    • If a callable, it must accept two pyfar.Coordinates arguments (targets, estimations) as the first two positional arguments, plus any keyword arguments forwarded via **kwargs. The user is responsible for coordinate convention and units. The callable must return either a single float or a tuple (error_value, auxiliary_data).

  • auxiliary_output (bool, default=False) – Ignored when metric is a callable (the callable handles its own return shape). When True and metric is a registered string, returns the auxiliary output dict alongside the error value.

  • degrees (bool, default=False) – When True, convert the returned error value to degrees. Has no effect for metrics whose output_unit is already 'degrees' or 'percentage'.

  • **kwargs (dict, optional) –

    Forwarded to the metric function.

    • For registered metrics, kwargs are validated against the function signature. Unknown kwargs raise a UserWarning and are dropped; valid ones are forwarded. See describe_metrics (name) for the per-metric kwarg list.

    • For callables, kwargs are forwarded as-is with no validation.

Returns:

The computed localization error. If auxiliary_output is True, the output will be a tuple: (error_value, auxiliary_data_dict). If the metric function does not provide auxiliary data, auxiliary_data_dict will be an empty dictionary.

Return type:

float or tuple

Examples

Registered metric with extra kwarg:

>>> error = localization_error(targets, estimations,
...                            'accL_cutoff',
...                            cutoff=np.deg2rad(30))

Registered metric with auxiliary output:

>>> error, aux = localization_error(targets, estimations,
...                                 'querrMiddlebrooks',
...                                 auxiliary_output=True)
>>> print(error)
9.375
>>> print(aux)
{'confusion_count': 48, 'response_count': 512}

Custom callable with extra kwarg:

>>> def my_metric(targets, estimations, threshold=0.5):
...     ...
>>> error = localization_error(targets, estimations,
...                            my_metric,
...                            threshold=0.1)
bayesian_listener.metrics.wrap_polar_angle(angle_rad)[source]

Wrap polar (vertical) angles to \([-\pi/2, 3\pi/2)\).

The interaural-polar convention places the front pole at 0 and the rear pole at π; wrapping to [-π/2, 3π/2) keeps the upper hemisphere contiguous and simplifies front/back error computations.

Parameters:

angle_rad (float or numpy.ndarray) – Polar angle(s) in radians.

Returns:

Wrapped angle(s) in radians, same shape as angle_rad.

Return type:

float or numpy.ndarray

Metric registry

Custom metrics can be registered and queried via the decorator API.

bayesian_listener.metrics.register_metric(name, coord_convention, input_unit, output_unit=None, description=None, kwargs_description=None, **extra_metadata)[source]

Decorator to register a metric function with metadata.

Parameters:
  • name (str) – Name of the metric.

  • coord_convention (str) – Coordinate convention used (e.g., ‘horizontal-polar’).

  • input_unit (str) – Unit of the input data (e.g., ‘radians’).

  • output_unit (str, optional) – Unit of the output data (e.g., ‘radians’, ‘percentage’).

  • description (str, optional) – Description of the metric.

  • kwargs_description (dict, optional) – Dictionary describing extra keyword arguments expected by the metric function. Keys are argument names, values are descriptions.

  • **extra_metadata (dict) – Additional metadata to store.

Returns:

decorator – Decorator that wraps the target function and registers it under name in METRIC_FUNCTIONS.

Return type:

callable

bayesian_listener.metrics.get_metric_metadata(name)[source]

Retrieve metadata for a registered metric.

Parameters:

name (str) – Name of the metric.

Returns:

metadata – Metadata dictionary for the metric.

Return type:

dict

bayesian_listener.metrics.describe_metrics(name=None)[source]

Print descriptions of registered metrics.

Parameters:

name (str, optional) – Name of the metric to describe. If None, lists all metrics.

Built-in metrics

Lateral error

bayesian_listener.metrics.sdL(true, est)[source]

Lateral standard-deviation error within \(\pm 80^\circ\) lateral.

Returns the standard deviation (square root of variance) of the response–target lateral-angle difference, restricted to estimations whose lateral angle satisfies \(|\hat{\alpha}| \le 80^\circ\). See Middlebrooks[1] for the foundational definition.

Parameters:
  • true (numpy.ndarray) – Target directions in horizontal-polar convention with lateral angles in radians, shape (..., 3).

  • est (numpy.ndarray) – Estimated directions, same shape and convention as true.

Returns:

Lateral SD in radians, or np.nan if no estimations fall within the ±80° band.

Return type:

float

bayesian_listener.metrics.rmsL(true, est)[source]

Lateral RMS error within \(\pm 60^\circ\) lateral (Middlebrooks[1]).

Parameters:
  • true (numpy.ndarray) – Target directions, horizontal-polar with lateral angle in radians.

  • est (numpy.ndarray) – Estimated directions, same convention as true.

Returns:

Lateral RMS in radians, or np.nan if no estimations fall within the ±60° band.

Return type:

float

bayesian_listener.metrics.accL_cutoff(true, est, cutoff=3.141592653589793)[source]

Lateral bias (mean signed error) within \(\pm\) cutoff.

Parameters:
  • true (numpy.ndarray) – Target directions, horizontal-polar with lateral angle in radians.

  • est (numpy.ndarray) – Estimated directions.

  • cutoff (float, default=π) – Lateral-angle threshold in radians; only targets with \(|\alpha| \le\) cutoff are included.

Returns:

Mean signed lateral error in radians (positive: rightward bias), or np.nan if no targets fall within the band.

Return type:

float

Polar error

bayesian_listener.metrics.rmsPmedianlocal(true, est)[source]

Local RMS polar error within \(\pm 30^\circ\) lateral, excluding quadrant errors.

Restricted to estimations with lateral angle \(|\hat{\alpha}| \le 30^\circ\) and polar error \(|\Delta \beta| < 90^\circ\). Definition follows Middlebrooks[1].

Parameters:
  • true (numpy.ndarray) – Target directions, horizontal-polar with angles in radians.

  • est (numpy.ndarray) – Estimated directions.

Returns:

Local polar RMS in radians.

Return type:

float

Raises:

ValueError – If estimated lateral angles fall outside \([-\pi/2, \pi/2]\), if no estimations land in the central band, or if every central estimation has a polar error \(\ge 90^\circ\).

bayesian_listener.metrics.accP_cutoff(true, est, cutoff=np.float64(0.5235987755982988))[source]
Polar bias (mean signed error) within \(\pm\) cutoff

lateral (Middlebrooks[1]).

Parameters:
  • true (numpy.ndarray) – Target directions, horizontal-polar with angles in radians.

  • est (numpy.ndarray) – Estimated directions.

  • cutoff (float, default=π/6) – Lateral-angle threshold in radians; only estimations with \(|\hat{\alpha}| \le\) cutoff are included.

Returns:

Mean signed polar error in radians (positive: upward bias), or np.nan if no estimations fall within the band.

Return type:

float

Global error

bayesian_listener.metrics.querrMiddlebrooks(true, est)[source]

Quadrant-error rate within \(\pm 30^\circ\) lateral (Middlebrooks[1]).

Counts the fraction of central-band estimations whose polar error satisfies \(|\Delta \beta| \ge 90^\circ\).

Parameters:
  • true (numpy.ndarray) – Target directions, horizontal-polar with angles in radians.

  • est (numpy.ndarray) – Estimated directions.

Returns:

  • qerr (float) – Quadrant-error rate as a percentage.

  • aux (dict) – Mapping with keys:

    • 'confusion_count' (int) — number of estimations with \(|\Delta \beta| \ge 90^\circ\).

    • 'response_count' (int) — total estimations within the central ±30° lateral band.

Raises:

ValueError – If estimated lateral angles fall outside \([-\pi/2, \pi/2]\), or if no estimations land in the central ±30° band.

bayesian_listener.metrics.angular_error(true, est)[source]

Mean great-circle angular error between target and estimation unit vectors.

Computes \(\bar{\theta} = \frac{1}{N} \sum \arccos( \mathbf{t}_i \cdot \hat{\mathbf{e}}_i)\) with the dot product clipped to \([-1, 1]\) for numerical safety.

Parameters:
  • true (numpy.ndarray) – Target directions in Cartesian coordinates, shape (..., 3); each row should be unit-norm.

  • est (numpy.ndarray) – Estimated directions, same shape and convention.

Returns:

Mean angular error in radians.

Return type:

float