visualdynamics.core.stroke¶
stroke
¶
Whether a shock pulse fits on the shaker: its stroke, velocity and force against the shaker's shock ratings.
A shaker can deliver a pulse only if it can deliver three things at once: the force for the peak, the velocity the pulse leaves the table with, and the travel the whole event needs, compensation included. The three are spent by different parts of the pulse. The peak acceleration costs force (the moving mass times the peak). The duration costs stroke, since displacement grows with the peak times the duration squared. The velocity sits between them. So the check reads all three off the pulse and sets each against its rating.
The pulse is a record or a nominal one. compensated_half_sine builds
the nominal pulse a stroke is usually first estimated on: a half-sine
with a half-sine pre-pulse before it and a post-pulse after it, each at
a share of the peak (a fifth by default, COMPENSATION_SHARE) and
opposite in sign, each lasting long enough to carry half the main
pulse's velocity change back. The table then starts and ends at rest:
the pre-pulse takes it to minus half the velocity change, the main
pulse to plus half, and the post-pulse back to zero, so its peak
velocity is half the velocity change. At a fifth of the peak the whole
event lasts six durations; at a tenth, eleven.
read_stroke integrates the acceleration twice with nothing removed,
the cumulative trapezoid rule of filters.integrate called with
drift_corner=None, from rest at the record's first sample. It is
the raw path on purpose. The displacement of a compensated pulse is
content at a few hertz, exactly where the default 2 Hz drift high-pass
stops being transparent, and with it the 50 g, 11 ms pulse's stroke
reads about 4 % high and no longer starts and ends at rest. A stroke
estimate is integrated raw, and a record whose velocity does not come
back to rest is a record to fix before its stroke is believed.
The reading is the peak acceleration, the peak velocity, the velocity
change, and the displacement each way from rest with its peak to peak.
The travel, the velocity and the force are judged by the rule in
core.shaker, the one the replication fit judges by, and three
corrections are carried with it:
- The shaker body. The ratings are the armature's motion relative to the body, and a body on isolation mounts moves the other way by the ratio of the moving mass to its own, so the travel that reaches the stops, and the velocity the coil moves at, are the table's times one plus that ratio. The compensation is low in frequency, where the body moves most. Given the body mass with the moving mass, both are counted that way.
- The stops each way. The stroke is peak to peak, and the armature rests at the middle of it, held there by its suspension, so the stops are half the stroke away on each side. The symmetric arrangement above travels one way only, to its full peak to peak and back, so it can be inside the stroke peak to peak and still reach a stop. The stroke share is therefore the larger travel each way from center over half the stroke, what the stops see, and the peak to peak is reported as a number without a verdict. When the peak to peak fits and the share is over, the reading says so: centering the travel is the controller's compensation, an asymmetric pre- and post-pulse.
- The first check. The peak to peak of the nominal arrangement is
close to A T^2 / 2 for a half-sine of peak A and duration T, which in
the units shock is specified in is about 193 A T^2 inches with A in g
and T in seconds (
rule_stroke). The reading reports it beside the integrated value, computed for the half-sine of the record's own peak and velocity change, so on the nominal pulse the rule reads 0.16 % high (the same on every pulse, since the ratio is the arrangement's) and on any other pulse the difference is what its shape and its compensation are worth.
A controller that shapes its compensation for least displacement does better than the symmetric arrangement, sometimes by a useful margin, so the nominal reading is a first check: a pulse it passes with room fits, and one it puts near a rating sends the operator to the controller's own prediction and to a measurement.
References
The double integration and the compensated pulse are standard; these are where the compensation, and why the table must end at rest, are set out.
- Department of Defense (2019). MIL-STD-810H, Environmental Engineering Considerations and Laboratory Tests. Method 516.8, paragraph 2.3.2.3.2: a classical pulse on a vibration exciter compensated, what the compensation costs the pulse's spectrum, and the band that limits it; Figures 516.8-3 to 516.8-5: the acceleration before and after the pulse, where its compensation goes, held within a fifth of the peak over 2.5 durations either side.
- NASA-STD-7003A (2011), Pyroshock Test Criteria. Paragraph 4.4: a shock on a shaker changes velocity by nothing over the whole event, or the armature reaches its stops.
Classes:
| Name | Description |
|---|---|
StrokeReading |
One channel's stroke, velocity and force against the ratings |
Functions:
| Name | Description |
|---|---|
compensated_half_sine |
A half-sine with symmetric half-sine compensation, as a record. |
rule_stroke |
The half-sine rule's peak to peak, in m: |
read_stroke |
Integrate one acceleration channel twice, raw, and read it |
amount |
|
Classes¶
StrokeReading
dataclass
¶
StrokeReading(dof: str, sample_rate: float, start: float, acceleration: ndarray, velocity: ndarray, displacement: ndarray, rating: ShakerRating)
One channel's stroke, velocity and force against the ratings given.
The arrays are the acceleration, and the velocity and displacement
integrated from it raw, in SI (m/s^2, m/s and m), from rest at the
record's first sample. rating holds the shaker's shock ratings and
the masses, in SI, with None where none was given; a rating that is
None is not judged. Its stroke is the shaker's shock stroke, peak to
peak, the travel of the armature relative to the body.
Methods:
| Name | Description |
|---|---|
with_ratings |
This reading against other ratings, the arrays kept: the |
shares |
Each demand as a share of its rating, by |
to_the_stop |
The larger travel from center against the half stroke to its |
describe |
The reading in lines, the numbers in |
Attributes:
| Name | Type | Description |
|---|---|---|
time |
ndarray
|
Each sample's time on the record's clock, in seconds. |
duration |
float
|
How long the record lasts, first sample to last, in s. |
peak_acceleration |
float
|
The largest acceleration either way, in m/s^2. |
peak_velocity |
float
|
The table's largest velocity either way, in m/s. |
relative_velocity |
float
|
The armature's largest velocity against the body, in m/s: |
velocity_change |
float
|
The span from the lowest velocity to the highest, in m/s |
lowest |
float
|
The table's furthest travel below where it started, in m: |
highest |
float
|
The table's furthest travel above where it started, in m: |
peak_to_peak |
float
|
The table's displacement, highest less lowest, in m. |
counts_body |
bool
|
Whether the body's motion is counted: the body mass and the |
travel |
float
|
The armature's peak-to-peak travel relative to the body, in |
travel_down |
float
|
The relative travel below center, where the armature rests, |
travel_up |
float
|
The relative travel above center, where the armature rests, |
equivalent_duration |
float
|
The duration of the half-sine with this record's peak and |
rule |
float
|
The half-sine rule's peak to peak for this record's peak and |
force |
float | None
|
The force the coil must make, the moving mass times the peak |
fits |
bool | None
|
Whether every rating given holds the pulse; None when no |
fits_stroke |
bool | None
|
Whether the travel stays inside half the stroke each way from |
Attributes¶
peak_acceleration
property
¶
The largest acceleration either way, in m/s^2.
relative_velocity
property
¶
The armature's largest velocity against the body, in m/s:
peak_velocity with the body counted, what the velocity rating
is judged against.
velocity_change
property
¶
The span from the lowest velocity to the highest, in m/s
(core.shock_check.velocity_span): for a one-signed pulse with
compensation either side, the main pulse's change.
lowest
property
¶
The table's furthest travel below where it started, in m: zero or negative.
highest
property
¶
The table's furthest travel above where it started, in m: zero or positive.
counts_body
property
¶
Whether the body's motion is counted: the body mass and the moving mass were both given.
travel
property
¶
The armature's peak-to-peak travel relative to the body, in m: the table's peak to peak with the body counted. A number, not judged: the stops see the travel each way.
travel_down
property
¶
The relative travel below center, where the armature rests, in m, positive.
travel_up
property
¶
The relative travel above center, where the armature rests, in m, positive.
equivalent_duration
property
¶
The duration of the half-sine with this record's peak and velocity change, in s: πΔV / (2A).
On a half-sine it is the pulse's own duration; on any other shape it is the half-sine the rule beside the integration is computed for.
rule
property
¶
The half-sine rule's peak to peak for this record's peak and
equivalent_duration, in m: the first check beside the
integrated peak_to_peak (rule_stroke).
force
property
¶
The force the coil must make, the moving mass times the peak acceleration, in N; None without a moving mass.
fits
property
¶
Whether every rating given holds the pulse; None when no rating was given.
fits_stroke
property
¶
Whether the travel stays inside half the stroke each way from center, where the armature rests and the stops are half the stroke away; None without a stroke.
Methods:¶
with_ratings
¶
with_ratings(*, stroke: float | None = None, velocity: float | None = None, force: float | None = None, moving_mass: float | None = None, body_mass: float | None = None) -> StrokeReading
This reading against other ratings, the arrays kept: the
integration does not depend on the ratings, so a rating moved
in the panel does not integrate the record again. The ratings
are taken as read_stroke takes them, zero and None both
meaning none.
Source code in src/visualdynamics/core/stroke.py
shares
¶
Each demand as a share of its rating, by core.shaker's rule:
'stroke' (the larger travel each way from center over half the
stroke, so one is a stop), 'velocity' (counted against the body)
and 'force'. None where the rating, or for the force the moving
mass, was not given.
Source code in src/visualdynamics/core/stroke.py
to_the_stop
¶
to_the_stop(unit_system: UnitSystem | None = None) -> str | None
The larger travel from center against the half stroke to its stop, in words, such as 'one-sided travel 1.46 in against 1.25 in to the stop'; None without a stroke.
Source code in src/visualdynamics/core/stroke.py
describe
¶
describe(unit_system: UnitSystem | None = None) -> list[str]
The reading in lines, the numbers in unit_system
(units.DEFAULT_SYSTEM when omitted): the travel to the stop,
the velocity and the force each against its rating, the
displacement each way, and the peak to peak beside the half-sine
rule.
Source code in src/visualdynamics/core/stroke.py
Functions:¶
compensated_half_sine
¶
compensated_half_sine(peak: float, duration: float, sample_rate: float, *, share: float = COMPENSATION_SHARE, response_dof: str = '1Z+', unit: str | None = None) -> TimeHistory
A half-sine with symmetric half-sine compensation, as a record.
pulse = compensated_half_sine(50.0, 0.011, 102400.0, unit='g')
The main pulse, of peak peak and duration duration, sits between
a pre-pulse and a post-pulse of the opposite sign, each at share
times the peak and each lasting duration / (2 * share), so each
carries back half the main pulse's area. The record opens at the
pre-pulse's first sample and closes at the post-pulse's last, and
the table starts and ends it at rest: its net velocity change and
its net displacement are both zero.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
peak
|
float
|
The main pulse's peak, in |
required |
duration
|
float
|
The main pulse's duration, in seconds. |
required |
sample_rate
|
float
|
Samples per second. |
required |
share
|
float
|
The compensation pulses' height as a share of the peak, between zero and one. |
`COMPENSATION_SHARE`
|
response_dof
|
str
|
The channel the record is at. |
'1Z+'
|
unit
|
str
|
The unit |
None
|
Returns:
| Type | Description |
|---|---|
TimeHistory
|
One acceleration channel, stored in SI, on a clock that starts at zero. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the peak, the duration or the sample rate is not positive, the share is not between zero and one, or the main pulse is shorter than four samples. |
Source code in src/visualdynamics/core/stroke.py
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | |
rule_stroke
¶
The half-sine rule's peak to peak, in m: RULE times A T^2.
peak is in m/s^2 and duration in seconds. In inches with the
peak in g this is 193 A T^2. It reads the peak to peak of a
half-sine compensated symmetrically at a fifth of its peak 0.16 %
high, and it is the relation to keep in the head:
double the peak and the stroke doubles, double the duration and it
quadruples.
Source code in src/visualdynamics/core/stroke.py
read_stroke
¶
read_stroke(history: TimeHistory, channel: int | str | None = None, *, stroke: float | None = None, velocity: float | None = None, force: float | None = None, moving_mass: float | None = None, body_mass: float | None = None) -> StrokeReading
Integrate one acceleration channel twice, raw, and read it against the shaker's shock ratings.
reading = read_stroke(compensated_half_sine(50.0, 0.011, 102400.0,
unit='g'),
stroke=0.0635, velocity=1.778,
moving_mass=45.4, body_mass=1361.0)
The record is integrated from rest at its first sample with nothing
removed (filters.integrate with drift_corner=None; the module
docstring says why raw), over its whole length, so a record of one
event should open before the event and close after it. Every rating
is optional, and one not given, or given as zero, is reported
without a verdict. The ratings are judged by core.shaker's rule.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
history
|
TimeHistory
|
The shock record, or a nominal pulse from
|
required |
channel
|
int or str
|
The record's index or its DOF; its first acceleration channel when omitted. Only a channel whose unit is declared counts. |
None
|
stroke
|
float
|
The shaker's shock stroke, peak to peak, in m: the armature's travel relative to the body. |
None
|
velocity
|
float
|
The shaker's shock velocity, in m/s. |
None
|
force
|
float
|
The shaker's shock force, in N. |
None
|
moving_mass
|
float
|
Everything that moves, in kg; with |
None
|
body_mass
|
float
|
The shaker body's mass, in kg; with |
None
|
Returns:
| Type | Description |
|---|---|
StrokeReading
|
The arrays, the peaks, the travel each way, the half-sine rule and the shares of each rating. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the channel is not an acceleration channel of the record, the record has none, the channel holds a sample that is not finite, or a rating or mass is negative or not finite. |
Source code in src/visualdynamics/core/stroke.py
amount
¶
amount(value: float, dimension: str, unit_system: UnitSystem) -> str
value, in SI, as a number and a unit in unit_system: three
significant figures, whole numbers from a thousand up with a
thousands separator, then the system's label for dimension. The
stroke check and the sine profile both write amounts this way, so a
value reads the same in each.