AlgoRep/code/node.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

130 lines
4.0 KiB
Python

"""
Classe Node : Représentation d'un nœud capteur dans le réseau WSN
"""
import math
import random
from config import (
E_ELEC, E_FS, E_MP, D0, E_DA,
FIELD_WIDTH, FIELD_HEIGHT, MAX_DISPLACEMENT_PER_ROUND
)
class Node:
"""
Représente un nœud (capteur) dans le réseau WSN.
Attributes:
node_id (int): Identifiant unique du nœud
x, y (float): Position en mètres
energy (float): Énergie résiduelle en Joules
initial_energy (float): Énergie initiale (pour calcul %)
is_alive (bool): État du nœud
is_cluster_head (bool): Est-ce un CH?
cluster_id (int): ID du cluster auquel le nœud appartient
packets_to_send (int): Nombre de paquets en attente
"""
def __init__(self, node_id, x, y, initial_energy):
self.node_id = node_id
self.x = x
self.y = y
self.energy = initial_energy
self.initial_energy = initial_energy
self.is_alive = True
self.is_cluster_head = False
self.cluster_id = None
self.packets_to_send = 0
self.total_packets_sent = 0
def distance_to(self, other_x, other_y):
"""Calcule la distance euclidienne vers un point."""
return math.sqrt((self.x - other_x) ** 2 + (self.y - other_y) ** 2)
def consume_energy(self, energy_amount):
"""Consomme de l'énergie et met à jour l'état du nœud."""
self.energy -= energy_amount
if self.energy <= 0:
self.energy = 0
self.is_alive = False
def transmit(self, data_bits, distance):
"""
Calcule et consomme l'énergie de transmission.
Args:
data_bits (int): Nombre de bits à transmettre
distance (float): Distance jusqu'au récepteur
Returns:
float: Énergie consommée
"""
if distance <= D0:
# Modèle espace libre
energy_tx = E_ELEC * data_bits + E_FS * data_bits * (distance ** 2)
else:
# Modèle multi-trajet
energy_tx = E_ELEC * data_bits + E_MP * data_bits * (distance ** 4)
self.consume_energy(energy_tx)
return energy_tx
def receive(self, data_bits):
"""
Calcule et consomme l'énergie de réception.
Args:
data_bits (int): Nombre de bits reçus
Returns:
float: Énergie consommée
"""
energy_rx = E_ELEC * data_bits
self.consume_energy(energy_rx)
return energy_rx
def aggregate(self, data_bits):
"""
Calcule et consomme l'énergie d'agrégation de données.
Args:
data_bits (int): Nombre de bits agrégés
Returns:
float: Énergie consommée
"""
energy_agg = E_DA * data_bits
self.consume_energy(energy_agg)
return energy_agg
def move(self):
"""
Met à jour la position du nœud avec un déplacement aléatoire.
Déplacement max = MAX_DISPLACEMENT_PER_ROUND mètres.
Reste dans les limites du champ.
"""
angle = random.uniform(0, 2 * math.pi)
distance = random.uniform(0, MAX_DISPLACEMENT_PER_ROUND)
new_x = self.x + distance * math.cos(angle)
new_y = self.y + distance * math.sin(angle)
# Limiter aux bords du champ
self.x = max(0, min(FIELD_WIDTH, new_x))
self.y = max(0, min(FIELD_HEIGHT, new_y))
def reset_for_round(self):
"""Reset les données de ronde (cluster, CH status, etc.)"""
self.is_cluster_head = False
self.cluster_id = None
self.packets_to_send = 0
def get_energy_percentage(self):
"""Retourne le pourcentage d'énergie restante."""
if self.initial_energy == 0:
return 0
return (self.energy / self.initial_energy) * 100
def __repr__(self):
return f"Node({self.node_id}, pos=({self.x:.1f}, {self.y:.1f}), E={self.energy:.4f}J, alive={self.is_alive})"