visualdynamics.io.rattlesnake¶
rattlesnake
¶
Reader for Rattlesnake vibration controller output files (.nc4).
Rattlesnake writes its results to netCDF4 with a channel table that includes each channel's engineering unit (read in whatever case it was typed), so an import is unit-aware with no unit declaration needed. Values are converted to SI as they are read, and each record keeps the unit the file named. The layout, for file_version 3.x:
- root attributes: sample_rate, hardware, file_version and others
- time_data (response_channels, time_samples), in each channel's engineering unit
- a channels group: node_number, node_direction, unit, channel_type and the other per-channel fields
- one group per environment (for example 'Random'), which may hold a specification CPSD matrix (specification_frequency_lines, specification_cpsd_matrix_*) and its limits (specification_warning_matrix and specification_abort_matrix, each (2, lines, channels), lower first)
A run is saved to two files that share no data: streaming writes the time histories, and a separate save writes what the environment computed from them. Both are read here, and so is a saved system-ID package.
load returns a dict: 'channel_table' -> ChannelTable, and whichever
of these the file holds: 'time_data' -> TimeHistory (with
'time_data_2' and so on for later streams); 'full_cpsd is set), or a SineSweepSpecification or
TransientSpecification for a sine or transient environment;
'
A modal environment counts every enabled channel as a response and never excludes its references, so the drives appear among the responses and the saved matrix includes each drive against the drives. Those rows are identity and cross-talk by construction (|H| exactly 1 against itself, numerically zero against the others, coherence exactly 1), so they are dropped: they come from the arithmetic, not from a measurement, and would add a force-per-force axis to the plot.
A spectral file has no time data and, after Rattlesnake's own random save, no root attributes either, so the sample rate may be missing. The frequency axis then comes from the specification's lines, or with no specification the lines are numbered by index. The noise cross spectra a random save also writes are not read: they describe the measurement's noise floor and would double the number of objects for something rarely looked at.
The reader does not write .nc4 files. A .nc4 records a controller
run, including hardware settings and environments, that Visual
Dynamics does not hold, so a file written from here would describe a
test that never happened (see docs/export.md). The one exception adds
nothing of its own: save_window copies a run with its streams cut to
a time window, and every other attribute, dimension and variable as
the file has it.
Functions:
| Name | Description |
|---|---|
machine_memory |
The machine's physical memory in bytes, or 0 when it cannot be |
last_window |
The start time of a window holding the last |
window_name |
The file name for a copy of a run cut to a window: the run's own |
save_window |
Copy a run with its time data cut to a window, and nothing else |
stream_summary |
The size of each of a run's streams and the memory an import of |
stream_preview |
One channel's envelope over a whole stream, read in slabs. |
sniff |
Whether |
environment_kinds |
{environment name: kind} for the environments the file holds. |
run_kind |
The kind of test the file holds, as the file states it. |
project_type |
The Visual Dynamics project type this file is a run of, or None |
streamed_sysid_candidate |
Whether a streamed save looks like a system ID: exactly two |
load |
Everything a Rattlesnake |
Classes¶
Functions:¶
machine_memory
¶
The machine's physical memory in bytes, or 0 when it cannot be found.
This is the one query of the operating system this package makes,
used to tell whether a stream about to be imported would take a
large share of memory. POSIX systems are read through sysconf,
Windows through GlobalMemoryStatusEx.
Source code in src/visualdynamics/io/rattlesnake.py
last_window
¶
The start time of a window holding the last last seconds of a
run.
The import dialog's Last field and a script's last= both use
this function. A run seconds long is read from seconds - last
to its end, and a run no longer than last is read whole, which
the None result means. Asking for the last 100 s of a 28 s run is
not an error; it is the whole run. Raises ValueError unless last
is positive.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seconds
|
float
|
The instant of the run's last sample on its own clock. |
required |
last
|
float
|
How many seconds before the end the window opens; positive. |
required |
Returns:
| Type | Description |
|---|---|
float or None
|
The |
Source code in src/visualdynamics/io/rattlesnake.py
window_name
¶
The file name for a copy of a run cut to a window: the run's own
name with the window added, for example random_30-60s.nc4.
The copy's time starts at zero again and nothing in the file says
where the window began, so the name records it. An open start is
written as 0 and an open stop as end (random_30s-end.nc4).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str or PathLike
|
The run. |
required |
start
|
float or None
|
The window, in seconds on the run's time axis; None for the run's start or end. |
required |
stop
|
float or None
|
The window, in seconds on the run's time axis; None for the run's start or end. |
required |
Returns:
| Type | Description |
|---|---|
str
|
A path in the same folder as the run. |
Source code in src/visualdynamics/io/rattlesnake.py
save_window
¶
save_window(path: str | PathLike, target: str | PathLike, start: float | None = None, stop: float | None = None, progress: Callable[[int, int], None] | None = None) -> dict[str, int]
Copy a run with its time data cut to a window, and nothing else changed.
Every group, attribute, dimension and variable is written as the
file has it (the hardware settings, the channel fields, each
environment's control settings and specification) except the
streams and their time_samples dimensions. Each stream is cut to
the samples the window holds, the same samples an import of that
window reads. A stream the window misses is written with no
samples, as a spectral file's is. Nothing is added: the file has no
attribute for where the window began, so the copy's time starts at
zero again (window_name puts the window in the file name
instead). All channels are kept, because leaving one out would
mean rewriting the channel table, each environment's active
channels and its control indices.
Raises ValueError when target is the run itself, when the run has
no time data, when the window runs backward, or when it holds fewer
than two samples of every stream.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str or PathLike
|
The run, a Rattlesnake |
required |
target
|
str or PathLike
|
Where the copy goes; not the run itself. |
required |
start
|
float
|
The window, in seconds on the run's time axis, both ends included; the run's start and end when not given. |
None
|
stop
|
float
|
The window, in seconds on the run's time axis, both ends included; the run's start and end when not given. |
None
|
progress
|
callable
|
Called with |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
{stream variable: samples kept}. |
Source code in src/visualdynamics/io/rattlesnake.py
stream_summary
¶
The size of each of a run's streams and the memory an import of it would take, without reading the stream data.
The import dialog uses this to ask whether a stream is a large share of the machine's memory. It is read from the file's dimensions alone, so it is fast even on a 22 GB run.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str or PathLike
|
A Rattlesnake |
required |
Returns:
| Type | Description |
|---|---|
dict
|
'sample_rate'; 'channels', the table's coordinates in row
order; 'units', their units as the file spells them;
'streams', one dict per stream with 'key' (the name the
import gives it), 'variable', 'channels', 'samples',
'seconds' and 'bytes' (as float64, the size the import holds);
'memory', |
Source code in src/visualdynamics/io/rattlesnake.py
stream_preview
¶
stream_preview(path: str | PathLike, channel: int | str = 0, stream: str = 'time_data', points: int = PREVIEW_POINTS) -> dict[str, Any]
One channel's envelope over a whole stream, read in slabs.
This is the plot an import window is chosen from: it shows where
the run reaches level, where it stops, and any false start at the
front. Each of points buckets keeps its smallest and largest
sample (the same peak thinning the stage applies, done as the
channel is read), so the preview of a 22 GB run holds one slab at
a time in memory and returns a few thousand points. The file's
chunks run along one channel at a time, so reading one channel is
a sequential read.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str or PathLike
|
A Rattlesnake |
required |
channel
|
int or str
|
The channel's row in the table, or its coordinate ('101Z+'). |
0
|
stream
|
str
|
Which stream variable ('time_data', 'time_data_1', …). |
'time_data'
|
points
|
int
|
How many buckets to thin to. |
PREVIEW_POINTS
|
Returns:
| Type | Description |
|---|---|
dict
|
'times', the bucket centers in seconds on the run's time axis; 'low' and 'high', each bucket's smallest and largest value in the file's own unit, not converted, and NaN where a bucket holds only NaN; 'dof', 'unit' and 'dim' of the channel; and 'samples' and 'sample_rate' of the stream. |
Source code in src/visualdynamics/io/rattlesnake.py
sniff
¶
Whether path is a Rattlesnake .nc4 or .nc file this module
can read: a streamed run, a spectral save or a system-ID package.
Never raises; a file that cannot be opened is not one.
Source code in src/visualdynamics/io/rattlesnake.py
environment_kinds
¶
{environment name: kind} for the environments the file holds.
The kinds are 'random', 'transient', 'sine', 'time' and 'modal', read from the file's environment type codes, or from what each environment group holds when the file has no codes. The result is empty when the file identifies none, for example an nc4 put together by hand.
Source code in src/visualdynamics/io/rattlesnake.py
run_kind
¶
The kind of test the file holds, as the file states it.
'modal', 'random', 'transient', 'sine' or 'time' for a run of one kind; 'mixed' when more than one environment drove the article (a random run with a sine sweep, for example); None when the file does not say. An environment that only records ('time') does not make a run mixed.
Source code in src/visualdynamics/io/rattlesnake.py
project_type
¶
The Visual Dynamics project type this file is a run of, or None when there is no project type for that kind of run or the file does not say what kind it is.
A saved system-ID package is a 'System ID' project. A random run
with a sine sweep is a 'Random and Sine' project
(MIXED_PROJECTS), whose report covers both. Any other mixed run
takes the type of its first kind in MIXED_PRECEDENCE. Every
environment's specification is imported either way, so the type
only decides which workflow the tree shows first.
Source code in src/visualdynamics/io/rattlesnake.py
streamed_sysid_candidate
¶
Whether a streamed save looks like a system ID: exactly two streams, a quiet one and then a loud one (the ambient measurement and the driven excitation).
The file cannot answer this by itself, because a run whose stream
was stopped and restarted once has the same layout. So a True
result is a reason to ask the person, not to decide. The level
check keeps the question from being asked about every two-stream
file: a restarted run's two streams are at the same level, while a
system ID's differ by the whole test. The driven stream must be
more than 10 dB above the quiet one (standard deviation of the
first SNIFF_SAMPLES samples of each), which is well under any
real ambient-to-driven difference and well over a level change
within one run. Never raises; False for a file that cannot be read.
Source code in src/visualdynamics/io/rattlesnake.py
load
¶
load(path: str | PathLike, full_cpsd: bool = False, start: float | None = None, stop: float | None = None, channels: Iterable[int | str] | None = None, progress: Callable[[int, int], None] | None = None) -> dict[str, Any]
Everything a Rattlesnake .nc4 holds, keyed by the names the
tree shows.
The streamed time data, the channel table, and each environment's
specification, FRF, coherence and spectra; or a saved system-ID
package on its own. start, stop and channels import part of
the streams, for a long run that would not fit in memory whole
(the import dialog asks for them; a script passes them). The
window includes both ends, on the run's time axis, and the records
keep those times. A stream the window misses entirely is left out,
and each windowed record's comment says which part of which file
it is. A part of a stream is imported as one recording, so it is
never split into frames the way a spectral save's stack of
captures is.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str or PathLike
|
The file. |
required |
full_cpsd
|
bool
|
Import the cross terms of a random specification's CPSD matrix even when its off-diagonal holds only zeros. Cross terms that hold values are imported either way, and a pair the file never wrote (all NaN) never is. |
False
|
start
|
float
|
The window in seconds; either end open when omitted. |
None
|
stop
|
float
|
The window in seconds; either end open when omitted. |
None
|
channels
|
iterable of int or str
|
Which channels of the streams to import, by table row or by coordinate ('101Z+'). All of them when omitted. An environment's virtual responses are included only when every control channel they are computed from is selected. |
None
|
progress
|
callable
|
Called with |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
Objects by key: 'time_data' (and 'time_data_2', …),
'channel_table', and ' |
Source code in src/visualdynamics/io/rattlesnake.py
1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 | |