Test API

class pydysp.test.Test(name, description=None, source_file=None, timestamp=None, channels=<factory>, tags=<factory>, meta=<factory>)[source]

Bases: object

Container for an experiment composed of multiple time-history channels.

The Test object stores an ordered list of Channel instances together with test-level metadata (name, description, source file, timestamp, tags, and arbitrary meta). It provides helpers for selecting channels, batch processing (drift/filter/baseline/trim), pairwise spectral analyses, simple modal identification glue, plotting, and common I/O routines (MAT/CSV).

Parameters:
  • name (str) – Human-readable name for the test.

  • description (str, optional) – Longer description of the test.

  • source_file (str, optional) – Path or identifier of the primary data file used to build this test.

  • timestamp (str, optional) – String representation of the test date/time.

  • channels (list of Channel, optional) – Ordered list of Channel objects belonging to this test.

  • tags (set of str, optional) – Free-form tags for grouping and filtering tests.

  • meta (dict, optional) – Free-form metadata dictionary.

name: str
description: str | None = None
source_file: str | None = None
timestamp: str | None = None
channels: List[Channel]
tags: set[str]
meta: Dict[str, Any]
iter_channels(selector=None, tags=None, require_all_tags=False)[source]

Iterate over channels selected by index/name and optional tags.

Parameters:
  • selector (ChannelSelector, optional) –

    How to pick the initial set of channels:

    • None (default) : all channels.

    • int : single channel by index.

    • str : single channel by name (via __getitem__).

    • Channel : that channel (if it belongs to this test).

    • slice : slice of the channels list.

    • Sequence[…] : sequence of any of the above.

  • tags (iterable of str, optional) – If provided, only channels whose ch.tags intersect (or contain) these will be yielded.

  • require_all_tags (bool, optional) –

    Tag matching rule:

    • False (default) : keep channel if it has any of the requested tags.

    • True : keep channel only if it has all requested tags.

Yields:

Channel – Channels matching the selector and tag conditions.

Raises:
  • TypeError – If selector has an unsupported type.

  • ValueError – If a Channel passed in selector does not belong to this Test.

Return type:

Iterable[Channel]

channel_names()[source]

Return a list of preferred channel names for this test.

For each channel the priority is:

  • name_user

  • name_input

  • fallback: "ch{index}" (e.g. "ch0", "ch1", …)

Returns:

List of channel names in the same order as self.channels.

Return type:

list of str

property channel: Test

Convenience view over this test’s channels.

This property allows access patterns such as:

test.channel[3]       # 4th Channel (by index)
test.channel["Acc1"]  # Channel with matching name_input/name_user

The underlying list is still available as test.channels.

property n_channels: int

Return the number of channels in the test.

Returns:

Number of channels.

Return type:

int

property n_timesteps: int

Return the number of timesteps (samples) per channel.

Returns:

Number of time samples in each channel.

Return type:

int

Raises:

ValueError – If channels have differing numbers of samples.

property shape: tuple[int, int]

Return the (n_channels, n_timesteps) shape of this test.

Returns:

Tuple (n_channels, n_timesteps).

Return type:

tuple of int

property duration: float

Return the total duration of the test in seconds.

Returns:

Total duration of the test.

Return type:

float

Raises:

ValueError – If channels have inconsistent durations.

property dt: float

Return the sampling interval of the test in seconds.

Returns:

Sampling interval dt in seconds.

Return type:

float

Raises:

ValueError – If the test has no channels or if channels have inconsistent dt values.

info()[source]

Return a human-readable summary of this test and its channels.

The summary includes basic test-level metadata, sampling information, and a small table of channel-level fields.

Returns:

Multi-line string summary (not printed automatically).

Return type:

str

classmethod from_channels(name, channels, description=None, source_file=None, timestamp=None, tags=None, meta=None)[source]

Construct a test directly from an existing sequence of channels.

Parameters:
  • name (str) – Human-readable name for this test (e.g. "Test 07").

  • channels (sequence of Channel) – Sequence of Channel instances to include in the test.

  • description (str, optional) – Description of the experiment.

  • source_file (str, optional) – Path or identifier of the original data file.

  • timestamp (str, optional) – Timestamp string for the experiment.

  • tags (iterable of str, optional) – Iterable of test-level tags (e.g. {"sofsi", "equals"}).

  • meta (mapping, optional) – Additional metadata (e.g. {"specimen_id": "ABC123"}).

Returns:

New Test instance.

Return type:

Test

Notes

This is a thin convenience wrapper around the dataclass constructor: it normalises channels, tags and meta into the expected container types and lets __post_init__ do the remaining validation.

classmethod from_sofsi_mat(filename, name=None, description=None, tags=None, meta=None)[source]

Construct a test from a SoFSI-style MATLAB .mat file.

Expected format

Required

Channel_1_Data : 1D time vector (s) Channel_i_Data : 1D data arrays, i >= 2

Optional

File_Header : struct with any subset of:

NumberOfChannels, NumberOfSamplesPerChannel,
SampleFrequency, Date, Comment,
NumberOfSamplesPerBlock, ...

Channel_i_Header : structs with fields:

SignalName, Unit, MaxLevel, Correction, ...

Header fields are used only for metadata; missing fields are ignored.

param filename:

Path to the MAT file.

type filename:

str

param name:

Test name. If not given, the stem of filename is used.

type name:

str, optional

param description:

Description of the test. If not given, defaults to name.

type description:

str, optional

param tags:

Iterable of test-level tags (e.g. {"demo"}).

type tags:

iterable of str, optional

param meta:

Mapping used to initialise Test.meta (e.g. {"specimen": "ABC"}).

type meta:

mapping, optional

returns:

New Test instance built from the MAT file.

rtype:

Test

raises FileNotFoundError:

If filename cannot be found.

raises KeyError:

If the expected time channel "Channel_1_Data" is missing.

raises ValueError:

If time or data arrays have incompatible shapes.

Parameters:
  • filename (str)

  • name (str | None)

  • description (str | None)

  • tags (Iterable[str] | None)

  • meta (Mapping[str, Any] | None)

Return type:

Test

classmethod from_equals_mat(filename, name=None, description=None, tags=None, meta=None)[source]

Construct a test from an EQUALS-style MATLAB .mat file.

Expected format

Required

t : 1D numeric time vector (s) output : 2D numeric array, shape (n_samples, n_channels)

Optional

Testdate, Time, Frequency, Points, No_Channels, File_name, Buffer_Size, sampling, Filter, P_ref, …

Header fields are used only for metadata; missing fields are ignored.

param filename:

Path to the MAT file.

type filename:

str

param name:

Test name. If not given, the stem of filename is used.

type name:

str, optional

param description:

Description of the test. If not given, defaults to name.

type description:

str, optional

param tags:

Iterable of test-level tags (e.g. {"demo"}).

type tags:

iterable of str, optional

param meta:

Mapping to initialise Test.meta with (e.g. {"specimen": "ABC"}).

type meta:

mapping, optional

returns:

New Test instance built from the MAT file.

rtype:

Test

raises FileNotFoundError:

If filename cannot be found.

raises KeyError:

If required variables "t" or "output" are missing.

raises ValueError:

If inputs have incompatible shapes.

Parameters:
  • filename (str)

  • name (str | None)

  • description (str | None)

  • tags (Iterable[str] | None)

  • meta (Mapping[str, Any] | None)

Return type:

Test

classmethod from_csv(filename, name=None, description=None, tags=None, meta=None)[source]

Construct a test from a CSV file in wide format.

Expected format

  • First row is a header.

  • First column is time (header "Time").

  • Remaining columns are channels.

  • All values are numeric.

param filename:

Path to the CSV file.

type filename:

str

param name:

Test name. If not given, the stem of filename is used.

type name:

str, optional

param description:

Description of the test. If not given, defaults to name.

type description:

str, optional

param tags:

Iterable of test-level tags (e.g. {"csv", "demo"}).

type tags:

iterable of str, optional

param meta:

Mapping used to initialise Test.meta with (e.g. {"specimen": "ABC"}).

type meta:

mapping, optional

returns:

New Test instance built from the CSV file.

rtype:

Test

raises ValueError:

If the header is missing or the required time column is not present.

Parameters:
  • filename (str)

  • name (str | None)

  • description (str | None)

  • tags (Iterable[str] | None)

  • meta (Mapping[str, Any] | None)

Return type:

Test

to_csv(filename, selector=None, include_axis_labels=True, overwrite=True)[source]

Export selected channels to a CSV file (wide format).

The output has the form:

Time, Ch1, Ch2, ...
Parameters:
  • filename (str) – Output CSV file path.

  • selector (ChannelSelector, optional) – Channels to export (index, name, list, slice, etc.). If None (default), all channels are exported.

  • include_axis_labels (bool, optional) – If True (default), use channel.label_axis (preferred), channel.name_user or channel.name_input as column names. Otherwise fallback to "Ch1", "Ch2", …

  • overwrite (bool, optional) – If False and the file already exists, a FileExistsError is raised.

Raises:
  • FileExistsError – If overwrite is False and the file exists.

  • ValueError – If no channels are selected or if selected channels do not share the same time vector.

Return type:

None

channel_info_to_csv(filename, overwrite=True)[source]

Export channel metadata to CSV (one row per channel).

Columns are written only if they contain non-identical data across channels, to avoid redundant storage.

Notes

The column "idx" (channel index) is always included.

Parameters:
  • filename (str) – Output CSV file path.

  • overwrite (bool, optional) – If False and the file exists, a FileExistsError is raised. Default is True.

Return type:

None

with_channel_info_from_csv(filename)[source]

Return a new test with channel metadata updated from CSV.

Header matching is flexible (underscores/spaces and case are ignored), and rows are matched to channels as follows:

  1. If an idx column is present, it is used first.

  2. Otherwise, matching is attempted against name_user or name_input (case-insensitive).

Any row that cannot be matched raises a ValueError. Only metadata is updated; data and processing parameters are left unchanged.

Parameters:

filename (str) – Path to the CSV file produced e.g. by channel_info_to_csv.

Returns:

New Test instance with updated channel metadata.

Return type:

Test

Raises:
  • FileNotFoundError – If filename does not exist.

  • ValueError – If the CSV is empty, has no recognised columns, or a row cannot be matched to any channel.

add_channel(ch)[source]

Return a new test with a channel appended to the channel list.

The original Test instance is left unchanged.

Parameters:

ch (Channel) – Channel instance to append.

Returns:

New Test instance with one extra channel.

Return type:

Test

Raises:

TypeError – If ch is not a Channel instance.

drop_channels(selector)[source]

Return a new test with the selected channels removed.

Parameters:

selector (ChannelSelector) –

Channels to remove. Can be anything accepted by iter_channels(), e.g.:

  • int : index.

  • str : name (name_user / name_input).

  • Channel : that channel.

  • slice : slice of the channels list.

  • Sequence[…] : list of the above.

Returns:

New Test instance with selected channels removed.

Return type:

Test

Raises:

ValueError – If selector is None.

drift_corrected(selector=None, **override)[source]

Return a new test with drift-corrected versions of selected channels.

This applies Channel.drift_corrected() to the selected channels and leaves the others unchanged.

Parameters:
  • selector (ChannelSelector, optional) – Channels to process (index, name, Channel, list, slice…). If None (default), all channels are processed.

  • **override – Keyword arguments forwarded to Channel.drift_corrected(), e.g. points=100. These override stored drift parameters.

Returns:

New Test instance with updated channels.

Return type:

Test

Raises:

ValueError – If no channels are selected for drift correction.

filtered(selector=None, **override)[source]

Return a new test with filtered versions of selected channels.

This applies Channel.filtered() to the selected channels.

Parameters:
  • selector (ChannelSelector, optional) – Channels to process (index, name, Channel, list, slice…). If None (default), all channels are processed.

  • **override – Keyword arguments forwarded to Channel.filtered(), e.g. btype="highpass", fc=0.5, order=4. These override the stored filter parameters.

Returns:

New Test instance with updated channels.

Return type:

Test

Raises:

ValueError – If no channels are selected for filtering.

baseline_corrected(selector=None, **override)[source]

Return a new test with baseline-corrected selected channels.

This applies Channel.baseline_corrected() to the selected channels.

Parameters:
  • selector (ChannelSelector, optional) – Channels to process (index, name, Channel, list, slice…). If None (default), all channels are processed.

  • **override – Keyword arguments forwarded to Channel.baseline_corrected(), e.g. type="linear". These override stored baseline parameters.

Returns:

New Test instance with updated channels.

Return type:

Test

Raises:

ValueError – If no channels are selected for baseline correction.

trimmed(selector=None, **override)[source]

Return a new test with manually trimmed selected channels.

This is the generic manual-window trimming interface based on explicit t_start and t_end (in seconds), using Channel.trimmed().

Parameters:
  • selector (ChannelSelector, optional) – Channels to process (index, name, Channel, list, slice…). If None (default), all channels are processed.

  • **override – Keyword arguments forwarded to Channel.trimmed(), typically including t_start and t_end (in seconds).

Returns:

New Test instance with updated channels.

Return type:

Test

Raises:

ValueError – If no channels are selected for trimming.

trimmed_by_threshold(selector=None, ref=None, threshold=0.01, use_abs=True, buffer_before=0.0, buffer_after=0.0, processed=True, use_cache=True)[source]

Return a new test with threshold-based aligned trimming.

A single time window is derived from one reference channel using Channel.trim_by_threshold(), and then applied to all selected channels.

Strategy

  • Choose a reference channel:

    • If ref is given, use that (must belong to this test and be part of the selected set).

    • Otherwise, use the first selected channel.

  • On the reference channel, compute a threshold-based window via Channel.trim_by_threshold().

  • Extract t_start and t_end from the reference channel’s trim_params.

  • Apply Channel.trimmed() with this window to all selected channels.

param selector:

Channels to trim (index, name, Channel, list, slice…). If None (default), all channels are trimmed.

type selector:

ChannelSelector, optional

param ref:

Reference channel used to define the trim window. Can be an index, name, or Channel instance. If None, the first selected channel is used. The reference must be part of the selected set.

type ref:

ChannelKey, optional

param threshold:

Threshold value in signal units used to detect when the motion starts/stops (see Channel.trim_by_threshold()).

type threshold:

float, optional

param use_abs:

If True (default), thresholding is applied to abs(signal). If False, thresholding is applied to the raw signal.

type use_abs:

bool, optional

param buffer_before:

Time buffer (in seconds) to extend the window before the detected start time.

type buffer_before:

float, optional

param buffer_after:

Time buffer (in seconds) to extend the window after the detected end time.

type buffer_after:

float, optional

param processed:

Whether to use processed data for the reference channel when computing the window. Default is True.

type processed:

bool, optional

param use_cache:

Whether to use the channel-level processing cache for the reference channel. Default is True.

type use_cache:

bool, optional

returns:

New Test instance with aligned trimming across channels.

rtype:

Test

raises ValueError:

If no channels are selected, if the reference channel is not part of this test, or if it is not in the selected set.

Parameters:
  • selector (int | str | Channel | Sequence[int | str | Channel] | slice | None)

  • ref (int | str | Channel | None)

  • threshold (float)

  • use_abs (bool)

  • buffer_before (float)

  • buffer_after (float)

  • processed (bool)

  • use_cache (bool)

Return type:

Test

trimmed_by_fraction_of_peak(selector=None, ref=None, fraction=0.05, use_abs=True, buffer_before=0.0, buffer_after=0.0, processed=True, use_cache=True)[source]

Return a new test with fraction-of-peak aligned trimming.

A single time window is derived from a fraction-of-peak criterion on one reference channel using Channel.trim_by_fraction_of_peak(), and then applied to all selected channels.

Strategy

  • Choose a reference channel (as in trimmed_by_threshold()).

  • On the reference channel, compute the window via Channel.trim_by_fraction_of_peak().

  • Extract t_start and t_end from the reference channel’s trim_params.

  • Apply Channel.trimmed() with this window to all selected channels.

param selector:

Channels to trim (index, name, Channel, list, slice…). If None (default), all channels are trimmed.

type selector:

ChannelSelector, optional

param ref:

Reference channel used to define the trim window. Can be an index, name, or Channel instance. If None, the first selected channel is used. The reference must be part of the selected set.

type ref:

ChannelKey, optional

param fraction:

Fraction of the peak amplitude in (0, 1] used to define the effective-motion window (see Channel.trim_by_fraction_of_peak()).

type fraction:

float, optional

param use_abs:

If True (default), use absolute amplitude when computing the peak.

type use_abs:

bool, optional

param buffer_before:

Time buffer (in seconds) to extend the window before the detected start time.

type buffer_before:

float, optional

param buffer_after:

Time buffer (in seconds) to extend the window after the detected end time.

type buffer_after:

float, optional

param processed:

Whether to use processed data for the reference channel when computing the window.

type processed:

bool, optional

param use_cache:

Whether to use the channel-level processing cache for the reference channel.

type use_cache:

bool, optional

returns:

New Test instance with aligned trimming across channels.

rtype:

Test

raises ValueError:

If no channels are selected, if the reference channel is not part of this test, or if it is not in the selected set.

Parameters:
  • selector (int | str | Channel | Sequence[int | str | Channel] | slice | None)

  • ref (int | str | Channel | None)

  • fraction (float)

  • use_abs (bool)

  • buffer_before (float)

  • buffer_after (float)

  • processed (bool)

  • use_cache (bool)

Return type:

Test

trimmed_by_arias(selector=None, ref=None, lower=0.05, upper=0.95, g=9.81, buffer_before=0.0, buffer_after=0.0, processed=True, use_cache=True)[source]

Return a new test with Arias-intensity-based aligned trimming.

A single significant-duration window is derived from one reference channel using Channel.trim_by_arias(), and then applied to all selected channels.

Strategy

  • Choose a reference channel (as in trimmed_by_threshold()).

  • On the reference channel, compute the Arias-based window via

    Channel.trim_by_arias().

  • Extract t_start and t_end from the reference channel’s trim_params.

  • Apply Channel.trimmed() with this window to all selected channels.

param selector:

Channels to trim (index, name, Channel, list, slice…). If None (default), all channels are trimmed.

type selector:

ChannelSelector, optional

param ref:

Reference channel used to define the trim window. Can be an index, name, or Channel instance. If None, the first selected channel is used. The reference must be part of the selected set.

type ref:

ChannelKey, optional

param lower:

Lower fraction of Arias intensity in [0, 1] that defines the start of the significant-duration window (typically 0.05).

type lower:

float, optional

param upper:

Upper fraction of Arias intensity in [0, 1] that defines the end of the significant-duration window (typically 0.95).

type upper:

float, optional

param g:

Gravitational acceleration in m/s² used for Arias intensity.

type g:

float, optional

param buffer_before:

Time buffer (in seconds) to extend the window before the detected lower time.

type buffer_before:

float, optional

param buffer_after:

Time buffer (in seconds) to extend the window after the detected upper time.

type buffer_after:

float, optional

param processed:

Whether to use processed data for the reference channel when computing the window.

type processed:

bool, optional

param use_cache:

Whether to use the channel-level processing cache for the reference channel.

type use_cache:

bool, optional

returns:

New Test instance with aligned trimming across channels.

rtype:

Test

raises ValueError:

If no channels are selected, if the reference channel is not part of this test, or if it is not in the selected set.

Parameters:
  • selector (int | str | Channel | Sequence[int | str | Channel] | slice | None)

  • ref (int | str | Channel | None)

  • lower (float)

  • upper (float)

  • g (float)

  • buffer_before (float)

  • buffer_after (float)

  • processed (bool)

  • use_cache (bool)

Return type:

Test

cross_spectrum(x, y, processed=True, use_cache=True, **kwargs)[source]

Compute the cross power spectral density (CPSD) between two channels.

The CPSD is computed using scipy.signal.csd().

Parameters:
  • x (ChannelKey) – Input (excitation) channel key (index, name or Channel).

  • y (ChannelKey) – Output (response) channel key (index, name or Channel).

  • processed (bool, optional) – If True (default), use processed data from each channel.

  • use_cache (bool, optional) – If True (default), use the channel-level processing cache.

  • **kwargs – Additional keyword arguments forwarded to scipy.signal.csd(), e.g. nperseg, window, noverlap. If nperseg is not given, a MATLAB-like default of min(256, n) is used.

Returns:

  • f (np.ndarray) – Frequency array in Hz.

  • Pxy (np.ndarray) – Complex cross-spectrum \(P_{xy}(f)\).

Raises:

ValueError – If the channels are empty, have different lengths, or have inconsistent or non-positive dt values.

Return type:

tuple[ndarray, ndarray]

transfer_function(x, y, kind='H1', processed=True, use_cache=True, **kwargs)[source]

Estimate the frequency-domain transfer function between two channels.

Cross- and auto-spectra are computed with scipy.signal.csd(). Two standard estimators are supported:

  • H1: H1(f) = G_yx(f) / G_xx(f), preferred when the input is noisy.

  • H2: H2(f) = G_yy(f) / G_yx(f), preferred when the output is noisy.

Here, G_yx is the cross-spectrum between output y and input x, and G_xx / G_yy are the auto-spectra of input and output.

Parameters:
  • x (ChannelKey) – Input (excitation) channel key (index, name or Channel).

  • y (ChannelKey) – Output (response) channel key (index, name or Channel).

  • kind ({"H1", "H2"}, optional) – Type of transfer-function estimator (default "H1").

  • processed (bool, optional) – If True (default), use processed data from each channel.

  • use_cache (bool, optional) – If True (default), use the channel-level processing cache.

  • **kwargs – Additional keyword arguments forwarded to scipy.signal.csd(), e.g. nperseg, window, noverlap. If nperseg is not given, a MATLAB-like default of min(256, n) is used.

Returns:

  • f (np.ndarray) – Frequency array in Hz.

  • H (np.ndarray) – Complex transfer function values \(H(f)\).

Raises:

ValueError – If the channels are empty, have different lengths, or have inconsistent or non-positive dt values, or if kind is not one of "H1" or "H2".

Return type:

tuple[ndarray, ndarray]

plot_transfer_function(x, y, kind='H1', processed=True, use_cache=True, phase=False, fmax=None, ax=None, tf_kwargs=None, label=None, **plot_kwargs)[source]

Plot the magnitude (and optionally phase) of the transfer function.

This is a convenience wrapper around transfer_function():

  • Computes H1 or H2 transfer function between input x and output y.

  • Plots the linear magnitude |H(f)| versus frequency on a logarithmic x-axis.

  • Optionally overlays the phase angle in degrees on a secondary y-axis.

Parameters:
  • x (ChannelKey) – Input (excitation) channel key (index, name or Channel).

  • y (ChannelKey) – Output (response) channel key (index, name or Channel).

  • kind ({"H1", "H2"}, optional) – Transfer function estimator (default "H1").

  • processed (bool, optional) – If True (default), use processed data from each channel.

  • use_cache (bool, optional) – If True (default), use the channel-level processing cache.

  • phase (bool, optional) – If True, also plot the phase angle (in degrees) on a secondary y-axis.

  • fmax (float or None, optional) – Optional upper frequency limit in Hz for plotting. If None, the full available frequency range is plotted.

  • ax (matplotlib.axes.Axes or None, optional) – Axes to plot on. If None, a new figure and axes are created.

  • tf_kwargs (mapping or None, optional) – Additional keyword arguments forwarded to transfer_function() and ultimately scipy.signal.csd(), e.g. nperseg, window, noverlap.

  • label (str or None, optional) – Label for the magnitude curve (for legends). If None, a default label based on the channel names is used.

  • **plot_kwargs – Additional keyword arguments forwarded to Axes.semilogx() (e.g. linestyle, linewidth).

Returns:

Axes with the plotted transfer function magnitude (and, optionally, phase).

Return type:

matplotlib.axes.Axes

time_delay(x, y, processed=True, use_cache=True)[source]

Estimate the time delay between two channels using cross-correlation.

A positive delay means that the output y lags the input x, based on the lag at which the cross-correlation between y and x is maximised.

Parameters:
  • x (ChannelKey) – Input (excitation) channel key (index, name or Channel).

  • y (ChannelKey) – Output (response) channel key (index, name or Channel).

  • processed (bool, optional) – If True (default), use processed data from each channel.

  • use_cache (bool, optional) – If True (default), use the channel-level processing cache.

Returns:

Estimated time delay in seconds (positive if y lags x).

Return type:

float

Raises:

ValueError – If the channels are empty, have different lengths, or have inconsistent or non-positive dt values.

ema_model(input, outputs, kind='H1', processed=True, use_cache=True, **model_kwargs)[source]

Build and return an sdypy.EMA.Model for experimental modal analysis.

This method computes frequency-response functions (FRFs) between one input channel and multiple output channels using transfer_function(), and then constructs an sdypy.EMA.Model instance using **model_kwargs.

The returned object provides pole estimation, stabilisation charts, modal parameter extraction and FRF reconstruction.

Parameters:
  • input (ChannelKey) – Input (excitation) channel.

  • outputs (ChannelSelector) – Output (response) channels (single selector or sequence).

  • kind ({"H1", "H2"}, optional) – Transfer function estimator (default "H1").

  • processed (bool, optional) – Use processed channel data (default True).

  • use_cache (bool, optional) – Use channel-level cache (default True).

  • **model_kwargs

    Additional keyword arguments passed directly to sdypy.EMA.Model. Typical options include:

    • lower : lower frequency for pole estimation.

    • upper : upper frequency for pole estimation.

    • pol_order_high : highest model order for LSCF.

    • driving_point : index of driving FRF.

    • frf_type : "accelerance", "mobility", "receptance", etc.

Returns:

Modal analysis model from the sdypy.EMA package.

Return type:

sdypy.EMA.Model

Raises:
  • ImportError – If the optional dependency sdypy is not installed.

  • ValueError – If no output channels are selected or if FRFs do not share identical frequency grids.

Examples

Typical usage:

model = test.ema_model(input="Shaker", outputs=[...], lower=1.0, upper=50.0)

# 1) Get poles (LSCF)
model.get_poles()

# 2) Select stable poles (interactive or automatic)
model.select_poles()
# or
model.select_closest_poles([f1, f2, ...])

# 3) Print modal data (natural frequencies, damping, mode shapes)
model.print_modal_data()
# or
print(model.nat_freq)
print(model.nat_xi)
print(model.phi)

# 4) Reconstruct FRFs and modal constants
frf_rec, modal_const = model.get_constants()
plot_grid(layout=None, plot_type='timehistory', sharex=True, sharey=True, title_suffix=None, make_caption=False, **kwargs)[source]

Plot channels from this test in a grid of subplots.

The layout argument describes how channels are arranged on the grid. Each cell in layout can be:

  • None : leave the subplot empty.

  • a single channel key / Channel : one channel on that axes.

  • a sequence of channel keys / Channel : multiple channels overlaid on the same axes, with a legend.

If layout is None, a single-row layout containing all channels (by index order) is used.

Parameters:
  • layout (Any, optional) – Layout specification (see above). If None, all channels are arranged in a single row.

  • plot_type (str, optional) – Plot type passed to the underlying channel-plotting methods (default "timehistory").

  • sharex (bool, optional) – If True (default), share the x-axis among subplots.

  • sharey (bool, optional) – If True (default), share the y-axis among subplots.

  • title_suffix (str or None, optional) – Optional suffix appended to the figure title, after the test name (e.g. "Test 04: Accelerations").

  • make_caption (bool, optional) – If True, also return a simple figure caption describing the plotted channels.

  • **kwargs – Additional keyword arguments forwarded to the channel plotting methods (e.g. color, fmax=..., etc.).

Returns:

  • fig, axes ((matplotlib.figure.Figure, np.ndarray of Axes)) – Figure and array of axes with the plotted channels.

  • caption (str, optional) – If make_caption is True, a third return value containing a simple caption string is provided.

plot_channels(selector=None, ncols=3, plot_type='timehistory', sharex=True, sharey=True, title_suffix=None, make_caption=False, **kwargs)[source]

Plot a list of channels from this test in a grid with fixed columns.

Channels are selected via selector and arranged row-wise into subplots with ncols columns. This is convenient for plotting many similar channels (e.g. all accelerograms) at once.

Parameters:
  • selector (ChannelSelector, optional) – Channels to plot (index, name, Channel, list, slice…). If None (default), all channels are plotted.

  • ncols (int, optional) – Number of columns in the subplot grid (default is 3).

  • plot_type (str, optional) – Plot type passed to the underlying channel-plotting methods (default "timehistory").

  • sharex (bool, optional) – If True (default), share the x-axis among subplots.

  • sharey (bool, optional) – If True (default), share the y-axis among subplots.

  • title_suffix (str or None, optional) – Optional suffix appended to the figure title.

  • make_caption (bool, optional) – If True, also return a simple caption string.

  • **kwargs – Additional keyword arguments forwarded to the channel plotting methods.

Returns:

  • fig, axes ((matplotlib.figure.Figure, np.ndarray of Axes)) – Figure and array of axes with the plotted channels.

  • caption (str, optional) – If make_caption is True, a third return value containing a simple caption string is provided.

Raises:

ValueError – If no channels are selected for plotting.

channel_health(selector=None, fraction_for_event=0.05, min_peak=None, min_snr=3.0, min_crest=2.0, processed=True, use_cache=True, tablefmt='github')[source]

Check basic health of selected channels using simple time-domain metrics.

The method computes peak, RMS, crest factor, pre-event RMS and a simple SNR-like ratio for each channel, and returns a tabulated string summarising the results.

Parameters:
  • selector (ChannelSelector, optional) – Channels to inspect. If None, all channels are checked.

  • fraction_for_event (float, optional) – Fraction of the peak used to define the event window.

  • min_peak (float or None, optional) – Minimum acceptable peak amplitude. If None, this criterion is not applied.

  • min_snr (float, optional) – Minimum RMS(event)/RMS(pre-event) ratio for a healthy response.

  • min_crest (float, optional) – Minimum crest factor (peak/RMS) for a healthy response.

  • processed (bool, optional) – Passed to Channel.xy() (default True).

  • use_cache (bool, optional) – Passed to Channel.xy() (default True).

  • tablefmt (str, optional) – Table format passed to tabulate() (default "github").

Returns:

Health check table as a formatted string. If no channels are selected, a short message is returned.

Return type:

str

Notes

The status column is a simple qualitative label based on the peak amplitude, crest factor and SNR thresholds and should be interpreted as a quick screening rather than a rigorous test.