1use 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 let normal_readings = generate_industrial_data(30);
16 println!(
17 "Generated {} sensor readings (1 month)",
18 normal_readings.len()
19 );
20
21 let mut detector = AnomalyDetector::new(4)?; detector.train(&normal_readings)?;
27
28 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)?; 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 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 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); println!("Detection time: {energy_time:?}");
107 } else {
108 println!("Energy consumption within normal parameters");
109 }
110
111 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 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; let cost_savings = downtime_prevented as f64 * 5000.0; let maintenance_costs = maintenance_alerts as f64 * 2000.0; 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; let normal_patterns = vec![
170 vec!["TEMP_NORMAL", "TEMP_STABLE", "TEMP_WITHIN_RANGE"],
172 vec!["TEMP_STARTUP", "TEMP_RISING", "TEMP_NORMAL", "TEMP_STABLE"],
173 vec!["PRESSURE_NORMAL", "PRESSURE_STABLE", "PRESSURE_OPTIMAL"],
175 vec!["PRESSURE_STARTUP", "PRESSURE_BUILDING", "PRESSURE_NORMAL"],
176 vec!["VIBRATION_LOW", "VIBRATION_NORMAL", "VIBRATION_STABLE"],
178 vec![
179 "VIBRATION_STARTUP",
180 "VIBRATION_SETTLING",
181 "VIBRATION_NORMAL",
182 ],
183 vec!["FLOW_NORMAL", "FLOW_STABLE", "FLOW_OPTIMAL"],
185 vec!["FLOW_STARTUP", "FLOW_RAMPING", "FLOW_NORMAL"],
186 vec!["POWER_NORMAL", "POWER_EFFICIENT", "POWER_STABLE"],
188 vec!["POWER_STARTUP", "POWER_RAMPING", "POWER_NORMAL"],
189 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 "VIBRATION_NORMAL",
208 "TEMP_NORMAL",
209 "SOUND_NORMAL",
210 "VIBRATION_SLIGHT_INCREASE",
212 "TEMP_SLIGHT_RISE",
213 "SOUND_CHANGE",
214 "VIBRATION_IRREGULAR",
215 "TEMP_FLUCTUATION",
216 "SOUND_GRINDING",
217 "VIBRATION_HIGH",
219 "TEMP_HIGH",
220 "SOUND_LOUD_GRINDING",
221 "VIBRATION_SEVERE",
222 "TEMP_CRITICAL",
223 "SOUND_METAL_ON_METAL",
224 "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 "CONVEYOR_NORMAL",
355 "ROBOT_CYCLE_COMPLETE",
356 "QUALITY_PASS",
357 "CONVEYOR_NORMAL",
358 "ROBOT_CYCLE_COMPLETE",
359 "QUALITY_PASS",
360 "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 "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 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 } else if critical_indicators > 1 {
436 24 } else {
438 168 }
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 }
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 }
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}