Examples¶
Real-world code examples for common use cases. Each example includes complete, runnable code you can adapt for your own data.
Solar Farm SCADA Data¶
Detect inverter faults, irradiance sensor failures, and tracker angle anomalies.
import tsqc
import pandas as pd
from tsqc.rules import FlatlineRule, RangeRule, DeltaRule
# Load solar farm SCADA data
df = pd.read_csv("solar_scada.csv") # timestamp, tag_name, value
# Define rules in Python
rules = [
FlatlineRule(window="1h", min_delta=0.01, level="sus"),
RangeRule(min_val=-10, max_val=2000, level="bad"), # Catch invalid readings
DeltaRule(max_delta=500, level="sus"), # Catch spikes
]
# Run check
result = tsqc.check(df, rules=rules, assume_tz="America/Phoenix")
# View summary
print(result.summary())
# Generate interactive chart
fig = result.plot(title="Solar Farm Quality Timeline")
fig.show()
# Export report
result.export_report("solar_qc_report.html", title="Solar Farm QC - June 2026")
YAML version:
# solar_rules.yaml
default_rules:
- check: flatline
window: 1h
min_delta: 0.01
level: sus
- check: range
min: -10
max: 2000
level: bad
- check: delta
max_delta: 500
level: sus
tag_rules:
"INVERTER.*":
- check: range
min: 0
max: 5000
level: bad
"MET.IRRADIANCE":
- check: range
min: 0
max: 1500
level: bad
- check: flatline
window: 30min
min_delta: 1.0
level: sus
Oil & Gas Well Pad¶
Monitor pressure sensors, flow meters, and temperature readings.
import tsqc
import pandas as pd
# Load well pad data
df = pd.read_csv("wellpad_data.csv")
# Detect flatlines at zero (common sensor failure)
from tsqc.rules import FlatlineRule, CustomRule, RangeRule
def is_zero_flatline(series):
"""Detect flatlines specifically at zero value"""
return (series == 0) & (series.shift(1) == 0)
rules = [
CustomRule(fn=is_zero_flatline, name="zero_flatline", level="bad"),
FlatlineRule(window="2h", min_delta=0.5, level="sus"),
RangeRule(min_val=0, max_val=10000, level="bad"), # Physical limits
]
result = tsqc.check(df, rules=rules, assume_tz="America/Chicago")
# Find problematic tags
issue_summary = result.issue_summary()
worst_tags = issue_summary.groupby("tag_name")["n_rows_with_issues"].sum().sort_values(ascending=False)
print("Tags with most issues:")
print(worst_tags.head(10))
OSIsoft PI Historian Integration¶
Use existing PI quality codes alongside internal rules.
import tsqc
import pandas as pd
# Load data from PI with quality column
# Assume quality codes: 0=Good, 192=Bad, 193=Questionable
df = pd.read_csv("pi_export.csv") # includes 'pi_quality' column
# Define quality map
quality_map = {
0: "good",
192: "bad",
193: "sus",
194: "bad", # I/O Timeout
195: "bad", # Bad Input
}
# Combined mode: merge PI quality with internal rules
result = tsqc.check(
df,
external_quality_col="pi_quality",
quality_mode="combined",
quality_map=quality_map,
rules="pi_rules.yaml",
assume_tz="UTC",
)
# Rows flagged by both PI and internal rules will show combined reasons
print(result.df[["timestamp", "tag_name", "value", "quality", "quality_reasons"]].head())
# Example output:
# quality_reasons: "source_data_quality: 192|flatline @ 45.2000"
YAML with quality_map:
# pi_rules.yaml
quality_map:
0: good
192: bad
193: sus
194: bad
195: bad
default_rules:
- check: null
level: bad
- check: flatline
window: 1h
min_delta: 0.001
level: sus
See full historian integration guide →
Manufacturing Line Monitoring¶
Detect machine downtime, sensor drift, and out-of-spec conditions.
import tsqc
import pandas as pd
from tsqc.rules import OutlierRule, RangeRule, DeltaRule
# Load production line sensor data
df = pd.read_csv("production_sensors.csv")
# Use statistical outlier detection for anomaly detection
rules = [
OutlierRule(method="zscore", threshold=3.0, window="24h", level="sus"),
RangeRule(min_val=0, max_val=100, level="bad"), # Process limits
DeltaRule(max_delta=10, level="sus"), # Sudden changes
]
result = tsqc.check(df, rules=rules, assume_tz="Europe/Berlin")
# Flag rows where machine downtime occurred
downtime_mask = (result.df["tag_name"].str.contains("SPEED")) & (result.df["value"] == 0)
print(f"Detected {downtime_mask.sum()} downtime events")
# Visualize
fig = result.plot(title="Production Line Quality - Week 27")
fig.show()
Multi-Site Battery Storage¶
Monitor voltage, current, and temperature across multiple battery sites.
import tsqc
import pandas as pd
# Load data from multiple sites
df = pd.read_csv("battery_fleet_data.csv")
# Tag-specific rules using glob patterns
yaml_config = """
default_rules:
- check: null
level: bad
- check: outlier
method: mad
threshold: 3.5
window: 168h # 1 week
level: sus
tag_rules:
"SITE_*.VOLTAGE":
- check: range
min: 800
max: 1000
level: bad
"SITE_*.CURRENT":
- check: range
min: -500
max: 500
level: bad
"SITE_*.TEMP_C":
- check: range
min: -10
max: 60
level: bad
- check: delta
max_delta: 5
level: sus
"""
with open("battery_rules.yaml", "w") as f:
f.write(yaml_config)
result = tsqc.check(df, rules="battery_rules.yaml", assume_tz="UTC")
# Group issues by site
result.df["site"] = result.df["tag_name"].str.extract(r"(SITE_\d+)")
site_summary = result.df.groupby("site")["quality"].value_counts().unstack(fill_value=0)
print(site_summary)
Automated Daily Reporting¶
Schedule quality checks and email reports automatically.
import tsqc
import pandas as pd
from datetime import datetime, timedelta
def daily_quality_report(data_source, output_dir="./reports"):
"""
Run daily quality check and generate HTML report.
Can be scheduled with cron or Task Scheduler.
"""
# Load today's data
today = datetime.now().date()
df = pd.read_csv(f"{data_source}/data_{today}.csv")
# Run check
result = tsqc.check(df, rules="production_rules.yaml", assume_tz="UTC")
# Generate report
report_path = f"{output_dir}/qc_report_{today}.html"
result.export_report(report_path, title=f"Daily QC Report - {today}")
# Get summary stats
summary = result.summary()
critical_tags = summary[summary["pct_bad"] > 5.0]
# Log results
print(f"Report generated: {report_path}")
print(f"Tags with >5% bad quality: {len(critical_tags)}")
if len(critical_tags) > 0:
print("⚠️ Critical quality issues detected:")
print(critical_tags[["tag_name", "pct_bad", "n_bad"]])
# Send alert email here
return result, report_path
# Run daily report
result, report_path = daily_quality_report("/data/scada_exports")
Cron schedule (Linux):
Windows Task Scheduler:
# Create scheduled task
$action = New-ScheduledTaskAction -Execute "python" -Argument "C:\scripts\daily_report.py"
$trigger = New-ScheduledTaskTrigger -Daily -At 6am
Register-ScheduledTask -Action $action -Trigger $trigger -TaskName "DailyQC" -Description "Run timeseries-qc daily report"
Timestamp Quality Validation¶
Detect gaps, duplicates, and frequency drift in your time series.
import tsqc
import pandas as pd
df = pd.read_csv("sensor_data.csv")
result = tsqc.check(df, assume_tz="UTC")
# Check timestamp health
ts_issues = result.check_timestamps(expected_freq="1min", freq_tolerance=0.1)
print("Timestamp Issues:")
print(ts_issues)
# Example output:
# tag_name issue_type timestamp description
# TAG_001 gap 2026-01-01 05:00 Gap of 15.0 minutes
# TAG_002 duplicate 2026-01-01 12:30 Duplicate timestamp
# TAG_003 non_monotonic 2026-01-01 18:00 Earlier than previous
# TAG_004 freq_drift 2026-01-01 23:45 Actual: 1.2min vs expected: 1.0min
Next Steps¶
- Quickstart Tutorial - Get started in 5 lines
- User Guide - Complete walkthrough
- API Reference - Full API documentation
- YAML Configuration - Configure rules in YAML
- SCADA Integration Guide - OSIsoft PI, OPC UA, etc.
- Tutorials - Step-by-step industry-specific guides