industrial_iot_monitoring/
industrial_iot_monitoring.rs

1//! Industrial IoT Monitoring Example
2//!
3//! This example demonstrates predictive maintenance and anomaly detection
4//! in industrial IoT environments using anomaly-grid for equipment monitoring,
5//! failure prediction, and operational optimization.
6
7use anomaly_grid::*;
8use std::time::Instant;
9
10fn main() -> Result<(), Box<dyn std::error::Error>> {
11    println!("šŸ­ Industrial IoT Monitoring with Anomaly Grid");
12    println!("Predictive maintenance and equipment failure detection\n");
13
14    // Simulate 1 year of normal industrial operations
15    let normal_operations = generate_industrial_data(365); // 1 year
16    println!(
17        "Generated {} sensor readings (1 year)",
18        normal_operations.len()
19    );
20
21    // Initialize anomaly detection for IoT sensor data
22    let mut detector = AnomalyDetector::new(4)?; // Order 4 for sensor patterns
23
24    // Train on normal operational data
25    detector.train(&normal_operations)?;
26
27    // Equipment monitoring scenarios
28    println!("\nšŸ”§ Equipment Health Monitoring");
29
30    let equipment_scenarios = vec![
31        ("Bearing Wear", generate_bearing_wear_pattern()),
32        ("Vibration Anomaly", generate_vibration_anomaly()),
33        ("Temperature Drift", generate_temperature_drift()),
34        ("Pressure Fluctuation", generate_pressure_fluctuation()),
35        ("Lubrication Failure", generate_lubrication_failure()),
36        ("Motor Imbalance", generate_motor_imbalance()),
37        ("Seal Degradation", generate_seal_degradation()),
38    ];
39
40    let mut maintenance_alerts = 0;
41    let mut critical_failures_prevented = 0;
42
43    for (equipment_issue, sensor_sequence) in equipment_scenarios {
44        println!("\nMonitoring: {equipment_issue}");
45
46        let detect_start = Instant::now();
47        let anomalies = detector.detect_anomalies(&sensor_sequence, 0.005)?; // Sensitive for safety
48        let detect_time = detect_start.elapsed();
49
50        if !anomalies.is_empty() {
51            maintenance_alerts += 1;
52
53            let severity = calculate_severity(&anomalies);
54            let time_to_failure = estimate_time_to_failure(&sensor_sequence);
55            let maintenance_cost = estimate_maintenance_cost(equipment_issue);
56
57            println!("  āš ļø MAINTENANCE ALERT");
58            println!("  šŸ“Š Anomalies detected: {}", anomalies.len());
59            println!("  Severity: {severity}");
60            println!("  Time to failure: {time_to_failure} hours");
61            println!("  Estimated maintenance cost: ${maintenance_cost:.0}");
62            println!("  Detection time: {detect_time:?}");
63
64            if severity == "CRITICAL" {
65                critical_failures_prevented += 1;
66                println!("  🚨 IMMEDIATE SHUTDOWN RECOMMENDED");
67            }
68
69            generate_maintenance_recommendation(equipment_issue, &severity, time_to_failure);
70        } else {
71            println!("  āœ… Equipment operating normally");
72        }
73    }
74
75    // Production line monitoring
76    println!("\nšŸ­ Production Line Monitoring");
77    let production_data = generate_production_line_data();
78
79    let line_start = Instant::now();
80    let line_anomalies = detector.detect_anomalies(&production_data, 0.01)?;
81    let line_time = line_start.elapsed();
82
83    if !line_anomalies.is_empty() {
84        let efficiency_impact = calculate_efficiency_impact(&line_anomalies);
85        println!("Production anomalies detected: {}", line_anomalies.len());
86        println!("Efficiency impact: {efficiency_impact:.1}%");
87        println!("Detection time: {line_time:?}");
88    } else {
89        println!("Production line operating normally");
90    }
91
92    // Energy consumption monitoring
93    println!("\n⚔ Energy Consumption Monitoring");
94    let energy_data = generate_energy_consumption_data();
95
96    let energy_start = Instant::now();
97    let energy_anomalies = detector.detect_anomalies(&energy_data, 0.02)?;
98    let energy_time = energy_start.elapsed();
99
100    if !energy_anomalies.is_empty() {
101        let energy_waste = calculate_energy_waste(&energy_anomalies);
102        println!("Energy anomalies detected: {}", energy_anomalies.len());
103        println!("Estimated energy waste: {energy_waste:.0} kWh");
104        println!("Cost impact: ${:.2}", energy_waste * 0.12); // $0.12/kWh
105        println!("Detection time: {energy_time:?}");
106    } else {
107        println!("Energy consumption within normal parameters");
108    }
109
110    // Batch processing for multiple machines
111    println!("\nšŸ“¦ Multi-Machine Batch Processing");
112    let machine_data = vec![
113        generate_machine_data("CNC_001"),
114        generate_machine_data("PRESS_002"),
115        generate_machine_data("ROBOT_003"),
116        generate_machine_data("CONVEYOR_004"),
117        generate_machine_data("WELDER_005"),
118    ];
119
120    let batch_start = Instant::now();
121    let config = AnomalyGridConfig::default().with_max_order(6)?;
122    let batch_results = batch_process_sequences(&machine_data, &config, 0.01)?;
123    let batch_time = batch_start.elapsed();
124
125    println!(
126        "Processed {} machines in {:?}",
127        machine_data.len(),
128        batch_time
129    );
130    for (i, results) in batch_results.iter().enumerate() {
131        let machine_names = [
132            "CNC_001",
133            "PRESS_002",
134            "ROBOT_003",
135            "CONVEYOR_004",
136            "WELDER_005",
137        ];
138        println!(
139            "  {}: {} anomalies detected",
140            machine_names[i],
141            results.len()
142        );
143    }
144
145    // Summary and ROI calculation
146    println!("\nšŸ“Š Predictive Maintenance Summary");
147    println!("Maintenance alerts generated: {maintenance_alerts}");
148    println!("Critical failures prevented: {critical_failures_prevented}");
149
150    let downtime_prevented = critical_failures_prevented * 8; // 8 hours per failure
151    let cost_savings = downtime_prevented as f64 * 5000.0; // $5000/hour downtime cost
152    let maintenance_costs = maintenance_alerts as f64 * 2000.0; // $2000 per maintenance
153    let net_savings = cost_savings - maintenance_costs;
154
155    println!("Downtime prevented: {downtime_prevented} hours");
156    println!("Cost savings: ${cost_savings:.0}");
157    println!("Maintenance costs: ${maintenance_costs:.0}");
158    println!("Net savings: ${net_savings:.0}");
159    println!("ROI: {:.1}%", (net_savings / maintenance_costs) * 100.0);
160
161    Ok(())
162}
163
164fn generate_industrial_data(days: usize) -> Vec<String> {
165    let mut data = Vec::new();
166    let readings_per_day = 1440; // One reading per minute
167
168    let normal_patterns = vec![
169        // Temperature readings
170        vec!["TEMP_NORMAL", "TEMP_STABLE", "TEMP_WITHIN_RANGE"],
171        vec!["TEMP_STARTUP", "TEMP_RISING", "TEMP_NORMAL", "TEMP_STABLE"],
172        // Pressure readings
173        vec!["PRESSURE_NORMAL", "PRESSURE_STABLE", "PRESSURE_OPTIMAL"],
174        vec!["PRESSURE_STARTUP", "PRESSURE_BUILDING", "PRESSURE_NORMAL"],
175        // Vibration readings
176        vec!["VIBRATION_LOW", "VIBRATION_NORMAL", "VIBRATION_STABLE"],
177        vec![
178            "VIBRATION_STARTUP",
179            "VIBRATION_SETTLING",
180            "VIBRATION_NORMAL",
181        ],
182        // Flow readings
183        vec!["FLOW_NORMAL", "FLOW_STABLE", "FLOW_OPTIMAL"],
184        vec!["FLOW_STARTUP", "FLOW_RAMPING", "FLOW_NORMAL"],
185        // Power consumption
186        vec!["POWER_NORMAL", "POWER_EFFICIENT", "POWER_STABLE"],
187        vec!["POWER_STARTUP", "POWER_RAMPING", "POWER_NORMAL"],
188        // Lubrication system
189        vec!["LUBE_PRESSURE_OK", "LUBE_FLOW_NORMAL", "LUBE_TEMP_OK"],
190        vec!["LUBE_CYCLE_START", "LUBE_DISPENSING", "LUBE_CYCLE_COMPLETE"],
191    ];
192
193    for _ in 0..days {
194        for _ in 0..readings_per_day {
195            let pattern = &normal_patterns[data.len() % normal_patterns.len()];
196            data.extend(pattern.iter().map(|s| s.to_string()));
197        }
198    }
199
200    data
201}
202
203fn generate_bearing_wear_pattern() -> Vec<String> {
204    vec![
205        // Early stage
206        "VIBRATION_NORMAL",
207        "TEMP_NORMAL",
208        "SOUND_NORMAL",
209        // Developing wear
210        "VIBRATION_SLIGHT_INCREASE",
211        "TEMP_SLIGHT_RISE",
212        "SOUND_CHANGE",
213        "VIBRATION_IRREGULAR",
214        "TEMP_FLUCTUATION",
215        "SOUND_GRINDING",
216        // Advanced wear
217        "VIBRATION_HIGH",
218        "TEMP_HIGH",
219        "SOUND_LOUD_GRINDING",
220        "VIBRATION_SEVERE",
221        "TEMP_CRITICAL",
222        "SOUND_METAL_ON_METAL",
223        // Imminent failure
224        "VIBRATION_EXTREME",
225        "TEMP_OVERHEATING",
226        "SOUND_CATASTROPHIC",
227    ]
228    .into_iter()
229    .map(String::from)
230    .collect()
231}
232
233fn generate_vibration_anomaly() -> Vec<String> {
234    vec![
235        "VIBRATION_NORMAL",
236        "VIBRATION_NORMAL",
237        "VIBRATION_NORMAL",
238        "VIBRATION_SPIKE",
239        "VIBRATION_HIGH",
240        "VIBRATION_OSCILLATING",
241        "VIBRATION_HARMONIC",
242        "VIBRATION_RESONANCE",
243        "VIBRATION_UNSTABLE",
244        "VIBRATION_CRITICAL",
245        "VIBRATION_SHUTDOWN_REQUIRED",
246    ]
247    .into_iter()
248    .map(String::from)
249    .collect()
250}
251
252fn generate_temperature_drift() -> Vec<String> {
253    vec![
254        "TEMP_NORMAL",
255        "TEMP_NORMAL",
256        "TEMP_SLIGHT_RISE",
257        "TEMP_GRADUAL_INCREASE",
258        "TEMP_ABOVE_NORMAL",
259        "TEMP_TRENDING_UP",
260        "TEMP_HIGH",
261        "TEMP_VERY_HIGH",
262        "TEMP_CRITICAL",
263        "TEMP_OVERHEATING",
264        "TEMP_SHUTDOWN_THRESHOLD",
265    ]
266    .into_iter()
267    .map(String::from)
268    .collect()
269}
270
271fn generate_pressure_fluctuation() -> Vec<String> {
272    vec![
273        "PRESSURE_NORMAL",
274        "PRESSURE_STABLE",
275        "PRESSURE_SLIGHT_DROP",
276        "PRESSURE_FLUCTUATING",
277        "PRESSURE_UNSTABLE",
278        "PRESSURE_CYCLING",
279        "PRESSURE_LOW",
280        "PRESSURE_VERY_LOW",
281        "PRESSURE_CRITICAL_LOW",
282        "PRESSURE_SYSTEM_FAILURE",
283        "PRESSURE_EMERGENCY_STOP",
284    ]
285    .into_iter()
286    .map(String::from)
287    .collect()
288}
289
290fn generate_lubrication_failure() -> Vec<String> {
291    vec![
292        "LUBE_PRESSURE_OK",
293        "LUBE_FLOW_NORMAL",
294        "LUBE_TEMP_OK",
295        "LUBE_PRESSURE_DROP",
296        "LUBE_FLOW_REDUCED",
297        "LUBE_TEMP_RISE",
298        "LUBE_PRESSURE_LOW",
299        "LUBE_FLOW_INSUFFICIENT",
300        "LUBE_TEMP_HIGH",
301        "LUBE_SYSTEM_FAILURE",
302        "LUBE_STARVATION",
303        "LUBE_EMERGENCY",
304    ]
305    .into_iter()
306    .map(String::from)
307    .collect()
308}
309
310fn generate_motor_imbalance() -> Vec<String> {
311    vec![
312        "MOTOR_BALANCED",
313        "CURRENT_NORMAL",
314        "TORQUE_STABLE",
315        "MOTOR_SLIGHT_IMBALANCE",
316        "CURRENT_FLUCTUATION",
317        "TORQUE_VARIATION",
318        "MOTOR_IMBALANCED",
319        "CURRENT_SPIKES",
320        "TORQUE_IRREGULAR",
321        "MOTOR_SEVERE_IMBALANCE",
322        "CURRENT_OVERLOAD",
323        "TORQUE_UNSTABLE",
324    ]
325    .into_iter()
326    .map(String::from)
327    .collect()
328}
329
330fn generate_seal_degradation() -> Vec<String> {
331    vec![
332        "SEAL_INTACT",
333        "PRESSURE_STABLE",
334        "NO_LEAKAGE",
335        "SEAL_WEAR_INITIAL",
336        "PRESSURE_SLIGHT_DROP",
337        "MINOR_SEEPAGE",
338        "SEAL_DEGRADED",
339        "PRESSURE_LOSS",
340        "VISIBLE_LEAK",
341        "SEAL_FAILURE",
342        "PRESSURE_CRITICAL",
343        "MAJOR_LEAK",
344    ]
345    .into_iter()
346    .map(String::from)
347    .collect()
348}
349
350fn generate_production_line_data() -> Vec<String> {
351    vec![
352        // Normal production
353        "CONVEYOR_NORMAL",
354        "ROBOT_CYCLE_COMPLETE",
355        "QUALITY_PASS",
356        "CONVEYOR_NORMAL",
357        "ROBOT_CYCLE_COMPLETE",
358        "QUALITY_PASS",
359        // Anomaly
360        "CONVEYOR_SLOW",
361        "ROBOT_CYCLE_DELAYED",
362        "QUALITY_FAIL",
363        "CONVEYOR_JAM",
364        "ROBOT_ERROR",
365        "QUALITY_REJECT",
366        "PRODUCTION_STOP",
367        "MAINTENANCE_REQUIRED",
368    ]
369    .into_iter()
370    .map(String::from)
371    .collect()
372}
373
374fn generate_energy_consumption_data() -> Vec<String> {
375    vec![
376        "POWER_BASELINE",
377        "EFFICIENCY_NORMAL",
378        "CONSUMPTION_OPTIMAL",
379        "POWER_BASELINE",
380        "EFFICIENCY_NORMAL",
381        "CONSUMPTION_OPTIMAL",
382        // Energy waste
383        "POWER_SPIKE",
384        "EFFICIENCY_DROP",
385        "CONSUMPTION_HIGH",
386        "POWER_EXCESSIVE",
387        "EFFICIENCY_POOR",
388        "CONSUMPTION_WASTEFUL",
389        "POWER_CRITICAL",
390        "EFFICIENCY_FAILURE",
391        "CONSUMPTION_EXTREME",
392    ]
393    .into_iter()
394    .map(String::from)
395    .collect()
396}
397
398fn generate_machine_data(machine_id: &str) -> Vec<String> {
399    vec![
400        format!("{}_STARTUP", machine_id),
401        format!("{}_NORMAL_OPERATION", machine_id),
402        format!("{}_CYCLE_COMPLETE", machine_id),
403        format!("{}_NORMAL_OPERATION", machine_id),
404        format!("{}_MAINTENANCE_DUE", machine_id),
405    ]
406}
407
408fn calculate_severity(anomalies: &[AnomalyScore]) -> String {
409    let max_strength = anomalies
410        .iter()
411        .map(|a| a.anomaly_strength)
412        .fold(0.0, f64::max);
413
414    if max_strength > 0.9 {
415        "CRITICAL".to_string()
416    } else if max_strength > 0.7 {
417        "HIGH".to_string()
418    } else if max_strength > 0.5 {
419        "MEDIUM".to_string()
420    } else {
421        "LOW".to_string()
422    }
423}
424
425fn estimate_time_to_failure(sequence: &[String]) -> u32 {
426    // Estimate based on severity indicators
427    let critical_indicators = sequence
428        .iter()
429        .filter(|s| s.contains("CRITICAL") || s.contains("SEVERE") || s.contains("EXTREME"))
430        .count();
431
432    if critical_indicators > 3 {
433        2 // 2 hours
434    } else if critical_indicators > 1 {
435        24 // 24 hours
436    } else {
437        168 // 1 week
438    }
439}
440
441fn estimate_maintenance_cost(equipment_issue: &str) -> f64 {
442    match equipment_issue {
443        "Bearing Wear" => 5000.0,
444        "Vibration Anomaly" => 3000.0,
445        "Temperature Drift" => 2000.0,
446        "Pressure Fluctuation" => 4000.0,
447        "Lubrication Failure" => 1500.0,
448        "Motor Imbalance" => 8000.0,
449        "Seal Degradation" => 2500.0,
450        _ => 3000.0,
451    }
452}
453
454fn calculate_efficiency_impact(anomalies: &[AnomalyScore]) -> f64 {
455    let avg_strength =
456        anomalies.iter().map(|a| a.anomaly_strength).sum::<f64>() / anomalies.len() as f64;
457
458    avg_strength * 15.0 // Up to 15% efficiency impact
459}
460
461fn calculate_energy_waste(anomalies: &[AnomalyScore]) -> f64 {
462    let total_strength = anomalies.iter().map(|a| a.anomaly_strength).sum::<f64>();
463
464    total_strength * 100.0 // kWh wasted
465}
466
467fn generate_maintenance_recommendation(
468    equipment_issue: &str,
469    severity: &str,
470    time_to_failure: u32,
471) {
472    println!("  šŸ“‹ MAINTENANCE RECOMMENDATION");
473
474    let action = match severity {
475        "CRITICAL" => "IMMEDIATE SHUTDOWN AND REPAIR",
476        "HIGH" => "SCHEDULE URGENT MAINTENANCE",
477        "MEDIUM" => "PLAN MAINTENANCE WITHIN 48 HOURS",
478        _ => "MONITOR AND SCHEDULE ROUTINE MAINTENANCE",
479    };
480
481    println!("    Issue: {equipment_issue}");
482    println!("    Action: {action}");
483    println!("    Timeline: {time_to_failure} hours");
484
485    let parts_needed = match equipment_issue {
486        "Bearing Wear" => "Replacement bearings, lubricant",
487        "Vibration Anomaly" => "Balancing weights, alignment tools",
488        "Temperature Drift" => "Cooling system components, sensors",
489        "Pressure Fluctuation" => "Seals, pressure regulators",
490        "Lubrication Failure" => "Lubricant, filters, pumps",
491        "Motor Imbalance" => "Motor components, alignment equipment",
492        "Seal Degradation" => "Replacement seals, gaskets",
493        _ => "Standard maintenance kit",
494    };
495
496    println!("    Parts needed: {parts_needed}");
497}