Using devices in simulations
Once a device has been added to the device library, it can be used in a simulation where it can act both as a source and a receiver.
What happens behind the scenes depends on the simulation type and on which source is active:
For wave-based (DG) simulations:
- The geometry of the device is injected into room geometry mesh at the location and orientation specified (as with the boundary velocity source submodel).
- Device microphones are added as mono receivers at their relative locations. This inherently accounts for the near field response from the sources.
- The job runs normally when the device is the active source, but for external sources a spatial receiver is placed at the location of the device and the device microphones are automatically rendered during postprocessing.
For geometrical acoustics (GA) simulations:
- The directivity pattern extracted during device creation is used for the source radiation.
- A spatial receiver is placed at the device location to pick up all reflections, but the direct sound is removed for this particular receiver in the simulation.
- During postprocessing the near field response of the device is injected into the response (these are extracted during device creation).
- A device render is performed for all device microphones. This applies both for the device source on the same device (where the direct sound was ignored), but also for responses from external sources to create a coherent results package across all the simulation's sources.
In hybrid simulations the processing for the wave-based and geometrical acoustics simulation runs separately, producing device IRs for each source. Those are hybridized at the crossover frequency.
Room simulation example
Here, we use the two-way loudspeaker registered to the device library in Creating a device.
Start by initializing the SDK and fetching your project and device:
from treble_tsdk import treble
# Initialize Treble SDK instance and authenticate
tsdk = treble.TSDK()
# Get or create a project
project = tsdk.get_or_create_project('devices')
# Fetch your device
device = tsdk.device_library.get_device_by_name("loudspeaker-twoway")
Next, fetch a furnished living room from the Treble geometry library and assign a material to each of its layers. See Room creation for how to create your own room geometries.
# Fetch a living room from the geometry library
living_rooms = tsdk.geometry_library.get_dataset("LivingRooms")
model = living_rooms[305]
# Assign a material to each layer in the room
materials = {
"InteriorDoorPosts": "20% Absorption",
"WindowFrames": "20% Absorption",
"Furniture/Arm chair": "Rockwool 75 mm, 57 kg/m3, glass fiber surface",
"ExteriorWall": "13 mm Gypsum/Plaster board on frame, 100 mm mineral wool behind",
"Furniture/Ceiling Lamps": "20% Absorption",
"Furniture/TV screen": "20% Absorption",
"Furniture/Kitchen Appliances": "20% Absorption",
"Floor": "Wooden flooring",
"Furniture/TV table": "Wood",
"Windows": "Window glass",
"Furniture/Coffee table": "Wood",
"Furniture/Kitchen": "Wood",
"Ceiling": "Acoustic ceiling (glasswool), 40 mm , 30 kg/m3, suspended 100 mm",
"InteriorWall": "13 mm Gypsum/Plaster board on frame, 100 mm mineral wool behind",
"Furniture/Couch": "Rockwool 75 mm, 57 kg/m3, glass fiber surface",
"Furniture/Dining_Group/Table": "Wood",
"Furniture/Dining_Group/Chairs": "Wood",
"Furniture/Dining_Group/Set": "Wood",
"Furniture/Carpet": "Heavy carpet on concrete",
"InteriorDoors": "Wooden door",
"Furniture/Dining_Group/Pendants": "20% Absorption",
"ApartmentWall": "13 mm Gypsum/Plaster board on frame, 100 mm mineral wool behind",
}
material_assignment = [
treble.MaterialAssignment(layer_name, tsdk.material_library.get_by_name(material_name))
for layer_name, material_name in materials.items()
]
Using devices as sources
To use your device as a source in the room simulation, define a device source using treble.Source.make_device.
This requires you to specify the following:
location: Coordinates within the room where the device is placed. The placement is relative to the coordinate system origin in your device geometry.orientation: Atreble.Rotation, or a point (such as aPoint3dor aReceiver) for the device to face.label: A short label for this source.device: The device object.
Here, we place the loudspeaker in the corner of the room, turned to face the couch:
device_source = treble.Source.make_device(
location=treble.Point3d(x=-0.8, y=3.5, z=1.0),
orientation=treble.Rotation(azimuth=210),
label="device",
device=device,
)
You may then initialize a SimulationDefinition using any combination of receivers;
here we choose a single spatial receiver for a listener on the couch:
# Place a single spatial receiver on the couch
receiver = treble.Receiver.make_spatial(
treble.Point3d(x=-3.54, y=2.92, z=1.12), "couch-listener", ambisonics_order=16
)
# Place an additional source in the room: a person talking in the kitchen
speech_directivity = tsdk.source_directivity_library.get_by_name("Speech")
other_source = treble.Source.make_directive(
location=treble.Point3d(x=-5.5, y=-3.5, z=1.5),
orientation=treble.Rotation(azimuth=45),
label="kitchen-talker",
source_directivity=speech_directivity,
)
# Wrap the simulation parameters in a simulation definition
sim_def = treble.SimulationDefinition(
name="device-source-simulation",
model=model,
receiver_list=[receiver],
source_list=[device_source, other_source],
simulation_type=treble.SimulationType.hybrid,
material_assignment=material_assignment,
crossover_frequency=710,
ir_length=0.6,
)
# Inspect the simulation layout before starting it
sim_def.plot()

Once you are satisfied with your simulation layout, register and start the simulation:
# Fetch the simulation object if it exists, otherwise register and start the simulation
sim = project.get_simulation_by_name("device-source-simulation")
if sim is None:
sim = project.add_simulation(sim_def)
sim.start()
sim.as_live_progress()
Results are stored separately per source layer. By default, fetching the results of a device source sums all its source layers; to retrieve and inspect a single layer, provide the layer name:
# Fetch the results wrapper for the whole simulation
results = sim.get_results_object()
# Fetch the summed response of all source layers
spatial_ir = results.get_spatial_ir("device", "couch-listener")
# Fetch results for each source layer separately
spatial_ir_woofer = results.get_spatial_ir("device", "couch-listener", source_layer="woofer")
spatial_ir_tweeter = results.get_spatial_ir("device", "couch-listener", source_layer="tweeter")
spatial_ir.plot()

If you did not specify source filters as part of the device definition, you can apply them and combine the device signals post-hoc at the spatial IR level:
lp = treble.ButterworthFilter(lp_order=4, lp_frequency=2000)
hp = treble.ButterworthFilter(hp_order=4, hp_frequency=2000)
combined_spatial_ir = spatial_ir_woofer.filter(lp) + spatial_ir_tweeter.filter(hp)
By default, the response of a device source is referenced to 1 m/s velocity of the membrane in the passband of the simulation. Reference filters recalibrate the source so that its response is referenced to the pressure at a chosen position instead.
The device object features methods to extract a filter for referencing either the on-axis
response or any of the reference microphones that were specified in the device simulation.
The source index follows the order of the source layers in the device simulation, so here 0 is the woofer.
ref_mic_reference_filter = device.get_reference_mic_reference_filter(
source_index=0, mic_label="ref-mic-woofer"
)
on_axis_reference_filter = device.get_on_axis_reference_filter(source_index=0)
spatial_ir_referenced = spatial_ir_woofer.filter(on_axis_reference_filter)
Using devices as receivers
If a device with microphones is placed within a simulation, the signal they record is automatically processed and stored as a DeviceIR.
Device impulse responses contain a channel of rendered signal for each microphone on the device:
results = sim.get_results_object()
device_ir = results.get_device_ir("kitchen-talker", "device")
device_ir.plot()

To use your device exclusively as a receiver, inject a spatial receiver into your simulation
and render the device after the simulation has finished running.
In the example above, the couch-listener spatial receiver can be
repurposed as a microphone device by rendering the receiver's spatial IR:
spatial_ir = results.get_spatial_ir("kitchen-talker", "couch-listener")
device_ir = spatial_ir.render_device_ir(
device=device,
orientation=treble.Rotation(azimuth=90, elevation=0, roll=0),
)