dpss#
- scipy.signal.windows.dpss(M, NW, Kmax=None, sym=True, norm=None, return_ratios=False, *, xp=None, device=None)[источник]#
Вычислить дискретные пролатные сфероидальные последовательности (DPSS).
DPSS (или последовательности Слепяна) часто используются в многоленточной оценке спектральной плотности мощности (см. [1]). Первое окно в последовательности можно использовать для максимизации концентрации энергии в главном лепестке и также называется окном Слепяна.
- Параметры:
- Mint
Длина окна.
- NWfloat
Стандартизированная половинная ширина полосы, соответствующая
2*NW = BW/f0 = BW*M*dtгдеdtпринимается как 1.- Kmaxint | None, optional
Количество возвращаемых окон DPSS (порядки
0черезKmax-1). Если None (по умолчанию), возвращается только одно окно формы(M,)вместо массива окон формы(Kmax, M).- symbool, необязательно
Когда True (по умолчанию), генерирует симметричное окно для использования в проектировании фильтров. Когда False, генерирует периодическое окно для использования в спектральном анализе.
- norm{2, 'approximate', 'subsample'} | None, optional
Если 'approximate' или 'subsample', то окна нормализуются по максимуму, и применяется поправочный масштабный коэффициент для окон четной длины, используя
M**2/(M**2+NW)(«приблизительный») или сдвиг на основе БПФ с субдискретизацией («subsample»), подробности см. в примечаниях. Если None, то «приблизительный» используется, когдаKmax=Noneи 2 в противном случае (что использует норму l2).- return_ratiosbool, необязательно
Если True, также возвращает коэффициенты концентрации в дополнение к окнам.
- xparray_namespace, опционально
Опциональное пространство имён массивов. Должно быть совместимо со стандартом array API или поддерживаться array-api-compat. По умолчанию:
numpy- устройство: любое
необязательная спецификация устройства для вывода. Должна соответствовать одной из поддерживаемых спецификаций устройств в
xp.
- Возвращает:
- vndarray, форма (Kmax, M) или (M,)
Окна DPSS. Будет одномерным, если Kmax равно None.
- rndarray, форма (Kmax,) или float, опционально
Коэффициенты концентрации для окон. Возвращается только если return_ratios вычисляется как True. Будет 0D, если Kmax равно None.
Примечания
Это вычисление использует тридиагональную формулировку собственных векторов, приведённую в [2].
Нормализация по умолчанию для
Kmax=None, т.е. режим генерации окна, простое использование l-бесконечной нормы создаст окно с двумя единичными значениями, что приводит к небольшим различиям в нормировке между чётными и нечётными порядками. Приблизительная коррекцияM**2/float(M**2+NW)для чётных номеров выборок используется для противодействия этому эффекту (см. примеры ниже).Для очень длинных сигналов (например, 1e6 элементов) может быть полезно вычислять окна на порядки короче и использовать интерполяцию (например,
scipy.interpolate.interp1d) для получения сужений длиной M, но это в общем случае не сохранит ортогональность между тейперами.Добавлено в версии 1.1.
Ссылки
[1]Персиваль Д.Б., Уолден У.Т. Спектральный анализ для физических приложений: Многоленточные и традиционные одномерные методы. Издательство Кембриджского университета; 1993.
[2]Slepian, D. Prolate spheroidal wave functions, Fourier analysis, and uncertainty V: The discrete case. Bell System Technical Journal, Volume 57 (1978), 1371430.
[3]Kaiser, JF, Schafer RW. On the Use of the I0-Sinh Window for Spectrum Analysis. IEEE Transactions on Acoustics, Speech and Signal Processing. ASSP-28 (1): 105-107; 1980.
Примеры
Мы можем сравнить окно с
kaiser, который был изобретен как альтернатива, более простая для вычисления [3] (пример адаптирован из здесь):>>> import numpy as np >>> import matplotlib.pyplot as plt >>> from scipy.signal import windows, freqz >>> M = 51 >>> fig, axes = plt.subplots(3, 2, figsize=(5, 7)) >>> for ai, alpha in enumerate((1, 3, 5)): ... win_dpss = windows.dpss(M, alpha) ... beta = alpha*np.pi ... win_kaiser = windows.kaiser(M, beta) ... for win, c in ((win_dpss, 'k'), (win_kaiser, 'r')): ... win /= win.sum() ... axes[ai, 0].plot(win, color=c, lw=1.) ... axes[ai, 0].set(xlim=[0, M-1], title=rf'$\alpha$ = {alpha}', ... ylabel='Amplitude') ... w, h = freqz(win) ... axes[ai, 1].plot(w, 20 * np.log10(np.abs(h)), color=c, lw=1.) ... axes[ai, 1].set(xlim=[0, np.pi], ... title=rf'$\beta$ = {beta:0.2f}', ... ylabel='Magnitude (dB)') >>> for ax in axes.ravel(): ... ax.grid(True) >>> axes[2, 1].legend(['DPSS', 'Kaiser']) >>> fig.tight_layout() >>> plt.show()
А вот примеры первых четырёх окон вместе с их коэффициентами концентрации:
>>> M = 512 >>> NW = 2.5 >>> win, eigvals = windows.dpss(M, NW, 4, return_ratios=True) >>> fig, ax = plt.subplots(1) >>> ax.plot(win.T, linewidth=1.) >>> ax.set(xlim=[0, M-1], ylim=[-0.1, 0.1], xlabel='Samples', ... title=f'DPSS, {M:d}, {NW:0.1f}') >>> ax.legend([f'win[{ii}] ({ratio:0.4f})' ... for ii, ratio in enumerate(eigvals)]) >>> fig.tight_layout() >>> plt.show()
Используя стандартный \(l_{\infty}\) norm даст два единичных значения для чётных M, но только одно единичное значение для нечётных M. Это создает неравномерную мощность окна, которую можно компенсировать приблизительной коррекцией
M**2/float(M**2+NW), который можно выбрать с помощьюnorm='approximate'(что совпадает сnorm=NoneкогдаKmax=None, как в данном случае). Альтернативно, более медленныйnorm='subsample'может использоваться, который использует сдвиг подвыборки в частотной области (БПФ) для вычисления поправки:>>> Ms = np.arange(1, 41) >>> factors = (50, 20, 10, 5, 2.0001) >>> energy = np.empty((3, len(Ms), len(factors))) >>> for mi, M in enumerate(Ms): ... for fi, factor in enumerate(factors): ... NW = M / float(factor) ... # Corrected using empirical approximation (default) ... win = windows.dpss(M, NW) ... energy[0, mi, fi] = np.sum(win ** 2) / np.sqrt(M) ... # Corrected using subsample shifting ... win = windows.dpss(M, NW, norm='subsample') ... energy[1, mi, fi] = np.sum(win ** 2) / np.sqrt(M) ... # Uncorrected (using l-infinity norm) ... win /= win.max() ... energy[2, mi, fi] = np.sum(win ** 2) / np.sqrt(M) >>> fig, ax = plt.subplots(1) >>> hs = ax.plot(Ms, energy[2], '-o', markersize=4, ... markeredgecolor='none') >>> leg = [hs[-1]] >>> for hi, hh in enumerate(hs): ... h1 = ax.plot(Ms, energy[0, :, hi], '-o', markersize=4, ... color=hh.get_color(), markeredgecolor='none', ... alpha=0.66) ... h2 = ax.plot(Ms, energy[1, :, hi], '-o', markersize=4, ... color=hh.get_color(), markeredgecolor='none', ... alpha=0.33) ... if hi == len(hs) - 1: ... leg.insert(0, h1[0]) ... leg.insert(0, h2[0]) >>> ax.set(xlabel='M (samples)', ylabel=r'Power / $\sqrt{M}$') >>> ax.legend(leg, ['Uncorrected', r'Corrected: $\frac{M^2}{M^2+NW}$', ... 'Corrected (subsample)']) >>> fig.tight_layout()