spectral_kurtosis — ACOUSTICS bearing op

資料種類:signaltable

呼叫:import acoustics; acoustics.spectral_kurtosis(x, rate, win=None, hop=None, window='hann')(或 opsacoustics.get("spectral_kurtosis"))

用法

哪個頻帶是衝擊性的 —— 也就是該在哪裡解調。

> 以下的詳細說明為原文 —— 摘要與標題已翻譯。

:func:envelope_spectrum needs a band, and picking it by eye from a

spectrum picks the *loudest* band, which is usually a gear mesh or a line

harmonic rather than the bearing. Spectral kurtosis picks the *most

non-stationary* band instead: for each frequency bin it measures the

fourth-order behaviour of that bin's STFT coefficient across frames.

The normalisation is chosen so the two reference cases are exact:

• stationary complex circular Gaussian noise gives `SK = 0`,

• a pure tone (constant magnitude in its bin) gives `SK = -1`,

• a repetitive transient gives `SK > 0`, and the larger it is the more

concentrated in time the band's content is.

Measured over 8192 samples at 16 kHz at the default window (64, 509 interior

frames): white Gaussian noise gives a mean SK of -0.0444 over the

interior bins, against the estimator's own standard deviation

`4/sqrt(509) = 0.1773`, so it is zero; and a 2 kHz tone gives -1.0000

in its bin. Both reference cases land on their closed forms.

**The answer is a band, and it depends on the window — measured, not

asserted.** The frame has to be *shorter than the gap between transients*,

or every frame contains one and the band looks perfectly stationary. On the

`mode="impulse"` bearing signal (25.6 kHz, resonance 3000 Hz, impulses

every 9.35 ms, ring time constant 1.06 ms):

====== ========== ======= ========== =============

win frame (ms) max SK at (Hz) bin spacing

====== ========== ======= ========== =============

16 0.62 29.58 6400 1600 Hz

32 1.25 12.86 1600 800 Hz

64 2.50 5.38 2000 400 Hz

128 5.00 1.66 1600 200 Hz

256 10.00 -0.13 12200 100 Hz

====== ========== ======= ========== =============

The last row is the failure mode: at a 10 ms frame against a 9.35 ms impulse

spacing, every frame holds exactly one impulse, the band is stationary by

construction, and the operator reports a *negative* kurtosis at an unrelated

frequency. Nothing raises. So `window_seconds` is returned, to be compared

against the repetition period you expect, and sweeping `win` is part of

using this operator rather than an optimisation.

What survives the sweep is the *band*, not the bin. On the same signal with

`noise_sigma=0.05` (the noiseless one is impulsive in every bin at once

and its top six bins differ by 0.03, which is itself worth knowing), the six

highest bins at `win=64` are 2000, 2400, 1600, 4000, 3600 and 1200 Hz —

bracketing the true 3000 Hz resonance without any of them being it. And that

is enough: feeding the band this operator returns straight into

:func:envelope_spectrum recovers the defect rate exactly — measured

107.0000 Hz from the 1600-2400 Hz band the operator chose by itself,

with no knowledge of the resonance.

The band is returned, not left to the caller to assemble. `band_lo` /

`band_hi are max_freq -+ bin_hz` *clamped into the open interval*

`(0, rate/2) that :func:envelope_spectrum` accepts, so

`envelope_spectrum(x, rate, sk["band_lo"], sk["band_hi"])` is always a

legal call. Assembling the band by hand is not: `freqs` runs up to and

including Nyquist, so whenever the winning bin is the topmost interior one,

`max_freq + bin_hz lands exactly *on* Nyquist and envelope_spectrum`

refuses it — correctly, since no such band exists in the recording. Measured

on the `mode="am"` bearing signal (25600 Hz, 1 s, 3 kHz carrier, 107 Hz

defect, `m = 0.5`), whose kurtosis maximum lands on the top interior bin

(12400 Hz, `bin_hz` 400):

=========================== ===================== ==============================

band handed to the consumer value `envelope_spectrum`

=========================== ===================== ==============================

`max_freq -+ bin_hz 12000.0 - 12800.0 Hz ValueError` (12800 = Nyquist)

`band_lo / band_hi` 12000.0 - 12600.0 Hz returns

=========================== ===================== ==============================

Returning is not the same as finding something, and this row is the honest

case: `max_kurtosis is **-0.2725** against noise_sigma` 0.1001, so

there was never a band to find — an amplitude-modulated tone is stationary in

every bin, which is exactly what a negative SK says. Demodulating the band

anyway gives `peak_freq **1.0000** Hz at band_fraction`

5.080e-05: nothing lives up there, and the returned diagnostics say so.

(The same signal over the known resonance, 2000-4000 Hz, gives `peak_freq`

107.0000 at `band_fraction` 0.9999.) The contract this repair adds

is only that the handoff is *legal* — refusing to answer a well-posed call is

the caller's bug to hit, whereas judging the answer stays with

`max_kurtosis / noise_sigma / band_fraction`.

The clamp margin is half a bin: an edge cannot be placed more finely than

`bin_hz` in the first place, and half a bin is the smallest offset that is

still a resolvable distance from the boundary — no epsilon, no rate-dependent

fudge. `band_lo < band_hi always holds, because max_freq` is by

construction an interior bin and therefore at least one full bin away from

both 0 and Nyquist.

`win` defaults to the largest power of two that leaves at least 8 interior

frames, clamped to [16, 64] — short, for the reason in the table — and the

value used is returned. Fewer than 8 interior frames makes the fourth moment

meaningless and is refused.

DC and Nyquist bins are excluded from `max_kurtosis / max_freq`: their

STFT coefficients are real, not complex circular, so the -2 normalisation is

the wrong one there and they read about -1 for noise. They are still present

in `kurtosis with the same formula, and real_bins` names them.

Returns a dict: `freqs, kurtosis, max_kurtosis, max_freq`,

`band_lo, band_hi` (the demodulation band, ready for

:func:envelope_spectrum), `n_frames, win, hop, real_bins`,

`window_seconds, bin_hz, noise_sigma` (the estimator's own standard

deviation, `4/sqrt(n_frames)` — a peak below this is not a finding).

Raises `ValueError: everything :func:stft` refuses, plus a signal too

short for 8 frames at the chosen window.

詳細使用指南

acoustic_condition_monitoring 族使用指南

參考(範例資料・文獻)

• 範例資料目錄(下載 URL / 授權) —— 2-D 用 skimage.data(BSD/公有領域)加合成圖,3-D 給出真實資料源(Stanford/PDS 等)的下載 URL。

• 運算子來歷與參考文獻 —— 該運算子族所依據的研究/方法出處。

• 演算法的正典(作者・年份)與用途見上面的族使用指南

可執行的範例(實際呼叫該運算子並已驗證的樣例)

acoustic_condition_monitoringpy -3.11 examples/acoustic_condition_monitoring.py

poc_bearing_diagnosispy -3.11 examples/poc_bearing_diagnosis.py

型別可銜接的下一個運算子(可接受 table 作為輸入)

istft

同類別(bearing)

envelope_spectrum · bearing_defect_frequencies · cepstrum


*Provenance: acoustics.py — ACOUSTICS 運算子登記表。本條目由 tools/opdocs.py md 自動產生(請勿手動編輯)。*

© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.