Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
132 changes: 106 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,49 +1,129 @@
# BeachHack Template Repository
# Industrial IoT Predictive Maintenance System

![BeachHack Banner](https://github.com/user-attachments/assets/b46c3336-f9eb-473a-ba76-bcf5c0f29d0d)

Official starter template repository for **BeachHack** hackathon participants.
An explainable **Industrial IoT Predictive Maintenance System** built entirely during **BeachHack**.
The system focuses on **physics-based simulation**, **transparent feature extraction**, and **Explainable AI (XAI)** to generate trustworthy, auditable maintenance insights.

---

## 📌 Instructions
## 👤 My Contribution: Data Simulation & Feature Extraction

All teams must **fork this repository** at the start of the hackathon and use the forked repository for all development work. Use of personal or pre-existing repositories is not allowed.
As **Member 1** of the team, I designed and implemented the **core data pipeline** that powers the system.
This includes realistic sensor data simulation and pure signal-processing-based feature extraction to support explainable decision-making.

You are **not restricted to the track or domain** you submitted your initial idea under. Teams are free to choose **any of the released problem statements**.
---

## 📊 Data Simulation Layer

Generates **physics-based sensor streams** that emulate real industrial asset degradation and failure behavior.

### Key Characteristics

- **Sensor Types**
- Vibration (mm/s RMS)
- Temperature (°C)
- Load (%)

- **Failure Progression**
- Normal → Degradation → Pre-failure → Failure Risk

- **Cross-Sensor Causality**
- Vibration spikes precede temperature rise by **2–4 hours**
- Load-dependent resonance effects

- **Industrial Realism**
- Packet loss: **3%**
- Timestamp jitter: **±8 seconds**
- Non-stationary noise

- **Output Format**
- CSV files with **ground-truth `failure_phase` labels**

### Sample CSV Output

```csv
timestamp,asset_id,vibration_rms,temperature_c,load_percent,failure_phase
2026-01-01 00:00:03,pump-001,3.05,44.8,75.2,0
2026-01-01 00:01:07,pump-001,3.12,45.1,76.1,0
```

---

## ⏱️ Important Rules
## ⚙️ Feature Extraction Layer

Transforms raw sensor streams into **diagnostic-ready numerical features**.

- All development must begin **after forking** this repository.
- The problem statements were shared in advance **only for ideation and planning**.
- **No pre-built or pre-developed solutions** are allowed in any form.
- Commit history and repository metadata will be actively reviewed.
- Any violation of these rules may result in **immediate disqualification**.
⚠️ **No decision logic included — pure signal processing only**

### Extracted Features

| Feature | Meaning | Diagnostic Value |
|-------|--------|------------------|
| `vibration_rms` | Current shake intensity | Primary failure indicator |
| `vibration_trend` | Degradation rate (mm/s per min) | Predicts time-to-failure |
| `vibration_delta` | Change vs. 10 mins ago | Early warning signal |
| `temperature_c` | Current temperature | Secondary confirmation |
| `temperature_delta` | Thermal lag evidence | Proves vibration → heat causality |
| `load_avg` | Process demand context | Rules out load-induced false alarms |

### Output Format (JSON)

```json
{
"timestamp": "2026-01-01T01:21:06Z",
"component": "COMPRESSOR",
"features": {
"vibration_rms": 3.2,
"vibration_trend": 0.007,
"vibration_delta": 0.12,
"temperature_c": 44.6,
"temperature_delta": -0.4,
"load_avg": 77.3
}
}
```

---

## 🛠️ Project Setup
## ✅ Why This Matters for Explainable AI (XAI)

This repository does **not enforce any folder structure or technology stack**.
Teams are free to organize their project and choose tools, frameworks, and platforms as required by their solution.
- **Ground-truth labels (`failure_phase`)** enable verification of explanations
- **Physics-based causality** supports sensor-level reasoning
- **Clean feature separation** ensures decisions remain interpretable
- **Heterogeneous assets** (pump, conveyor, compressor) prove scalability

---

## 📤 Submission Guidelines
## 🚀 Full System Flow

Your forked repository will be considered your final submission.
Ensure your repository includes a clear README describing:
- Selected problem statement
- Project overview
- Technical approach
- Setup instructions
- Demo links
- Screenshots
```text
[Physics-Based Simulation]
↓ (CSV)
[Feature Extraction]
↓ (JSON)
[XAI Reasoning Engine]
→ Decision Trace
→ LLM Translator
→ Human-readable Work Orders
```

---

Good luck, and happy hacking 🚀
**– Team BeachHack**
## 📌 Development Notes

- Built entirely during **BeachHack**
- No pre-existing code or datasets used
- Designed for industrial scalability and explainability

---

## 🔮 Future Work

- Online feature streaming with Kafka / MQTT
- Remaining Useful Life (RUL) estimation
- SHAP-based sensor attribution
- Integration with CMMS systems

---

*All components were built during BeachHack — no pre-existing code was used.*
Binary file added Sensor data/.DS_Store
Binary file not shown.
200 changes: 200 additions & 0 deletions Sensor data/Feature_Extraction.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"provenance": []
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python"
}
},
"cells": [
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"id": "FS-3XlPJd6ry"
},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"import json\n",
"from pathlib import Path"
]
},
{
"cell_type": "code",
"source": [
"class FeatureExtractor:\n",
" def __init__(self, window_size_min: int = 10):\n",
" self.window_size_min = window_size_min\n",
"\n",
" def load_raw_data(self, filepath: str) -> pd.DataFrame:\n",
" path = Path(filepath)\n",
" if path.suffix == '.csv':\n",
" df = pd.read_csv(filepath, parse_dates=['timestamp'])\n",
" elif path.suffix == '.json':\n",
" with open(filepath) as f:\n",
" data = json.load(f)\n",
" df = pd.DataFrame(data)\n",
" df['timestamp'] = pd.to_datetime(df['timestamp'])\n",
" else:\n",
" raise ValueError(f\"Unsupported format: {path.suffix}\")\n",
"\n",
" required = {'timestamp', 'asset_id', 'vibration_rms', 'temperature_c', 'load_percent'}\n",
" assert required.issubset(set(df.columns)), f\"Missing columns: {required - set(df.columns)}\"\n",
" print(f\"✓ Loaded {len(df):,} raw samples from {filepath}\")\n",
" return df\n",
"\n",
" def map_component_type(self, asset_id: str) -> str:\n",
" asset_id_lower = asset_id.lower()\n",
" if 'pump' in asset_id_lower:\n",
" return 'PUMP'\n",
" elif 'conveyor' in asset_id_lower:\n",
" return 'CONVEYOR'\n",
" elif 'compressor' in asset_id_lower:\n",
" return 'COMPRESSOR'\n",
" else:\n",
" return 'UNKNOWN'\n",
"\n",
" def extract_features(self, df: pd.DataFrame) -> list:\n",
" features_list = []\n",
" window = self.window_size_min\n",
"\n",
" for asset_id, asset_df in df.groupby('asset_id'):\n",
" asset_df = asset_df.sort_values('timestamp').reset_index(drop=True)\n",
" component_type = self.map_component_type(asset_id)\n",
"\n",
" for i in range(len(asset_df)):\n",
" row = asset_df.iloc[i]\n",
"\n",
" # Base measurements\n",
" vibration_rms = float(row['vibration_rms'])\n",
" temperature_c = float(row['temperature_c'])\n",
" load_avg = float(row['load_percent']) # Context only — no trend/delta\n",
"\n",
" # Vibration trend (degradation rate) — PRIMARY diagnostic\n",
" if i >= window - 1:\n",
" x = np.arange(window)\n",
" y_vib = asset_df['vibration_rms'].values[i - window + 1:i + 1]\n",
" vibration_trend = float(np.polyfit(x, y_vib, 1)[0])\n",
" vibration_delta = float(row['vibration_rms'] - asset_df['vibration_rms'].iloc[i - window + 1])\n",
" else:\n",
" vibration_trend = 0.0\n",
" vibration_delta = 0.0\n",
"\n",
" # Temperature delta (thermal lag evidence) — SECONDARY confirmation\n",
" if i >= window - 1:\n",
" temperature_delta = float(row['temperature_c'] - asset_df['temperature_c'].iloc[i - window + 1])\n",
" else:\n",
" temperature_delta = 0.0\n",
"\n",
" # CRITICAL DESIGN CHOICE: NO load_trend / load_delta\n",
" # Reason: Load is an external driver (production demand), not a degradation indicator.\n",
" # Including load trends would confuse root cause analysis in XAI layer.\n",
"\n",
" feature_packet = {\n",
" \"timestamp\": row['timestamp'].strftime(\"%Y-%m-%dT%H:%M:%SZ\"),\n",
" \"component\": component_type,\n",
" \"features\": {\n",
" \"vibration_rms\": round(vibration_rms, 2), # PRIMARY\n",
" \"vibration_trend\": round(vibration_trend, 3), # Degradation rate\n",
" \"vibration_delta\": round(vibration_delta, 2), # Early warning\n",
" \"temperature_c\": round(temperature_c, 1), # SECONDARY\n",
" \"temperature_delta\": round(temperature_delta, 1), # Thermal lag proof\n",
" \"load_avg\": round(load_avg, 1) # CONTEXT only\n",
" }\n",
" }\n",
" features_list.append(feature_packet)\n",
"\n",
" print(f\"✓ Extracted {len(features_list):,} feature packets (6 high-value features)\")\n",
" return features_list\n",
"\n",
" def export_features(self, features: list, output_path: str = \"extracted_features.json\"):\n",
" with open(output_path, 'w') as f:\n",
" json.dump(features, f, indent=2)\n",
" print(f\"✅ Features exported: {output_path}\")\n",
" print(f\" Example packet:\\n{json.dumps(features[0], indent=2)}\")"
],
"metadata": {
"id": "W_4sTDRweCO5"
},
"execution_count": 5,
"outputs": []
},
{
"cell_type": "code",
"source": [
"def main():\n",
" RAW_DATA_PATH = \"simulated_assets.csv\"\n",
" OUTPUT_PATH = \"extracted_features.json\"\n",
"\n",
" extractor = FeatureExtractor(window_size_min=10)\n",
" raw_df = extractor.load_raw_data(RAW_DATA_PATH)\n",
" features = extractor.extract_features(raw_df)\n",
" extractor.export_features(features, OUTPUT_PATH)\n",
"\n",
" # Validation\n",
" assert len(features) > 0\n",
" assert all(k in features[0]['features'] for k in [\n",
" 'vibration_rms', 'vibration_trend', 'vibration_delta',\n",
" 'temperature_c', 'temperature_delta', 'load_avg'\n",
" ]), \"Missing required features\"\n",
" print(\"\\n✅ FEATURE EXTRACTION COMPLETE — 6 high-value features ready for XAI layer\")\n",
"\n",
"\n",
"if __name__ == \"__main__\":\n",
" main()"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "kQtTVsOyf-S8",
"outputId": "e494b8e9-4b79-4d7b-9c5c-aa32c84afa56"
},
"execution_count": 6,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"✓ Loaded 30,240 raw samples from simulated_assets.csv\n",
"✓ Extracted 30,240 feature packets (6 high-value features)\n",
"✅ Features exported: extracted_features.json\n",
" Example packet:\n",
"{\n",
" \"timestamp\": \"2026-01-01T00:00:05Z\",\n",
" \"component\": \"COMPRESSOR\",\n",
" \"features\": {\n",
" \"vibration_rms\": 2.78,\n",
" \"vibration_trend\": 0.0,\n",
" \"vibration_delta\": 0.0,\n",
" \"temperature_c\": 44.5,\n",
" \"temperature_delta\": 0.0,\n",
" \"load_avg\": 73.2\n",
" }\n",
"}\n",
"\n",
"✅ FEATURE EXTRACTION COMPLETE — 6 high-value features ready for XAI layer\n"
]
}
]
},
{
"cell_type": "code",
"source": [],
"metadata": {
"id": "FF4UtLmtgDpf"
},
"execution_count": 6,
"outputs": []
}
]
}
Loading