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