Build an IR dataset with IR collections
Use this tutorial to build a filtered impulse-response dataset for downstream audio tasks. First, you'll set up, preprocess, and save an IR collection on one machine (e.g., your laptop). Then you'll load it on a different machine (e.g., cloud compute cluster) to access audio and iterate over the collection for a downstream task.
For focused examples of individual collection operations, see the IR collections how-to. For the IR collection data model and technical details, see the reference on IR collections.
This tutorial follows these key steps:
- Set up and preprocess the collection
1.1 Get the collection from a dataset
1.2 Enrich the collection with metadata
1.3 Filter and sample the collection
1.4 Create a train/test split - Use the collection on a different machine for a downstream task
2.1 Preload audio
2.2 Iterate over the collection
Set up and preprocess the collection
In this part, you prepare the IR collection. You start from the Treble10 dataset, add direction of arrival (DOA), source-receiver distance, and acoustic parameter columns, filter and sample the rows, create a train/test split, and write the final IR collection parquet file.
Get the collection from a dataset
Start by importing the packages used for preprocessing and loading Treble10 as an IR collection:
from pathlib import Path
import hashlib
import polars as pl
from treble_tsdk import treble
from treble_tsdk.collections.ir_info import IRInfo
from treble_tsdk.collections.distributions import Uniform
# This tutorial requires SDK credentials configured in the default location.
tsdk = treble.TSDK()
work_dir = Path("./ir_dataset_tutorial")
work_dir.mkdir(parents=True, exist_ok=True)
# Treble10 is a free dataset available through the SDK dataset library.
ir_collection = tsdk.datasets.purchase("Treble10")
print(f"IR count: {len(ir_collection)}")
print(ir_collection.columns)
Enrich the collection with metadata
Add direction-of-arrival (DOA) metadata. The DOA column stores [azimuth, elevation] in degrees, and the scalar doa_azimuth column is used later for sampling:
def compute_doa(ir_info: IRInfo) -> list[float]:
doa_vec = ir_info.source.location - ir_info.receiver.location
doa_sph = treble.Rotation.cartesian_to_spherical(*doa_vec.to_list())
return doa_sph.to_list()[:2] # Return azimuth and elevation; discard radius.
ir_collection.add_column("doa", compute_doa)
ir_collection = ir_collection.apply(
lambda df: df.with_columns(
pl.col("doa").list.get(0).alias("doa_azimuth"),
pl.col("doa").list.get(1).alias("doa_elevation"),
)
)
Add acoustic parameters from completed simulation results:
acoustic_parameters = ["t30", "edt", "d50", "c50"]
ir_collection.enrich_with_acoustic_parameters(
acoustic_parameters=acoustic_parameters,
work_dir=work_dir / "acoustic_parameters",
)
Explore the added columns:
print(ir_collection.dataframe.select(["doa", "doa_azimuth", "source_receiver_dist", "t30", "c50"]))
Filter and sample the collection
Filter the collection to keep IRs with a source-receiver distance between 1 and 3 m:
filtered_collection = ir_collection.filter_collection(
(pl.col("source_receiver_dist") >= 1.0) & (pl.col("source_receiver_dist") <= 3.0)
)
print(f"Filtered IR count: {len(filtered_collection)}")
Sample the filtered collection so the selected rows follow a uniform azimuth angle distribution:
sampled_collection = filtered_collection.sample_with_distribution(
column="doa_azimuth",
n_samples=1000,
distribution=Uniform(low=-180.0, high=180.0, seed=42),
)
Visualize the resulting collection:
sampled_collection.plot()
Create a train/test split
Create a deterministic train/test split and add the corresponding metadata as a new column to the IR collection:
def split_fn(simulation) -> str:
key = simulation.id
hashed_key = int(hashlib.md5(str(key).encode("utf-8")).hexdigest(), 16)
return "train" if (hashed_key % 100) < 80 else "test"
collection.add_column("split", split_fn)
Finally, save the dataset as a parquet file. Move this file to the downstream machine or store it in shared storage:
dataset_metadata_path = work_dir / "treble10_preprocessed_metadata.parquet"
dataset_collection.write_parquet(dataset_metadata_path)
Use the collection on a different machine for a downstream task
In this part, you work on the downstream machine. You reload the prepared IR collection file, preload the audio into a local cache, and iterate over the collection rows used by a training or evaluation pipeline.
Preload audio
Load the prepared metadata file and create a data loader. The loader writes audio data to the cache directory so later iterations can reuse local files:
from pathlib import Path
from treble_tsdk import treble
# This step requires SDK credentials configured on the downstream machine.
tsdk = treble.TSDK()
# Replace this path with the prepared metadata file from the preprocessing machine.
dataset_metadata_path = Path(
"/Users/georggoetz/Documents/TSDK/Code/own-demo-notebooks/2026-docs-update/ir_dataset_tutorial/treble10_preprocessed_metadata.parquet"
)
cache_dir = Path("./ir_dataset_cache")
dataset_collection = tsdk.collections.ir_collection_from_file(dataset_metadata_path)
data_loader = dataset_collection.get_data_loader(
work_dir=cache_dir,
)
data_loader.preload_data(dataset_collection)
The metadata file and cache directory serve different purposes. The metadata file defines the collection rows and columns. The cache directory stores downloaded IR audio used by get_mono_ir(), get_spatial_ir(), get_moving_ir(), and get_device_ir().
Iterate over the collection
Iterate over the IR collection to access azimuth angle, source-receiver distance, and mono IR audio for your downstream task:
for ir_info in dataset_collection:
# Read values and audio from collection:
mono_ir = ir_info.get_mono_ir(data_loader=data_loader)
audio = mono_ir.unpadded_data()
azi = dataset_collection[0].dataframe_row["doa_azimuth"]
dist = dataset_collection[0].dataframe_row["source_receiver_dist"]
# Replace this with your downstream task:
is_frontal = "in front" if abs(azi) < 15 else "not in front"
print(
f"Source {ir_info.source.label} is {is_frontal} of receiver {ir_info.receiver.label}:\t"
+ f"Azimuth = {azi:.02f} degrees, Source-receiver distance: {dist:.02f} m"
)
print(f"IR peak value: {max(abs(audio)):.02f}")
You now have a portable IR collection file, a local IR cache on the downstream machine, and an iteration pattern that keeps each mono IR paired with DOA, source-receiver distance, acoustic parameters, and split metadata.
See IR collections for additional filtering, sorting, device-rendering, and preprocessing examples.