Getting Started#

The Acoular library is based on Python. This guide walks through a small frequency-domain beamforming workflow using the same example scripts that are built and tested in the documentation gallery.

Prerequisites#

This tutorial assumes that Acoular is installed together with its dependencies and matplotlib.

If you have not run the demo yet, run acoular.demo.run() in Python once. Besides checking that the installation works, the demo creates a three_sources.h5 file in the current working directory. The following example uses that file.

The full runnable scripts used on this page are:

Generate Example Data#

If you want to create the input data yourself instead of using the demo output, the gallery example Three sources – Generate synthetic microphone array data. generates a synthetic measurement file with three sources.

The example imports Acoular and defines the output file and basic signal setup:

from pathlib import Path

import acoular as ac

# Define simulation setup.
sfreq = 51200
duration = 1
num_samples = duration * sfreq
micgeofile = Path(ac.__file__).parent / 'xml' / 'array_64.xml'
h5savefile = Path('three_sources.h5')

Then it creates three point sources, mixes them, and writes the result to three_sources.h5:

m = ac.MicGeom(file=micgeofile)
n1 = ac.WNoiseGenerator(sample_freq=sfreq, num_samples=num_samples, seed=1)
n2 = ac.WNoiseGenerator(sample_freq=sfreq, num_samples=num_samples, seed=2, rms=0.7)
n3 = ac.WNoiseGenerator(sample_freq=sfreq, num_samples=num_samples, seed=3, rms=0.5)
p1 = ac.PointSource(signal=n1, mics=m, loc=(-0.1, -0.1, -0.3))
p2 = ac.PointSource(signal=n2, mics=m, loc=(0.15, 0, -0.3))
p3 = ac.PointSource(signal=n3, mics=m, loc=(0, 0.1, -0.3))
p = ac.Mixer(source=p1, sources=[p2, p3])
wh5 = ac.WriteH5(source=p, file=h5savefile)
wh5.save()

Beamforming Example Step By Step#

One common Acoular workflow is classic delay-and-sum beamforming in the frequency domain. The gallery example Basic Beamforming – Generate a map of three sources. contains the full runnable script. This section walks through the same script in small pieces.

First, import the required packages and define the paths to the microphone geometry and the input data:

from pathlib import Path

import acoular as ac

import matplotlib.pyplot as plt

# Define paths to geometry and data.
micgeofile = Path(ac.__file__).parent / 'xml' / 'array_64.xml'
datafile = Path('three_sources.h5')
assert datafile.exists(), 'Data file not found, run example_three_sources.py first'

The microphone geometry is loaded from the Acoular package, and the time-domain measurement data is accessed through a TimeSamples object:

mg = ac.MicGeom(file=micgeofile)
ts = ac.TimeSamples(file=datafile)

The ts object provides access to the HDF5 file and its metadata. The sample data is not loaded into memory all at once. Instead, Acoular reads it in blocks when later processing steps request it.

Next, define the spectral processing. The PowerSpectra object computes the cross-spectral matrix using Welch’s method with a block size of 128 samples and a Hanning window:

ps = ac.PowerSpectra(source=ts, block_size=128, window='Hanning')

At this point no cross-spectral matrix has been calculated yet. Acoular uses Lazy Evaluation, so the expensive work starts only when a result is actually requested.

To beamform, define a focus grid and steering vector:

rg = ac.RectGrid(x_min=-0.2, x_max=0.2, y_min=-0.2, y_max=0.2, z=-0.3, increment=0.01)
st = ac.SteeringVector(grid=rg, mics=mg)

The grid contains the candidate source positions. The steering vector combines that grid with the microphone geometry and sound propagation model.

Now create the beamformer and request a third-octave map around 8000 Hz:

bb = ac.BeamformerBase(freq_data=ps, steer=st)
pm = bb.synthetic(8000, 3)
Lm = ac.L_p(pm)

This is the line where processing starts. Acoular reads the time data, calculates the cross-spectral matrix, performs beamforming, and converts the result to decibels.

Plotting The Result#

The beamforming map is plotted as:

plt.figure(1)
plt.imshow(Lm.T, origin='lower', vmin=Lm.max() - 10, extent=rg.extent, interpolation='bicubic')
plt.colorbar()

../_images/three_source_py3_colormap.png

The same example also plots the microphone arrangement:

plt.figure(2)
plt.plot(mg.pos[0], mg.pos[1], 'o')
plt.axis('equal')
plt.show()
../_images/array64_py3colormap.png

The map shows three local maxima at the simulated source positions. Their relative levels match the synthetic input data:

Source

Location

Level

1

(-0.1,-0.1,0.3)

1 Pa

2

(0.15,0,0.3)

0.7 Pa

3

(0,0.1,0.3)

0.5 Pa

Next Steps#