visualdynamics.core.breakpoints¶
breakpoints
¶
A random specification written by slope: the level a slope reaches, each segment's area, and the rms accumulated from the low end.
A random specification arrives as a breakpoint table, and many tables do not print a level at every breakpoint. They give a level, a slope in decibels per octave and the next frequency, and leave the level there to the reader. Between two breakpoints the specification is a straight line on log-log axes, a power law W = C f**n, and a decibel on a density is ten times the logarithm of a ratio, so a slope of N dB per octave is an exponent
n = N / (10 log10 2) = N / 3.0103
and the level it reaches at f2 from (f1, W1) is W1 (f2 / f1)**n. Plus
3 dB per octave is an exponent of 0.9966, minus 6 is -1.993; the
documents write 3 where they mean 3.01, and the difference in a level
is a third of a percent per octave. OCTAVE_DB is the exact 3.0103,
for a slope meant as an exponent of exactly one.
The rms of the specification is the square root of the area under it,
and a breakpoint table makes the area a sum of segments, each with a
closed form (core.compliance.log_log_areas, which every rms here is
computed by). For a segment from (f1, W1) to (f2, W2) with exponent n,
W1 f1 ((f2/f1)**(n+1) - 1) / (n + 1) for every n but -1
W1 f1 ln(f2/f1) when n is -1
The second line is the special case the first divides by zero at: an exponent of minus one is minus 3.0103 dB per octave (minus 10 dB per decade), common at the top of a profile. A segment typed at minus 3 dB per octave is an exponent of -0.9966 and takes the first line, which is continuous with the second.
The areas say where the rms comes from, which the plot does not: on log axes a slope at the top of the band looks short, and on linear ones it is often the largest area of all, because a hertz at 1,500 Hz counts as much as a hertz at 100 Hz. The running rms, the root of the area from the lowest breakpoint up to each frequency, shows the same thing as a curve: it climbs where the area is. Averaging a sloped segment's two end levels and multiplying by its width (the trapezoid) is right only at an exponent of one, and is the error a hand check that disagrees with these numbers usually holds.
level_at_slope, segment_slopes and levels_from_slopes convert
between the two ways a table is written. levels_with_slope and
levels_holding_slopes are the two edits a table written by slope
takes, each holding every slope it was not asked to change: they are
what core.author.SpecificationDraft.with_slope and with_level do
to each channel. segment_areas, running_rms and read_breakpoints
read a table, whichever way it was written. Every function takes
levels in any unit of density and returns areas in that unit times
hertz and rms in its square root; nothing here converts units.
References
The slope in decibels per octave as a power-law exponent, the level it
reaches, and the closed-form area under each segment, with its
logarithmic case at an exponent of minus one, are standard results of
random vibration practice; these are where they are set out, the
first with a worked example, which tests/test_breakpoint_slopes.py
repeats, and the second with a written spectrum whose printed overall
level they reproduce.
- Irvine, T. (2000). "Integration of the Power Spectral Density Function", Revision B. The area under a segment that is a straight line on log-log axes, in its two cases (its equation 11), the overall rms as the root of the summed areas, and, in its Appendix A, the level a slope in decibels per octave reaches over any frequency ratio (equation A-12).
- GSFC-STD-7000B (2021), General Environmental Verification Standard (GEVS). Table 2.4-4: a workmanship random vibration spectrum written as levels joined by slopes of plus and minus 3 dB per octave, with its overall level printed as 6.8 grms, which these closed forms give as 6.78.
Classes:
| Name | Description |
|---|---|
BreakpointReading |
A breakpoint table read: its slopes, its areas and its rms. |
Functions:
| Name | Description |
|---|---|
slope_exponent |
The power-law exponent of a slope in decibels per octave, |
slope_db |
The slope in decibels per octave of a power-law exponent, |
level_at_slope |
The level a slope reaches: from |
segment_slopes |
Each segment's slope in decibels per octave, one fewer than the |
levels_from_slopes |
The level at every breakpoint of a table written by slope: the |
levels_with_slope |
The levels after one segment's slope is typed: the segment's end |
levels_holding_slopes |
The levels after one breakpoint's level is typed in a table |
segment_areas |
The area under each segment of the table, one fewer than the |
running_rms |
The rms accumulated from the lowest breakpoint up to each of |
read_breakpoints |
Read a breakpoint table: each segment's slope in decibels per |
Classes¶
BreakpointReading
¶
Bases: NamedTuple
A breakpoint table read: its slopes, its areas and its rms.
Attributes:
frequencies: The breakpoints, in Hz.
levels: The level at each breakpoint, in the table's unit of
density.
slopes: Each segment's slope in decibels per octave.
areas: Each segment's area, in the levels' unit times hertz.
running: The rms accumulated from the first breakpoint to the
end of each segment, one per segment; the last is rms.
Attributes:
| Name | Type | Description |
|---|---|---|
total_area |
float
|
The whole table's area, the sum of the segments'. |
rms |
float
|
The table's rms, the square root of its whole area. |
shares |
ndarray
|
Each segment's share of the whole area, from 0 to 1: where |
Functions:¶
slope_exponent
¶
The power-law exponent of a slope in decibels per octave,
db_per_octave / OCTAVE_DB: 3 dB per octave is 0.9966.
Source code in src/visualdynamics/core/breakpoints.py
slope_db
¶
The slope in decibels per octave of a power-law exponent,
exponent * OCTAVE_DB: the inverse of slope_exponent.
level_at_slope
¶
level_at_slope(frequency: float, level: float, next_frequency: float, db_per_octave: float) -> float
The level a slope reaches: from level at frequency, at
db_per_octave, the level at next_frequency.
This is the unprinted level of a breakpoint table written as a
level, a slope and the next frequency. The next frequency may lie
below the first, in which case the slope is followed downward.
Raises ValueError for a frequency that is not positive or a level
that is not positive and finite.
Source code in src/visualdynamics/core/breakpoints.py
segment_slopes
¶
Each segment's slope in decibels per octave, one fewer than the
breakpoints: ten log ten of the level ratio over log two of the
frequency ratio. A flat segment is 0. Raises ValueError for a
table no specification could be written from.
Source code in src/visualdynamics/core/breakpoints.py
levels_from_slopes
¶
The level at every breakpoint of a table written by slope: the first breakpoint's level, and a slope in decibels per octave into each breakpoint after it.
The levels are accumulated in logarithms, so a long table does not
gather rounding from a running product. Raises ValueError when
there is not one slope per segment, or for frequencies or a level
no specification could hold.
Source code in src/visualdynamics/core/breakpoints.py
levels_with_slope
¶
levels_with_slope(frequencies: ArrayLike, levels: ArrayLike, segment: int, db_per_octave: float) -> ndarray
The levels after one segment's slope is typed: the segment's end level is the one the slope reaches from its start, and every segment after it keeps its slope, so the levels past it move by the same factor. The levels before the segment are unchanged.
Raises ValueError for a segment that is not one of the table's.
Source code in src/visualdynamics/core/breakpoints.py
levels_holding_slopes
¶
levels_holding_slopes(frequencies: ArrayLike, levels: ArrayLike, index: int, level: float) -> ndarray
The levels after one breakpoint's level is typed in a table written by slope: the slope into it changes, and every slope after it is held, so the levels past it move by the same factor. Typed at the first breakpoint, the whole table moves with it.
Raises ValueError for a breakpoint that is not one of the table's
or a level that is not positive and finite.
Source code in src/visualdynamics/core/breakpoints.py
segment_areas
¶
The area under each segment of the table, one fewer than the
breakpoints, by the closed form of core.compliance.log_log_areas
(the logarithmic case at an exponent of minus one included). The
unit is the levels' times hertz: g^2 for levels in g^2/Hz. Raises
ValueError for a table no specification could be written from.
Source code in src/visualdynamics/core/breakpoints.py
running_rms
¶
The rms accumulated from the lowest breakpoint up to each of at:
the square root of the area under the table between its first
breakpoint and that frequency.
With at omitted, the running rms at every breakpoint, the first
of which is zero and the last the table's rms. A frequency below
the first breakpoint reads zero, and one above the last reads the
whole table's rms, since outside the table nothing is specified.
Source code in src/visualdynamics/core/breakpoints.py
read_breakpoints
¶
read_breakpoints(frequencies: ArrayLike, levels: ArrayLike) -> BreakpointReading
Read a breakpoint table: each segment's slope in decibels per octave, its area by the closed form, and the rms accumulated from the low end at the end of each segment.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
frequencies
|
array_like
|
The breakpoints in Hz, positive and increasing, at least two. |
required |
levels
|
array_like
|
The level at each breakpoint, positive and finite, in any unit
of density. A table written by slope has its levels computed
first ( |
required |
Returns:
| Type | Description |
|---|---|
BreakpointReading
|
The slopes, the areas in the levels' unit times hertz, and the running rms in its square root. |
Raises:
| Type | Description |
|---|---|
ValueError
|
For a table no specification could be written from. |