visualdynamics.core.rms_check¶
rms_check
¶
The rms check: the rms a spectrum carries beside the rms of the record it was computed from.
The area under an autospectral density is the mean square of the record it came from (Parseval's theorem), so the square root of the sum of its lines, each times the line spacing, should come back to the rms of the time history. It is the cheapest check there is on a spectral computation, and it catches the scaling errors no plot shows: the amplitude correction of a window applied to a density (the window's noise bandwidth too high, 1.76 dB on a Hann density), the one-sided doubling left out or applied twice (3.01 dB either way), and one side in g where the other is in m/s² (19.83 dB). A spectrum that cannot give back the rms of its own record is wrong, whatever its plot looks like.
Two time-history numbers are read, because a window makes the check an
estimate rather than an identity. With no window and frames laid end to
end every sample is used once at the same weight and the two rms agree
to rounding. A tapering window weights the middle of each frame more
than its ends, so an averaged, windowed spectrum is an estimate of the
record's mean square, and on a long random record it lands within a few
hundredths of a decibel of it. So the check reads, beside the record's
own rms over the span the frames cover (RmsCheck.time_rms), the mean
square as the frames themselves see it: each frame leveled as the
averaging levels it, windowed, its mean square taken with the sum of
the window's squares, and the frames averaged (RmsCheck.framed_rms).
A correctly scaled spectrum computed with that averaging carries
exactly that, to rounding, whatever the window; so when the gap to the
record is over the threshold and the gap to the frames is not, the
window's weighting is the whole of it and the scaling is right.
The gap is the spectrum's rms over the record's, in decibels, positive when the spectrum reads high, and it is judged against a threshold that is an argument. Its default is a few hundredths of a decibel: wide enough for a windowed average of a long random record, and an order below the smallest scaling error the check exists to catch.
References
The check is Parseval's theorem applied to the averaged periodogram; the window's noise bandwidth is what names the commonest error.
- Welch, P. D. (1967). "The Use of Fast Fourier Transform for the Estimation of Power Spectra: A Method Based on Time Averaging Over Short, Modified Periodograms." IEEE Transactions on Audio and Electroacoustics, 15(2), 70-73. doi:10.1109/TAU.1967.1161901 The averaged, windowed periodogram, scaled by the sum of the window's squares, whose area is the frames' mean square.
- 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 The equivalent noise bandwidth, the factor between a window's amplitude correction and its energy correction.
Classes:
| Name | Description |
|---|---|
RmsCheck |
One record's rms check: the rms from the spectrum beside the rms |
Functions:
| Name | Description |
|---|---|
time_rms |
The rms of a record's samples: the square root of their mean |
rms_check |
Check an autospectrum against the record it came from: its rms |
matching_records |
The records of |
refusal |
Why record |
check_record |
The rms check of record |
Classes¶
RmsCheck
dataclass
¶
RmsCheck(dof: str, spectrum_rms: float, time_rms: float, framed_rms: float | None, threshold_db: float, lines: int, spacing: float, samples: int, window: str | None = None, noise_bandwidth: float | None = None, span: tuple[float, float] | None = None, notes: tuple[str, ...] = (), coverage: str | None = None)
One record's rms check: the rms from the spectrum beside the rms of the time history, and the gap between them in dB.
The rms are in the record's SI unit, as the data is stored (m/s²
for an acceleration). gap_db is 20 log10 of the spectrum's rms
over the record's, positive when the spectrum reads high; NaN when
either is not a positive number. framed_rms is the mean square
as the averaging's frames see it, square-rooted, when the averaging
is known and has the spectrum's line spacing; None otherwise.
Methods:
| Name | Description |
|---|---|
describe |
One line for a status bar: both rms, the gap and the verdict. |
Attributes:
| Name | Type | Description |
|---|---|---|
gap_db |
float
|
The spectrum's rms over the record's, in dB: positive when the |
framed_gap_db |
float | None
|
The spectrum's rms over the frames' own, in dB; None when the |
window_gap_db |
float | None
|
The frames' rms over the record's, in dB: how much of the gap |
passed |
bool
|
Whether the gap is within the threshold. False when there is |
explained |
bool
|
Whether a gap over the threshold is the window's alone: the |
cause |
str | None
|
The scaling error a failed gap matches, in words, or None. |
unjudged |
str | None
|
Why there is no gap to judge, in words, or None when there is |
verdict |
str
|
The judgment in words: agree, the window's gap, a named |
Attributes¶
gap_db
property
¶
The spectrum's rms over the record's, in dB: positive when the spectrum reads high. NaN when either is not a positive number.
framed_gap_db
property
¶
The spectrum's rms over the frames' own, in dB; None when the frames are not known. Near zero for a correctly scaled spectrum of those frames, whatever the window.
window_gap_db
property
¶
The frames' rms over the record's, in dB: how much of the gap the window's weighting of the samples accounts for. None when the frames are not known.
passed
property
¶
Whether the gap is within the threshold. False when there is no gap to judge (a record of zeros, a spectrum with no lines).
explained
property
¶
Whether a gap over the threshold is the window's alone: the spectrum carries the frames' own mean square, so its scaling is right and the frames weighted the record unevenly.
cause
property
¶
The scaling error a failed gap matches, in words, or None.
Named only when the gap sits within CAUSE_DB of one and the
window is not the whole of it: a window's amplitude correction
applied to a density (the window's noise bandwidth, so only
when the window is known and tapers), the one-sided doubling
left out or applied twice, and a density in g²/Hz read as
(m/s²)²/Hz or the other way.
unjudged
property
¶
Why there is no gap to judge, in words, or None when there is one: the record or the spectrum carries no finite mean square, or carries zero.
verdict
property
¶
The judgment in words: agree, the window's gap, a named scaling error, a gap to look for one behind, or no gap to judge and why.
Methods:¶
describe
¶
One line for a status bar: both rms, the gap and the verdict.
scale converts the rms from SI into unit.
Source code in src/visualdynamics/core/rms_check.py
Functions:¶
time_rms
¶
The rms of a record's samples: the square root of their mean square, with nothing removed.
samples is one array, or several (the captures of one channel),
pooled sample for sample, so a long capture weighs more than a
short one, as it does in the average. A sample that is not a finite
number is left out, the rule core.time_statistics reads a record
by, so the two give one rms for one record; rms_check counts them
in its notes. NaN when no sample is finite.
Source code in src/visualdynamics/core/rms_check.py
rms_check
¶
rms_check(frequencies: ArrayLike, values: ArrayLike, samples: ArrayLike | Sequence[ArrayLike], *, threshold_db: float = GAP_DB, framed_rms: float | None = None, window: Any = None, dof: str = '') -> RmsCheck
Check an autospectrum against the record it came from: its rms from the area under it beside the record's own.
The spectrum's rms is compliance.rms: every line times its bin's
width, summed and square-rooted, which on evenly spaced lines is
the sum of the lines times the spacing, exactly Parseval's total.
The record's is time_rms of samples, which should be the span
the spectrum's frames covered.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
frequencies
|
array_like
|
The spectrum's lines, in Hz, evenly spaced. |
required |
values
|
array_like
|
The one-sided density at each line, in the square of the record's unit per hertz. |
required |
samples
|
array_like or sequence of array_like
|
The record over the span the frames covered, or the captures of one channel, pooled. |
required |
threshold_db
|
float
|
The gap, in dB either way, beyond which the two disagree. |
`GAP_DB`
|
framed_rms
|
float
|
The frames' own mean square, windowed and leveled as they were
averaged, square-rooted, when the averaging is known
( |
None
|
window
|
str or Averaging
|
The window the spectrum was averaged with, which names the amplitude-correction error by its noise bandwidth. |
None
|
dof
|
str
|
The channel's name, carried on the result. |
''
|
Returns:
| Type | Description |
|---|---|
RmsCheck
|
Both rms, in the record's unit, the gap and the verdict. |
Raises:
| Type | Description |
|---|---|
ValueError
|
For a negative threshold, a spectrum on uneven lines or with fewer than two, or a record with no samples. |
Notes
Lines that are not finite or are below zero are left out of the
area (compliance.rms), and samples that are not finite out of the
record's rms (time_rms); the result's notes count both.
Source code in src/visualdynamics/core/rms_check.py
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 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 | |
matching_records
¶
matching_records(history: TimeHistory, dof: str, dimension: str, hint: str | None = None) -> list[int]
The records of history that are the channel a spectrum's record
is the autospectrum of (TimeHistory.channel_key): the same DOF,
measuring the quantity whose square per hertz dimension is
('acceleration' for 'acceleration**2/frequency'), and for a spectrum
whose units are not declared, the channel its hint names. Every
capture of the channel is returned, in order; none when there is no
such channel or more than one could be meant.
Source code in src/visualdynamics/core/rms_check.py
refusal
¶
refusal(spectrum: Psd, record: int = 0) -> str | None
Why record record of spectrum cannot be rms-checked, in words,
or None when it can: an autospectrum on evenly spaced lines. A
banded spectrum, one written at breakpoints and a cross spectrum
are refused, since none of them has an area that is a mean square
of one record.
Source code in src/visualdynamics/core/rms_check.py
check_record
¶
check_record(spectrum: Psd, history: TimeHistory, record: int = 0, *, averaging: Averaging | None = None, threshold_db: float = GAP_DB) -> RmsCheck
The rms check of record record of spectrum against the channel
of history it is the autospectrum of.
The frames are the ones a PSD of history averages
(TimeHistory._spectral_frame, under the averaging
TimeHistory._resolved_averaging settles on), so the check cannot
cut, level or window them differently, and the channel is the one
those frames are grouped by (TimeHistory.channel_key), every
capture of it pooled as the average pools them. The record's rms is
read over the span the frames cover, from its start to the end of
its last frame. A frame leveled before its window
(Averaging.detrend) has its mean or line taken out, so the span is
leveled the same way before its rms is taken, and the notes say so:
leveled frame by frame, the frames shed a little more of the lowest
lines than the span does. The frames' own mean square
(RmsCheck.framed_rms) is read when the averaging has the
spectrum's line spacing; an averaging with another is not the one
the spectrum was made with, and the notes say that too. A spectrum
whose lines do not run from 0 to half the sample rate holds only
part of the record's power, and says so (RmsCheck.coverage).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spectrum
|
Psd
|
The autospectrum, computed or imported. |
required |
history
|
TimeHistory
|
The record it was computed from. |
required |
record
|
int
|
Which record of |
0
|
averaging
|
Averaging
|
How the spectrum was averaged; |
None
|
threshold_db
|
float
|
The gap, in dB either way, beyond which the two disagree. |
`GAP_DB`
|
Returns:
| Type | Description |
|---|---|
RmsCheck
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
When the record cannot be checked ( |
Source code in src/visualdynamics/core/rms_check.py
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 | |