Beamforming and array processing

Array signal processing / beamforming toolbox.

arlpy.bf.bartlett(x, fc, sd, shading=None, complex_output=False)

Frequency-domain Bartlett beamformer.

The timeseries data must be 2D with narrowband complex timeseries for each sensor in individual rows. The steering delays must also be 2D with a row per steering direction.

If the timeseries data is specified as 1D array, it is assumed to represent multiple sensors at a single time.

Parameters:
  • x – narrowband complex timeseries data for multiple sensors (row per sensor)
  • fc – carrier frequency for the array data (Hz)
  • sd – steering delays (s)
  • shading – window function to use for array shading (None means no shading)
  • complex_output – True for complex signal, False for beamformed power
Returns:

beamformer output averaged across time

>>> from arlpy import bf
>>> import numpy as np
>>> # narrowband (1 kHz) timeseries array data assumed to be loaded in x
>>> # sensor positions assumed to be in pos
>>> y = bf.bartlett(x, 1000, bf.steering_plane_wave(pos, 1500, np.linspace(-np.pi/2, np.pi/2, 181)))
arlpy.bf.bartlett_beampattern(i, fc, sd, shading=None, theta=None, show=False)

Computes the beampattern for a Bartlett or delay-and-sum beamformer.

Parameters:
  • i – row index of target steering distances
  • fc – carrier frequency for the array data (Hz)
  • sd – steering delays (s)
  • shading – window function to use for array shading (None means no shading)
  • theta – angles (in radians) for display if beampattern is plotted
  • show – True to plot the beampattern, False to return it
Returns:

beampattern power response at all directions corresponding to rows in sd

>>> from arlpy import bf
>>> import numpy as np
>>> sd = bf.steering_plane_wave(np.linspace(0, 5, 11), 1500, np.linspace(-np.pi/2, np.pi/2, 181))
>>> bp = bf.bartlett_beampattern(90, 1500, sd, show=True)
arlpy.bf.broadband(x, fs, nfft, sd, f0=0, fmin=None, fmax=None, overlap=0, beamformer=<function bartlett>, **kwargs)

Frequency-domain broadband beamformer operating on time-domain input data.

The broadband beamformer is implementing by taking STFT of the data, applying narrowband beamforming to each frequency bin, and integrating the beamformer output power across the entire bandwidth.

The array data must be 2D with timeseries for each sensor in individual rows. The steering delays must also be 2D with a row per steering direction.

The STFT window size should be chosen such that the corresponding distance (based on wave propagation speed) is much larger than the aperture size of the array.

If the array data is real and f0 is zero, the data is assumed to be passband and so only half the frequency components are computed.

Parameters:
  • x – timeseries data for multiple sensors (row per sensor)
  • fs – sampling rate for array data (Hz)
  • c – wave propagation speed (m/s)
  • nfft – STFT window size
  • sd – steering delays (s)
  • f0 – carrier frequency (for baseband data) (Hz)
  • fmin – minimum frequency to integrate (Hz)
  • fmax – maximum frequency to integrate (Hz)
  • overlap – window overlap for STFT
  • beamformer – narrowband beamformer to use
Returns:

beamformer output with steering directions as the first axis, time as the second, and if complex output, fft bins as the third

>>> from arlpy import bf
>>> # passband timeseries array data assumed to be loaded in x, sampled at fs
>>> # sensor positions assumed to be in pos
>>> sd = bf.steering_plane_wave(pos, 1500, np.linspace(-np.pi/2, np.pi/2, 181))
>>> y = bf.broadband(x, fs, 256, sd, beamformer=capon)
>>> y1 = bf.music(x, fs, 256, sd, beamformer=music, nsignals=1)
arlpy.bf.capon(x, fc, sd, complex_output=False)

Frequency-domain Capon beamformer.

The timeseries data must be 2D with narrowband complex timeseries for each sensor in individual rows. The steering delays must also be 2D with a row per steering direction.

If the timeseries data is specified as 1D array, it is assumed to represent multiple sensors at a single time.

The covariance matrix of x is estimated over the entire timeseries, and used to compute the optimal weights for the Capon beamformer.

Parameters:
  • x – narrowband complex timeseries data for multiple sensors (row per sensor)
  • fc – carrier frequency for the array data (Hz)
  • sd – steering delays (s)
  • complex_output – True for complex signal, False for beamformed power
Returns:

beamformer output averaged across time

>>> from arlpy import bf
>>> import numpy as np
>>> # narrowband (1 kHz) timeseries array data assumed to be loaded in x
>>> # sensor positions assumed to be in pos
>>> y = bf.capon(x, 1000, bf.steering_plane_wave(pos, 1500, np.linspace(-np.pi/2, np.pi/2, 181)))
arlpy.bf.covariance(x)

Compute array covariance matrix.

Parameters:x – narrowband complex timeseries data for multiple sensors (row per sensor)
arlpy.bf.delay_and_sum(x, fs, sd, shading=None)

Time-domain delay-and-sum beamformer.

The array data must be 2D with timeseries for each sensor in individual rows. The steering delays must also be 2D with a row per steering direction.

Parameters:
  • x – passband real timeseries data for multiple sensors (row per sensor)
  • fs – sampling rate for the array data (Hz)
  • sd – steering delays (s)
  • shading – window function to use for array shading (None means no shading)
Returns:

beamformer timeseries output with time as the last axis, and steering directions as the first

>>> from arlpy import bf
>>> import numpy as np
>>> # timeseries array data assumed to be loaded in x
>>> # sensor positions assumed to be in pos
>>> y = bf.delay_and_sum(x, 1000, bf.steering_plane_wave(pos, 1500, np.linspace(-np.pi/2, np.pi/2, 181)))
arlpy.bf.music(x, fc, sd, nsignals=1, complex_output=False)

Frequency-domain MUSIC beamformer.

The timeseries data must be 2D with narrowband complex timeseries for each sensor in individual rows. The steering delays must also be 2D with a row per steering direction.

If the timeseries data is specified as 1D array, it is assumed to represent multiple sensors at a single time.

The covariance matrix of x is estimated over the entire timeseries, and used to compute the optimal weights for the MUSIC beamformer via eigen-decomposition.

Parameters:
  • x – narrowband complex timeseries data for multiple sensors (row per sensor)
  • fc – carrier frequency for the array data (Hz)
  • sd – steering delays (s)
  • nsignals – number of signal eigenvectors (rest are considered noise)
  • complex_output – True for complex signal, False for beamformed power
Returns:

beamformer output averaged across time

>>> from arlpy import bf
>>> import numpy as np
>>> # narrowband (1 kHz) timeseries array data assumed to be loaded in x
>>> # sensor positions assumed to be in pos
>>> y = bf.music(x, 1000, bf.steering_plane_wave(pos, 1500, np.linspace(-np.pi/2, np.pi/2, 181)))
arlpy.bf.normalize(x, unit_variance=True)

Normalize array timeseries data to be zero-mean and equal variance.

The average signal power across the array is retained if unit_variance is set to True so that the beamformed data can be compared with other datsets.

Parameters:
  • x – passband real timeseries data for multiple sensors (row per sensor)
  • unit_variance – True to make timeseries unit variance, False to retain average signal power across the array
Returns:

normalized passband real timeseries data

arlpy.bf.steering_plane_wave(pos, c, theta)

Compute steering delays assuming incoming signal has a plane wavefront.

For linear arrays, pos is 1D array. For planar and 3D arrays, pos is a 2D array with a sensor position vector in each row.

For linear arrays, theta is a 1D array of angles (in radians) with 0 being broadside. For planar and 3D arrays, theta is a 2D array with an (azimuth, elevation) pair in each row. Such arrays can be easily generated using the arlpy.utils.linspace2d() function.

The broadside direction is along the x-axis of a right-handed coordinate system with z-axis pointing upwards, and has azimuth and elevation as 0. In case of linear arrays, the y-coordinate is the sensor position. In case of planar arrays, if only 2 coordinates are provided, these coordinates are assumed to be y and z.

Parameters:
  • pos – sensor positions (m)
  • c – signal propagation speed (m/s)
  • theta – steering directions (radians)
Returns:

steering delays with a row for each direction (s)

>>> import numpy as np
>>> from arlpy import bf, utils
>>> pos1 = [0.0, 0.5, 1.0, 1.5, 2.0]
>>> a1 = bf.steering_plane_wave(pos1, 1500, np.deg2rad(np.linspace(-90, 90, 181)))
>>> pos2 = [[0.0, 0.0],
            [0.0, 0.5],
            [0.5, 0.0],
            [0.5, 0.5]]
>>> a2 = bf.steering_plane_wave(pos2, 1500, np.deg2rad(utils.linspace2d(-20, 20, 41, -10, 10, 21)))
arlpy.bf.stft(x, nfft, overlap=0, window=None)

Compute short time Fourier transform (STFT) of array data.

Parameters:
  • x – passband real timeseries data for multiple sensors (row per sensor)
  • nfft – window length in samples
  • overlap – number of samples of overlap between windows
  • window – window function to use (None means rectangular window)
Returns:

3d array of time x frequency x sensor

For supported window functions, see documentation for scipy.signal.get_window().