Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Signal Detection

Signal detection identifies out-of-control conditions in your process using the Western Electric (WECO) rules. These rules detect patterns that indicate special cause variation.

What You’ll Learn

  1. Understand all 8 Western Electric rules

  2. Configure which rules to apply

  3. Interpret signal detection results

  4. Visualize rule violations on charts

Setup

import numpy as np
import pandas as pd
from processbehavior import ProcessBehavior

Create Data with Various Patterns

We’ll create data that exhibits different out-of-control patterns to demonstrate each rule:

np.random.seed(42)

n = 50
values = np.random.normal(100, 2, n)

# Rule 1: Point beyond limits (index 10)
values[10] = 112  # Beyond 3-sigma

# Rule 4: Run (8 consecutive same side) (indices 20-27)
values[20:28] = np.random.normal(103, 0.5, 8)  # All above center

# Rule 5: Trend (6 consecutive increasing) (indices 35-40)
values[35:41] = [98, 99, 100, 101, 102, 103]

df = pd.DataFrame({
    'day': range(1, n + 1),
    'measurement': np.round(values, 2)
})

print(f"Dataset: {len(df)} observations")
df.head()
Dataset: 50 observations
Loading...

Create Analysis

pb = ProcessBehavior(df)
study = pb.formulate(
    response=pb.cols.measurement,
    time=pb.cols.day
)
result = study.execute()   # single stream over time -> recommended chart is X

The 8 Western Electric Rules

Zone Definitions

The rules reference three zones on each side of the centerline:

  • Zone C: Within 1 sigma of centerline

  • Zone B: Between 1 and 2 sigma

  • Zone A: Between 2 and 3 sigma

The Rules

RuleNamePatternInterpretation
1Beyond Limits1 point > 3σ from centerObvious special cause
2Zone A2 of 3 consecutive in Zone ALikely shift
3Zone B4 of 5 consecutive in Zone B+Process shifting
4Run8+ consecutive same sideSustained shift
5Trend6+ consecutive increasing/decreasingDrift
6Oscillation14+ consecutive alternatingOvercontrol
7Hugging Center15+ consecutive in Zone CReduced variation
8Avoiding Center8+ consecutive not in Zone CBimodal distribution

Standard vs. Extended Rules

ProcessBehavior offers three rule sets:

  • 'standard': Rules 1-4 (most common, lower false alarm rate)

  • 'extended': Rules 1-8 (more sensitive, higher false alarm rate)

  • 'all': Same as extended

# Default rules (chart-appropriate: all 8 for an X chart)
signals = result.detect_signals(chart='X')
print(f"Signals found: {signals.count}")

# The documented presets:
std = result.detect_signals(chart='X', rules='standard')   # rules 1-4
ext = result.detect_signals(chart='X', rules='extended')   # rules 1-8
print(f"standard (1-4): {std.count} | extended (1-8): {ext.count}")
Signals found: 11
standard (1-4): 8 | extended (1-8): 11

Examining Signal Results

signals = result.detect_signals(chart='X')

print(f"Has signals: {signals.has_signals}")
print(f"Total count: {signals.count}")
print(f"\nFlagged observations: {signals.flagged_observations}")
Has signals: True
Total count: 11

Flagged observations: {np.int64(10), np.int64(23), np.int64(24), np.int64(25), np.int64(26), np.int64(27), np.int64(28)}
# View all violations
print("All Violations:")
signals.violations
All Violations:
Loading...
# Summary by rule
print(signals.summary)

======================================================================
Signal Detection Summary: X
======================================================================
Total violations: 11
Flagged observations: 7

Violations by rule:
  rule_3: 6
  rule_8: 3
  rule_1: 1
  rule_4: 1

First violations:
  • Obs 10: Point beyond control limits (value=112.000)
  • Obs 23: 4 of 5 consecutive points in Zone B or beyond (value=103.310)
  • Obs 24: 4 of 5 consecutive points in Zone B or beyond (value=103.520)
  • Obs 25: 4 of 5 consecutive points in Zone B or beyond (value=103.470)
  • Obs 25: 8+ consecutive points avoiding Zone C (value=103.470)
  ... and 6 more

======================================================================

# Violations grouped by rule
print("\nViolations by Rule:")
for rule, violations in signals.by_rule.items():
    print(f"  {rule}: {len(violations)} violation(s)")

Violations by Rule:
  rule_1: 1 violation(s)
  rule_3: 6 violation(s)
  rule_4: 1 violation(s)
  rule_8: 3 violation(s)

Visualize with Rule Violations

fig = result.plot(
    show_zones=True,
    show_rules=True,  # Shows all rule violations
    highlight_signals=True
)
fig.show()
Loading...

Custom Rule Configuration

Pass an explicit list of rule names, or build a RuleSet for precise control:

# Custom rule configuration using a list of rule names
signals_custom = result.detect_signals(
    chart='X',
    rules=['rule_1', 'rule_4']  # Beyond limits and runs
)
print(f"Custom rules found: {signals_custom.count} signals")
Custom rules found: 2 signals
# Specific rules - just Rule 1 (beyond limits)
signals_rule1 = result.detect_signals(
    chart='X',
    rules=['rule_1']
)
print(f"Rule 1 only: {signals_rule1.count} signals")
Rule 1 only: 1 signals
# The RuleSet builder: compose exactly the rules you want
from processbehavior.signals import RuleSet

rules = RuleSet().beyond_limits().run(length=8).trend(length=6)
signals_rs = result.detect_signals(chart='X', rules=rules)

print(f"Rules applied: {rules.get_rules()}")
print(f"Signals found: {signals_rs.count}")
Rules applied: ['rule_1', 'rule_4', 'rule_5']
Signals found: 2

Rule Applicability by Chart Type

Not all rules apply to all chart types:

Chart TypeApplicable Rules
XAll 8 rules
mRAll 8 rules
XbarRule 1 only
SRule 1 only

Why the Difference?

  • X and mR charts are time-ordered, so sequential patterns (runs, trends) are meaningful

  • Xbar/S charts compare subgroups, which may not be time-ordered

  • For Xbar/S, only points beyond limits indicate special causes

Understanding Each Rule

Rule 1: Beyond Limits

Pattern: Single point beyond 3σ limits

Interpretation: Almost certainly a special cause. In a stable process, the chance of a point beyond 3σ is about 0.27%.

Action: Investigate immediately. What changed?

# Our data point at index 10 (day 11) should trigger Rule 1
print(f"Value at day 11: {df.loc[10, 'measurement']}")
stats = result.get_statistics('X')
print(f"UPL: {stats['upl']:.2f}")
Value at day 11: 112.0
UPL: 106.56

Rule 4: Run

Pattern: 8+ consecutive points on same side of centerline

Interpretation: The process has shifted. Even small shifts (< 1σ) will eventually produce runs.

Action: Look for what caused the sustained change.

# Days 21-28 should all be above centerline
print("Values at days 21-28:")
print(df.loc[20:27, ['day', 'measurement']])
print(f"\nCenterline: {stats['center']:.2f}")
Values at days 21-28:
    day  measurement
20   21       103.16
21   22       102.81
22   23       102.66
23   24       103.31
24   25       103.52
25   26       103.47
26   27       102.58
27   28       102.85

Centerline: 100.54

Rule 5: Trend

Pattern: 6+ consecutive points increasing or decreasing

Interpretation: Process is drifting. Common causes: tool wear, temperature changes, material degradation.

Action: Identify and address the source of drift.

# Days 36-41 have increasing trend
print("Values at days 36-41:")
print(df.loc[35:40, ['day', 'measurement']])
Values at days 36-41:
    day  measurement
35   36         98.0
36   37         99.0
37   38        100.0
38   39        101.0
39   40        102.0
40   41        103.0

False Alarm Rates

More rules = more sensitivity = more false alarms

Rule SetApprox. False Alarm Rate
Rule 1 only0.27% per point
Rules 1-4~1-2% per point
Rules 1-8~3-5% per point

Recommendation: Start with standard rules (1-4). Only use extended rules when you have enough data and can investigate false alarms.

Summary

In this tutorial, you learned:

  • The 8 Western Electric rules detect different patterns

  • Use 'standard' (rules 1-4) for most applications

  • Use 'extended' (rules 1-8) for more sensitive detection

  • Use RuleSet() builder for custom configurations

  • Only Rule 1 applies to Xbar/S charts; all 8 apply to X and mR

  • More rules = more sensitivity = more false alarms

Next Steps