RUL Predictor CCGT is an LSTM-based model fine-tuned for predicting Remaining Useful Life of Combined Cycle Gas Turbine components. Designed for real-world deployment where historian data is incomplete, sensor readings drift, and timestamps are inconsistent.
Pre-training: NASA C-MAPSS turbofan degradation dataset (FD001-FD004)
Why LSTM: Captures long-term degradation patterns in sequential sensor data
Transfer Learning to CCGT Domain
Phase 1: Pre-train on C-MAPSS (general turbomachinery patterns)
└── 100 engines, 21 sensors, run-to-failure trajectories
Phase 2: Domain Adaptation to GE Frame 7FA
└── Synthetic data based on GE TIL (Technical Information Letters)
└── Maintenance interval patterns from industry benchmarks
Phase 3: Fine-tune on target fleet
└── Progressive unfreezing (output layers → all layers)
└── Learning rate warmup: 1e-5 → 1e-3 over 5 epochs
Hyperparameter Tuning
Parameter
Value
Tuning Method
Sequence Length
50 cycles
Grid search [30, 50, 100]
LSTM Units
64, 32
Bayesian optimization
Dropout
0.2
Cross-validation
Learning Rate
1e-3
Cosine annealing
Batch Size
32
Memory constraints
Early Stopping
10 epochs patience
Validation loss
Handling Messy Historian Data
Real-world PI/OSIsoft historian data has quality issues. This model includes preprocessing for:
1. Missing Values & Gaps
python
1# Gap handling strategy2defhandle_gaps(df, max_gap_minutes=5):3"""
4 - Gaps < 5 min: Linear interpolation
5 - Gaps 5-60 min: Forward-fill with decay factor
6 - Gaps > 60 min: Mark as separate sequence
7 """8 df = df.resample('1T').asfreq()# Ensure uniform timestamps910# Short gaps: interpolate11 df = df.interpolate(method='linear', limit=5)1213# Medium gaps: forward-fill with exponential decay14 df = df.fillna(method='ffill', limit=60)1516return df
2. Sensor Drift Correction
python
1# Detect and correct calibration drift2defcorrect_drift(series, window=168):# 1-week rolling window3"""
4 Identifies gradual baseline shift vs. true degradation.
5 Uses Hodrick-Prescott filter to separate trend from drift.
6 """7from statsmodels.tsa.filters.hp_filter import hpfilter
8 cycle, trend = hpfilter(series, lamb=1600)910# Only correct if drift exceeds 2% of baseline11 drift_magnitude =(trend.max()- trend.min())/ series.mean()12if drift_magnitude >0.02:13return series - trend + trend.iloc[0]14return series
3. Outlier Removal
python
1# Robust outlier detection for sensor data2defremove_outliers(df, columns, threshold=3):3"""
4 Z-score based outlier removal with rolling statistics.
5 Uses MAD (Median Absolute Deviation) for robustness.
6 """7for col in columns:8 rolling_median = df[col].rolling(window=60, center=True).median()9 rolling_mad = df[col].rolling(window=60, center=True).apply(10lambda x: np.median(np.abs(x - np.median(x)))11)1213 z_scores =0.6745*(df[col]- rolling_median)/ rolling_mad
14 df.loc[np.abs(z_scores)> threshold, col]= np.nan
1516return df.interpolate(method='linear')
4. Timestamp Alignment
python
1# Align timestamps from multiple data sources2defalign_timestamps(dfs, tolerance='1T'):3"""
4 SCADA, DCS, and historian may have different clock sources.
5 Aligns to nearest minute with configurable tolerance.
6 """7 aligned = pd.concat(dfs, axis=1)8 aligned.index = aligned.index.round(tolerance)9return aligned.groupby(level=0).first()
5. Bad Quality Flag Handling
python
1# OPC UA quality codes2QUALITY_GOOD =[192,216]# Good, Good_LocalOverride3QUALITY_UNCERTAIN =[64,68,80]# Uncertain values45deffilter_by_quality(df, quality_col='opc_quality'):6"""
7 Filters data based on OPC UA quality codes.
8 Marks uncertain values for interpolation.
9 """10 mask_good = df[quality_col].isin(QUALITY_GOOD)11 mask_uncertain = df[quality_col].isin(QUALITY_UNCERTAIN)1213# Keep good, interpolate uncertain, drop bad14 df.loc[~mask_good &~mask_uncertain]= np.nan
15return df.interpolate(method='linear', limit=10)
Prompt Engineering (Maintenance Strategy)
The model outputs RUL cycles. An LLM generates maintenance recommendations:
System Prompt
You are a gas turbine maintenance advisor for a power generation fleet.
Given equipment health data, provide actionable maintenance recommendations.
Context:
- Asset: GE Frame 7FA Combined Cycle Gas Turbine
- Criticality: High (baseload unit, >$2M/day revenue impact)
- Maintenance Philosophy: Condition-based with OEM intervals
Output Format (JSON):
{
"urgency": "IMMEDIATE|SCHEDULED|ROUTINE",
"recommended_action": "string",
"parts_required": ["part_number", ...],
"estimated_duration_hours": int,
"risk_if_deferred": "string"
}
Few-Shot Examples
Example 1:
Input: RUL = 15 cycles, Health Index = 35%, Primary Degradation = Vibration
Output: {
"urgency": "IMMEDIATE",
"recommended_action": "Schedule bearing inspection within 48 hours. Borescope compressor section.",
"parts_required": ["GE-7FA-BRG-001", "GE-7FA-SEAL-003"],
"estimated_duration_hours": 72,
"risk_if_deferred": "Potential bearing seizure leading to compressor blade contact. Forced outage risk: HIGH"
}
Example 2:
Input: RUL = 120 cycles, Health Index = 78%, Primary Degradation = Heat Rate
Output: {
"urgency": "SCHEDULED",
"recommended_action": "Plan combustion inspection during next maintenance window. Check fuel nozzles for coking.",
"parts_required": ["GE-7FA-NOZZLE-SET"],
"estimated_duration_hours": 120,
"risk_if_deferred": "Gradual efficiency loss (~0.5%/month). No immediate reliability concern."
}
Model Architecture
Input Sequence (50 timesteps × 5 features):
├── health_index (%) - Composite health score [0-100]
├── vibration_trend (in/s) - 24h rolling average
├── heat_rate_delta (%) - Deviation from design
├── operating_hours - Since last major overhaul
└── start_count - Thermal cycles (equivalent)
LSTM Layer 1: 64 units, return_sequences=True
└── Dropout: 0.2
LSTM Layer 2: 32 units, return_sequences=False
└── Dropout: 0.2
Dense: 16 units, ReLU
Dense: 1 unit, Linear (RUL output)
Total Parameters: 45,697
Trainable: 45,697
Performance
Metric
C-MAPSS (Pre-train)
CCGT (Fine-tuned)
MAE
14.2 cycles
12.3 cycles
RMSE
21.5 cycles
18.7 cycles
R²
0.87
0.91
Early Warning Rate
89%
94%
Usage
python
1import joblib
2import numpy as np
3import pandas as pd
45# Load model6model = joblib.load("rul_predictor_ccgt.joblib")78# Prepare input sequence (last 50 cycles of health data)9health_history = pd.read_csv("unit_health.csv")10sequence = health_history[['health_index','vibration','heat_rate_delta',11'operating_hours','start_count']].tail(50).values
12sequence = sequence.reshape(1,50,5)# Batch of 11314# Predict RUL15rul = model.predict(sequence)[0]16print(f"Predicted Remaining Useful Life: {rul:.0f} cycles")1718# Generate maintenance strategy (requires LLM)19if rul <30:20print("⚠️ IMMEDIATE attention required")21elif rul <100:22print("📅 Schedule maintenance in next window")23else:24print("✓ Normal monitoring")