Skip to content

Index

engineering ¤

Engineering Events

Detectors for engineering-related patterns over shaped timeseries.

  • SetpointChangeEvents: Detect setpoint changes and compute response KPIs.
  • detect_setpoint_steps: Point events where |Δsetpoint| ≥ min_delta and holds for min_hold.
  • detect_setpoint_ramps: Intervals where |dS/dt| ≥ min_rate for at least min_duration.
  • detect_setpoint_changes: Unified table of steps and ramps with standardized columns.
  • time_to_settle: Time until |actual − setpoint| ≤ tol for a hold duration within a window.
  • overshoot_metrics: Peak overshoot magnitude/percent and time-to-peak after a change.
  • control_quality_metrics: Rise time, overshoot, settling and decay per setpoint change.
  • decay_rate: Estimate exponential decay rate of the settling behavior.
  • oscillation_frequency: Estimate the frequency of oscillations during settling.
  • rise_time: Time for the actual value to go from 10 % to 90 % of a step.
  • time_to_settle_derivative: Settling time from the rate of change falling below a threshold.

  • StartupDetectionEvents: Detect startup intervals from thresholds or slope.

  • detect_startup_by_threshold: Rising threshold crossing with minimum dwell above threshold.
  • detect_startup_by_slope: Intervals with sustained positive slope ≥ min_slope for min_duration.
  • assess_startup_quality: Assess the quality of detected startup events.
  • detect_failed_startups: Detect failed or aborted startup attempts.
  • detect_startup_adaptive: Startups against an adaptive threshold from the recent baseline.
  • detect_startup_multi_signal: Startups from several signals combined with AND / OR logic.
  • track_startup_phases: Track progression through defined startup phases.

  • ThresholdMonitoringEvents: Multi-level threshold monitoring with hysteresis.

  • multi_level_threshold: Intervals exceeding warning/alarm/critical levels.
  • threshold_with_hysteresis: Alarm entry/exit with separate high/low thresholds.
  • time_above_threshold: Time and percentage above threshold per window.
  • threshold_exceedance_trend: Track exceedance frequency over time.

  • RateOfChangeEvents: Detect rapid changes and step jumps.

  • detect_rapid_change: Flag intervals where rate exceeds threshold.
  • rate_statistics: Per-window rate of change statistics.
  • detect_step_changes: Sudden value jumps within a short duration.

  • SteadyStateDetectionEvents: Identify steady-state vs transient periods.

  • detect_steady_state: Intervals where rolling std stays below threshold.
  • detect_transient_periods: Intervals where signal is changing.
  • steady_state_statistics: Summary of steady vs transient time.
  • steady_state_value_bands: Operating band (mean ± std) per steady interval.

  • SignalComparisonEvents: Compare two signals and detect divergence.

  • detect_divergence: Intervals where |actual - reference| > tolerance.
  • deviation_statistics: Per-window MAE, max error, RMSE, bias.
  • tracking_error_trend: Whether deviation is growing or shrinking.
  • correlation_windows: Per-window Pearson correlation.

  • OperatingRangeEvents: Analyze signal operating envelope and range.

  • operating_envelope: Per-window min/max/mean/percentiles.
  • detect_regime_change: Detect shifts in the operating point.
  • time_in_range: Percentage of time within a defined range.
  • value_distribution: Histogram of signal values.

  • WarmUpCoolDownEvents: Detect and characterize warm-up / cool-down curves.

  • detect_warmup: Rising ramp intervals.
  • detect_cooldown: Falling ramp intervals.
  • warmup_consistency: Compare warm-up durations and rates.
  • time_to_target: Time from ramp start until target value is reached.

  • ProcessWindowEvents: Time-windowed process statistics and shift detection.

  • windowed_statistics: Per-window count, mean, std, min, max, percentiles.
  • detect_mean_shift: Flag windows where mean shifts significantly.
  • detect_variance_change: Flag windows where variance changes.
  • window_comparison: Compare each window to overall baseline.

  • ControlLoopHealthEvents: Continuous PID/control loop health assessment.

  • error_integrals: Per-window IAE, ISE, ITAE, bias.
  • detect_oscillation: Sustained oscillation in the error signal.
  • output_saturation: Valve pegged at limits.
  • loop_health_summary: Shift-level report card.

  • DisturbanceRecoveryEvents: Detect external upsets and measure recovery.

  • detect_disturbances: Intervals where signal deviates from baseline.
  • recovery_time: Time until signal returns to baseline after disturbance.
  • disturbance_frequency: Count disturbances per window.
  • before_after_comparison: Compare process stats before vs after disturbance.

  • MaterialBalanceEvents: Check whether inputs and outputs balance.

  • balance_check: Per-window sum(inputs) vs sum(outputs).
  • imbalance_trend: Track whether imbalance is growing or shrinking.
  • detect_balance_exceedance: Sustained imbalance events.
  • contribution_breakdown: Each signal's share of total input/output.

  • ProcessStabilityIndexEvents: Single 0-100 stability score per shift/day.

  • stability_score: Composite 0-100 score per window.
  • score_trend: Is stability improving or degrading?
  • worst_periods: N worst-scoring windows.
  • stability_comparison: Compare each window to best-observed.

  • TimeToThresholdEvents: Predictive time-to-threshold analysis (trend fit over a lookback window; see also FailurePredictionEvents.time_to_threshold for a per-sample rate estimate).

  • time_to_threshold: Estimate time until signal reaches a value.
  • time_to_threshold_windows: Per-window time-to-threshold estimates.
  • remaining_useful_range: Time until signal leaves acceptable band.
  • crossing_forecast: Forecast crossing times for multiple thresholds.

ControlLoopHealthEvents ¤

ControlLoopHealthEvents(
    dataframe: DataFrame,
    setpoint_uuid: str,
    actual_uuid: str,
    *,
    output_uuid: str | None = None,
    event_uuid: str = "eng:control_loop_health",
    value_column: str = "value_double",
    time_column: str = "systime"
)

Bases: Base

Engineering: Control Loop Health

Continuously assess PID/control loop health from setpoint + actual pairs, independent of setpoint changes. Computes error integrals, detects oscillation in the error signal, and checks for valve saturation.

Methods: - error_integrals: Per-window IAE, ISE, ITAE, bias. - detect_oscillation: Sustained oscillation in the error signal. - output_saturation: Valve pegged at limits. - loop_health_summary: Shift-level report card.

error_integrals ¤

error_integrals(
    window: str = "1h", *, max_gap: str | None = None
) -> pd.DataFrame

Per-window error integrals for control loop performance.

Parameters:

Name Type Description Default
window str

Resample window (e.g. '1h', '8h').

'1h'
max_gap str | None

Default None weights each error by the time since the previous sample, with no gap cap. When set, each error is held until the next sample (zero-order hold, i.e. weighted by the time after it) and any interval longer than max_gap contributes nothing, so a communication gap is not integrated as one huge error.

None

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, iae, ise,

DataFrame

itae, bias, sample_count. end is start + window.

detect_oscillation ¤

detect_oscillation(
    window: str = "5min", min_crossings: int = 4
) -> pd.DataFrame

Detect sustained oscillation in the error signal.

Parameters:

Name Type Description Default
window str

Analysis window size.

'5min'
min_crossings int

Minimum zero-crossings to flag oscillation.

4

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid (setpoint and actual uuids, comma-joined), is_delta,

DataFrame

crossing_count, estimated_period_seconds, amplitude,

DataFrame

damping_direction.

output_saturation ¤

output_saturation(
    upper_limit: float = 100.0,
    lower_limit: float = 0.0,
    window: str = "1h",
) -> pd.DataFrame

Detect when controller output is pegged at limits.

Requires output_uuid in constructor.

Parameters:

Name Type Description Default
upper_limit float

Upper output limit, in the output signal's units. Samples within 1% of the upper_limit - lower_limit range of it count as saturated high. Default 100.0.

100.0
lower_limit float

Lower output limit, in the output signal's units. Samples within 1% of the range of it count as saturated low. Default 0.0.

0.0
window str

Resample window as a pandas offset string (e.g. '1h').

'1h'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid (the output uuid), pct_time_at_high, pct_time_at_low,

DataFrame

pct_time_saturated, longest_saturation_seconds. One row per

DataFrame

window; end is start + window.

DataFrame

Canonical twin columns: time_at_high_pct (after pct_time_at_high),

DataFrame

time_at_low_pct (after pct_time_at_low), time_saturated_pct

DataFrame

(after pct_time_saturated); each holds the same values as the deprecated

DataFrame

column right before it, which is removed in the next major release.

loop_health_summary ¤

loop_health_summary(
    window: str = "8h",
    oscillation_window: str = "5min",
    min_crossings: int = 4,
) -> pd.DataFrame

Shift-level report card combining all loop health metrics.

Oscillation is detected with :meth:detect_oscillation on short analysis windows of oscillation_window (not on the report window: a whole shift would almost always contain enough zero-crossings). oscillation_count is the number of merged oscillation episodes that start inside each report window.

Parameters:

Name Type Description Default
window str

Report window as a pandas offset string (e.g. '8h' for a shift). Used for the error integrals, the saturation share and to bucket the oscillation episodes.

'8h'
oscillation_window str

Analysis window passed to :meth:detect_oscillation (default '5min').

'5min'
min_crossings int

Minimum zero-crossings per oscillation_window to flag oscillation, passed to :meth:detect_oscillation.

4

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, iae, bias,

DataFrame

oscillation_count, pct_saturated, health_grade. end is

DataFrame

start + window.

DataFrame

Canonical twin columns: saturated_pct (after pct_saturated); each

DataFrame

holds the same values as the deprecated column right before it, which is

DataFrame

removed in the next major release.

DisturbanceRecoveryEvents ¤

DisturbanceRecoveryEvents(
    dataframe: DataFrame,
    signal_uuid: str,
    *,
    setpoint_uuid: str | None = None,
    event_uuid: str = "eng:disturbance_recovery",
    value_column: str = "value_double",
    time_column: str = "systime"
)

Bases: Base

Engineering: Disturbance / Upset Detection and Recovery

Detect external upsets hitting a process signal and measure how the process recovered. Works with a rolling baseline or an optional setpoint.

Methods: - detect_disturbances: Intervals where signal deviates from baseline. - recovery_time: How long until signal returns to normal after each upset. - disturbance_frequency: Count disturbances per shift/day. - before_after_comparison: Did the upset permanently change the process?

detect_disturbances ¤

detect_disturbances(
    baseline_window: str = "10min",
    n_sigma: float = 3.0,
    min_duration: str = "30s",
) -> pd.DataFrame

Detect intervals where signal deviates significantly from baseline.

Parameters:

Name Type Description Default
baseline_window str

Window for rolling baseline computation.

'10min'
n_sigma float

Deviation threshold in multiples of rolling std.

3.0
min_duration str

Minimum disturbance duration.

'30s'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, is_delta, peak_deviation, mean_deviation, direction,

DataFrame

disturbance_type.

recovery_time ¤

recovery_time(
    baseline_window: str = "10min",
    n_sigma: float = 3.0,
    recovery_pct: float = 0.95,
    max_recovery: str = "1h",
) -> pd.DataFrame

Measure recovery time after each disturbance.

Parameters:

Name Type Description Default
baseline_window str

Window for the rolling baseline and rolling std (pandas offset string). Ignored for the baseline when a setpoint_uuid was given; the setpoint is used instead.

'10min'
n_sigma float

Deviation threshold in multiples of the rolling std.

3.0
recovery_pct float

Signal must return to within (1 - recovery_pct) of peak deviation to be considered recovered.

0.95
max_recovery str

Maximum time to look for recovery.

'1h'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds (of the

DataFrame

disturbance), uuid, source_uuid, recovery_time_seconds, recovered,

DataFrame

pre_disturbance_mean, post_recovery_mean, residual_offset.

disturbance_frequency ¤

disturbance_frequency(
    window: str = "8h",
    baseline_window: str = "10min",
    n_sigma: float = 3.0,
) -> pd.DataFrame

Count disturbances per time window.

Parameters:

Name Type Description Default
window str

Counting window as a pandas offset string (e.g. '8h' per shift, '1D' per day).

'8h'
baseline_window str

Window for the rolling baseline and rolling std used by :meth:detect_disturbances.

'10min'
n_sigma float

Deviation threshold in multiples of the rolling std.

3.0

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds,

DataFrame

disturbance_count, total_disturbance_seconds, pct_time_disturbed,

DataFrame

avg_recovery_seconds. end is start + window.

DataFrame

Canonical twin columns: time_disturbed_pct (after

DataFrame

pct_time_disturbed); each holds the same values as the deprecated column

DataFrame

right before it, which is removed in the next major release.

before_after_comparison ¤

before_after_comparison(
    baseline_window: str = "10min",
    n_sigma: float = 3.0,
    comparison_window: str = "5min",
) -> pd.DataFrame

Compare process statistics before vs after each disturbance.

Parameters:

Name Type Description Default
baseline_window str

Window for the rolling baseline and rolling std used by :meth:detect_disturbances.

'10min'
n_sigma float

Deviation threshold in multiples of the rolling std.

3.0
comparison_window str

Length of the span compared just before the disturbance start and just after its end. Disturbances with fewer than two samples on either side are skipped.

'5min'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, pre_mean, post_mean, pre_std, post_std, mean_shift,

DataFrame

variance_ratio. start / end are the disturbance bounds.

MaterialBalanceEvents ¤

MaterialBalanceEvents(
    dataframe: DataFrame,
    input_uuids: list[str],
    output_uuids: list[str],
    *,
    event_uuid: str = "eng:material_balance",
    value_column: str = "value_double",
    time_column: str = "systime",
    time_weighted: bool = True,
    missing_as_zero: bool = False
)

Bases: Base

Engineering: Material / Energy Balance

Check whether inputs and outputs balance (mass, energy, flow) per time window. The most fundamental daily engineering check for any process.

Methods: - balance_check: Per-window sum(inputs) vs sum(outputs). - imbalance_trend: Track whether imbalance is growing or shrinking. - detect_balance_exceedance: Sustained imbalance events. - contribution_breakdown: Each signal's share of total input/output.

Parameters:

Name Type Description Default
dataframe DataFrame

Long-format input data.

required
input_uuids list[str]

Signals flowing into the balance boundary.

required
output_uuids list[str]

Signals flowing out of it.

required
event_uuid str

UUID assigned to generated events.

'eng:material_balance'
value_column str

Column holding the flow values.

'value_double'
time_column str

Timestamp column.

'systime'
time_weighted bool

True (default) averages each flow by time (value held until the next sample). False uses resample().mean() over the samples, which is biased on irregular or change-encoded flow signals.

True
missing_as_zero bool

False (default) leaves a window's totals NaN when a signal has no data in it; the window is marked not balanced but is not reported by :meth:detect_balance_exceedance, so a sensor outage is not read as a real imbalance. True treats a window without data for a signal as zero flow.

False

balance_check ¤

balance_check(
    window: str = "1h", tolerance_pct: float = 5.0
) -> pd.DataFrame

Per-window balance check: sum(inputs) vs sum(outputs).

Parameters:

Name Type Description Default
window str

Resample window.

'1h'
tolerance_pct float

Maximum acceptable imbalance percentage.

5.0

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds,

DataFrame

total_input, total_output, imbalance, imbalance_pct, balanced.

DataFrame

end is start + window.

imbalance_trend ¤

imbalance_trend(window: str = '1h') -> pd.DataFrame

Track whether imbalance is growing, shrinking, or stable.

Parameters:

Name Type Description Default
window str

Resample window passed to :meth:balance_check. The rolling average spans the last three windows.

'1h'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds,

DataFrame

imbalance_pct, rolling_avg_imbalance, trend_direction. end is

DataFrame

start + window.

detect_balance_exceedance ¤

detect_balance_exceedance(
    window: str = "1h",
    tolerance_pct: float = 5.0,
    min_duration: str = "2h",
) -> pd.DataFrame

Detect sustained imbalance events.

Parameters:

Name Type Description Default
window str

Resample window passed to :meth:balance_check.

'1h'
tolerance_pct float

Maximum acceptable imbalance percentage per window.

5.0
min_duration str

Minimum length of a run of consecutive unbalanced windows to report it as an event (pandas offset string). Windows whose totals are NaN (missing data) end a run.

'2h'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid (input and output uuids, comma-joined), is_delta,

DataFrame

avg_imbalance_pct, max_imbalance_pct, likely_cause.

contribution_breakdown ¤

contribution_breakdown(window: str = '1h') -> pd.DataFrame

Each signal's contribution to total input/output per window.

Parameters:

Name Type Description Default
window str

Resample window (pandas offset string).

'1h'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, role, value, pct_of_total. uuid and

DataFrame

source_uuid both hold the contributing signal's uuid; end

DataFrame

is start + window.

DataFrame

Canonical twin columns: share_of_total_pct (after pct_of_total); each

DataFrame

holds the same values as the deprecated column right before it, which is

DataFrame

removed in the next major release.

OperatingRangeEvents ¤

OperatingRangeEvents(
    dataframe: DataFrame,
    signal_uuid: str,
    *,
    event_uuid: str = "eng:operating_range",
    value_column: str = "value_double",
    time_column: str = "systime"
)

Bases: Base

Engineering: Operating Range Analysis

Analyze the operating envelope of a signal — what ranges it operates in, how often, and when the operating point shifts.

Methods: - operating_envelope: Per-window min/max/mean/percentiles. - detect_regime_change: Detect significant shifts in the operating point. - time_in_range: Percentage of time within a defined range per window. - value_distribution: Histogram of signal values.

operating_envelope ¤

operating_envelope(window: str = '1h') -> pd.DataFrame

Per-window operating envelope statistics.

Parameters:

Name Type Description Default
window str

Resample window (pandas offset string, e.g. '1h').

'1h'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, min_value, p5, mean_value, p95, max_value,

DataFrame

range_width. end is start + window.

detect_regime_change ¤

detect_regime_change(
    window: str = "1h", shift_threshold: float = 2.0
) -> pd.DataFrame

Detect significant shifts in the operating point between windows.

A regime change is flagged when the window mean differs from the previous window mean by more than shift_threshold * pooled std.

Parameters:

Name Type Description Default
window str

Resample window (pandas offset string). Windows with fewer than two samples are skipped.

'1h'
shift_threshold float

Minimum shift between consecutive window means, in multiples of the two windows' average std, to flag a regime change.

2.0

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, is_delta, prev_mean, new_mean, shift_magnitude.

DataFrame

start is the previous window's start and end the new

DataFrame

window's start.

time_in_range ¤

time_in_range(
    lower_limit: float,
    upper_limit: float,
    window: str = "1h",
    time_weighted: bool = True,
) -> pd.DataFrame

Share of each window spent within, below and above a range.

By default the *_pct columns are percentages of time: each value is held until the next sample (zero-order hold), so a window without samples that holds an earlier value is reported too. With time_weighted=False they are percentages of the samples in each window (equal to the share of time only for evenly spaced data).

Parameters:

Name Type Description Default
lower_limit float

Lower bound of the range (inclusive), in signal units.

required
upper_limit float

Upper bound of the range (inclusive), in signal units.

required
window str

Resample window (pandas offset string).

'1h'
time_weighted bool

True (default) weights each value by how long it was held; False counts samples.

True

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, time_in_range_pct, time_below_pct, time_above_pct.

DataFrame

end is start + window.

value_distribution ¤

value_distribution(n_bins: int = 10) -> pd.DataFrame

Histogram of signal values.

Parameters:

Name Type Description Default
n_bins int

Number of equal-width histogram bins between the signal's minimum and maximum.

10

Returns:

Type Description
DataFrame

DataFrame with columns: bin_lower, bin_upper, count, pct,

DataFrame

cumulative_pct.

ProcessStabilityIndexEvents ¤

ProcessStabilityIndexEvents(
    dataframe: DataFrame,
    signal_uuid: str,
    *,
    target: float | None = None,
    lower_spec: float | None = None,
    upper_spec: float | None = None,
    event_uuid: str = "eng:stability_index",
    value_column: str = "value_double",
    time_column: str = "systime"
)

Bases: Base

Engineering: Process Stability Index

Generate a single 0-100 stability score per shift/day for a signal. Answers 'is my process running well today?' with one number.

Methods: - stability_score: Composite 0-100 score per window. - score_trend: Is stability improving or degrading? - worst_periods: N worst-scoring windows. - stability_comparison: Compare each window to best-observed.

stability_score ¤

stability_score(window: str = '8h') -> pd.DataFrame

Composite 0-100 stability score per window.

Four sub-scores (each 0-25): - variance_score: low std = high score - bias_score: on-target = high score - excursion_score: in-spec = high score - smoothness_score: low point-to-point jitter = high score

Parameters:

Name Type Description Default
window str

Scoring window (pandas offset string, e.g. '8h' per shift). Windows with fewer than two samples are skipped.

'8h'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, stability_score,

DataFrame

variance_score, bias_score, excursion_score, smoothness_score,

DataFrame

grade.

score_trend ¤

score_trend(
    window: str = "8h", n_windows: int = 7
) -> pd.DataFrame

Track whether stability is improving or degrading.

Parameters:

Name Type Description Default
window str

Scoring window passed to :meth:stability_score.

'8h'
n_windows int

Number of windows in the rolling average of the score.

7

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, stability_score,

DataFrame

rolling_avg, trend_direction, score_change.

worst_periods ¤

worst_periods(
    window: str = "1h", n: int = 5
) -> pd.DataFrame

Return the N worst-scoring windows.

Parameters:

Name Type Description Default
window str

Scoring window passed to :meth:stability_score.

'1h'
n int

Number of lowest-scoring windows to return.

5

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, stability_score,

DataFrame

variance_score, bias_score, excursion_score, smoothness_score,

DataFrame

primary_issue.

stability_comparison ¤

stability_comparison(window: str = '8h') -> pd.DataFrame

Compare each window to the best-observed window.

Parameters:

Name Type Description Default
window str

Scoring window passed to :meth:stability_score.

'8h'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, stability_score,

DataFrame

best_score, gap_to_best, pct_of_best.

DataFrame

Canonical twin columns: share_of_best_pct (after pct_of_best); each holds

DataFrame

the same values as the deprecated column right before it, which is removed

DataFrame

in the next major release.

ProcessWindowEvents ¤

ProcessWindowEvents(
    dataframe: DataFrame,
    signal_uuid: str,
    *,
    event_uuid: str = "eng:process_window",
    value_column: str = "value_double",
    time_column: str = "systime"
)

Bases: Base

Engineering: Process Window Analysis

Analyze time-windowed process statistics for shift reports, SPC context, and trend monitoring. Answers 'how is my process doing this hour/shift/day?'

Methods: - windowed_statistics: Per-window count, mean, std, min, max, percentiles. - detect_mean_shift: Flag windows where mean shifts significantly. - detect_variance_change: Flag windows where variance changes significantly. - window_comparison: Compare each window to overall baseline.

windowed_statistics ¤

windowed_statistics(window: str = '1h') -> pd.DataFrame

Per-window descriptive statistics.

Parameters:

Name Type Description Default
window str

Resample window (pandas offset string, e.g. '1h', '8h').

'1h'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, count, mean, std, min, max, median, p25, p75, range.

DataFrame

end is start + window.

detect_mean_shift ¤

detect_mean_shift(
    window: str = "1h", sensitivity: float = 2.0
) -> pd.DataFrame

Flag windows where mean shifts significantly from the previous window.

A shift is detected when |current_mean - prev_mean| > sensitivity * prev_std.

Parameters:

Name Type Description Default
window str

Resample window passed to :meth:windowed_statistics.

'1h'
sensitivity float

Shift between consecutive window means, in multiples of the previous window's std, above which (strictly) a window is flagged.

2.0

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, is_delta, prev_mean, current_mean, shift_sigma.

DataFrame

start is the previous window's start, end the current

DataFrame

window's start.

detect_variance_change ¤

detect_variance_change(
    window: str = "1h", ratio_threshold: float = 2.0
) -> pd.DataFrame

Flag windows where variance changes significantly.

A change is detected when (current_std / prev_std) > ratio_threshold or < (1 / ratio_threshold).

Parameters:

Name Type Description Default
window str

Resample window passed to :meth:windowed_statistics.

'1h'
ratio_threshold float

Std ratio (current / previous) strictly above which, or strictly below whose reciprocal, a window is flagged. Should be > 1.

2.0

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, is_delta, prev_std, current_std, variance_ratio.

DataFrame

start is the previous window's start, end the current

DataFrame

window's start.

window_comparison ¤

window_comparison(window: str = '1h') -> pd.DataFrame

Compare each window mean to the overall baseline.

Parameters:

Name Type Description Default
window str

Resample window passed to :meth:windowed_statistics. A window is anomalous when its mean is more than 2 std of the window means away from their average.

'1h'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, mean, z_score_vs_global, is_anomalous.

RateOfChangeEvents ¤

RateOfChangeEvents(
    dataframe: DataFrame,
    signal_uuid: str,
    *,
    event_uuid: str = "eng:rate_of_change",
    value_column: str = "value_double",
    time_column: str = "systime"
)

Bases: Base

Engineering: Rate of Change Events

Detect rapid changes and step jumps in a numeric signal.

Methods: - detect_rapid_change: Flag intervals where rate of change exceeds threshold. - rate_statistics: Per-window rate of change statistics. - detect_step_changes: Sudden value jumps within a short duration.

detect_rapid_change ¤

detect_rapid_change(
    threshold: float, window: str | None = None
) -> pd.DataFrame

Flag intervals where rate of change exceeds threshold.

Each run of consecutive samples whose absolute rate is at or above threshold becomes one interval.

Parameters:

Name Type Description Default
threshold float

Minimum absolute rate (units/second) to flag.

required
window str | None

Deprecated and not used: the rate is always computed between consecutive samples. Passing any value emits a DeprecationWarning. Filter the result on duration_seconds to drop short intervals.

None

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, max_rate, direction.

rate_statistics ¤

rate_statistics(window: str = '1h') -> pd.DataFrame

Per-window rate of change statistics.

Parameters:

Name Type Description Default
window str

Resample window.

'1h'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, mean_rate,

DataFrame

std_rate, max_rate, min_rate. end is start + window.

detect_step_changes ¤

detect_step_changes(
    min_delta: float, max_duration: str = "5s"
) -> pd.DataFrame

Detect sudden value jumps within a short duration.

Parameters:

Name Type Description Default
min_delta float

Minimum absolute value change to qualify.

required
max_duration str

Maximum time window for the step to occur.

'5s'

Returns:

Type Description
DataFrame

DataFrame with columns: systime, uuid, source_uuid, time, start,

DataFrame

end, value_before, value_after, delta, duration,

DataFrame

duration_seconds. systime and end equal time (the

DataFrame

instant after the jump; time is a deprecated twin), start

DataFrame

is the sample before the jump, and duration_seconds is the

DataFrame

float-seconds twin of the Timedelta duration.

SetpointChangeEvents ¤

SetpointChangeEvents(
    dataframe: DataFrame,
    setpoint_uuid: str,
    *,
    event_uuid: str = "eng:setpoint_change",
    value_column: str = "value_double",
    time_column: str = "systime"
)

Bases: Base

Detect step/ramp changes on a setpoint signal and compute follow-up KPIs like time-to-settle and overshoot based on an actual (process) value.

Schema assumptions (columns): - uuid, sequence_number, systime, plctime, is_delta - value_integer, value_string, value_double, value_bool, value_bytes

Example

import pandas as pd from ts_shape import SetpointChangeEvents df = pd.DataFrame({ ... "systime": pd.date_range("2025-01-01 08:00", periods=4, freq="10min"), ... "uuid": "oven:setpoint", ... "value_double": [50.0, 50.0, 60.0, 60.0], ... }) steps = SetpointChangeEvents(df, "oven:setpoint").detect_setpoint_steps(min_delta=5.0) steps[["start", "prev_level", "new_level", "magnitude"]] start prev_level new_level magnitude 0 2025-01-01 08:20:00 50.0 60.0 10.0

detect_setpoint_steps ¤

detect_setpoint_steps(
    min_delta: float,
    min_hold: str = "0s",
    filter_noise: bool = False,
    noise_threshold: float = 0.01,
) -> pd.DataFrame

Point events at times where the setpoint changes by >= min_delta and the new level holds for at least min_hold (no subsequent change within that time).

Parameters:

Name Type Description Default
min_delta float

Minimum magnitude of change to detect

required
min_hold str

Minimum duration the new level must hold

'0s'
filter_noise bool

If True, filter out changes smaller than noise_threshold

False
noise_threshold float

Threshold for noise filtering (absolute value)

0.01

Returns:

Type Description
DataFrame

DataFrame with columns: start, end (== start), duration_seconds

DataFrame

(0.0), uuid, source_uuid, is_delta, change_type='step', magnitude,

DataFrame

prev_level, new_level.

detect_setpoint_ramps ¤

detect_setpoint_ramps(
    min_rate: float, min_duration: str = "0s"
) -> pd.DataFrame

Interval events where |dS/dt| >= min_rate for at least min_duration.

Parameters:

Name Type Description Default
min_rate float

Minimum absolute setpoint rate of change, in setpoint units per second, for a sample-to-sample step to count as ramping.

required
min_duration str

Minimum time from the first to the last ramping sample of a contiguous run (pandas offset string). Default "0s".

'0s'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, is_delta, change_type='ramp', avg_rate, delta.

detect_setpoint_changes ¤

detect_setpoint_changes(
    *,
    min_delta: float = 0.0,
    min_rate: float | None = None,
    min_hold: str = "0s",
    min_duration: str = "0s"
) -> pd.DataFrame

Unified setpoint change table (steps + ramps) with standardized columns.

Parameters:

Name Type Description Default
min_delta float

Minimum step magnitude, passed to :meth:detect_setpoint_steps.

0.0
min_rate float | None

Minimum ramp rate in setpoint units per second, passed to :meth:detect_setpoint_ramps. None skips ramp detection.

None
min_hold str

Minimum time a new step level must hold, passed to :meth:detect_setpoint_steps.

'0s'
min_duration str

Minimum ramp duration, passed to :meth:detect_setpoint_ramps.

'0s'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, is_delta, change_type, magnitude, prev_level,

DataFrame

new_level, avg_rate, delta.

time_to_settle ¤

time_to_settle(
    actual_uuid: str,
    *,
    tol: float = 0.0,
    settle_pct: float | None = None,
    hold: str = "0s",
    lookahead: str = "10min"
) -> pd.DataFrame

For each setpoint change (any change), compute the settling time: the time after which the actual signal enters the ±tolerance band around the new setpoint and stays inside it until the end of the evaluation window (Ogata, Modern Control Engineering, settling time t_s). The first entry into the band is not the settling time: an underdamped response crosses the band on every swing long before it settles.

Parameters:

Name Type Description Default
actual_uuid str

UUID of the actual/process value signal

required
tol float

Absolute tolerance, used when settle_pct is None.

0.0
settle_pct float | None

Tolerance as a fraction of the step magnitude (e.g. 0.02 for 2%). When given it wins over tol; passing both emits a UserWarning.

None
hold str

Minimum duration the final inside-band run must last before the window ends for the settle to count as confirmed (settled).

'0s'
lookahead str

Evaluation window after each change. It also ends at the next (later) setpoint change, after which the process follows a different setpoint. The response must be inside the band at the window's last sample to have settled.

'10min'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end (start + the lookahead window),

DataFrame

duration_seconds, uuid, source_uuid (","),

DataFrame

is_delta, t_settle_seconds (seconds from the change to the start

DataFrame

of the final inside-band run; None when the response is

DataFrame

outside the band at the end of the window), settled_within_window

DataFrame

(True when the response is inside the band at the end of the

DataFrame

window, so a settling time exists) and settled

DataFrame

(settled_within_window and the final inside-band run lasts at

DataFrame

least hold).

overshoot_metrics ¤

overshoot_metrics(
    actual_uuid: str, *, window: str = "10min"
) -> pd.DataFrame

For each change, compute peak overshoot, undershoot, and oscillation metrics relative to the new setpoint within a lookahead window.

Parameters:

Name Type Description Default
actual_uuid str

UUID of the actual (process value) signal.

required
window str

Lookahead window after each setpoint change in which the peak, undershoot and oscillations are measured (pandas offset string).

'10min'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end (start + the lookahead window),

DataFrame

duration_seconds, uuid, source_uuid (","),

DataFrame

is_delta, overshoot_abs, overshoot_pct, overshoot_ratio,

DataFrame

t_peak_seconds, undershoot_abs, undershoot_pct, undershoot_ratio,

DataFrame

t_undershoot_seconds, oscillation_count, oscillation_amplitude.

DataFrame

overshoot_pct is the peak overshoot in percent of the step

DataFrame

magnitude (0-100+, Ogata's maximum percent overshoot M_p);

DataFrame

overshoot_ratio is the same quantity as a fraction (0-1+).

DataFrame

undershoot_pct / undershoot_ratio are the swing back past

DataFrame

the new setpoint after it is first reached, in the same two units.

time_to_settle_derivative ¤

time_to_settle_derivative(
    actual_uuid: str,
    *,
    rate_threshold: float = 0.01,
    lookahead: str = "10min",
    hold: str = "0s"
) -> pd.DataFrame

Detect settling based on rate of change (derivative) falling below threshold. More sensitive to when the process has truly stopped moving.

Parameters:

Name Type Description Default
actual_uuid str

UUID of the actual/process value signal

required
rate_threshold float

Maximum absolute rate of change to consider settled

0.01
lookahead str

Maximum time window to search for settling

'10min'
hold str

Minimum duration the rate must stay below threshold

'0s'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end (start + the lookahead window),

DataFrame

duration_seconds, uuid, source_uuid (","),

DataFrame

is_delta, t_settle_seconds, settled, final_rate.

rise_time ¤

rise_time(
    actual_uuid: str,
    *,
    start_pct: float = 0.1,
    end_pct: float = 0.9,
    lookahead: str = "10min"
) -> pd.DataFrame

Compute rise time: time for actual to go from start_pct to end_pct of the setpoint change. Typically measured from 10% to 90% of the final value.

Parameters:

Name Type Description Default
actual_uuid str

UUID of the actual/process value signal

required
start_pct float

Starting percentage of change (e.g., 0.1 for 10%)

0.1
end_pct float

Ending percentage of change (e.g., 0.9 for 90%)

0.9
lookahead str

Maximum time window to search

'10min'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end (start + the lookahead window),

DataFrame

duration_seconds, uuid, source_uuid (","),

DataFrame

is_delta, rise_time_seconds, reached_end.

decay_rate ¤

decay_rate(
    actual_uuid: str,
    *,
    lookahead: str = "10min",
    min_points: int = 5
) -> pd.DataFrame

Estimate exponential decay rate of the settling behavior. Fits error(t) = A * exp(-lambda * t) and returns lambda.

Parameters:

Name Type Description Default
actual_uuid str

UUID of the actual/process value signal

required
lookahead str

Time window for analysis

'10min'
min_points int

Minimum number of points required for fitting

5

Returns:

Type Description
DataFrame

DataFrame with columns: start, end (start + the lookahead window),

DataFrame

duration_seconds, uuid, source_uuid (","),

DataFrame

is_delta, decay_rate_lambda, fit_quality_r2.

oscillation_frequency ¤

oscillation_frequency(
    actual_uuid: str,
    *,
    window: str = "10min",
    min_oscillations: int = 2
) -> pd.DataFrame

Estimate the frequency of oscillations during settling. Counts zero crossings and estimates period.

Parameters:

Name Type Description Default
actual_uuid str

UUID of the actual/process value signal

required
window str

Time window for analysis

'10min'
min_oscillations int

Minimum number of oscillations to compute frequency

2

Returns:

Type Description
DataFrame

DataFrame with columns: start, end (start + the lookahead window),

DataFrame

duration_seconds, uuid, source_uuid (","),

DataFrame

is_delta, oscillation_freq_hz, period_seconds.

control_quality_metrics ¤

control_quality_metrics(
    actual_uuid: str,
    *,
    tol: float = 0.0,
    settle_pct: float | None = None,
    hold: str = "0s",
    lookahead: str = "10min",
    rate_threshold: float = 0.01
) -> pd.DataFrame

Comprehensive control quality metrics combining multiple performance indicators.

Computes all available metrics for each setpoint change and returns them in a single DataFrame. This includes: settling time, rise time, overshoot, undershoot, oscillations, and decay characteristics. The change table and the response windows are gathered once and shared by all of them.

Parameters:

Name Type Description Default
actual_uuid str

UUID of the actual/process value signal

required
tol float

Absolute tolerance for settling, used when settle_pct is None.

0.0
settle_pct float | None

Settling tolerance as a fraction of the step magnitude. When given it wins over tol; passing both emits a UserWarning.

None
hold str

Minimum duration to confirm settling

'0s'
lookahead str

Time window for all analyses

'10min'
rate_threshold float

Rate threshold for derivative-based settling

0.01

Returns:

Type Description
DataFrame

DataFrame with comprehensive metrics including:

DataFrame
  • start, end (start + lookahead), duration_seconds, uuid, source_uuid (","), is_delta
DataFrame
  • t_settle_seconds, settled, settled_within_window (from time_to_settle)
DataFrame
  • t_settle_derivative_seconds (from time_to_settle_derivative)
DataFrame
  • rise_time_seconds (from rise_time)
DataFrame
  • overshoot_abs, overshoot_pct (percent), overshoot_ratio (fraction) (from overshoot_metrics)
DataFrame
  • undershoot_abs, undershoot_pct (percent), undershoot_ratio
DataFrame
  • oscillation_count, oscillation_amplitude, oscillation_freq_hz
DataFrame
  • decay_rate_lambda, fit_quality_r2
DataFrame
  • steady_state_error (final error in window)

SignalComparisonEvents ¤

SignalComparisonEvents(
    dataframe: DataFrame,
    reference_uuid: str,
    *,
    event_uuid: str = "eng:signal_comparison",
    value_column: str = "value_double",
    time_column: str = "systime"
)

Bases: Base

Engineering: Signal Comparison

Compare two related signals (e.g. setpoint vs actual, sensor A vs sensor B) and detect divergence, compute deviation statistics, and track correlation.

Methods: - detect_divergence: Intervals where |actual - reference| exceeds tolerance. - deviation_statistics: Per-window MAE, max error, RMSE, bias. - tracking_error_trend: Whether deviation is growing or shrinking over time. - correlation_windows: Per-window Pearson correlation.

detect_divergence ¤

detect_divergence(
    actual_uuid: str,
    tolerance: float,
    min_duration: str = "1min",
) -> pd.DataFrame

Detect intervals where |actual - reference| > tolerance.

Parameters:

Name Type Description Default
actual_uuid str

UUID of the actual/comparison signal.

required
tolerance float

Maximum acceptable absolute deviation.

required
min_duration str

Minimum duration of divergence interval.

'1min'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid (reference and actual uuids, comma-joined), is_delta,

DataFrame

max_deviation, mean_deviation, direction.

deviation_statistics ¤

deviation_statistics(
    actual_uuid: str, window: str = "1h"
) -> pd.DataFrame

Per-window deviation statistics.

Parameters:

Name Type Description Default
actual_uuid str

UUID of the actual signal compared with the reference signal. Deviation is actual minus reference.

required
window str

Resample window (pandas offset string, e.g. '1h').

'1h'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, mae,

DataFrame

max_error, rmse, bias. end is start + window.

tracking_error_trend ¤

tracking_error_trend(
    actual_uuid: str, window: str = "1D"
) -> pd.DataFrame

Track whether deviation is growing or shrinking over time.

Parameters:

Name Type Description Default
actual_uuid str

UUID of the actual signal compared with the reference signal.

required
window str

Resample window passed to :meth:deviation_statistics.

'1D'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, mae,

DataFrame

trend_slope, trend_direction. end is start + window.

correlation_windows ¤

correlation_windows(
    actual_uuid: str, window: str = "1h"
) -> pd.DataFrame

Per-window Pearson correlation between reference and actual.

Parameters:

Name Type Description Default
actual_uuid str

UUID of the actual signal compared with the reference signal.

required
window str

Resample window (pandas offset string). Windows with fewer than two aligned samples are skipped.

'1h'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds,

DataFrame

correlation, sample_count. end is start + window.

StartupDetectionEvents ¤

StartupDetectionEvents(
    dataframe: DataFrame,
    target_uuid: str,
    *,
    event_uuid: str = "eng:startup",
    value_column: str = "value_double",
    time_column: str = "systime"
)

Bases: Base

Detect equipment startup intervals based on threshold crossings or sustained positive slope in a numeric metric (speed, temperature, etc.).

Schema assumptions (columns): - uuid, sequence_number, systime, plctime, is_delta - value_integer, value_string, value_double, value_bool, value_bytes

detect_startup_by_threshold ¤

detect_startup_by_threshold(
    *,
    threshold: float,
    hysteresis: tuple[float, float] | None = None,
    min_above: str = "0s"
) -> pd.DataFrame

Startup begins at first crossing above threshold (or hysteresis enter) and is valid only if the metric stays above the (exit) threshold for at least min_above.

Parameters:

Name Type Description Default
threshold float

Level in signal units; a startup starts where the signal rises to or above it. Reported in the threshold column.

required
hysteresis tuple[float, float] | None

Optional (enter, exit) pair that replaces threshold: the rising edge is detected against enter and the dwell is checked against exit. None uses threshold for both.

None
min_above str

Minimum time the signal must stay at or above the exit level after the crossing (pandas offset string). It also sets end (start + min_above). Default "0s".

'0s'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, is_delta, method, threshold.

detect_startup_by_slope ¤

detect_startup_by_slope(
    *,
    min_slope: float,
    slope_window: str = "0s",
    min_duration: str = "0s"
) -> pd.DataFrame

Startup intervals where per-second slope >= min_slope for at least min_duration.

With the default slope_window="0s" the slope is the instantaneous slope between consecutive samples. With a positive slope_window the slope at each sample is taken over a trailing window: the change from the latest sample at or before t - slope_window to the current sample, divided by the actual elapsed seconds. Samples with no sample that far back get no slope. A longer window smooths noise.

Parameters:

Name Type Description Default
min_slope float

Minimum slope in signal units per second.

required
slope_window str

Trailing window for the slope as a pandas offset string (default '0s': between consecutive samples).

'0s'
min_duration str

Minimum time from the first to the last sample of a contiguous run at or above min_slope (pandas offset string).

'0s'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, is_delta, method, min_slope, avg_slope.

detect_startup_multi_signal ¤

detect_startup_multi_signal(
    signals: dict[str, dict[str, Any]],
    logic: str = "all",
    *,
    time_tolerance: str = "30s"
) -> pd.DataFrame

Detect startups based on multiple signals with configurable AND/OR logic.

Parameters:

Name Type Description Default
signals dict[str, dict[str, Any]]

Dict mapping uuid to detection config. Each config should contain: - 'method': 'threshold' or 'slope' - For threshold: 'threshold', optional 'hysteresis', 'min_above' - For slope: 'min_slope', optional 'slope_window', 'min_duration'

required
logic str

'all' (AND - all signals must detect) or 'any' (OR - at least one)

'all'
time_tolerance str

Maximum time difference between signals for 'all' logic

'30s'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, uuid, is_delta, method, signals_triggered, signal_details

detect_startup_adaptive ¤

detect_startup_adaptive(
    *,
    baseline_window: str | None = None,
    sensitivity: float = 2.0,
    min_above: str = "10s",
    lookback_periods: int = 5
) -> pd.DataFrame

Detect startups using adaptive thresholds calculated from historical baseline data.

The baseline (mean and std) is computed from samples before each point, so a rising value does not raise its own threshold.

Parameters:

Name Type Description Default
baseline_window str | None

Time span of preceding samples for the baseline (e.g. '1h'). Default None uses the last lookback_periods samples instead. (This parameter used to default to '1h' but was ignored.)

None
sensitivity float

Multiplier for standard deviation (threshold = mean + sensitivity * std)

2.0
min_above str

Minimum time the value must stay above threshold

'10s'
lookback_periods int

Number of preceding samples for the baseline when baseline_window is None

5

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, is_delta, method, adaptive_threshold, baseline_mean,

DataFrame

baseline_std

assess_startup_quality ¤

assess_startup_quality(
    startup_events: DataFrame,
    *,
    smoothness_window: int = 5,
    anomaly_threshold: float = 3.0
) -> pd.DataFrame

Assess the quality of detected startup events.

Parameters:

Name Type Description Default
startup_events DataFrame

DataFrame of detected startup events (must have 'start' and 'end' columns)

required
smoothness_window int

Window size for calculating smoothness metrics

5
anomaly_threshold float

Z-score threshold for detecting anomalies

3.0

Returns:

Type Description
DataFrame

DataFrame with quality metrics for each startup: - duration: Total duration of startup - smoothness_score: Inverse of derivative variance (higher = smoother) - anomaly_flags: Number of anomalous points detected - value_change: Total change in value during startup - avg_rate: Average rate of change - max_value: Maximum value reached - stability_score: Measure of how stable the final state is

track_startup_phases ¤

track_startup_phases(
    phases: list[dict[str, Any]],
    *,
    min_phase_duration: str = "5s"
) -> pd.DataFrame

Track progression through defined startup phases.

Parameters:

Name Type Description Default
phases list[dict[str, Any]]

List of phase definitions, each containing: - 'name': Phase name - 'condition': 'threshold', 'range', or 'slope' - For 'threshold': 'min_value' (value must be >= min_value) - For 'range': 'min_value' and 'max_value' (value in range) - For 'slope': 'min_slope' (slope must be >= min_slope)

required
min_phase_duration str

Minimum time to stay in phase to be considered valid

'5s'

Returns:

Type Description
DataFrame

DataFrame with phase transitions: - phase_name: Name of the phase - phase_number: Sequential phase number (0-indexed) - start: Phase start time - end: Phase end time - duration: Time spent in phase - next_phase: Name of the next phase (None for last phase) - completed: Whether full startup sequence completed

detect_failed_startups ¤

detect_failed_startups(
    *,
    threshold: float,
    min_rise_duration: str = "5s",
    max_completion_time: str = "5min",
    completion_threshold: float | None = None,
    required_stability: str = "10s"
) -> pd.DataFrame

Detect failed or aborted startup attempts.

A failed startup is identified when: 1. Value rises above threshold for at least min_rise_duration 2. But fails to reach completion_threshold within max_completion_time 3. Or drops back below threshold before achieving required_stability

Parameters:

Name Type Description Default
threshold float

Initial threshold that must be crossed to begin startup

required
min_rise_duration str

Minimum time above threshold to consider it a startup attempt

'5s'
max_completion_time str

Maximum time allowed to complete startup

'5min'
completion_threshold float | None

Target threshold for successful completion (default: 2x threshold)

None
required_stability str

Time that must be maintained at completion level

'10s'

Returns:

Type Description
DataFrame

DataFrame with columns: systime (= start, the startup attempt),

DataFrame

uuid, source_uuid, start, end, is_delta, method, failure_reason,

DataFrame

max_value_reached, time_to_failure

SteadyStateDetectionEvents ¤

SteadyStateDetectionEvents(
    dataframe: DataFrame,
    signal_uuid: str,
    *,
    event_uuid: str = "eng:steady_state",
    value_column: str = "value_double",
    time_column: str = "systime"
)

Bases: Base

Engineering: Steady-State Detection

Identify when a process signal has settled into a steady operating state (low variance, no trend) versus transient/dynamic periods.

Methods: - detect_steady_state: Intervals where rolling std stays below threshold. - detect_transient_periods: Inverse — intervals where signal is changing. - steady_state_statistics: Summary of steady vs transient time (one row). - steady_state_value_bands: Operating band (mean +/- std) per steady interval.

detect_steady_state ¤

detect_steady_state(
    window: str = "5min",
    std_threshold: float = 1.0,
    min_duration: str = "10min",
    *,
    interval_end: str = "next_change"
) -> pd.DataFrame

Detect intervals where signal is in steady state.

Parameters:

Name Type Description Default
window str

Rolling window for std computation.

'5min'
std_threshold float

Maximum rolling std to consider steady.

1.0
min_duration str

Minimum duration of a steady interval.

'10min'
interval_end str

"next_change" (default) ends an interval at the next sample (the transition), so the interval spans the time the condition held and change-encoded signals -- one row per change -- keep their duration. "last_sample" ends it at its last flagged sample. See :func:ts_shape.utils.intervals.interval_end_times.

'next_change'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, uuid, source_uuid, is_delta,

DataFrame

mean_value, std_value, duration_seconds.

detect_transient_periods ¤

detect_transient_periods(
    window: str = "5min",
    std_threshold: float = 1.0,
    *,
    interval_end: str = "next_change"
) -> pd.DataFrame

Detect intervals where signal is in transient/dynamic state.

Parameters:

Name Type Description Default
window str

Rolling window for std computation.

'5min'
std_threshold float

Minimum rolling std to consider transient.

1.0
interval_end str

"next_change" (default) ends an interval at the next sample (the transition), so the interval spans the time the condition held and change-encoded signals -- one row per change -- keep their duration. "last_sample" ends it at its last flagged sample. See :func:ts_shape.utils.intervals.interval_end_times.

'next_change'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, uuid, source_uuid, is_delta,

DataFrame

max_std, duration_seconds.

steady_state_statistics ¤

steady_state_statistics(
    window: str = ...,
    std_threshold: float = ...,
    min_duration: str = ...,
    *,
    as_frame: Literal[True] = ...
) -> pd.DataFrame
steady_state_statistics(
    window: str = ...,
    std_threshold: float = ...,
    min_duration: str = ...,
    *,
    as_frame: Literal[False]
) -> dict[str, Any]
steady_state_statistics(
    window: str = "5min",
    std_threshold: float = 1.0,
    min_duration: str = "10min",
    *,
    as_frame: bool = True
) -> pd.DataFrame | dict[str, Any]

Summary statistics of steady vs transient time.

Parameters:

Name Type Description Default
window str

Rolling window for the std computation (pandas offset string), passed to :meth:detect_steady_state.

'5min'
std_threshold float

Maximum rolling std, in signal units, to consider the signal steady.

1.0
min_duration str

Minimum duration of a steady interval.

'10min'
as_frame bool

When True (default), return a one-row DataFrame (see below). as_frame=False returns the dictionary form; it is deprecated, emits a DeprecationWarning and will be removed in the next major release.

True

Returns:

Name Type Description
DataFrame | dict[str, Any]

With as_frame=True (default), a one-row summary DataFrame with

columns DataFrame | dict[str, Any]

start, end, duration_seconds (the span of the signal;

DataFrame | dict[str, Any]

NaT / 0 without data), uuid (event uuid), source_uuid (signal

DataFrame | dict[str, Any]

uuid), total_steady_seconds, total_transient_seconds, steady_pct,

DataFrame | dict[str, Any]

num_steady_periods, avg_steady_duration_seconds.

DataFrame | dict[str, Any]

With as_frame=False (deprecated), a dict with the same keys

DataFrame | dict[str, Any]

from total_steady_seconds on.

steady_state_value_bands ¤

steady_state_value_bands(
    window: str = "5min",
    std_threshold: float = 1.0,
    min_duration: str = "10min",
) -> pd.DataFrame

Operating band (mean +/- std) for each steady-state interval.

Parameters:

Name Type Description Default
window str

Rolling window for the std computation (pandas offset string), passed to :meth:detect_steady_state.

'5min'
std_threshold float

Maximum rolling std, in signal units, to consider the signal steady.

1.0
min_duration str

Minimum duration of a steady interval.

'10min'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, mean_value, lower_band,

DataFrame

upper_band, duration_seconds.

ThresholdMonitoringEvents ¤

ThresholdMonitoringEvents(
    dataframe: DataFrame,
    signal_uuid: str,
    *,
    event_uuid: str = "eng:threshold",
    value_column: str = "value_double",
    time_column: str = "systime"
)

Bases: Base

Engineering: Threshold Monitoring

Multi-level threshold monitoring with hysteresis for numeric signals.

Methods: - multi_level_threshold: Intervals exceeding configurable warning/alarm/critical levels. - threshold_with_hysteresis: Alarm entry/exit with separate high/low thresholds. - time_above_threshold: Time and percentage above a threshold per window. - threshold_exceedance_trend: Track exceedance frequency over time.

Example

import pandas as pd from ts_shape import ThresholdMonitoringEvents df = pd.DataFrame({ ... "systime": pd.date_range("2025-01-01 08:00", periods=6, freq="1min"), ... "uuid": "temp", ... "value_double": [70.0, 82.0, 91.0, 85.0, 75.0, 70.0], ... }) monitor = ThresholdMonitoringEvents(df, "temp") monitor.multi_level_threshold({"warning": 80.0, "alarm": 90.0})[ ... ["start", "end", "level"]] start end level 0 2025-01-01 08:02:00 2025-01-01 08:03:00 alarm 1 2025-01-01 08:01:00 2025-01-01 08:04:00 warning monitor.threshold_with_hysteresis(upper_limit=80.0, lower_limit=76.0)[ ... ["start", "end", "duration_seconds"]] start end duration_seconds 0 2025-01-01 08:01:00 2025-01-01 08:04:00 180.0

multi_level_threshold ¤

multi_level_threshold(
    levels: dict[str, float],
    direction: str = "above",
    *,
    interval_end: str = "next_change"
) -> pd.DataFrame

Detect intervals where signal exceeds configurable threshold levels.

Parameters:

Name Type Description Default
levels dict[str, float]

Dict mapping level names to threshold values. e.g. {'warning': 80, 'alarm': 90, 'critical': 95}

required
direction str

'above' or 'below'.

'above'
interval_end str

"next_change" (default) ends an interval at the next sample (the transition), so the interval spans the time the condition held and change-encoded signals -- one row per change -- keep their duration. "last_sample" ends it at its last flagged sample. See :func:ts_shape.utils.intervals.interval_end_times.

'next_change'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, duration (Timedelta), level, peak_value.

threshold_with_hysteresis ¤

threshold_with_hysteresis(
    upper_limit: float,
    lower_limit: float,
    *,
    max_gap: str | Timedelta | None = None
) -> pd.DataFrame

Alarm intervals with hysteresis to prevent chattering.

Enter alarm when signal crosses upper_limit, exit when it drops below lower_limit.

Parameters:

Name Type Description Default
upper_limit float

Upper threshold to enter alarm state.

required
lower_limit float

Lower threshold to exit alarm state.

required
max_gap str | Timedelta | None

Longest time between two samples an alarm may span (e.g. "15min"). A longer gap is "no data": an open alarm ends at its last sample before the gap, and after the gap the signal must reach upper_limit again to start a new one. None (default): no limit.

None

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, duration (Timedelta), peak_value.

time_above_threshold ¤

time_above_threshold(
    threshold: float,
    window: str = "1h",
    *,
    interval_end: str = "next_change"
) -> pd.DataFrame

Per window: total time and percentage above threshold.

Parameters:

Name Type Description Default
threshold float

Value threshold.

required
window str

Resample window.

'1h'
interval_end str

"next_change" (default) holds each value until the next sample and measures the real time above the threshold inside each window (pct_above is relative to the window length). "last_sample" estimates the time as the fraction of samples above the threshold times the window length, which is only right for uniform sampling.

'next_change'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, time_above,

DataFrame

pct_above, exceedance_count. end is start + window.

DataFrame

Canonical twin columns: time_above_pct (after pct_above); each holds the

DataFrame

same values as the deprecated column right before it, which is removed in

DataFrame

the next major release.

threshold_exceedance_trend ¤

threshold_exceedance_trend(
    threshold: float, window: str = "1D"
) -> pd.DataFrame

Track exceedance frequency and duration trend over time.

Parameters:

Name Type Description Default
threshold float

Value threshold.

required
window str

Resample window (e.g. '1D' for daily).

'1D'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds,

DataFrame

exceedance_count, total_duration, trend_direction. end is

DataFrame

start + window.

TimeToThresholdEvents ¤

TimeToThresholdEvents(
    dataframe: DataFrame,
    signal_uuid: str,
    *,
    event_uuid: str = "eng:time_to_threshold",
    value_column: str = "value_double",
    time_column: str = "systime"
)

Bases: Base

Engineering: Time-to-Threshold Prediction

Answer the question "when will this signal hit X at the current rate?" by extrapolating recent trends. Complements :class:ThresholdMonitoringEvents (which detects when you crossed a threshold) with predictive analysis.

Methods: - time_to_threshold: Estimate time until the signal reaches a value. - time_to_threshold_windows: Per-window time-to-threshold estimates. - remaining_useful_range: Time until signal leaves an acceptable band. - crossing_forecast: Forecast crossing times for multiple thresholds.

time_to_threshold ¤

time_to_threshold(
    threshold: float,
    lookback: str = "1h",
    direction: str = "auto",
) -> pd.DataFrame

Estimate time until the signal reaches a threshold value.

Fits a linear trend to the most recent lookback window and extrapolates to find when the threshold would be crossed.

Parameters:

Name Type Description Default
threshold float

Target value to predict crossing time for.

required
lookback str

How far back to look for trend estimation.

'1h'
direction str

'rising', 'falling', or 'auto' (infer from slope sign).

'auto'

Returns:

Type Description
DataFrame

Single-row DataFrame with columns: current_value, slope_per_second,

DataFrame

threshold, estimated_seconds, estimated_time, confidence,

DataFrame

direction.

time_to_threshold_windows ¤

time_to_threshold_windows(
    threshold: float,
    window: str = "1h",
    lookback: str = "1h",
) -> pd.DataFrame

Per-window time-to-threshold estimates.

For each window, fits a trend to the preceding lookback period and estimates when the threshold will be crossed.

Parameters:

Name Type Description Default
threshold float

Target value.

required
window str

Analysis window frequency.

'1h'
lookback str

Lookback period for trend estimation.

'1h'

Returns:

Type Description
DataFrame

Summary DataFrame with columns: start, end, duration_seconds

DataFrame

(the window bounds), window_start (the resample label; a

DataFrame

deprecated twin of start), current_value,

DataFrame

slope_per_second, estimated_seconds, confidence, direction.

remaining_useful_range ¤

remaining_useful_range(
    lower_limit: float,
    upper_limit: float,
    lookback: str = "1h",
) -> pd.DataFrame

Estimate time until the signal leaves an acceptable operating band.

Parameters:

Name Type Description Default
lower_limit float

Lower acceptable limit.

required
upper_limit float

Upper acceptable limit.

required
lookback str

Lookback period for trend estimation.

'1h'

Returns:

Type Description
DataFrame

Single-row DataFrame with columns: current_value,

DataFrame

slope_per_second, nearest_bound, nearest_bound_value,

DataFrame

estimated_seconds, estimated_time, confidence.

crossing_forecast ¤

crossing_forecast(
    thresholds: dict[str, float], lookback: str = "1h"
) -> pd.DataFrame

Forecast crossing times for multiple named thresholds.

Parameters:

Name Type Description Default
thresholds dict[str, float]

Dict mapping names to values, e.g. {'warning': 80, 'alarm': 90, 'critical': 95}.

required
lookback str

Lookback period for trend estimation.

'1h'

Returns:

Type Description
DataFrame

DataFrame with columns: threshold_name, threshold_value,

DataFrame

estimated_seconds, estimated_time, reachable.

WarmUpCoolDownEvents ¤

WarmUpCoolDownEvents(
    dataframe: DataFrame,
    signal_uuid: str,
    *,
    event_uuid: str = "eng:warmup",
    value_column: str = "value_double",
    time_column: str = "systime"
)

Bases: Base

Engineering: Warm-Up / Cool-Down Analysis

Detect and characterize warm-up and cool-down curves — common for ovens, extruders, molds, hydraulic systems. Analyzes the shape, consistency, and timing of monotonic temperature/pressure ramps.

Methods: - detect_warmup: Intervals where signal rises by at least min_rise. - detect_cooldown: Intervals where signal falls by at least min_fall. - warmup_consistency: Compare warm-up durations and rates for consistency. - time_to_target: Time from warmup start until target value is reached.

detect_warmup ¤

detect_warmup(
    min_rise: float,
    min_duration: str = "1min",
    *,
    max_pause: int = 0
) -> pd.DataFrame

Detect intervals where signal rises by at least min_rise.

Parameters:

Name Type Description Default
min_rise float

Minimum total value increase to qualify.

required
min_duration str

Minimum duration of the ramp.

'1min'
max_pause int

Number of consecutive flat or reversed sample steps tolerated inside a ramp (default 0: any pause ends it).

0

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, uuid, source_uuid, is_delta,

DataFrame

start_value, end_value, rise, duration_seconds, avg_rate.

detect_cooldown ¤

detect_cooldown(
    min_fall: float,
    min_duration: str = "1min",
    *,
    max_pause: int = 0
) -> pd.DataFrame

Detect intervals where signal falls by at least min_fall.

Parameters:

Name Type Description Default
min_fall float

Minimum total value decrease to qualify (positive number).

required
min_duration str

Minimum duration of the ramp.

'1min'
max_pause int

Number of consecutive flat or reversed sample steps tolerated inside a ramp (default 0: any pause ends it).

0

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, uuid, source_uuid, is_delta,

DataFrame

start_value, end_value, fall, duration_seconds, avg_rate.

warmup_consistency ¤

warmup_consistency(
    min_rise: float, min_duration: str = "1min"
) -> pd.DataFrame

Compare warm-up curves for consistency in duration and rate.

Parameters:

Name Type Description Default
min_rise float

Minimum total value increase for a warm-up, passed to :meth:detect_warmup.

required
min_duration str

Minimum warm-up duration (pandas offset string), passed to :meth:detect_warmup.

'1min'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end, duration_seconds, uuid,

DataFrame

source_uuid, warmup_index, avg_rate,

DataFrame

deviation_from_median_duration. start / end are the

DataFrame

warm-up's bounds.

time_to_target ¤

time_to_target(
    target_value: float, direction: str = "rising"
) -> pd.DataFrame

Time from each ramp start until target value is reached.

Parameters:

Name Type Description Default
target_value float

The target value to reach.

required
direction str

'rising' or 'falling'.

'rising'

Returns:

Type Description
DataFrame

DataFrame with columns: start, end (= target_reached_at),

DataFrame

duration_seconds, uuid, source_uuid, target_reached_at,

DataFrame

time_to_target_seconds, overshoot.