Skip to content

Quality Control & SPC¤

Detect outliers, apply Statistical Process Control rules, and compute process capability indices. Built for inline quality monitoring on the shop floor.


Quality Analysis Flow¤

flowchart LR
    SIG["Process Signal"] --> OD["Outlier Detection<br/><i>Z-score, IQR, MAD, ML</i>"]
    SIG --> SPC["SPC Rules<br/><i>Western Electric, CUSUM</i>"]
    SIG --> TOL["Tolerance Check<br/><i>Cp, Cpk indices</i>"]

    OD --> ACT["Quality Actions"]
    SPC --> ACT
    TOL --> ACT

    style SIG fill:#0f2a3d,stroke:#38bdf8,color:#e0f2fe
    style ACT fill:#7f1d1d,stroke:#ef4444,color:#fecaca

Outlier Detection¤

Four detection methods, each suited to different signal distributions.

Method Best For Robustness
Z-score Normal distributions Low — sensitive to extremes
IQR Skewed distributions Medium
MAD Heavy-tailed / noisy signals High — most robust
IsolationForest Complex multivariate patterns High — ML-based

Basic outlier detection¤

from ts_shape.events.quality.outlier_detection import OutlierDetection

# Z-score (values > 3 std from mean)
outliers = OutlierDetection.detect_zscore_outliers(df, "value_double", threshold=3.0)
print(f"Found {len(outliers)} outliers")

# IQR-based
outliers = OutlierDetection.detect_iqr_outliers(df, "value_double", multiplier=1.5)

Advanced outlier detection with severity scores¤

from ts_shape.events.quality.outlier_detection import OutlierDetectionEvents

detector = OutlierDetectionEvents(
    dataframe=df,
    value_column="value_double",
    event_uuid="outlier_event",
    time_threshold="5min"
)

# MAD method (most robust for industrial signals)
outliers_mad = detector.detect_outliers_mad(threshold=3.5)

# IsolationForest (ML-based — detects complex anomaly patterns)
outliers_ml = detector.detect_outliers_isolation_forest(
    contamination=0.1, random_state=42
)

# All methods return severity scores
print(outliers_mad[['systime', 'value_double', 'severity_score']])

Statistical Process Control (SPC)¤

Full Western Electric Rules and CUSUM shift detection per ISA/IEC standards.

from ts_shape.events.quality.statistical_process_control import StatisticalProcessControlRuleBased

spc = StatisticalProcessControlRuleBased(
    dataframe=df,
    value_column="value_double",
    tolerance_uuid="control_limits",
    actual_uuid="measurements",
    event_uuid="spc_violation"
)

# Calculate control limits
limits = spc.calculate_control_limits()
print(f"Mean: {limits['mean'][0]:.2f}")
print(f"UCL (3s): {limits['3sigma_upper'][0]:.2f}")
print(f"LCL (3s): {limits['3sigma_lower'][0]:.2f}")

# Dynamic control limits (adapts over time)
dynamic_limits = spc.calculate_dynamic_control_limits(method='ewma', window=20)

Western Electric Rules¤

# Apply all 8 Western Electric Rules
violations = spc.apply_rules_vectorized()

# Or select specific rules
violations = spc.apply_rules_vectorized(
    selected_rules=['rule_1', 'rule_2', 'rule_3']
)

# Human-readable interpretations
interpreted = spc.interpret_violations(violations)
print(interpreted[['systime', 'rule', 'interpretation', 'recommendation']])

CUSUM Shift Detection¤

Sensitive to small, sustained shifts in the process mean.

shifts = spc.detect_cusum_shifts(k=0.5, h=5.0)
print(shifts[['systime', 'shift_direction', 'severity']])

Tolerance Deviation & Process Capability¤

Check values against specification limits and compute Cp/Cpk indices.

Simple tolerance check¤

from ts_shape.events.quality.tolerance_deviation import ToleranceDeviation

deviations = ToleranceDeviation.detect_out_of_tolerance(
    df, column="value_double", upper_limit=100, lower_limit=0
)

Process Capability Indices (Cp/Cpk)¤

from ts_shape.events.quality.tolerance_deviation import ToleranceDeviationEvents

tolerance_checker = ToleranceDeviationEvents(
    dataframe=df,
    tolerance_column="value_double",
    actual_column="value_double",
    upper_tolerance_uuid="upper_spec_limit",
    lower_tolerance_uuid="lower_spec_limit",
    actual_uuid="measurements",
    event_uuid="deviation_event",
    warning_threshold=0.8  # 80% of tolerance = warning zone
)

capability = tolerance_checker.compute_capability_indices()
print(f"Cp:  {capability['Cp']:.3f}")   # Potential capability
print(f"Cpk: {capability['Cpk']:.3f}")  # Actual capability

if capability['Cpk'] >= 1.33:
    print("Process is capable")
elif capability['Cpk'] >= 1.0:
    print("Process needs improvement")
else:
    print("Process is not capable")

Next Steps¤