HRTF

class hrtfpykit.hrtf.HRTF(Sofa=None)

Bases: HRTFPlots

Represent an HRTF or HRIR object loaded from SOFA data.

HRTF is the main in-memory object used to inspect, subset, transform, plot, synchronize, and save HRTF/HRIR data loaded from SOFA files. It supports the SimpleFreeFieldHRIR and SimpleFreeFieldHRTF conventions and keeps both acoustic representations available:

  • IR: time-domain impulse responses

  • TF: frequency-domain transfer functions

The object stores acoustic arrays separately from the backing SOFA object. Transformations and selections operate on the in-memory arrays first; SOFA variables are updated only when update_sofa() or save() is called. This makes processing workflows explicit and prevents intermediate edits from being written to the file representation automatically.

Spatial metadata and source-grid operations are exposed through Sources. That object resolves SOFA SourcePosition data, named directions, coordinate-system conversion, and plane-based queries used by both processing and visualization methods.

The object exposes plotting workflows for HRTF inspection and analysis. This includes source-grid visualizations, spectral views, plane projections, and metric-oriented plots that operate directly on the current in-memory state, including any selection or transformation.

The object stores the optional SOFA backing object and starts with empty metadata fields. Domain interface objects such as IR, TF, Sources, and Transform are created lazily when their properties are first accessed. Raw SOFA variables are not parsed and missing domains are not derived here; load_hrtf() performs that loading and synchronization work.

Notes

A typical workflow is to load an object with load_hrtf(), inspect or subset data with Sources and select(), apply transforms through transform, visualize using plotting methods, then synchronize and export with update_sofa() and save().

The instance keeps a reference to the backing SOFA object in Sofa. Transformation state is tracked internally; selected source subsets are tracked separately by Sources. Mesh2HRTF compatible loading state is also stored so reset and TF-domain workflows can reconstruct HRIR data with the same convention used at load time.

Parameters:

Sofa (SOFA | None, default=None) – SOFA object that backs the HRTF instance. When None, the object is created empty and should be populated later.

Sofa

Backing SOFA object used for source metadata, persistence, and SOFA synchronization.

Type:

SOFA or None

SOFAConventions

Active SOFA convention associated with the loaded or constructed HRTF object.

Type:

str or None

fft_length

FFT length used when synchronizing between IR and TF representations.

Type:

int or None

mesh2hrtf_compatible

Whether SimpleFreeFieldHRTF data should use Mesh2HRTF compatible TF-to-IR reconstruction.

Type:

bool

mesh2hrtf_n_shift

Circular shift in samples used when mesh2hrtf_compatible is True.

Type:

int or None

_transformed

Internal flag indicating whether the in-memory acoustic data were produced by a transform workflow.

Type:

bool

property IR: IR

Access the time-domain HRIR representation object.

This object stores IR.values and IR.sample_rate for the parent HRTF object and exposes time-domain inspection helpers such as sample length, duration, and ITD calculation.

Examples

Load a SOFA file and access the HRIR samples, sample-rate metadata, signal length, duration, and ITD values through hrtf.IR:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> ir_values = hrtf.IR.values
>>> sample_rate = hrtf.IR.sample_rate
>>> first_position_left_ir = hrtf.IR.values[0, 0, :]
>>> itd_samples = hrtf.IR.get_itd(output="samples")
>>> ir_values.shape
(793, 2, 256)
>>> sample_rate
44100.0
>>> first_position_left_ir.shape
(256,)
>>> hrtf.IR.ir_length
256
>>> hrtf.IR.ir_duration
0.005804988662131519
>>> itd_samples.shape
(793,)
property TF: TF

Access the frequency-domain HRTF representation object.

This object stores complex TF.values and TF.frequency_bins for the parent object and exposes derived magnitude, phase, real, and imaginary views used by transforms, metrics, and plots.

Examples

Load a SOFA file and access the frequency-domain HRTF values, frequency axis, bin metadata, and derived spectral arrays through hrtf.TF:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.TF.values.shape
(793, 2, 129)
>>> hrtf.TF.values.dtype
dtype('complex128')
>>> hrtf.TF.frequency_bins[:5]
array([  0.      , 172.265625, 344.53125 , 516.796875, 689.0625  ])
>>> hrtf.TF.tf_length
129
>>> hrtf.TF.frequency_bins_step
172.265625
>>> hrtf.TF.min_frequency_bin
0.0
>>> hrtf.TF.max_frequency_bin
22050.0
>>> hrtf.TF.magnitude.shape
(793, 2, 129)
>>> hrtf.TF.get_magnitude_db().shape
(793, 2, 129)
>>> hrtf.TF.phase.shape
(793, 2, 129)
>>> hrtf.TF.real.shape
(793, 2, 129)
>>> hrtf.TF.imag.shape
(793, 2, 129)
property Sources: Sources

Access the spatial source-grid object.

Sources reads SOFA SourcePosition data, converts between the supported coordinate systems, resolves named positions, and tracks selected source indices after spatial subsetting.

Examples

Load a SOFA file and access source-grid positions, coordinate-system metadata, available angles, nearest-position matches, and selected source views through hrtf.Sources:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.Sources.source_coordinate_system
'spherical'
>>> hrtf.Sources.get_positions().shape
(793, 3)
>>> hrtf.Sources.get_positions()[:3]
array([[  0. , -45. ,   1.5],
       [  0. , -30. ,   1.5],
       [  0. , -20. ,   1.5]])
>>> hrtf.Sources.get_positions(angle_unit="radians")[0]
array([ 0.        , -0.78539816,  1.5       ])
>>> hrtf.Sources.get_azimuth_angles()[:5]
array([ 0.,  5., 10., 15., 20.])
>>> hrtf.Sources.get_elevation_angles()
array([-45., -30., -20., -10.,   0.,  10.,  20.,  30.,  45.,  60.,  75.,
        90.])
>>> elevations_at_front, real_azimuth = (
...     hrtf.Sources.get_elevation_angles_for_azimuth(0.0)
... )
>>> elevations_at_front[:5]
array([-45., -30., -20., -10.,   0.])
>>> real_azimuth
0.0
>>> azimuths_on_horizontal, real_elevation = (
...     hrtf.Sources.get_azimuth_angles_for_elevation(0.0)
... )
>>> azimuths_on_horizontal[:5]
array([ 0.,  5., 10., 15., 20.])
>>> real_elevation
0.0
>>> hrtf.Sources.get_position_index("front")
(4, array([0. , 0. , 1.5]))
>>> selected = hrtf.select(positions=["front", "left", "right"])
>>> selected.Sources.get_positions().shape
(3, 3)
property transform: Transform

Access the immutable transformation interface for this HRTF.

Methods on this object clone the current HRTF, apply one processing operation, synchronize the affected IR or TF representation, and return the derived HRTF without mutating the original instance.

clone()

Create a deep clone of the current HRTF object.

The clone receives copied IR and TF arrays, sample-rate and frequency-bin metadata, FFT length, Mesh2HRTF compatible reconstruction settings, transformation state, and source selection state. When the backing SOFA object can be cloned, the clone receives an independent SOFA handle; otherwise the original handle is retained.

Returns:

New object with copied acoustic arrays, domain metadata, source selection state, SOFA convention metadata, Mesh2HRTF compatible loading state, and transformation flag.

Return type:

HRTF

Examples

Clone a loaded HRTF before changing array values so the original object remains unchanged:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf_copy = hrtf.clone()
>>> hrtf_copy.IR.values[0, 0, 0] += 1.0
>>> hrtf_copy.IR.values[0, 0, 0] == hrtf.IR.values[0, 0, 0]
False
reset()

Reset in-memory HRTF data to the backed SOFA content.

This method discards current in-memory acoustic edits and reloads the active domain data from Sofa. HRIR files are restored from Data.IR and Data.SamplingRate and then converted to TF. HRTF files are restored from Data.Real, Data.Imag, and N and then converted to IR. If the object was loaded with Mesh2HRTF compatible reconstruction, reset uses the same compatibility flag and sample shift. Source selections are cleared when the Sources object has already been initialized.

Returns:

Current instance after restoring IR/TF, source-state, and metadata from the backed SOFA object while keeping the stored Mesh2HRTF compatible reconstruction settings.

Return type:

HRTF

Raises:

ValueError – If no SOFA file is attached, the SOFA file is not loaded, the convention is unsupported, or required acoustic variables are missing or empty.

Examples

Restore a selected HRTF object from its backed SOFA content:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> selected = hrtf.select(positions=["front", "left", "right"])
>>> selected.IR.values.shape
(3, 2, 256)
>>> restored = selected.reset()
>>> restored.IR.values.shape
(793, 2, 256)
>>> restored.is_transformed()
False
is_transformed()

Return the current HRTF transformation flag.

The flag is set by transform workflows that modify acoustic data. It is a workflow state indicator, not a byte-by-byte comparison between in-memory arrays and the backing SOFA object. Source selection is tracked separately on Sources and is handled independently by update_sofa().

Returns:

True if a transform workflow has marked the object as transformed; False otherwise.

Return type:

bool

Examples

Check whether a transform returned a derived HRTF while the original object stayed unchanged:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> windowed = hrtf.transform.apply_window("hann")
>>> hrtf.is_transformed()
False
>>> windowed.is_transformed()
True
update_sofa(change_sofa_dimensions=False, sofa_convention='same')

Synchronize in-memory IR/TF data into the backed SOFA object.

The method converts the current acoustic representation into the requested SOFA convention and writes the corresponding SOFA variables on a cloned or updated SOFA object. It updates HRIR output through Data.IR and Data.SamplingRate; HRTF output through Data.Real, Data.Imag, and N. Obsolete variables from the opposite convention are removed when the output convention changes. If a SimpleFreeFieldHRTF file omitted the DC bin at load time, synchronization writes the normalized TF with the inserted DC bin.

Dimension handling is conservative. If transformed data no longer fit existing SOFA dimensions, synchronization raises unless change_sofa_dimensions=True. When resizing is allowed, supported dependent variables on the measurement axis are subset with the current source selection; unsupported dependent variables still raise explicit errors to avoid silently corrupting SOFA structure.

The method updates the in-memory Sofa object only. Use save() to persist the synchronized SOFA object to disk. When TF values must be converted back to IR during synchronization, the stored Mesh2HRTF compatible reconstruction settings are reused.

Parameters:
  • change_sofa_dimensions (bool, default=False) – If True, allows resizing fixed SOFA dimensions when transformed data shape differs from backed variables.

  • sofa_convention ({same, SimpleFreeFieldHRIR, SimpleFreeFieldHRTF}, default=``same``) – Output SOFA convention to enforce during synchronization. same keeps the original backed SOFA convention.

Returns:

This method updates Sofa in-place and does not return data.

Return type:

None

Raises:

ValueError – If no SOFA file is loaded, the convention is unsupported, required domain values are missing, transformed shapes cannot be represented by the SOFA dimensions, or requested dimension changes would affect variables that the method cannot update safely.

Examples

Synchronize a selected source subset into the backed SOFA object before saving or inspecting SOFA variables:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> selected = hrtf.select(positions=["front", "left", "right"])
>>> selected.update_sofa(change_sofa_dimensions=True)
>>> source_positions = selected.Sofa.Variables.get("SourcePosition").value
>>> source_positions.shape
(3, 3)
save(path=None, overwrite=False, change_sofa_dimensions=False, sofa_convention='same')

Update SOFA variables and save to disk.

This is the persistence endpoint for the HRTF workflow. It first calls update_sofa() so the backed SOFA object reflects the current in-memory IR/TF state and requested convention, then delegates the disk write to save().

Parameters:
  • path (str | Path | None, default=None) – Output file path. If None, the current backed SOFA path is used by the underlying SOFA object.

  • overwrite (bool, default=False) – If True, allows overwriting an existing file.

  • change_sofa_dimensions (bool, default=False) – Forwarded to update_sofa() to control SOFA dimension resizing.

  • sofa_convention ({same, SimpleFreeFieldHRIR, SimpleFreeFieldHRTF}, default=``same``) – Forwarded to update_sofa() to select output convention.

Returns:

Path to the saved SOFA file.

Return type:

Path

Raises:
  • ValueError – If no SOFA file is attached or synchronization fails.

  • FileExistsError – If the target path already exists and overwrite=False.

Examples

Save a processed HRTF to a new SOFA file using a relative output path:

>>> from pathlib import Path
>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> windowed = hrtf.transform.apply_window("hann")
>>> output_dir = Path("processed")
>>> output_dir.mkdir(exist_ok=True)
>>> saved_path = windowed.save(
...     output_dir / "P0001_windowed.sofa",
...     overwrite=True,
... )
>>> saved_path.name
'P0001_windowed.sofa'
select(positions=None, position_coordinate_system='spherical', plane=None, plane_angle=0.0, azimuth_angles=None, elevation_angles=None, ear='both', angle_unit='degrees', start_sample=None, end_sample=None)

Select a spatial subset, ear subset, and/or IR crop from the HRTF.

Selection returns a cloned HRTF object and leaves the original object unchanged. Spatial selection can be expressed with explicit positions, named positions, a geometric plane, or azimuth/elevation angle filters. These source-selection modes are mutually exclusive: positions cannot be combined with plane or angle filters, and plane cannot be combined with angle filters. azimuth_angles and elevation_angles may be used together; when both are provided, selected sources must satisfy both filters. Source selections are applied along the leading source axis of both IR.values and TF.values when those domains are available.

Ear selection keeps both ears by default. Selecting left or right removes the ear axis entry from available IR and TF arrays. IR cropping is applied along the final sample axis and automatically recomputes the TF representation from the cropped IR using the cropped IR length as the FFT length.

Parameters:
  • positions (np.ndarray | list[list[float]] | list[float] | None, default=None) – Explicit positions or named aliases to select. Named positions use the source-grid aliases such as front, back, left, and right. Numeric positions are interpreted in position_coordinate_system.

  • position_coordinate_system ({spherical, cartesian, lateral-polar}, default=``spherical``) – Coordinate system used by numeric positions queries.

  • plane (str | None, default=None) – Plane name to filter positions. Supported values are horizontal, median, and frontal.

  • plane_angle (float, default=0.0) – Plane angle used to resolve the nearest available plane. For the horizontal plane this is elevation; for median and frontal planes this is azimuth.

  • azimuth_angles (float, sequence of float, numpy.ndarray, or None, default=None) – Azimuth angle or angles used to keep matching source positions. Requested values resolve to the nearest available source-grid azimuth in spherical coordinates and may be combined only with elevation_angles.

  • elevation_angles (float, sequence of float, numpy.ndarray, or None, default=None) – Elevation angle or angles used to keep matching source positions. Requested values resolve to the nearest available source-grid elevation in spherical coordinates and may be combined only with azimuth_angles.

  • ear ({both, left, right}, default=``both``) – Ear selection.

  • angle_unit ({degrees, radians}, default=``degrees``) – Angle unit used for spatial queries and plane angles.

  • start_sample (int | None, default=None) – IR crop start sample index.

  • end_sample (int | None, default=None) – IR crop end sample index.

Returns:

New HRTF object containing the selected subset.

Return type:

HRTF

Raises:

ValueError – If the requested selection is invalid, no positions remain after filtering, more than one source-selection mode is requested, the requested ear is unavailable, crop boundaries are invalid, or IR data are unavailable for cropping.

Examples

Select three named directions, keep only the left ear, and crop the HRIR samples used in the returned HRTF:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.IR.values.shape
(793, 2, 256)
>>> selected = hrtf.select(
...     positions=["front", "left", "right"],
...     ear="left",
...     start_sample=0,
...     end_sample=128,
... )
>>> selected.IR.values.shape
(3, 128)
>>> selected.TF.values.shape
(3, 65)
>>> selected.fft_length
128

Composed interfaces

HRTF keeps the loaded HRTF/HRIR state in one object and exposes related data and operations through composed interface properties. In normal use, users do not create those interface objects directly. They load or receive an HRTF instance and access each working surface from that instance: IR for the IR object with time-domain HRIR values, sample-rate metadata, ir_duration, and get_itd(); TF for the TF object with frequency-domain HRTF values, frequency bins, magnitude, phase, real, and imag; Sources for the Sources object with get_positions(), coordinate conversion, named position queries, and selection state; and transform for the Transform object with immutable processing operations. Plotting methods from HRTFPlots are also available on the same HRTF instance. Users call methods such as plot_magnitude() or plot_source_grid() from the loaded HRTF object; they do not create an HRTFPlots object directly.

These access paths and plotting methods operate on the same parent HRTF state. A select() call, transformation, update_sofa() synchronization, metric calculation, or plot is therefore based on the current object rather than on detached copies of the IR, TF, source-grid, or transform logic.

class hrtfpykit.hrtf.domain.IR(hrtf)

Represent the time-domain HRIR view owned by an HRTF object.

IR stores the HRIR sample array and sample-rate metadata used by the parent HRTF abstraction. It is created lazily by IR and acts as the in-memory time-domain view of SOFA Data.IR data or data reconstructed from SimpleFreeFieldHRTF frequency-domain files.

The object does not own independent source metadata. Its leading axes are expected to stay aligned with Sources and with the sibling TF representation. Time-domain transforms update IR.values and IR.sample_rate first, then synchronize TF.values and TF.frequency_bins through FFT helpers.

Parameters:

hrtf (HRTF) – Parent HRTF object that owns this time-domain representation.

values

Time-domain impulse-response values. Standard HRTF data use layout (positions, ears, samples), but methods generally treat any leading axes before the final sample axis as preserved metadata axes.

Type:

numpy.ndarray or None

sample_rate

Sampling rate in hertz for the impulse-response data.

Type:

float or None

property ir_length: int

Return the number of HRIR samples along the final axis.

The value is derived from the final axis of IR.values and therefore reflects the current in-memory time-domain representation, including any padding, resampling, or replacement performed through transform.

Returns:

Number of samples on the final axis of IR.values.

Return type:

int

Raises:

AttributeError – If IR.values is None.

property ir_duration: float

Return the current HRIR duration in seconds.

Duration is computed from the sample count and IR.sample_rate using the shared DSP duration helper. Leading source and ear axes do not affect the result; only the final sample axis is used.

Returns:

Duration in seconds, computed from IR.values and IR.sample_rate.

Return type:

float

Raises:

ValueError – If IR.values is missing, not a NumPy array, has no sample axis, or IR.sample_rate is missing or not finite and positive.

get_itd(method='threshold', output='samples', thresh_level=-10.0, upper_cut_freq=3000.0, filter_order=10)

Compute interaural time difference from the current IR values.

This is the domain-object convenience wrapper around itd(). It estimates ITD from IR.values using IR.sample_rate and preserves any leading source axes before the final (ear, samples) layout. The ear convention is 0=left and 1=right.

Parameters:
  • method ({threshold, maxiacce}, default=``threshold``) – ITD estimator. threshold detects per-ear onset samples after low-pass filtering, while maxiacce uses envelope cross-correlation.

  • output ({seconds, samples}, default=``samples``) – Unit used for the returned ITD values.

  • thresh_level (float, default=-10.0) – Threshold offset in decibels used when method is threshold.

  • upper_cut_freq (float, default=3000.0) – Low-pass cutoff frequency in hertz applied before estimation.

  • filter_order (int, default=10) – Positive IIR Butterworth filter order used during preprocessing.

Returns:

ITD values in the selected unit. The output shape is IR.values.shape[:-2]. Positive values indicate a left-ear delay relative to the right ear.

Return type:

numpy.ndarray

Raises:

ValueError – If IR.values or IR.sample_rate is unavailable, the IR array does not contain at least two ears and two samples, the estimator configuration is invalid, or the threshold estimator cannot find a valid onset.

class hrtfpykit.hrtf.domain.TF(hrtf)

Represent the frequency-domain HRTF view owned by an HRTF object.

TF stores the complex HRTF frequency-response array and its frequency bins for the parent HRTF abstraction. It is created lazily by TF and acts as the in-memory frequency-domain view of SOFA Data.Real and Data.Imag data or data computed from HRIR files.

The object is expected to stay aligned with the sibling IR and Sources representations. Frequency-domain transforms update TF.values and TF.frequency_bins first, then synchronize IR.values and IR.sample_rate through inverse FFT helpers.

Parameters:

hrtf (HRTF) – Parent HRTF object that owns this frequency-domain representation.

values

Complex frequency-domain transfer-function values. Standard HRTF data use layout (positions, ears, frequency_bins), but derived properties preserve any leading axes before the final frequency axis.

Type:

numpy.ndarray or None

frequency_bins

One-dimensional frequency-bin values in hertz corresponding to the final axis of TF.values.

Type:

numpy.ndarray or None

property tf_length: int

Return the number of HRTF frequency bins along the final axis.

The value is derived from the final axis of TF.values and corresponds to the current one-sided frequency-domain representation used by the HRTF object.

Returns:

Number of frequency bins on the final axis of TF.values.

Return type:

int

Raises:

AttributeError – If TF.values is None.

property frequency_bins_step: float | None

Return the frequency-bin spacing in hertz when it is uniform.

The method compares consecutive entries in TF.frequency_bins. It returns the common spacing for uniformly sampled spectra and None when the bins are not uniformly spaced.

Returns:

Uniform spacing in hertz, or None when consecutive frequency differences are not equal within the local tolerance.

Return type:

float | None

Raises:
  • ValueError – If TF.frequency_bins is None.

  • IndexError – If fewer than two frequency bins are available.

property min_frequency_bin: float

Return the minimum available frequency bin in hertz.

This is normally 0 Hz for one-sided spectra loaded from HRIR data, but it reflects the current TF.frequency_bins array exactly.

Returns:

Minimum value in TF.frequency_bins.

Return type:

float

Raises:
property max_frequency_bin: float

Return the maximum available frequency bin in hertz.

For uniformly sampled one-sided spectra, this usually corresponds to the Nyquist frequency implied by the IR sample rate and FFT length.

Returns:

Maximum value in TF.frequency_bins.

Return type:

float

Raises:
property magnitude: ndarray

Return the linear magnitude of the complex HRTF values.

The result has the same source, ear, and frequency-bin layout as TF.values and is computed through the shared DSP magnitude helper.

Returns:

Linear magnitude values with the same shape as TF.values.

Return type:

numpy.ndarray

Raises:

ValueError – If TF.values is missing or is not a NumPy array.

get_magnitude_db(reference=1.0)

Return TF magnitude in decibels.

This method computes the linear magnitude of TF.values and converts it with the shared dB conversion helper. It is the domain-object convenience API used by plotting and spectral inspection workflows.

Parameters:

reference (float | {max}, default=1.0) – Positive reference magnitude used for 20 * log10(magnitude / reference). The special value max normalizes to the maximum magnitude present in TF.values.

Returns:

Magnitude values in decibels with the same shape as TF.values.

Return type:

numpy.ndarray

Raises:

ValueError – If TF.values is missing or invalid, if a magnitude is invalid, or if reference is not accepted by the dB conversion helper.

property phase: ndarray

Return the phase of the complex HRTF values in degrees.

The result has the same shape as TF.values and uses the library phase helper so phase handling is consistent with transform methods.

Returns:

Phase values in degrees with the same shape as TF.values.

Return type:

numpy.ndarray

Raises:

ValueError – If TF.values is missing or is not a NumPy array.

property real: ndarray

Return the real component of the complex HRTF values.

This property exposes Data.Real-style values for the current frequency-domain representation without modifying the parent HRTF.

Returns:

Real component of TF.values with the same shape.

Return type:

numpy.ndarray

Raises:

ValueError – If TF.values is missing or is not a NumPy array.

property imag: ndarray

Return the imaginary component of the complex HRTF values.

This property exposes Data.Imag-style values for the current frequency-domain representation without modifying the parent HRTF.

Returns:

Imaginary component of TF.values with the same shape.

Return type:

numpy.ndarray

Raises:

ValueError – If TF.values is missing or is not a NumPy array.

class hrtfpykit.hrtf.sources.Sources(hrtf=None)

Manage source positions, coordinate systems, and spatial selections.

Sources is the source-position manager used by HRTF. It reads SOFA SourcePosition values and their SourcePosition:Type and SourcePosition:Units attributes from the owning HRTF object, converts positions on demand, and resolves source-grid queries used by selection, metrics, spherical harmonics, and plotting utilities.

The manager stores the target coordinate system in source_coordinate_system. Changing that value changes how get_positions() and query methods expose positions; it does not rewrite the stored SOFA SourcePosition array by itself. Spatial subsets created through select() are also respected, so returned arrays and matched indices refer to the current HRTF view rather than necessarily to every source in the original SOFA file.

Notes

Conventions implemented by this class:

  • Spherical (SOFA-style): (azimuth, elevation, radius) with azimuth in [0, 360) degrees (anticlockwise in horizontal plane), elevation in [-90, 90] degrees (positive up), and non-negative radius.

  • Lateral-polar: (lateral, polar, radius) with lateral in [-90, 90] degrees (positive left), polar normalized to [-90, 270) degrees, and non-negative radius.

  • Cartesian: (x, y, z) with +y as left and +z as up.

At lateral poles (abs(lateral) == 90) and at zero radius, polar is singular. This implementation uses a deterministic placeholder polar = 0.

Parameters:

hrtf (HRTF | None, default=None) – Owning HRTF instance. Most user code obtains this object from Sources. A usable manager requires an HRTF with a loaded SOFA object containing SourcePosition metadata.

source_coordinate_system

Target coordinate system used by source-grid query methods.

Type:

str

_selected_indices

Source-position indices retained by the current HRTF view after spatial selection.

Type:

numpy.ndarray or None

get_positions(angle_unit='degrees')

Return the current source grid in the configured coordinate system.

Positions are read from the owning HRTF object’s SOFA SourcePosition variable each time this method is called. The SOFA coordinate system is taken from SourcePosition:Type and converted to source_coordinate_system. If the owning HRTF has been spatially selected, only the selected source rows are returned.

Parameters:

angle_unit ({degrees, radians}, default=``degrees``) – Angular unit used for returned spherical or lateral-polar angles. Cartesian coordinates are returned in their stored distance unit.

Returns:

Source-position array with shape (N, 3). The columns are (azimuth, elevation, radius) for spherical, (lateral, polar, radius) for lateral-polar, or (x, y, z) for cartesian coordinates.

Return type:

np.ndarray

Raises:

ValueError – If angle_unit is unsupported, the source or target coordinate system is unsupported, SOFA angular units cannot be interpreted, or the requested conversion is not implemented.

Notes

SOFA angular units are detected from the SourcePosition:Units attribute. Angular source data stored in radians are converted through cartesian coordinates when degree/radian conversion is required.

get_azimuth_angles(angle_unit='degrees')

Return unique azimuth values available in the current source grid.

The source grid is first normalized to spherical coordinates. This makes the result independent of the active source_coordinate_system while still respecting any spatial subset selected on the owning HRTF.

Parameters:

angle_unit ({degrees, radians}, default=``degrees``) – Angular unit used for returned azimuth values.

Returns:

One-dimensional array of sorted unique azimuth angles rounded to two decimals.

Return type:

np.ndarray

Raises:

ValueError – If positions cannot be read or converted to spherical coordinates.

get_elevation_angles(angle_unit='degrees')

Return unique elevation values available in the current source grid.

The source grid is first normalized to spherical coordinates. This makes the result independent of the active source_coordinate_system while still respecting any spatial subset selected on the owning HRTF.

Parameters:

angle_unit ({degrees, radians}, default=``degrees``) – Angular unit used for returned elevation values.

Returns:

One-dimensional array of sorted unique elevation angles rounded to two decimals.

Return type:

np.ndarray

Raises:

ValueError – If positions cannot be read or converted to spherical coordinates.

get_elevation_angles_for_azimuth(azimuth, angle_unit='degrees')

Return elevations available at the nearest source-grid azimuth.

This method is useful for plane-based plotting and selection UIs where a requested azimuth may not exist exactly in the measured source grid. The azimuth match is circular, so values near 0 and 360 degrees, or 0 and 2*pi radians, are treated as neighbors.

Parameters:
  • azimuth (float) – Requested azimuth angle used to query the source grid.

  • angle_unit ({degrees, radians}, default=``degrees``) – Angular unit for azimuth, returned elevations, and real_azimuth.

Returns:

(elevation_angles, real_azimuth) where elevation_angles is a one-dimensional array of unique elevations available at the matched azimuth, and real_azimuth is the actual azimuth selected from the grid. Both outputs are rounded to two decimals.

Return type:

tuple[np.ndarray, float]

Raises:

ValueError – If azimuth is boolean or non-finite, angle_unit is unsupported, or positions cannot be read or converted to spherical coordinates.

get_azimuth_angles_for_elevation(elevation, angle_unit='degrees')

Return azimuths available at the nearest source-grid elevation.

This method is useful for horizontal-plane workflows where the requested elevation may not exist exactly in the measured source grid. Elevation matching uses the nearest available numerical elevation in spherical coordinates.

Parameters:
  • elevation (float) – Requested elevation angle used to query the source grid.

  • angle_unit ({degrees, radians}, default=``degrees``) – Angular unit for elevation, returned azimuths, and real_elevation.

Returns:

(azimuth_angles, real_elevation) where azimuth_angles is a one-dimensional array of unique azimuths available at the matched elevation, and real_elevation is the actual elevation selected from the grid. Both outputs are rounded to two decimals.

Return type:

tuple[np.ndarray, float]

Raises:

ValueError – If elevation is boolean or non-finite, angle_unit is unsupported, or positions cannot be read or converted to spherical coordinates.

get_position_index(position, coordinate_system='spherical', angle_unit='degrees')

Return the nearest source index and its resolved grid position.

The query is matched against the current source grid, including any source subset already selected on the owning HRTF object. Numeric positions are interpreted in coordinate_system. Named positions use the canonical horizontal spherical aliases front, back, left, and right and are then returned in the requested coordinate system.

Parameters:
  • position (np.ndarray | list[float] | tuple[float, float, float] | str) – Query position. Numeric spherical and lateral-polar queries may be angle-only (2,) or full (3,) coordinates. Cartesian queries must be (3,). String queries must be one of the supported named positions.

  • coordinate_system ({spherical, cartesian, lateral-polar}, default=``spherical``) – Coordinate system of numeric position queries and returned real_position.

  • angle_unit ({degrees, radians}, default=``degrees``) – Angular unit for spherical/lateral-polar inputs and outputs.

Returns:

(idx, real_position) where idx is the nearest source index in the current source view and real_position is the matched grid coordinate rounded to two decimals in coordinate_system.

Return type:

tuple[int, np.ndarray]

Raises:

ValueError – If the coordinate system or angle unit is unsupported, source positions do not form an (N, 3) grid, a named position is unknown, a query has an invalid shape, or the needed coordinate conversion is unsupported.

class hrtfpykit.hrtf.transforms.Transform(hrtf)

Provide immutable HRTF-processing operations for one parent object.

Transform is accessed through transform and provides non-mutating HRTF-processing operations. Each method clones the parent HRTF object, applies one operation to the clone, resynchronizes the affected domain representation, marks the returned object as transformed, and leaves the original HRTF unchanged.

Time-domain operations modify the impulse-response array stored in IR.values, then refresh the frequency-response array stored in TF.values. Frequency-domain operations do the reverse: they modify the transfer-function array and refresh the impulse-response array. This keeps both acoustic representations available for later plotting, metric calculation, SOFA synchronization, and export.

Parameters:

hrtf (HRTF) – Parent HRTF object used as the source for cloned transform results.

Examples

Access the transform namespace from a loaded HRTF and apply a preprocessing step without changing the original object:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> windowed = hrtf.transform.apply_window("hann")
>>> hrtf.is_transformed()
False
>>> windowed.is_transformed()
True
apply_window(window_name)

Apply a time-domain window to IR values and rebuild TF.

The window is applied along the final IR sample axis. The returned HRTF keeps the original source and ear layout, stores the windowed IR, and recomputes the frequency-domain representation with the current fft_length.

Parameters:

window_name (str) – Window identifier passed to the DSP layer, for example hann, hamming, blackman, or rectangular.

Returns:

A new HRTF instance with windowed IR values and refreshed TF data.

Return type:

HRTF

Raises:

ValueError – If IR data are unavailable or the requested window is unsupported.

Examples

Apply a Hann window to the HRIR samples and keep the source and ear layout unchanged:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> windowed = hrtf.transform.apply_window("hann")
>>> windowed.IR.values.shape
(793, 2, 256)
>>> windowed.TF.values.shape
(793, 2, 129)
apply_padding(padding_length, location='end', value=0)

Pad IR values along the sample axis and rebuild TF.

Padding is applied to the final IR axis while preserving source and ear layout. The frequency-domain representation is recomputed from the padded IR in the returned HRTF.

Parameters:
  • padding_length (int) – Number of samples added to the IR.

  • location ({start, end}, default=``end``) – Side where the padding is applied.

  • value (float, default=0) – Constant value used in the padded region.

Returns:

A new HRTF instance with padded IR values and refreshed TF data.

Return type:

HRTF

Raises:

ValueError – If IR data are unavailable, padding length is invalid, or location is not supported.

Examples

Append silent samples to every HRIR and rebuild the frequency-domain representation from the padded signals:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.IR.values.shape
(793, 2, 256)
>>> padded = hrtf.transform.apply_padding(32, location="end")
>>> padded.IR.values.shape
(793, 2, 288)
>>> padded.TF.values.shape
(793, 2, 129)
upsampling(new_sample_rate)

Upsample impulse-response values and resynchronize TF data.

The transform changes IR.values and IR.sample_rate in the returned object, then recomputes TF.values and frequency bins from the resampled IR.

Parameters:

new_sample_rate (float) – Target sample rate in Hz. It must be strictly greater than the current IR sample rate.

Returns:

A new HRTF instance with upsampled IR values, updated IR sample rate, and refreshed TF data.

Return type:

HRTF

Raises:

ValueError – If IR data or sample-rate metadata are unavailable, or if the target sample rate is not finite and greater than the current rate.

Examples

Resample a SOFA-loaded HRTF to a higher sampling rate before later time-domain processing:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.IR.sample_rate
44100.0
>>> hrtf.IR.values.shape
(793, 2, 256)
>>> upsampled = hrtf.transform.upsampling(88200.0)
>>> upsampled.IR.sample_rate
88200.0
>>> upsampled.IR.values.shape
(793, 2, 512)
downsampling(new_sample_rate)

Downsample impulse-response values and resynchronize TF data.

The transform changes IR.values and IR.sample_rate in the returned object, then recomputes TF.values and frequency bins from the resampled IR.

Parameters:

new_sample_rate (float) – Target sample rate in Hz. It must be strictly lower than the current IR sample rate.

Returns:

A new HRTF instance with downsampled IR values, updated IR sample rate, and refreshed TF data.

Return type:

HRTF

Raises:

ValueError – If IR data or sample-rate metadata are unavailable, or if the target sample rate is not finite and lower than the current rate.

Examples

Resample a SOFA-loaded HRTF to a lower sampling rate and keep TF data synchronized with the new HRIR samples:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.IR.sample_rate
44100.0
>>> hrtf.IR.values.shape
(793, 2, 256)
>>> downsampled = hrtf.transform.downsampling(22050.0)
>>> downsampled.IR.sample_rate
22050.0
>>> downsampled.IR.values.shape
(793, 2, 128)
apply_fir_filter(filter, cutoff=None, num_taps=101, window=None)

Apply FIR filtering to IR values and rebuild TF.

Filtering is performed in the time domain along the final IR sample axis. The returned object stores the filtered IR and recomputes the TF representation from it.

Parameters:
  • filter (str) – Filter type. Low-pass, high-pass, and band-pass aliases are accepted by the DSP layer.

  • cutoff (float | tuple[float, float] | None, default=None) – Cutoff frequency or frequency pair in Hz.

  • num_taps (int, default=101) – FIR filter length.

  • window (str | None, default=None) – Optional FIR design window.

Returns:

A new HRTF instance with filtered IR values and refreshed TF data.

Return type:

HRTF

Raises:

ValueError – If IR data or sample-rate metadata are unavailable, filter arguments are invalid, or cutoff values are incompatible with the sample rate.

Examples

Low-pass filter the HRIRs with an FIR design and use the returned HRTF for subsequent metric or plotting workflows:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> filtered = hrtf.transform.apply_fir_filter(
...     filter="lowpass",
...     cutoff=3000.0,
...     num_taps=31,
... )
>>> filtered.IR.values.shape
(793, 2, 256)
>>> filtered.is_transformed()
True
apply_iir_filter(filter, cutoff=None, order=10)

Apply IIR filtering to IR values and rebuild TF.

Filtering is performed in the time domain along the final IR sample axis. The returned object stores the filtered IR and recomputes the TF representation from it.

Parameters:
  • filter (str) – Filter type. Low-pass, high-pass, and band-pass aliases are accepted by the DSP layer.

  • cutoff (float | tuple[float, float] | None, default=None) – Cutoff frequency or frequency pair in Hz.

  • order (int, default=10) – Butterworth filter order.

Returns:

A new HRTF instance with filtered IR values and refreshed TF data.

Return type:

HRTF

Raises:

ValueError – If IR data or sample-rate metadata are unavailable, filter arguments are invalid, or cutoff values are incompatible with the sample rate.

Examples

Apply a Butterworth low-pass filter to the HRIRs and keep the derived transfer functions available on the returned object:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> filtered = hrtf.transform.apply_iir_filter(
...     filter="lowpass",
...     cutoff=3000.0,
...     order=4,
... )
>>> filtered.IR.values.shape
(793, 2, 256)
>>> filtered.TF.values.shape
(793, 2, 129)
minimum_phase(method='homomorphic', fft_length=None, epsilon=1e-12)

Convert IR values to minimum phase and rebuild TF.

The transform replaces each current HRIR with a minimum-phase version derived from its magnitude response. The returned object then refreshes the TF representation from the minimum-phase IR.

Parameters:
  • method (str, default=``homomorphic``) – Minimum-phase method key passed to the DSP layer.

  • fft_length (int | None, default=None) – Optional FFT length used during cepstral reconstruction.

  • epsilon (float, default=1e-12) – Small positive floor used for numerical stability.

Returns:

A new HRTF instance with minimum-phase IR values and refreshed TF data.

Return type:

HRTF

Raises:

ValueError – If IR data are unavailable or minimum-phase parameters are invalid.

Examples

Convert the HRIRs to a minimum-phase representation while preserving the current HRTF layout:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> minimum = hrtf.transform.minimum_phase()
>>> minimum.IR.values.shape
(793, 2, 256)
>>> minimum.is_transformed()
True
to_ctf(weights=False, magnitude_average='log', attenuation=None)

Convert the current HRTF into its common transfer function (CTF).

The CTF collapses the source axis into a single common response per ear. The returned HRTF keeps a singleton source axis for compatibility with source-based plotting and SOFA update workflows.

Parameters:
  • weights (bool, optional) – If False, all source positions contribute equally. If True, diffuse-field weights are derived internally from the HRTF source positions using spherical Voronoi areas.

  • magnitude_average ({log, linear}, optional) – Rule used to average source magnitudes before the minimum-phase CTF reconstruction. log computes a log-magnitude average (geometric mean in linear magnitude). linear computes a direct linear-magnitude average (arithmetic mean).

  • attenuation (float | None, optional) – Optional attenuation in dB applied to the CTF magnitude before the minimum-phase reconstruction. If None, no attenuation is applied.

Returns:

A new HRTF instance containing the CTF. The output keeps a singleton compatibility source axis.

Return type:

HRTF

Raises:

ValueError – If TF data, IR reference length, source geometry, weighting inputs, or averaging parameters are invalid.

Examples

Estimate the common transfer function of a SOFA-loaded HRTF and inspect the singleton source axis kept in the result:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.TF.values.shape
(793, 2, 129)
>>> ctf = hrtf.transform.to_ctf(weights=False)
>>> ctf.TF.values.shape
(1, 2, 129)
to_dtf(weights=False, magnitude_average='log', attenuation=None)

Convert the current HRTF into its directional transfer function (DTF).

The DTF removes a common transfer component estimated from the current HRTF. The returned HRTF preserves the source layout of the input object and rebuilds IR data from the DTF-domain TF values.

Parameters:
  • weights (bool, optional) – If False, all source positions contribute equally to the internal CTF estimate. If True, diffuse-field weights are derived internally from the HRTF source positions using spherical Voronoi areas.

  • magnitude_average ({log, linear}, optional) – Rule used to estimate the internal CTF magnitude before the DTF division. log computes a log-magnitude average (geometric mean in linear magnitude). linear computes a direct linear-magnitude average (arithmetic mean).

  • attenuation (float | None, optional) – Optional attenuation in dB applied to the DTF after the CTF division. If None, no attenuation is applied.

Returns:

A new HRTF instance containing the DTF while preserving the source layout of the current HRTF.

Return type:

HRTF

Raises:

ValueError – If TF data, IR reference length, source geometry, weighting inputs, or averaging parameters are invalid.

Examples

Remove the common transfer component while keeping the original source grid layout:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.TF.values.shape
(793, 2, 129)
>>> dtf = hrtf.transform.to_dtf(weights=False)
>>> dtf.TF.values.shape
(793, 2, 129)
>>> dtf.IR.values.shape
(793, 2, 256)
modify_ir(new_ir)

Replace time-domain IR values and rebuild TF data.

new_ir replaces the full current IR array. The leading dimensions before the final sample axis must match the current spatial and ear layout. When new_ir is an IR or HRTF object and provides a sample rate, that sample rate is copied into the returned HRTF before TF recomputation.

Parameters:

new_ir (np.ndarray | IR | HRTF) – Time-domain data used to replace the current IR values. NumPy arrays must keep the same spatial and ear layout as the current HRTF. IR and HRTF inputs contribute their IR values, and when available their sample rate.

Returns:

A new HRTF instance with modified IR values and rebuilt TF data.

Return type:

HRTF

Raises:

ValueError – If replacement data are missing, empty, not array-like in the expected way, or do not match the current leading IR/TF layout.

Examples

Replace HRIR values with an edited copy and let the transform rebuild the transfer functions:

>>> import numpy as np
>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> ir = np.array(hrtf.IR.values, copy=True)
>>> ir[..., :8] = 0.0
>>> modified = hrtf.transform.modify_ir(ir)
>>> modified.IR.values[0, 0, :8]
array([0., 0., 0., 0., 0., 0., 0., 0.])
>>> modified.IR.values.shape
(793, 2, 256)
>>> modified.TF.values.shape
(793, 2, 129)
modify_phase(new_phase, unit='degrees')

Replace TF phase values and rebuild IR.

The transform preserves the current TF magnitude and replaces only the phase component. The replacement phase must be compatible with the current TF layout and is interpreted according to unit.

Parameters:
  • new_phase (np.ndarray) – Phase array with the same TF layout as the current HRTF.

  • unit ({degrees, radians}, default=``degrees``) – Unit used by new_phase.

Returns:

A new HRTF instance with modified TF phase and rebuilt IR data.

Return type:

HRTF

Raises:

ValueError – If TF data or frequency bins are unavailable, unit is invalid, or the replacement phase cannot be broadcast to the TF layout.

Examples

Replace phase values with an edited phase array while preserving the current TF magnitude:

>>> import numpy as np
>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> phase = np.array(hrtf.TF.phase, copy=True)
>>> phase[..., 1:] *= 0.95
>>> modified = hrtf.transform.modify_phase(phase, unit="radians")
>>> modified.TF.values.shape
(793, 2, 129)
>>> modified.IR.values.shape
(793, 2, 256)
modify_tf(new_tf)

Replace frequency-domain TF values and rebuild IR data.

new_tf replaces the full complex TF array. The leading dimensions before the frequency axis must match the current TF layout, or the current IR leading layout when no TF data are present. Frequency bins are copied from TF or HRTF inputs when available; otherwise they are reused or inferred from the current sample rate when the TF length changes.

Parameters:

new_tf (np.ndarray | TF | HRTF) – Frequency-domain data used to replace the current TF values. NumPy arrays must keep the same spatial and ear layout as the current HRTF. TF and HRTF inputs contribute their TF values and, when available, their frequency bins.

Returns:

A new HRTF instance with modified TF values and rebuilt IR data.

Return type:

HRTF

Raises:

ValueError – If replacement data are missing, empty, have incompatible leading shape, contain too few frequency bins, or require frequency-bin inference without valid sample-rate metadata.

Examples

Replace TF values with a scaled complex copy and rebuild the time-domain representation:

>>> import numpy as np
>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> round(float(hrtf.TF.magnitude[0, 0, 1]), 6)
0.209696
>>> tf = np.array(hrtf.TF.values, copy=True) * 0.98
>>> modified = hrtf.transform.modify_tf(tf)
>>> round(float(modified.TF.magnitude[0, 0, 1]), 6)
0.205502
>>> modified.TF.values.shape
(793, 2, 129)
>>> modified.IR.values.shape
(793, 2, 256)
modify_magnitude(new_magnitude, scale='linear')

Replace TF magnitude values and rebuild IR.

The transform preserves the current TF phase and replaces only the magnitude component. new_magnitude must be compatible with the current TF layout and is interpreted according to scale.

Parameters:
  • new_magnitude (np.ndarray) – Magnitude array with the same TF layout as the current HRTF.

  • scale ({linear, db}, default=``linear``) – Magnitude scale used by new_magnitude.

Returns:

A new HRTF instance with modified TF magnitude and rebuilt IR data.

Return type:

HRTF

Raises:

ValueError – If TF data or frequency bins are unavailable, scale is invalid, or the replacement magnitude cannot be broadcast to the TF layout.

Examples

Replace the TF magnitude with a slightly attenuated copy and keep the original phase:

>>> import numpy as np
>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> round(float(hrtf.TF.magnitude[0, 0, 1]), 6)
0.209696
>>> magnitude = np.array(hrtf.TF.magnitude, copy=True) * 0.95
>>> modified = hrtf.transform.modify_magnitude(magnitude, scale="linear")
>>> round(float(modified.TF.magnitude[0, 0, 1]), 6)
0.199212
>>> modified.TF.values.shape
(793, 2, 129)
>>> modified.IR.values.shape
(793, 2, 256)
apply_gain(gain, scale='db')

Apply a TF-domain gain and rebuild IR.

Gain modifies TF magnitude while preserving phase. Scalar gains apply globally; array gains can target sources, ears, or frequency bins when they are broadcast-compatible with TF.values.

Parameters:
  • gain (float | np.ndarray) – Gain applied to the current TF magnitude while preserving phase. Scalar gains affect every source, ear, and bin equally. Array gains must be broadcast-compatible with the current TF shape. In scale=``db``, negative values attenuate and positive values amplify.

  • scale ({linear, db}, default=``db``) – Scale used by gain.

Returns:

A new HRTF instance with gain-adjusted TF values and rebuilt IR data.

Return type:

HRTF

Raises:

ValueError – If TF data or frequency bins are unavailable, scale is invalid, or gain cannot be broadcast to the current TF layout.

Examples

Apply a broadband attenuation in dB to all source positions and ears:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> round(float(hrtf.TF.magnitude[0, 0, 1]), 6)
0.209696
>>> quieter = hrtf.transform.apply_gain(-3.0, scale="db")
>>> round(float(quieter.TF.magnitude[0, 0, 1]), 6)
0.148454
>>> quieter.TF.values.shape
(793, 2, 129)
>>> quieter.is_transformed()
True
modify_fft_length(new_fft_length)

Set the HRTF FFT length and recompute TF from the current IR.

The returned object keeps the current IR unchanged and rebuilds TF using new_fft_length. This changes frequency-bin spacing and TF length but does not add time-domain information to the HRIR.

Parameters:

new_fft_length (int) – FFT size used for IR-to-TF conversion.

Returns:

A new HRTF instance with updated FFT length and recomputed TF data.

Return type:

HRTF

Raises:

ValueError – If IR data are unavailable or the FFT length is invalid for real-FFT conversion.

Examples

Increase the FFT length used for IR-to-TF conversion and inspect the resulting frequency-bin count:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.fft_length
256
>>> hrtf.TF.values.shape
(793, 2, 129)
>>> modified = hrtf.transform.modify_fft_length(512)
>>> modified.fft_length
512
>>> modified.TF.values.shape
(793, 2, 257)
modify_source_coordinate_system(coordinate_system)

Update the target source coordinate system.

This updates the coordinate system used by get_positions() on the returned HRTF. It does not rewrite SOFA SourcePosition values; positions are converted on read through the source manager.

Parameters:

coordinate_system ({spherical, cartesian, lateral-polar}) – Target coordinate system used by Sources when positions are read.

Returns:

A new HRTF instance with updated source_coordinate_system.

Return type:

HRTF

Raises:

ValueError – If coordinate_system is not one of the supported source coordinate systems.

Examples

Read source positions in Cartesian coordinates from a transformed HRTF:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.Sources.source_coordinate_system
'spherical'
>>> cartesian = hrtf.transform.modify_source_coordinate_system("cartesian")
>>> positions = cartesian.Sources.get_positions()
>>> cartesian.Sources.source_coordinate_system
'cartesian'
>>> positions.shape
(793, 3)
add_itd(itd, unit='samples')

Add an interaural time delay to IR values and rebuild TF.

Positive ITD values delay the left ear; negative values delay the right ear. A scalar delay is applied to every source position. Array delays must match the leading IR shape before the ear and sample axes, which allows position-dependent ITD perturbations.

Parameters:
  • itd (float) – ITD value to apply. Positive values delay the left ear and negative values delay the right ear.

  • unit ({seconds, samples}, default=``samples``) – Unit used by itd.

Returns:

A new HRTF instance with ITD-modified IR values and refreshed TF data.

Return type:

HRTF

Raises:

ValueError – If IR data do not contain two ear channels, delay values are non-finite, delay-array shape is incompatible with the IR layout, seconds are requested without sample-rate metadata, or the absolute delay is not smaller than the IR length.

Examples

Add a two-sample delay to the left ear for every source position:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.IR.get_itd(output="samples")[:5]
array([-3, -4, -3, -4, -4])
>>> delayed = hrtf.transform.add_itd(2, unit="samples")
>>> delayed.IR.get_itd(output="samples")[:5]
array([-1, -2, -1, -2, -2])
>>> delayed.IR.values.shape
(793, 2, 256)
>>> delayed.is_transformed()
True
delete_itd(method='threshold', thresh_level=-10.0, upper_cut_freq=3000.0, filter_order=10)

Estimate and remove ITD from the current IR values, then resync TF.

The ITD sign convention follows itd: positive ITD means left-ear delay relative to right-ear and negative ITD means right-ear delay relative to left-ear. Compensation is applied per source by advancing the delayed channel and zero-filling the tail introduced by the shift.

Parameters:
  • method ({threshold, maxiacce}, default=``threshold``) – ITD estimator used to compute the delay per position.

  • thresh_level (float, default=-10.0) – Threshold offset in dB used when method=``threshold``.

  • upper_cut_freq (float, default=3000.0) – Low-pass cutoff in Hz applied before ITD estimation.

  • filter_order (int, default=10) – Butterworth low-pass filter order used before ITD estimation.

Returns:

A new HRTF instance with ITD-compensated IR values and refreshed TF data. Compensation is applied per source position.

Return type:

HRTF

Raises:

ValueError – If IR data do not contain two ear channels, ITD estimation parameters are invalid, or an estimated delay is not smaller than the IR length.

Examples

Estimate and remove ITD from each source position before comparing magnitude-focused features:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.IR.get_itd(output="samples")[:5]
array([-3, -4, -3, -4, -4])
>>> no_itd = hrtf.transform.delete_itd()
>>> no_itd.IR.get_itd(output="samples")[:5]
array([0, 0, 0, 0, 0])
>>> no_itd.IR.values.shape
(793, 2, 256)
>>> no_itd.TF.values.shape
(793, 2, 129)
class hrtfpykit.plots.hrtf.HRTFPlots

Visualization methods inherited by HRTF.

HRTFPlots groups the plotting operations that operate on an HRTF object’s current IR, TF, and Sources state. The methods are attached to the main HRTF abstraction so plots reflect any previous loading, source selection, domain conversion, ITD compensation, windowing, or other transformation applied to the object.

The plotting surface covers the main inspection workflows used in HRTF and HRIR analysis: time-domain impulse responses, frequency-domain magnitude responses, frequency-angle spectrum heatmaps, interaural cue curves, absolute polar cue summaries, and 3D source-grid geometry. Position queries are resolved through the same source manager used by processing methods, so named directions, spherical coordinate queries, and plane selections follow the library’s normal spatial-resolution rules.

Notes

These methods are intended to be called from an HRTF instance, not from a standalone HRTFPlots object. Every plotting method validates the required domain representation before drawing, creates a Matplotlib figure through the hrtfpykit plotting wrappers, optionally calls matplotlib.pyplot.show(), and returns None.

Examples

Load an HRTF and call the plotting methods from the main HRTF object:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.plot_magnitude(positions="front", x_axis="log", ear="left")
plot_magnitude(positions=('front', 'back', 'left', 'right'), x_axis='linear', unit='db', ear='both', reference=1.0, freq_min=None, freq_max=None, show=True, titles=True)

Plot HRTF magnitude responses at selected source positions.

The method selects one to four source directions from the current HRTF source grid, extracts the corresponding transfer-function magnitudes, and draws one subplot per direction. Frequency values are displayed in kilohertz while freq_min and freq_max are interpreted in hertz, matching the frequency bins stored by the frequency-domain object.

Position queries are resolved in spherical coordinates in degrees. Named positions use hrtfpykit’s built-in aliases, while numeric queries should use [azimuth, elevation]. When unit=``db``, magnitudes are converted with magnitude-to-decibel conversion using either the supplied numeric reference or the maximum selected value when reference=``max``.

Parameters:
  • positions (str | list | tuple | np.ndarray, default=(front, back, left, right)) – One position or a collection of positions. Named aliases such as front, back, left, and right are accepted. Numeric queries must use spherical coordinates in degrees as [azimuth, elevation], for example [0.0, 0.0] for the front direction. Up to four positions can be shown in one figure.

  • x_axis ({linear, log}, default=``linear``) – Frequency scale used on the x axis.

  • unit ({db, linear}, default=``db``) – Magnitude representation used on the y axis.

  • ear ({left, right, both}, default=``both``) – Ear channel to display. When both is selected, left and right responses are drawn together in each subplot.

  • reference (float | {max}, default=1.0) – Reference used when unit=``db``. max normalizes the plotted magnitude to the maximum selected value.

  • freq_min (float | None, default=None) – Minimum frequency in Hz included in the plot.

  • freq_max (float | None, default=None) – Maximum frequency in Hz included in the plot.

  • show (bool, default=True) – If True, call matplotlib.pyplot.show() before returning.

  • titles (bool, default=True) – If False, suppress generated default subplot titles.

  • hrtf (Any)

Return type:

None

Raises:
  • AttributeError – If unit, x_axis, or ear is not one of the supported values.

  • ValueError – If TF values or frequency bins are missing, no positions are requested, more than four positions are requested, the selected frequency range contains no bins, or the requested ear channel is not available.

Notes

One position uses Layout_1, two positions use Layout_2Vertical, and three or four positions use Layout_3. With ear=``both``, left and right channels are drawn together on each subplot and labelled with the shared ear legend.

Examples

Plot one normalized magnitude response for the front direction on a logarithmic frequency axis:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.plot_magnitude(
...     positions="front",
...     x_axis="log",
...     ear="both",
...     reference="max",
...     freq_max=16000.0,
... )
plot_amplitude(positions=('front', 'back', 'left', 'right'), ear='both', x_axis='time', show=True, titles=True)

Plot HRIR amplitude responses for up to four source positions.

The method selects one to four source directions from the current source grid and draws the corresponding time-domain impulse responses. Positions are resolved in spherical coordinates in degrees and may be provided through named aliases or numeric [azimuth, elevation] queries.

The x-axis can show elapsed time in seconds or raw sample indices. Time mode requires IR.sample_rate because sample positions are converted to seconds before plotting.

Parameters:
  • positions (str | list | tuple | np.ndarray, default=(front, back, left, right)) – One position or a collection of positions. Named aliases such as front, back, left, and right are accepted. Numeric queries must use spherical coordinates in degrees as [azimuth, elevation], for example [0.0, 0.0] for the front direction. Up to four positions can be shown in one figure.

  • ear ({left, right, both}, default=``both``) – Ear channel to display. When both is selected, left and right ear waveforms are drawn together in each subplot.

  • x_axis ({time, samples}, default=``time``) – Horizontal axis used for the waveform plot.

  • show (bool, default=True) – If True, call matplotlib.pyplot.show() before returning.

  • titles (bool, default=True) – If False, suppress generated default subplot titles.

  • hrtf (Any)

Return type:

None

Raises:
  • AttributeError – If ear or x_axis is not one of the supported values.

  • ValueError – If IR data is missing, a time axis is requested without a sample rate, no positions are requested, more than four positions are requested, the IR array has no samples, or the requested ear channel is not available.

Notes

One position uses Layout_1, two positions use Layout_2Vertical, and three or four positions use Layout_3. With ear=``both``, left and right HRIR channels are drawn on the same subplot and labelled with the shared ear legend.

Examples

Plot one front HRIR waveform:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.plot_amplitude(
...     positions="front",
...     ear="both",
...     x_axis="samples",
... )
plot_amplitude_and_magnitude(position='front', ear='both', amplitude_x_axis='time', magnitude_x_axis='linear', magnitude='db', reference=1.0, show=True, titles=True)

Plot amplitude and magnitude views for a single source position.

This method creates a two-panel summary for one source direction. The top subplot shows the time-domain HRIR amplitude response and the bottom subplot shows the corresponding frequency-domain HRTF magnitude response for the same source. The amplitude subplot can use seconds or sample indices, while the magnitude subplot can use a linear or logarithmic frequency axis.

The method requires both the time-domain and frequency-domain representations to be available. When magnitude=``db``, the magnitude response is converted with magnitude-to-decibel conversion using either a numeric reference or the selected direction’s maximum magnitude when reference=``max``.

Parameters:
  • position (str | list | np.ndarray, default=``front``) – Position query to plot. Exactly one position is accepted. Named aliases such as front, back, left, and right are accepted. Numeric queries must use spherical coordinates in degrees as [azimuth, elevation], for example [0.0, 0.0].

  • ear ({left, right, both}, default=``both``) – Ear channel to display in both subplots.

  • amplitude_x_axis ({time, samples}, default=``time``) – Horizontal axis used for the amplitude subplot.

  • magnitude_x_axis ({linear, log}, default=``linear``) – Frequency-axis scale used on the magnitude subplot.

  • magnitude ({db, linear}, default=``db``) – Magnitude representation used on the bottom subplot.

  • reference (float | {max}, default=1.0) – Reference used when magnitude=``db`` for the magnitude subplot.

  • show (bool, default=True) – If True, call matplotlib.pyplot.show() before returning.

  • titles (bool, default=True) – If False, suppress the generated default figure title.

  • hrtf (Any)

Return type:

None

Raises:
  • AttributeError – If ear, amplitude_x_axis, magnitude_x_axis, or magnitude is not one of the supported values.

  • ValueError – If IR or TF data is missing, a time axis is requested without a sample rate, zero or multiple positions are supplied, the selected frequency range contains no bins, or the requested ear channel is not available in IR or TF data.

Notes

The plot uses a vertical two-panel layout with independent x axes. This makes it useful for checking whether a transformation applied to the HRIR is reflected in the corresponding magnitude response.

Examples

Plot the impulse response and magnitude response for one source direction in the same figure:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.plot_amplitude(positions="front", ear="both")
plot_spectrum_plane(plane='horizontal', elevation_angle=0.0, x_axis='linear', unit='db', ear='both', reference='max', colormap='jet', freq_min=None, freq_max=None, show=True, titles=True)

Plot a frequency-angle spectrum heatmap for an HRTF plane.

The method selects a spatial plane from the current source grid and renders HRTF magnitude as a frequency-by-angle heatmap. Frequency is shown on the horizontal axis in kilohertz, while the vertical axis is either azimuth for horizontal planes or lateral-polar angle for the median plane.

Horizontal planes are selected by the nearest available elevation to elevation_angle. Median-plane plots use the canonical sagittal path at azimuth zero. With ear=``both``, the method creates one heatmap for the left ear and one heatmap for the right ear using shared color limits.

Parameters:
  • plane ({horizontal, median}, default=``horizontal``) – Plane to visualize. horizontal uses a horizontal plane selected by elevation. median uses the canonical median plane defined by the front-back sagittal path.

  • elevation_angle (float, default=0.0) – Target elevation used when plane=``horizontal``. The nearest available horizontal plane in the grid is selected. This parameter is not used for the median plane.

  • x_axis ({linear, log}, default=``linear``) – Frequency scale used on the x axis.

  • unit ({db, linear}, default=``db``) – Magnitude representation used for the heatmap values.

  • ear ({left, right, both}, default=``both``) – Ear channel to display. When both is selected, a separate subplot is created for each ear.

  • reference (float | {max}, default=``max``) – Reference used when unit=``db``. max normalizes the plotted plane to its maximum value.

  • colormap (str, default=``jet``) – Matplotlib colormap name used for the heatmap.

  • freq_min (float | None, default=None) – Minimum frequency in Hz included in the plot.

  • freq_max (float | None, default=None) – Maximum frequency in Hz included in the plot.

  • show (bool, default=True) – If True, call matplotlib.pyplot.show() before returning.

  • titles (bool, default=True) – If False, suppress generated default subplot and figure titles.

  • hrtf (Any)

Return type:

None

Raises:
  • AttributeError – If plane, unit, x_axis, or ear is not one of the supported values, or if elevation_angle is not finite.

  • ValueError – If TF data is missing, elevation_angle is used with a non- horizontal plane, the selected plane has no positions, frequency bins are invalid, the selected frequency range contains no bins, or the requested ear channel is not available.

Notes

Horizontal-plane azimuths are displayed in the signed -180 .. 180 convention. When unit=``db`` and reference=``max``, normalization is computed over the plotted plane and selected ear channels before conversion to decibels.

Examples

Plot a horizontal-plane spectrum heatmap around ear height:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.plot_spectrum_plane(
...     plane="horizontal",
...     elevation_angle=0.0,
...     x_axis="linear",
...     ear="left",
...     freq_max=16000.0,
... )
plot_elevation_spectrum(azimuth=0.0, x_axis='linear', unit='db', ear='both', reference='max', colormap='jet', freq_min=None, freq_max=None, show=True, titles=True)

Plot a fixed-azimuth elevation spectrum heatmap.

The method selects the nearest azimuth slice in the current source grid and renders HRTF magnitude as a frequency-by-elevation heatmap. Frequency is shown in kilohertz, elevation is shown in degrees, and the selected real azimuth is reported in the generated title when titles are enabled.

Numeric azimuths are interpreted in degrees. Named position aliases use their spherical azimuth component, so front, back, left, and right can be used for common vertical slices. With ear=``both``, the method creates one heatmap per ear using shared color limits.

Parameters:
  • azimuth (float | str, default=0.0) – Azimuth used to select the elevation slice. Named aliases such as front, back, left, and right are accepted. The nearest available azimuth in the source grid is used.

  • x_axis ({linear, log}, default=``linear``) – Frequency scale used on the x axis.

  • unit ({db, linear}, default=``db``) – Magnitude representation used for the heatmap values.

  • ear ({left, right, both}, default=``both``) – Ear channel to display. When both is selected, a separate subplot is created for each ear.

  • reference (float | {max}, default=``max``) – Reference used when unit=``db``. max normalizes the plotted slice to its maximum value.

  • colormap (str, default=``jet``) – Matplotlib colormap name used for the heatmap.

  • freq_min (float | None, default=None) – Minimum frequency in Hz included in the plot.

  • freq_max (float | None, default=None) – Maximum frequency in Hz included in the plot.

  • show (bool, default=True) – If True, call matplotlib.pyplot.show() before returning.

  • titles (bool, default=True) – If False, suppress generated default subplot and figure titles.

  • hrtf (Any)

Return type:

None

Raises:
  • AttributeError – If unit, x_axis, or ear is not one of the supported values.

  • ValueError – If TF data is missing, azimuth is not finite or is an unknown named position, the selected slice has no positions, frequency bins are invalid, the selected frequency range contains no bins, or the requested ear channel is not available.

Notes

When the requested azimuth is not present exactly in the source grid, the nearest available azimuth is selected using circular angular distance. When unit=``db`` and reference=``max``, normalization is computed over the plotted slice and selected ear channels.

Examples

Plot a front-facing elevation spectrum to inspect how magnitude changes from below to above the listener:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.plot_elevation_spectrum(
...     azimuth="front",
...     x_axis="log",
...     ear="left",
...     freq_max=16000.0,
... )
plot_itd_curve(elevation_angle=0.0, show=True, titles=True)

Plot signed ITD over a horizontal plane as azimuth versus time delay.

The method computes signed interaural time difference from the current HRIR data, selects the nearest horizontal plane to elevation_angle, and plots ITD in seconds against signed azimuth. The curve is sorted by azimuth so the plot follows the horizontal plane continuously.

Parameters:
  • elevation_angle (float, default=0.0) – Target elevation used to select the horizontal plane. The nearest available elevation in the grid is used.

  • show (bool, default=True) – If True, call matplotlib.pyplot.show() before returning.

  • titles (bool, default=True) – If False, suppress the generated default figure title.

  • hrtf (Any)

Return type:

None

Raises:

ValueError – If IR data or sample rate is missing, elevation_angle is not finite, the selected horizontal plane is empty, or the computed ITD values do not align with the number of source positions.

Notes

Azimuth is displayed in the signed -180 .. 180 convention, where positive azimuth values correspond to the left side and negative values correspond to the right side.

Examples

Plot signed ITD around the horizontal plane:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.plot_itd_curve(elevation_angle=0.0)
plot_absolute_itd(elevation_angle=0.0, show=True, titles=True)

Plot absolute ITD over a horizontal plane in polar coordinates.

The method computes absolute interaural time difference from the current HRIR data, selects the nearest horizontal plane to elevation_angle, and displays the resulting cue magnitude in a polar plot. Azimuth is represented on the angular axis and absolute ITD in seconds is represented on the radial axis.

Parameters:
  • elevation_angle (float, default=0.0) – Target elevation used to select the horizontal plane. The nearest available elevation in the grid is used.

  • show (bool, default=True) – If True, call matplotlib.pyplot.show() before returning.

  • titles (bool, default=True) – If False, suppress the generated default figure title.

  • hrtf (Any)

Return type:

None

Raises:

ValueError – If IR data or sample rate is missing, elevation_angle is not finite, or the selected horizontal plane cannot be resolved for the current source grid.

Notes

The polar azimuth axis uses 30-degree ticks with a north-up orientation. The radial label defaults to Labels.itd_seconds and radial ticks use the decimal-comma style configured by the polar-axis helper.

Examples

Plot the absolute ITD cue around the horizontal plane in polar form:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.plot_absolute_itd(elevation_angle=0.0)
plot_ild_plane(plane='horizontal', elevation_angle=0.0, colormap='jet', freq_min=None, freq_max=None, show=True, titles=True)

Plot a frequency-dependent ILD heatmap for an HRTF plane.

The method computes frequency-dependent interaural level difference from the current HRIR data and renders it as a frequency-by-angle heatmap. Frequency is shown in kilohertz. The vertical axis is azimuth for horizontal planes and lateral-polar angle for the median plane.

Horizontal planes are selected by the nearest available elevation to elevation_angle. Median-plane plots use the canonical sagittal path at azimuth zero. The ILD values are computed in decibels from the current impulse responses before plotting.

Parameters:
  • plane ({horizontal, median}, default=``horizontal``) – Plane to visualize. horizontal uses a horizontal plane selected by elevation. median uses the canonical median plane defined by the front-back sagittal path.

  • elevation_angle (float, default=0.0) – Target elevation used when plane=``horizontal``. The nearest available horizontal plane in the grid is selected. This parameter is not used for the median plane.

  • colormap (str, default=``jet``) – Matplotlib colormap name used for the heatmap.

  • freq_min (float | None, default=None) – Minimum frequency in Hz included in the plot.

  • freq_max (float | None, default=None) – Maximum frequency in Hz included in the plot.

  • show (bool, default=True) – If True, call matplotlib.pyplot.show() before returning.

  • titles (bool, default=True) – If False, suppress the generated default figure title.

  • hrtf (Any)

Return type:

None

Raises:
  • AttributeError – If plane is not horizontal or median, or if elevation_angle is not finite.

  • ValueError – If IR data or sample rate is missing, elevation_angle is used with a non-horizontal plane, the selected plane has no positions, frequency bins are invalid, the selected frequency range contains no bins, or frequency-dependent ILD values do not have the expected (positions, frequencies) shape.

Notes

Horizontal-plane azimuths are displayed in the signed -180 .. 180 convention. The frequency axis is always linear for this plot because the method currently builds a FrequencyLinearAxis configuration.

Examples

Plot frequency-dependent ILD over the horizontal plane:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.plot_ild_plane(
...     plane="horizontal",
...     elevation_angle=0.0,
...     freq_max=16000.0,
... )
plot_ild_curve(elevation_angle=0.0, show=True, titles=True)

Plot signed ILD over a horizontal plane as azimuth versus level difference.

The method computes signed broad-band interaural level difference from the current HRIR data, selects the nearest horizontal plane to elevation_angle, and plots ILD in decibels against signed azimuth. The curve is sorted by azimuth so the plot follows the horizontal plane continuously.

Parameters:
  • elevation_angle (float, default=0.0) – Target elevation used to select the horizontal plane. The nearest available elevation in the grid is used.

  • show (bool, default=True) – If True, call matplotlib.pyplot.show() before returning.

  • titles (bool, default=True) – If False, suppress the generated default figure title.

  • hrtf (Any)

Return type:

None

Raises:

ValueError – If IR data or sample rate is missing, elevation_angle is not finite, the selected horizontal plane is empty, or the computed ILD values do not align with the number of source positions.

Notes

Azimuth is displayed in the signed -180 .. 180 convention, where positive azimuth values correspond to the left side and negative values correspond to the right side.

Examples

Plot signed broad-band ILD around the horizontal plane:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.plot_ild_curve(elevation_angle=0.0)
plot_absolute_ild(elevation_angle=0.0, show=True, titles=True)

Plot absolute ILD over a horizontal plane in polar coordinates.

The method computes absolute broad-band interaural level difference from the current HRIR data, selects the nearest horizontal plane to elevation_angle, and displays the resulting cue magnitude in a polar plot. Azimuth is represented on the angular axis and absolute ILD in decibels is represented on the radial axis.

Parameters:
  • elevation_angle (float, default=0.0) – Target elevation used to select the horizontal plane. The nearest available elevation in the grid is used.

  • show (bool, default=True) – If True, call matplotlib.pyplot.show() before returning.

  • titles (bool, default=True) – If False, suppress the generated default figure title.

  • hrtf (Any)

Return type:

None

Raises:

ValueError – If IR data or sample rate is missing, elevation_angle is not finite, or the selected horizontal plane cannot be resolved for the current source grid.

Notes

The polar azimuth axis uses 30-degree ticks with a north-up orientation. The radial label defaults to Labels.ild_db and radial ticks are formatted as integer decibel values.

Examples

Plot the absolute broad-band ILD cue around the horizontal plane:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.plot_absolute_ild(elevation_angle=0.0)
plot_source_grid(show=True, titles=True)

Plot the source grid as an interactive three-dimensional scatter.

The method reads the current source positions from the HRTF instance, resolves them as Cartesian coordinates, and renders the grid in a 3D Matplotlib axis. Direction markers for front, right, and up are added to make the coordinate orientation clear in the default camera view.

This plot is useful after loading a SOFA file, selecting a spatial subset, or transforming source coordinates because it visualizes the exact source grid currently attached to the object.

Parameters:
  • show (bool, default=True) – If True, call matplotlib.pyplot.show() before returning.

  • titles (bool, default=True) – If False, suppress the generated default figure title.

  • hrtf (Any)

Return type:

None

Raises:

ValueError – If source positions cannot be resolved as a valid Cartesian grid or axis geometry cannot be computed from the current positions.

Notes

The plot uses an equal-aspect 3D axis derived from the full Cartesian source extent. Axis labels use the library’s 3D coordinate labels in meters.

Examples

Plot the measurement source grid from a loaded SOFA file:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.plot_source_grid()
plot_plane_grid(plane='horizontal', show=True, titles=True)

Plot the source grid and highlight canonical spatial planes in 3D.

The full source grid is displayed as a light background scatter, while the selected canonical plane or planes are overlaid with stronger colors. Plane membership is resolved through the same plane-selection helpers used by processing and metric plots, so the highlighted points match the library’s canonical horizontal, median, and frontal plane definitions.

Parameters:
  • plane (str | list[str] | tuple[str, ...], default=``horizontal``) – Plane or planes to highlight. Accepted values are horizontal, median, and frontal. A single string highlights one plane, while a list or tuple highlights multiple planes in the same figure.

  • show (bool, default=True) – If True, call matplotlib.pyplot.show() before returning.

  • titles (bool, default=True) – If False, suppress the generated default figure title.

  • hrtf (Any)

Return type:

None

Raises:

ValueError – If plane is empty, contains an unsupported plane name, source positions cannot be resolved as Cartesian coordinates, or axis geometry cannot be computed from the current source grid.

Notes

Duplicate plane names are ignored after the first occurrence. A legend is added to distinguish the background source grid from each highlighted plane.

Examples

Plot the source grid and highlight the canonical horizontal plane:

>>> from hrtfpykit.hrtf import load_hrtf
>>> hrtf = load_hrtf("hrtfs/P0001_FreeFieldComp_44kHz.sofa")
>>> hrtf.plot_plane_grid(plane="horizontal")