Source code for sfs.tapering

"""Weights (tapering) for the driving function.

.. plot::
    :context: reset

    import sfs
    import matplotlib.pyplot as plt
    import numpy as np
    plt.rcParams['figure.figsize'] = 8, 3  # inch
    plt.rcParams['axes.grid'] = True

    active1 = np.zeros(101, dtype=bool)
    active1[5:-5] = True

    # The active part can wrap around from the end to the beginning:
    active2 = np.ones(101, dtype=bool)
    active2[30:-10] = False

"""
import numpy as np


[docs]def none(active): """No tapering window. Parameters ---------- active : array_like, dtype=bool A boolean array containing ``True`` for active loudspeakers. Returns ------- type(active) The input, unchanged. Examples -------- .. plot:: :context: close-figs plt.plot(sfs.tapering.none(active1)) plt.axis([-3, 103, -0.1, 1.1]) .. plot:: :context: close-figs plt.plot(sfs.tapering.none(active2)) plt.axis([-3, 103, -0.1, 1.1]) """ return active
[docs]def tukey(active, *, alpha): """Tukey tapering window. This uses a function similar to :func:`scipy.signal.tukey`, except that the first and last value are not zero. Parameters ---------- active : array_like, dtype=bool A boolean array containing ``True`` for active loudspeakers. alpha : float Shape parameter of the Tukey window, see :func:`scipy.signal.tukey`. Returns ------- (len(active),) `numpy.ndarray` Tapering weights. Examples -------- .. plot:: :context: close-figs plt.plot(sfs.tapering.tukey(active1, alpha=0), label='alpha = 0') plt.plot(sfs.tapering.tukey(active1, alpha=0.25), label='alpha = 0.25') plt.plot(sfs.tapering.tukey(active1, alpha=0.5), label='alpha = 0.5') plt.plot(sfs.tapering.tukey(active1, alpha=0.75), label='alpha = 0.75') plt.plot(sfs.tapering.tukey(active1, alpha=1), label='alpha = 1') plt.axis([-3, 103, -0.1, 1.1]) plt.legend(loc='lower center') .. plot:: :context: close-figs plt.plot(sfs.tapering.tukey(active2, alpha=0.3)) plt.axis([-3, 103, -0.1, 1.1]) """ idx = _windowidx(active) alpha = np.clip(alpha, 0, 1) if alpha == 0: return none(active) # design Tukey window x = np.linspace(0, 1, len(idx) + 2) tukey = np.ones_like(x) first_part = x < alpha / 2 tukey[first_part] = 0.5 * ( 1 + np.cos(2 * np.pi / alpha * (x[first_part] - alpha / 2))) third_part = x >= (1 - alpha / 2) tukey[third_part] = 0.5 * ( 1 + np.cos(2 * np.pi / alpha * (x[third_part] - 1 + alpha / 2))) # fit window into tapering function result = np.zeros(len(active)) result[idx] = tukey[1:-1] return result
[docs]def kaiser(active, *, beta): """Kaiser tapering window. This uses :func:`numpy.kaiser`. Parameters ---------- active : array_like, dtype=bool A boolean array containing ``True`` for active loudspeakers. alpha : float Shape parameter of the Kaiser window, see :func:`numpy.kaiser`. Returns ------- (len(active),) `numpy.ndarray` Tapering weights. Examples -------- .. plot:: :context: close-figs plt.plot(sfs.tapering.kaiser(active1, beta=0), label='beta = 0') plt.plot(sfs.tapering.kaiser(active1, beta=2), label='beta = 2') plt.plot(sfs.tapering.kaiser(active1, beta=6), label='beta = 6') plt.plot(sfs.tapering.kaiser(active1, beta=8.6), label='beta = 8.6') plt.plot(sfs.tapering.kaiser(active1, beta=14), label='beta = 14') plt.axis([-3, 103, -0.1, 1.1]) plt.legend(loc='lower center') .. plot:: :context: close-figs plt.plot(sfs.tapering.kaiser(active2, beta=7)) plt.axis([-3, 103, -0.1, 1.1]) """ idx = _windowidx(active) window = np.zeros(len(active)) window[idx] = np.kaiser(len(idx), beta) return window
def _windowidx(active): """Return list of connected indices for window function. Note: Gaps within the active part are not allowed. """ # find index where active loudspeakers begin (works for connected contours) if (active[0] and not active[-1]) or np.all(active): first_idx = 0 else: first_idx = np.argmax(np.diff(active.astype(int))) + 1 # shift generic index vector to get a connected list of indices idx = np.roll(np.arange(len(active)), -first_idx) # remove indices of inactive secondary sources return idx[:np.count_nonzero(active)]