Acoular 25.03 documentation

SourceMixer

«  UncorrelatedNoiseSource   ::   sources   ::   PointSourceConvolve  »

SourceMixer

class acoular.sources.SourceMixer

Bases: SamplesGenerator

Combine signals from multiple sources by mixing their outputs.

The SourceMixer class takes signals generated by multiple SamplesGenerator instances and combines them into a single mixed output. The signals are weighted (if weights are provided) and added block-by-block, supporting efficient streaming.

See also

acoular.base.SamplesGenerator

Base class for signal generators.

Notes

  • All sources must have the same sampling frequency, number of channels, and number of samples for proper mixing.

  • The weights for the sources can be specified to control their relative contributions to the mixed output. If no weights are provided, all sources are equally weighted.

Examples

Mix a stationary point source emitting a sine signal with two pink noise emitting point sources circling it and white noise for each channel:

>>> import numpy as np
>>> import acoular as ac
>>>
>>> # Generate positional microphone data for a 3x3 grid in the x-y plane at z=0
>>> mic_positions = []
>>> for i in range(3):
...     for j in range(3):
...         mic_positions.append([i - 1, j - 1, 0])  # Center the grid at the origin
>>>
>>> # Convert positions to the format required by MicGeom
>>> mg = ac.MicGeom(pos_total=np.array(mic_positions).T)
>>>
>>> # Generate positional data for trajectories of two moving sources
>>> # Trajectory 1: Circle in x-y plane at z=1
>>> args = 2 * np.pi * np.arange(10) / 10  # Discrete points around the circle
>>> x = np.cos(args)
>>> y = np.sin(args)
>>> z = np.ones_like(x)  # Constant height at z=1
>>>
>>> locs1 = np.array([x, y, z])
>>> # Map time indices to positions for Trajectory 1
>>> points1 = {time: tuple(pos) for time, pos in enumerate(locs1.T)}
>>> tr1 = ac.Trajectory(points=points1)
>>>
>>> # Trajectory 2: Same circle but with a 180-degree phase shift
>>> locs2 = np.roll(locs1, 5, axis=1)  # Shift the positions by half the circle
>>> # Map time indices to positions for Trajectory 2
>>> points2 = {time: tuple(pos) for time, pos in enumerate(locs2.T)}
>>> tr2 = ac.Trajectory(points=points2)
>>>
>>> # Create signal sources
>>> # Pink noise sources with different RMS values and random seeds
>>> pinkNoise1 = ac.PNoiseGenerator(sample_freq=51200, num_samples=1024, rms=1.0, seed=42)
>>> pinkNoise2 = ac.PNoiseGenerator(sample_freq=51200, num_samples=1024, rms=0.5, seed=24)
>>>
>>> # Moving sources emitting pink noise along their respective trajectories
>>> pinkSource1 = ac.MovingPointSource(trajectory=tr1, signal=pinkNoise1, mics=mg)
>>> pinkSource2 = ac.MovingPointSource(trajectory=tr2, signal=pinkNoise2, mics=mg)
>>>
>>> # White noise source generating uncorrelated noise for each microphone channel
>>> whiteNoise = ac.WNoiseGenerator(sample_freq=51200, num_samples=1024, rms=1.0, seed=73)
>>> whiteSources = ac.UncorrelatedNoiseSource(signal=whiteNoise, mics=mg)
>>>
>>> # Stationary point source emitting a sine wave
>>> sineSignal = ac.SineGenerator(freq=1200, sample_freq=51200, num_samples=1024)
>>> sineSource = ac.PointSource(signal=sineSignal, loc=(0, 0, 1), mics=mg)
>>>
>>> # Combine all sources in a SourceMixer with specified weights
>>> sources = [pinkSource1, pinkSource2, whiteSources, sineSource]
>>> mixer = ac.SourceMixer(sources=sources, weights=[1.0, 1.0, 0.3, 2.0])
>>>
>>> # Generate and process the mixed output block by block
>>> for block in mixer.result(num=256):  # Generate blocks of 256 samples
...     print(block.shape)
Pink noise filter depth set to maximum possible value of 10.
Pink noise filter depth set to maximum possible value of 10.
(256, 9)
(256, 9)
(256, 9)
(256, 9)

The output contains blocks of mixed signals. Each block is a combination of the four signals, weighted according to the provided weights.

sources = List(Instance(SamplesGenerator, ()))

List of SamplesGenerator instances to be mixed. Each source provides a signal that will be combined in the output. All sources must have the same sampling frequency, number of channels, and number of samples. The list must contain at least one source.

sample_freq = Property(depends_on=['sdigest'])

Sampling frequency of the mixed signal in Hz. Derived automatically from the first source in sources. If no sources are provided, default is 0.

num_channels = Property(depends_on=['sdigest'])

Number of channels in the mixed signal. Derived automatically from the first source in sources. If no sources are provided, default is 0.

num_samples = Property(depends_on=['sdigest'])

Total number of samples in the mixed signal. Derived automatically from the first source in sources. If no sources are provided, default is 0.

weights = CArray(desc='channel weights')

Array of amplitude weights for the sources. If not set, all sources are equally weighted. The size of the weights array must match the number of sources in sources. For example, with two sources, weights = [1.0, 0.5] would mix the first source at full amplitude and the second source at half amplitude.

sdigest = Str()

Internal identifier for the combined state of all sources, used to track changes in the sources for reproducibility and caching.

digest = Property(depends_on=['sdigest', 'weights'])

A unique identifier for the current state of the source, based on the states of the sources and the weights. (read-only)

validate_sources()

Ensure that all sources are compatible for mixing.

This method checks that all sources in sources have the same sampling frequency, number of channels, and number of samples. A ValueError is raised if any mismatch is detected.

Raises:
ValueError

If any source has incompatible attributes.

result(num)

Generate uncorrelated the mixed signal at microphones in blocks.

The result() method combines signals from all sources block-by-block, applying the specified weights to each source. The output blocks contain the mixed signal for all channels.

Parameters:
numint

Number of samples per block to be yielded.

Yields:
numpy.ndarray

A 2D array of shape (num, num_channels) containing the mixed signal. The last block may have fewer samples if the total number of samples is not a multiple of num.

Raises:
ValueError

If the sources are not compatible for mixing.

«  UncorrelatedNoiseSource   ::   sources   ::   PointSourceConvolve  »