AlgoRep/code/analysis.py
paul.roost 7a33c7096d Add simulation results and launch script for LEACH/LEACH-C
- Created summary.csv to store simulation results for various scenarios, protocols, and metrics.
- Developed run.sh script to automate the simulation process, including dependency checks, simulation execution, and result analysis.
- Ensured proper directory structure for results and reports.
- Added error handling for Python and matplotlib dependencies.
2025-11-02 13:55:51 +01:00

239 lines
9.3 KiB
Python

"""
Analyseur et générateur de graphiques pour les résultats de simulation
"""
import json
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use('Agg') # Backend sans affichage
class ResultsAnalyzer:
"""Analyse et visualise les résultats des simulations."""
def __init__(self, results_file):
"""
Charge les résultats depuis un fichier JSON.
Args:
results_file (str): Chemin vers le fichier JSON
"""
with open(results_file, 'r') as f:
self.results = json.load(f)
def generate_comparison_graphs(self, output_dir):
"""
Génère les graphiques de comparaison LEACH vs LEACH-C.
Args:
output_dir (str): Répertoire de sortie
"""
# 1. FDN Comparison
self._plot_fdn_comparison(output_dir)
# 2. FMR Comparison
self._plot_fmr_comparison(output_dir)
# 3. DLBI Comparison
self._plot_dlbi_comparison(output_dir)
# 4. RSPI Comparison
self._plot_rspi_comparison(output_dir)
# 5. Alive Nodes Over Rounds
self._plot_alive_nodes(output_dir)
def _plot_fdn_comparison(self, output_dir):
"""Graphique : FDN pour tous les scénarios."""
scenarios = list(self.results.keys())
leach_fdn = []
leachc_fdn = []
for scenario in scenarios:
leach_metrics = self.results[scenario]["LEACH"]["metrics"]
leachc_metrics = self.results[scenario]["LEACH-C"]["metrics"]
leach_fdn.append(leach_metrics.get("first_dead_node_round") or 0)
leachc_fdn.append(leachc_metrics.get("first_dead_node_round") or 0)
fig, ax = plt.subplots(figsize=(12, 6))
x_pos = range(len(scenarios))
width = 0.35
ax.bar([i - width/2 for i in x_pos], leach_fdn, width, label='LEACH', color='#FF6B6B')
ax.bar([i + width/2 for i in x_pos], leachc_fdn, width, label='LEACH-C', color='#4ECDC4')
ax.set_xlabel('Scénario', fontsize=12)
ax.set_ylabel('Premier Nœud Mort (Round)', fontsize=12)
ax.set_title('Comparaison FDN (First Dead Node)', fontsize=14, fontweight='bold')
ax.set_xticks(x_pos)
ax.set_xticklabels(scenarios, rotation=45, ha='right')
ax.legend()
ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig(f"{output_dir}/01_FDN_Comparison.png", dpi=300)
plt.close()
def _plot_fmr_comparison(self, output_dir):
"""Graphique : FMR pour tous les scénarios."""
scenarios = list(self.results.keys())
leach_fmr = []
leachc_fmr = []
for scenario in scenarios:
leach_metrics = self.results[scenario]["LEACH"]["metrics"]
leachc_metrics = self.results[scenario]["LEACH-C"]["metrics"]
leach_fmr.append(leach_metrics.get("first_muted_round") or 9999)
leachc_fmr.append(leachc_metrics.get("first_muted_round") or 9999)
fig, ax = plt.subplots(figsize=(12, 6))
x_pos = range(len(scenarios))
width = 0.35
ax.bar([i - width/2 for i in x_pos], leach_fmr, width, label='LEACH', color='#FF6B6B')
ax.bar([i + width/2 for i in x_pos], leachc_fmr, width, label='LEACH-C', color='#4ECDC4')
ax.set_xlabel('Scénario', fontsize=12)
ax.set_ylabel('Premier Round Muet', fontsize=12)
ax.set_title('Comparaison FMR (First Muted Round)', fontsize=14, fontweight='bold')
ax.set_xticks(x_pos)
ax.set_xticklabels(scenarios, rotation=45, ha='right')
ax.legend()
ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig(f"{output_dir}/02_FMR_Comparison.png", dpi=300)
plt.close()
def _plot_dlbi_comparison(self, output_dir):
"""Graphique : DLBI pour tous les scénarios."""
scenarios = list(self.results.keys())
leach_dlbi = []
leachc_dlbi = []
for scenario in scenarios:
leach_metrics = self.results[scenario]["LEACH"]["metrics"]
leachc_metrics = self.results[scenario]["LEACH-C"]["metrics"]
leach_dlbi.append(leach_metrics.get("dlbi", 0))
leachc_dlbi.append(leachc_metrics.get("dlbi", 0))
fig, ax = plt.subplots(figsize=(12, 6))
x_pos = range(len(scenarios))
width = 0.35
ax.bar([i - width/2 for i in x_pos], leach_dlbi, width, label='LEACH', color='#FF6B6B')
ax.bar([i + width/2 for i in x_pos], leachc_dlbi, width, label='LEACH-C', color='#4ECDC4')
ax.set_xlabel('Scénario', fontsize=12)
ax.set_ylabel('DLBI (0 à 1)', fontsize=12)
ax.set_title('Comparaison DLBI (Dynamic Load Balancing Index)', fontsize=14, fontweight='bold')
ax.set_xticks(x_pos)
ax.set_xticklabels(scenarios, rotation=45, ha='right')
ax.set_ylim([0, 1.1])
ax.legend()
ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig(f"{output_dir}/03_DLBI_Comparison.png", dpi=300)
plt.close()
def _plot_rspi_comparison(self, output_dir):
"""Graphique : RSPI pour tous les scénarios."""
scenarios = list(self.results.keys())
leach_rspi = []
leachc_rspi = []
for scenario in scenarios:
leach_metrics = self.results[scenario]["LEACH"]["metrics"]
leachc_metrics = self.results[scenario]["LEACH-C"]["metrics"]
leach_rspi.append(leach_metrics.get("rspi", 0))
leachc_rspi.append(leachc_metrics.get("rspi", 0))
fig, ax = plt.subplots(figsize=(12, 6))
x_pos = range(len(scenarios))
width = 0.35
ax.bar([i - width/2 for i in x_pos], leach_rspi, width, label='LEACH', color='#FF6B6B')
ax.bar([i + width/2 for i in x_pos], leachc_rspi, width, label='LEACH-C', color='#4ECDC4')
ax.set_xlabel('Scénario', fontsize=12)
ax.set_ylabel('RSPI (0 à 1)', fontsize=12)
ax.set_title('Comparaison RSPI (Relative Silence Period Index)', fontsize=14, fontweight='bold')
ax.set_xticks(x_pos)
ax.set_xticklabels(scenarios, rotation=45, ha='right')
ax.set_ylim([0, 1.1])
ax.legend()
ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig(f"{output_dir}/04_RSPI_Comparison.png", dpi=300)
plt.close()
def _plot_alive_nodes(self, output_dir):
"""Graphique : Nombre de nœuds vivants au fil du temps."""
scenarios = list(self.results.keys())[:3] # Premiers 3 scénarios
fig, axes = plt.subplots(len(scenarios), 2, figsize=(14, 4*len(scenarios)))
for idx, scenario in enumerate(scenarios):
# LEACH
leach_detailed = self.results[scenario]["LEACH"]["detailed_rounds"]
rounds = [r["round"] for r in leach_detailed]
alive = [r["alive_nodes"] for r in leach_detailed]
axes[idx, 0].plot(rounds, alive, marker='o', label='LEACH', color='#FF6B6B')
axes[idx, 0].set_xlabel('Round')
axes[idx, 0].set_ylabel('Nœuds Vivants')
axes[idx, 0].set_title(f'LEACH - {scenario}')
axes[idx, 0].grid(alpha=0.3)
# LEACH-C
leachc_detailed = self.results[scenario]["LEACH-C"]["detailed_rounds"]
rounds = [r["round"] for r in leachc_detailed]
alive = [r["alive_nodes"] for r in leachc_detailed]
axes[idx, 1].plot(rounds, alive, marker='s', label='LEACH-C', color='#4ECDC4')
axes[idx, 1].set_xlabel('Round')
axes[idx, 1].set_ylabel('Nœuds Vivants')
axes[idx, 1].set_title(f'LEACH-C - {scenario}')
axes[idx, 1].grid(alpha=0.3)
plt.tight_layout()
plt.savefig(f"{output_dir}/05_Alive_Nodes_Over_Time.png", dpi=300)
plt.close()
def generate_summary_table(self, output_file):
"""
Génère un tableau récapitulatif en CSV.
Args:
output_file (str): Chemin du fichier CSV
"""
with open(output_file, 'w') as f:
# En-tête
f.write("Scenario,Protocol,FDN,FMR,Alive_Nodes,DLBI,RSPI\n")
# Données
for scenario_name, scenario_data in self.results.items():
for protocol in ["LEACH", "LEACH-C"]:
metrics = scenario_data[protocol]["metrics"]
f.write(f"{scenario_name},{protocol},")
f.write(f"{metrics.get('first_dead_node_round', 'N/A')},")
f.write(f"{metrics.get('first_muted_round', 'N/A')},")
f.write(f"{metrics.get('final_alive_nodes', 'N/A')},")
f.write(f"{metrics.get('dlbi', 'N/A'):.4f},")
f.write(f"{metrics.get('rspi', 'N/A'):.4f}\n")
print(f"OK - Tableau récapitulatif: {output_file}")
if __name__ == "__main__":
analyzer = ResultsAnalyzer("/home/paul/algo/results/simulation_results.json")
analyzer.generate_comparison_graphs("/home/paul/algo/results")
analyzer.generate_summary_table("/home/paul/algo/results/summary.csv")