Refactor report formatting and improve clarity in observations

- Updated section headings for consistency and clarity.
- Converted tables from markdown format to a structured table format for better readability.
- Enhanced descriptions in the analysis and conclusion sections to provide clearer insights into the performance of LEACH and LEACH-C protocols.
- Corrected minor typographical errors for improved professionalism.
This commit is contained in:
paul.roost 2025-11-03 14:12:51 +01:00
parent ab902bad5f
commit fff067809f
3 changed files with 8179 additions and 6914 deletions

View File

@ -1,50 +1,32 @@
"""
Analyseur et générateur de graphiques pour les résultats de simulation
Génération de graphiques et analyses visuelles pour les résultats de simulation LEACH/LEACH-C.
Lit les métriques JSON et produit des PNG comparatifs.
"""
import json
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use('Agg') # Backend sans affichage
matplotlib.use('Agg') # Pas d'affichage graphique (serveur)
class ResultsAnalyzer:
"""Analyse et visualise les résultats des simulations."""
"""Crée les graphiques de comparaison entre les protocoles et scénarios."""
def __init__(self, results_file):
"""
Charge les résultats depuis un fichier JSON.
Args:
results_file (str): Chemin vers le fichier JSON
"""
"""Charge le fichier JSON contenant les résultats de toutes les simulations."""
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
"""Crée tous les graphiques PNG en une seule passe."""
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."""
"""Graphique en barres : Premier Nœud Mort pour chaque scénario."""
scenarios = list(self.results.keys())
leach_fdn = []
leachc_fdn = []
@ -53,7 +35,6 @@ class ResultsAnalyzer:
leach_metrics = self.results[scenario]["LEACH"]["metrics"]
leachc_metrics = self.results[scenario]["LEACH-C"]["metrics"]
# Utiliser fdn du JSON (peut être null)
leach_fdn.append(leach_metrics.get("fdn") or 0)
leachc_fdn.append(leachc_metrics.get("fdn") or 0)
@ -72,7 +53,7 @@ class ResultsAnalyzer:
ax.legend()
ax.grid(axis='y', alpha=0.3)
# Ajouter note si pas de FDN (nœuds toujours vivants)
# Note si tous les nœuds survivent (valeur nulle = pas de mort)
if all(f == 0 for f in leach_fdn + leachc_fdn):
ax.text(0.5, 0.5, 'Pas de nœuds morts\n(tous les nœuds vivants)',
transform=ax.transAxes, ha='center', va='center',
@ -83,7 +64,7 @@ class ResultsAnalyzer:
plt.close()
def _plot_fmr_comparison(self, output_dir):
"""Graphique : FMR pour tous les scénarios."""
"""Graphique en barres : Premier Round Muet pour chaque scénario."""
scenarios = list(self.results.keys())
leach_fmr = []
leachc_fmr = []
@ -92,7 +73,6 @@ class ResultsAnalyzer:
leach_metrics = self.results[scenario]["LEACH"]["metrics"]
leachc_metrics = self.results[scenario]["LEACH-C"]["metrics"]
# Utiliser fmr du JSON (peut être null)
leach_fmr.append(leach_metrics.get("fmr") or 0)
leachc_fmr.append(leachc_metrics.get("fmr") or 0)
@ -116,7 +96,7 @@ class ResultsAnalyzer:
plt.close()
def _plot_dlbi_comparison(self, output_dir):
"""Graphique : DLBI pour tous les scénarios."""
"""Graphique en barres : Indice d'Équilibre de Charge pour chaque scénario."""
scenarios = list(self.results.keys())
leach_dlbi = []
leachc_dlbi = []
@ -149,7 +129,7 @@ class ResultsAnalyzer:
plt.close()
def _plot_rspi_comparison(self, output_dir):
"""Graphique : RSPI pour tous les scénarios."""
"""Graphique tableau : Indice de Stabilité du Réseau avec explications."""
scenarios = list(self.results.keys())
leach_rspi = []
leachc_rspi = []
@ -161,16 +141,14 @@ class ResultsAnalyzer:
leach_rspi.append(leach_metrics.get("rspi", 0))
leachc_rspi.append(leachc_metrics.get("rspi", 0))
# Graphique : Tableau de texte uniquement (plus lisible)
fig, ax = plt.subplots(figsize=(12, 8))
ax.axis('off')
# Créer un tableau affichant les valeurs
# Tableau affichant RSPI pour tous les scénarios
data = []
for scenario, lrspi, crspi in zip(scenarios, leach_rspi, leachc_rspi):
data.append([scenario, f"{lrspi:.6f}", f"{crspi:.6f}"])
# Ajouter en-tête
data.insert(0, ['Scénario', 'LEACH RSPI', 'LEACH-C RSPI'])
table = ax.table(cellText=data, cellLoc='center', loc='center',
@ -179,12 +157,12 @@ class ResultsAnalyzer:
table.set_fontsize(11)
table.scale(1, 3)
# Colorer l'en-tête
# Style en-tête
for i in range(3):
table[(0, i)].set_facecolor('#4ECDC4')
table[(0, i)].set_text_props(weight='bold', color='white', size=12)
# Colorer les lignes alternées et ajouter bordures
# Style lignes alternées
for i in range(1, len(data)):
for j in range(3):
if i % 2 == 0:
@ -193,11 +171,9 @@ class ResultsAnalyzer:
table[(i, j)].set_facecolor('white')
table[(i, j)].set_text_props(size=11)
# Titre
fig.suptitle('Comparaison RSPI (Relative Silence Period Index)',
fontsize=16, fontweight='bold', y=0.98)
# Ajouter explications
explanation = (
'RSPI = 0.0000 indique que le réseau reste STABLE pendant toute la simulation.\n'
'Les nœuds survivent jusqu\'à la fin, ce qui est un EXCELLENT résultat.\n\n'
@ -213,16 +189,14 @@ class ResultsAnalyzer:
plt.close()
def _plot_alive_nodes(self, output_dir):
"""
Graphique : Résumé complet des résultats en format très lisible.
"""
"""Graphique récapitulatif : Tous les résultats (FDN, FMR, DLBI, RSPI) par scénario."""
scenarios = list(self.results.keys())
fig = plt.figure(figsize=(16, 12))
ax = fig.add_subplot(111)
ax.axis('off')
# Préparer les données
# Préparer les données : FDN, FMR, DLBI, RSPI pour chaque protocole
data = []
for scenario in scenarios:
scenario_short = scenario.replace('Scenario_', '').replace('_', ' ')
@ -243,9 +217,7 @@ class ResultsAnalyzer:
data.append(row)
# Ajouter en-tête
header = ["Scénario", "LEACH", "LEACH-C"]
data.insert(0, header)
data.insert(0, ["Scénario", "LEACH", "LEACH-C"])
# Créer le tableau
table = ax.table(cellText=data, cellLoc='center', loc='center',
@ -254,14 +226,14 @@ class ResultsAnalyzer:
table.set_fontsize(11)
table.scale(1, 3.5)
# Style l'en-tête
# Style en-tête
for i in range(3):
cell = table[(0, i)]
cell.set_facecolor('#4ECDC4')
cell.set_text_props(weight='bold', color='white', size=13)
cell.set_height(0.12)
# Style les lignes alternées
# Style lignes alternées et bordures
for i in range(1, len(data)):
for j in range(3):
cell = table[(i, j)]
@ -275,16 +247,13 @@ class ResultsAnalyzer:
cell.set_linewidth(1.5)
cell.set_edgecolor('#cccccc')
# Ajouter bordures plus visibles
for key, cell in table.get_celld().items():
cell.set_linewidth(2)
cell.set_edgecolor('#333333')
# Titre
fig.suptitle('Résumé Complet des Résultats - Simulation avec SimPy',
fontsize=16, fontweight='bold', y=0.98)
# Légende
legend_text = (
'FDN: First Dead Node | FMR: First Muted Round | DLBI: Load Balancing (>0.7=excellent) | RSPI: Silence Index (0=excellent)'
)
@ -298,17 +267,10 @@ class ResultsAnalyzer:
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
"""
"""Exporte les résultats dans un fichier CSV pour analyse externe."""
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"]
@ -326,9 +288,8 @@ class ResultsAnalyzer:
if __name__ == "__main__":
import os
# Déterminer les chemins dynamiquement
script_dir = os.path.dirname(os.path.abspath(__file__)) # /home/paul/AlgoRep/code
project_dir = os.path.dirname(script_dir) # /home/paul/AlgoRep
script_dir = os.path.dirname(os.path.abspath(__file__))
project_dir = os.path.dirname(script_dir)
results_dir = os.path.join(project_dir, "results")
results_file = os.path.join(results_dir, "simulation_results.json")

File diff suppressed because it is too large Load Diff

View File

@ -310,7 +310,7 @@ $ "RSPI" = frac(2 times [(1 - "FR"_"muted"/"R"_"max") times (1 - "LR"_"dead"/"R"
== Observations Clés
=== 1. Durée de Vie Réseau (FDN)
=== Durée de Vie Réseau (FDN)
Tous les nœuds *survivent 3000 rounds* dans tous les scénarios. Cela démontre que :
- L'énergie initiale (0.5J par nœud) est *suffisante* pour 3000 rounds
@ -319,47 +319,56 @@ Tous les nœuds *survivent 3000 rounds* dans tous les scénarios. Cela démontre
*Implication* : FDN=null est un résultat positif le réseau maintient sa viabilité long terme.
=== 2. Premières Pertes (FMR)
=== Premières Pertes (FMR)
| Scénario | LEACH FMR | LEACH-C FMR | Interprétation |
|----------|-----------|-------------|---|
| 1 (l=2000, p=0.05, n=100) | 195 | null | LEACH commence à perdre des CHs élus |
| 2 (l=2000, p=0.50, n=100) | 1603 | null | LEACH perd CHs au round 1603 (53%) |
| 3 (l=2000, p=0.95, n=100) | null | null | Aucun CH ne mute réseau plein débit |
| 4 (l=4000, p=0.05, n=100) | 99 | null | Gros paquets causent pertes précoces |
| 5 (l=4000, p=0.05, n=200) | null | null | Réseau 200 nœuds très stable |
| 6 (l=4000, p=0.10, n=200) | null | null | Activité modérée stabilité |
#table(
columns: (1fr, auto, auto, 2fr),
align: (left, center, center, left),
[*Scénario*], [*LEACH FMR*], [*LEACH-C FMR*], [*Interprétation*],
[1 (l=2000, p=0.05, n=100)], [195], [null], [LEACH commence à perdre des CHs élus],
[2 (l=2000, p=0.50, n=100)], [1603], [null], [LEACH perd CHs au round 1603 (53%)],
[3 (l=2000, p=0.95, n=100)], [null], [null], [Aucun CH ne mute réseau plein débit],
[4 (l=4000, p=0.05, n=100)], [99], [null], [Gros paquets causent pertes précoces],
[5 (l=4000, p=0.05, n=200)], [null], [null], [Réseau 200 nœuds très stable],
[6 (l=4000, p=0.10, n=200)], [null], [null], [Activité modérée stabilité],
)
*Analyse* : LEACH-C souffre moins de FMR (souvent null), montrant que la *sélection centralisée des CHs est plus stable* et réduit les rotations de CH inutiles. Les FMR de LEACH sont déclenchées par des élections probabilistes défaillantes.
=== 3. Équilibre de Charge (DLBI)
=== Équilibre de Charge (DLBI)
| Scénario | LEACH DLBI | LEACH-C DLBI | Verdict |
|----------|-----------|-------------|---|
| 1 | 0.747 | 0.070 | LEACH bien supérieur |
| 2 | 0.801 | 0.035 | LEACH excellent, LEACH-C mauvais |
| 3 | 0.953 | 0.111 | LEACH extraordinaire, LEACH-C chaotique |
| 4 | 0.755 | 0.128 | LEACH bien supérieur |
| 5 | 0.681 | 0.088 | LEACH bon, LEACH-C déséquilibré |
| 6 | 0.651 | 0.102 | LEACH bon, LEACH-C mauvais |
#table(
columns: (auto, auto, auto, 2fr),
align: (left, center, center, left),
[*Scénario*], [*LEACH DLBI*], [*LEACH-C DLBI*], [*Verdict*],
[1], [0.747], [0.070], [LEACH bien supérieur],
[2], [0.801], [0.035], [LEACH excellent, LEACH-C mauvais],
[3], [0.953], [0.111], [LEACH extraordinaire, LEACH-C chaotique],
[4], [0.755], [0.128], [LEACH bien supérieur],
[5], [0.681], [0.088], [LEACH bon, LEACH-C déséquilibré],
[6], [0.651], [0.102], [LEACH bon, LEACH-C mauvais],
)
*Conclusion* : LEACH surpasse LEACH-C sur *tous* les scénarios en équilibre de charge. Moyenne LEACH = 0.775, Moyenne LEACH-C = 0.026.
*Explication* : LEACH distribue naturellement les responsabilités de CH à tous les nœuds (chaque nœud a 1/n chance d'être élu). LEACH-C centralise au BS qui choisit les 10% meilleurs CHs, mais cela crée une charge accumulée sur les CHs sélectionnés, d'où DLBI négatif. Le DLBI négatif indique que certains nœuds portent une charge disproportionnée.
=== 4. Stabilité Réseau (RSPI)
=== Stabilité Réseau (RSPI)
| Tous les Scénarios | RSPI LEACH | RSPI LEACH-C |
|-----------------|-----------|-------------|
| Moyenne | 0.0000 | 0.0000 |
| Min/Max | 0 / 0 | 0 / 0 |
#table(
columns: (2fr, auto, auto),
align: (left, center, center),
[*Tous les Scénarios*], [*RSPI LEACH*], [*RSPI LEACH-C*],
[Moyenne], [0.0000], [0.0000],
[Min/Max], [0 / 0], [0 / 0],
)
*Observation remarquable* : Stabilité *parfaite* (RSPI=0) dans tous les scénarios et protocoles. Cela signifie :
- Aucune oscillation d'énergie
- Aucune perturbation dans l'accessibilité
- Le réseau maintient un équilibre énergétique constant
*Implication* : La simulation SimPy avec reconnnexion dynamique crée un réseau extraordinairement stable.
*Implication* : La simulation SimPy avec reconnexion dynamique crée un réseau extraordinairement stable.
== Comparaison des Protocoles