visualdynamics.core.amplitude_spectrum¶
amplitude_spectrum
¶
A record's amplitude spectrum: each line scaled so a sine reads its amplitude, in peak units, under a window chosen for it.
TimeHistory.compute_spectra is the raw transform: a rectangular
window, no scaling (a sine of amplitude A on a line reads A·N/2) and a
complex mean across the averages, so content whose phase moves from one
frame to the next averages toward zero. Other code depends on it as it
is. This module is the scaled spectrum beside it, the one a tone is read
from in g peak.
The scaling, for a frame of N samples x_n windowed by w_n:
A(f_k) = 2·|X(k)| / Σw, X(k) = Σ w_n x_n e^(-i2πkn/N)
with the 2 left off at the DC line and, for an even frame, the Nyquist
line, which have no mirror twin at negative frequency to fold in. A
sine of amplitude A that sits on line k transforms to A·Σw/2 there, so
the line reads A whatever the window. Σw is the window's amplitude
correction: Σw/N, the window's mean, is its coherent gain (0.5 for
Hann), and dividing by Σw rather than N undoes it (a correction of
×2.000 for Hann). It is not the correction a density takes. A density is
mean square per hertz and is corrected by the sum of the window's
squares (TimeHistory.compute_psds); the two differ by the window's
noise bandwidth, and applying the amplitude correction to a density
reads every ASD 1.5 times too high under Hann.
The frames' magnitudes are averaged, not their complex values. A tone reads its amplitude in every frame whatever its phase there, so the average reads it too: a tone that is not locked to the frames, or a record saved as captures with a fresh phase each, keeps its amplitude where a complex mean would shrink it. A broadband floor reads its mean magnitude per line, which is not a level: it moves with the line spacing and the window, and a random record's level is read from its ASD. An amplitude spectrum is for tones. The same averaging makes a tone that is not well clear of the floor read high: the floor's magnitude adds to the tone's in every frame and does not average away.
The window is chosen here, not taken from the record's averaging. The
frames are the averaging's (its frame length, overlap, start, frame
count and detrend), because those are what was set for the record; but
the window right for a density of random data and the window right for a
tone's amplitude are not the same window. Hann is the default. It reads
a tone on a line exactly and one midway between lines up to 1.42 dB low,
because the tallest line then sits half a line off the tone's frequency
(scalloping). The flat top's crown is flat across a line, so a tone
reads within about 0.01 dB of its amplitude wherever it falls, at the
cost of a main lobe several lines wide; it is the window for amplitude
accuracy. Its correction depends on the variant a program implements and
how it is normalized; the one here is scipy's flattop, periodic, whose
coherent gain is 0.2156 (a correction of ×4.639). Every reading states
its window and its correction, so a number read here is never carried to
another program without them.
References
The amplitude correction is the window's coherent gain and the loss of a tone between lines its scalloping loss, both Harris's; the one-sided scaling and the doubling left off at DC and Nyquist are how the autospectrum beside it is scaled.
- Harris, F. J. (1978). "On the Use of Windows for Harmonic Analysis with the Discrete Fourier Transform." Proceedings of the IEEE, 66(1), 51-83. doi:10.1109/PROC.1978.10837 Coherent gain, equivalent noise bandwidth and scalloping loss, window by window.
- Bendat, J. S., & Piersol, A. G. (2010). Random Data: Analysis and Measurement Procedures, 4th ed. Wiley. The finite Fourier transform of a record and its one-sided spectra.
- Brandt, A. (2011). Noise and Vibration Analysis: Signal Analysis and Experimental Procedures. Wiley. The flat-top window, for reading a tone's amplitude off a spectrum wherever it falls between lines.
Classes:
| Name | Description |
|---|---|
AmplitudeSpectrum |
What |
Functions:
| Name | Description |
|---|---|
coherent_gain |
A window's coherent gain: its mean, Σw/N. |
amplitude_correction |
The factor a windowed transform's lines are multiplied by so a |
scalloping |
The share of its amplitude a sine midway between two lines reads |
amplitude_lines |
The amplitude spectrum of frames already windowed, their |
channel_row |
The row of an amplitude spectrum of |
amplitude_spectrum |
The amplitude spectrum of every channel of a time history, each |
Classes¶
AmplitudeSpectrum
dataclass
¶
AmplitudeSpectrum(frequencies: ndarray, amplitude: ndarray, response_dof: list[str], ordinate_dim: list[str], dimension_hint: list[str | None], window: str, window_parameter: float | None, frame_length: int, sample_rate: float, frames: tuple[int, ...], coherent_gain: float, noise_bandwidth: float, scalloping: float, leveled: ndarray | None = None, from_averaging: bool = True, labels: list[str] = list(), lowest_line: int = 1)
What amplitude_spectrum returns: a record's amplitude spectrum,
one row per channel, with the window and its correction stated.
amplitude is in peak units, SI as the record is stored (m/s² for an
acceleration). frames is how many frames each channel's
magnitudes were averaged over. coherent_gain is the window's mean
and correction its reciprocal, the factor its lines were
multiplied by; noise_bandwidth is in lines and scalloping is the
share of its amplitude a sine midway between lines reads.
leveled is the same spectrum of the same frames with each frame's
mean taken out before its window, which tallest reads: a record's
mean leaks through the window's main lobe into the lines just above
DC (under Hann a 5 g mean reads 5 g on line 1 as well as at DC), and
a tone on those lines is read without it. It is amplitude itself
when the averaging levels its frames already.
from_averaging says whether the frames are the record's averaging
(False: each record whole as one frame, the record having none).
lowest_line is the lowest line a tone is read on exactly under this
window: below it the tone's mirror at negative frequency is inside
the main lobe (1 for Hann, 3 for the flat top).
Methods:
| Name | Description |
|---|---|
label |
The channel's name, as the record labels it. |
tallest |
(frequency, amplitude) of the tallest line of channel |
mirror_note |
What to say of a tallest line read at |
correction_text |
The window and its correction, in words, as the plot and the |
describe |
One line for a status bar: the tallest line of channel |
Attributes:
| Name | Type | Description |
|---|---|---|
correction |
float
|
The amplitude correction applied: N/Σw (2.000 for Hann). |
spacing |
float
|
The line spacing in Hz: the sample rate over the frame |
scalloping_db |
float
|
How far low, in dB, a sine midway between lines reads: 1.42 |
Attributes¶
scalloping_db
property
¶
How far low, in dB, a sine midway between lines reads: 1.42 for Hann, as a positive number.
Methods:¶
label
¶
The channel's name, as the record labels it.
tallest
¶
(frequency, amplitude) of the tallest line of channel
record above DC, read off the frames with their means taken
out (leveled). A record's mean is not a tone, and it leaks:
under Hann a mean of 5 g reads 5 g at DC and 5 g again on the
line above, and under the flat top on four lines above. Taken
out before the window, it leaks into none, so a tone on line 1
reads its own line and amplitude under Hann. A tone's own
mirror at negative frequency lies 2k lines from it, and while
that is inside the main lobe the two add: the flat top's lobe
reaches five lines, so its lowest line read exactly is line 3
(lowest_line, and mirror_note says so).
band is (low, high) in Hz to look within; the whole spectrum
above DC when omitted. A line that is not a number is passed
over.
Raises:
| Type | Description |
|---|---|
ValueError
|
When no line of the channel is a number (it holds samples that are not finite), when every line is zero (the channel is zero throughout, or in the band), when the channel is constant (its lines above DC are rounding beside its mean), or when the band holds no line above DC. |
Source code in src/visualdynamics/core/amplitude_spectrum.py
mirror_note
¶
What to say of a tallest line read at frequency Hz when it
is below lowest_line, where the window mixes a tone with its
own mirror and neither the line nor the amplitude is the tone's;
None at or above it.
Source code in src/visualdynamics/core/amplitude_spectrum.py
correction_text
¶
The window and its correction, in words, as the plot and the pane state them: 'hann window, amplitude correction ×2.000'.
Source code in src/visualdynamics/core/amplitude_spectrum.py
describe
¶
One line for a status bar: the tallest line of channel
record in peak units, then the window and its correction.
scale converts the amplitude into unit.
Source code in src/visualdynamics/core/amplitude_spectrum.py
Functions:¶
coherent_gain
¶
coherent_gain(window: Any = 'hann', length: int | None = None, parameter: float | None = None) -> float
A window's coherent gain: its mean, Σw/N.
The share of a sine's amplitude a line on the sine keeps through the
window: 1 for a rectangle (scipy's 'boxcar'), 0.5 for Hann, 0.2156
for scipy's flat top. Its reciprocal is the amplitude correction
(amplitude_correction).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
window
|
str or Averaging
|
A window by any name |
'hann'
|
length
|
int
|
The frame length in samples; |
None
|
parameter
|
float
|
The Tukey window's alpha or the Kaiser window's beta. |
None
|
Returns:
| Type | Description |
|---|---|
float
|
|
Source code in src/visualdynamics/core/amplitude_spectrum.py
amplitude_correction
¶
amplitude_correction(window: Any = 'hann', length: int | None = None, parameter: float | None = None) -> float
The factor a windowed transform's lines are multiplied by so a sine reads its amplitude: N/Σw, one over the coherent gain.
2.000 for Hann, 4.639 for scipy's flat top, 1 for a rectangle. The
arguments are as for coherent_gain.
Source code in src/visualdynamics/core/amplitude_spectrum.py
scalloping
¶
scalloping(window: Any = 'hann', length: int | None = None, parameter: float | None = None) -> float
The share of its amplitude a sine midway between two lines reads at the taller of them: 0.849 for Hann (1.42 dB low), 0.637 for a rectangle (3.92 dB low), within a part in a thousand of 1 for the flat top.
Harris's scalloping loss, worked out from the window's own shape
(core.tone_readout.leakage), so it holds for every window offered.
The arguments are as for coherent_gain.
Source code in src/visualdynamics/core/amplitude_spectrum.py
amplitude_lines
¶
The amplitude spectrum of frames already windowed, their magnitudes averaged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
frames
|
array_like
|
One windowed frame per row, every row the same length N. |
required |
shape
|
array_like
|
The window they were multiplied by, N samples: its sum is the amplitude correction. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
N//2 + 1 lines, from DC up: 2·mean|X|/Σw, and mean|X|/Σw at DC and at the Nyquist line of an even frame. |
Source code in src/visualdynamics/core/amplitude_spectrum.py
channel_row
¶
The row of an amplitude spectrum of history that record
record is averaged into.
A row is a channel (TimeHistory.channel_key), in the order its
first record comes, so a history with one record per channel has
its rows in record order, and every capture of a channel saved as
captures maps to that channel's one row.
Source code in src/visualdynamics/core/amplitude_spectrum.py
amplitude_spectrum
¶
amplitude_spectrum(history: Any, averaging: Any = None, *, window: Any = 'hann', parameter: float | None = None) -> AmplitudeSpectrum
The amplitude spectrum of every channel of a time history, each line scaled so a sine reads its amplitude, the frames' magnitudes averaged.
The frames are the averaging's: averaging when given, else the
record's own, else each record whole as one frame, as
TimeHistory.compute_psds cuts them. Only the window is replaced:
window and parameter are this spectrum's own (the module says
why). Channels are grouped as a PSD groups them
(TimeHistory.channel_key), so a record saved as captures averages
every capture's frames together.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
history
|
TimeHistory
|
The record, evenly sampled. |
required |
averaging
|
Averaging
|
How to cut it into frames. |
None
|
window
|
str
|
Any window |
'hann'
|
parameter
|
float
|
The Tukey window's alpha or the Kaiser window's beta. |
None
|
Returns:
| Type | Description |
|---|---|
AmplitudeSpectrum
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If the samples are not evenly spaced, the frames do not fit in the record, or the window is not one offered. |
Source code in src/visualdynamics/core/amplitude_spectrum.py
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 | |