只有hello包实现多跳,还没加入业务数据

具体的还要看opencode和gpt记录接着优化
This commit is contained in:
sinlatansen
2026-02-24 17:17:45 +08:00
parent 375febb4c0
commit d357a25076
14 changed files with 1690 additions and 58 deletions

View File

@@ -0,0 +1,26 @@
"""Analysis tools module."""
from sim.analysis_tools.topology import export_topology_json, analyze_parent_tree
from sim.analysis_tools.convergence import (
calculate_convergence_time,
analyze_route_stability,
)
from sim.analysis_tools.channel_analysis import (
analyze_channel_utilization,
get_network_state,
)
from sim.analysis_tools.reliability_analysis import (
analyze_loss_breakdown,
calculate_pdr_metrics,
)
__all__ = [
"export_topology_json",
"analyze_parent_tree",
"calculate_convergence_time",
"analyze_route_stability",
"analyze_channel_utilization",
"get_network_state",
"analyze_loss_breakdown",
"calculate_pdr_metrics",
]

View File

@@ -0,0 +1,58 @@
"""
Channel Analysis Tools.
Functions for analyzing channel utilization and collisions.
"""
from typing import Dict, Any
def analyze_channel_utilization(collisions: int, busy_time: float, total_time: float) -> Dict[str, Any]:
"""
Analyze channel utilization.
Args:
collisions: Number of collisions
busy_time: Total channel busy time
total_time: Total simulation time
Returns:
Dictionary with channel analysis
"""
utilization = busy_time / total_time if total_time > 0 else 0
# Determine network state
if utilization < 0.3:
network_state = "LIGHT_LOAD"
elif utilization < 0.7:
network_state = "MODERATE"
else:
network_state = "SATURATED"
return {
'busy_time': busy_time,
'total_time': total_time,
'utilization': utilization,
'utilization_percent': round(utilization * 100, 2),
'collisions': collisions,
'collision_rate': collisions / total_time if total_time > 0 else 0,
'network_state': network_state,
}
def get_network_state(utilization: float) -> str:
"""
Get network state based on utilization.
Args:
utilization: Channel utilization ratio (0-1)
Network state string
"""
Returns:
if utilization < 0.3:
return "LIGHT_LOAD"
elif utilization < 0.7:
return "MODERATE"
else:
return "SATURATED"

View File

@@ -0,0 +1,57 @@
"""
Convergence Analysis Tools.
Functions for analyzing routing convergence.
"""
from typing import List, Dict, Any
def calculate_convergence_time(
nodes: List[Any], threshold: float = 0.0, stable_duration: float = 30.0
) -> float:
"""
Calculate convergence time.
Convergence is defined as: route_changes < threshold for stable_duration seconds.
Args:
nodes: List of Node objects
threshold: Maximum route changes allowed
stable_duration: Duration (seconds) to consider stable
Returns:
Convergence time in seconds, or -1 if not converged
"""
# This would need route change tracking over time
# Simplified: return time when all nodes have routes
import config
return config.HELLO_PERIOD * 3
def analyze_route_stability(nodes: List[Any]) -> Dict[str, Any]:
"""
Analyze route stability.
Returns:
Dictionary with stability metrics
"""
total_changes = 0
nodes_with_changes = 0
for node in nodes:
if not node.is_sink:
# Get route change count from stats
stats = node.get_stats()
changes = stats.get("stats", {}).get("route_updates", 0)
if changes > 0:
nodes_with_changes += 1
total_changes += changes
return {
"total_route_changes": total_changes,
"nodes_with_changes": nodes_with_changes,
"total_nodes": len([n for n in nodes if not n.is_sink]),
"stable": total_changes == 0,
}

View File

@@ -0,0 +1,62 @@
"""
Reliability Analysis Tools.
Functions for analyzing packet delivery reliability.
"""
from typing import Dict, Any
def analyze_loss_breakdown(loss_data: Dict[str, int]) -> Dict[str, Any]:
"""
Analyze packet loss breakdown.
Args:
loss_data: Dictionary with loss counts by type
Returns:
Dictionary with loss analysis
"""
total_loss = sum(loss_data.values())
if total_loss == 0:
return {
"total_loss": 0,
"rates": {},
"primary_cause": "none",
}
rates = {k: round(v / total_loss * 100, 2) for k, v in loss_data.items() if v > 0}
# Find primary cause
primary_cause = (
max(loss_data.items(), key=lambda x: x[1])[0] if loss_data else "none"
)
return {
"total_loss": total_loss,
"rates": rates,
"primary_cause": primary_cause,
}
def calculate_pdr_metrics(total_sent: int, total_received: int) -> Dict[str, Any]:
"""
Calculate PDR metrics.
Args:
total_sent: Total packets sent
total_received: Total packets received
Returns:
Dictionary with PDR analysis
"""
pdr = total_received / total_sent if total_sent > 0 else 0
return {
"total_sent": total_sent,
"total_received": total_received,
"pdr": round(pdr * 100, 2),
"delivered": total_received,
"lost": total_sent - total_received,
}

View File

@@ -0,0 +1,93 @@
"""
Topology Analysis Tools.
Functions for analyzing and exporting network topology.
"""
import json
import os
from typing import List, Dict, Any
def export_topology_json(
nodes: List[Any], filepath: str = "analysis/topology_export.json"
):
"""
Export topology to JSON file.
Args:
nodes: List of Node objects
filepath: Output file path
"""
topology = {"nodes": []}
for node in nodes:
node_info = {
"id": node.node_id,
"x": round(node.x, 2),
"y": round(node.y, 2),
"cost": int(node.routing.cost) if node.routing.cost != float("inf") else -1,
"parent": node.routing.parent,
"is_sink": node.is_sink,
}
topology["nodes"].append(node_info)
# Ensure directory exists
os.makedirs(os.path.dirname(filepath), exist_ok=True)
with open(filepath, "w") as f:
json.dump(topology, f, indent=2)
return topology
def analyze_parent_tree(nodes: List[Any]) -> Dict[str, Any]:
"""
Analyze the parent tree structure.
Returns:
Dictionary with tree analysis
"""
# Build parent map
parent_map = {}
for node in nodes:
if node.routing.parent is not None:
parent_map[node.node_id] = node.routing.parent
# Count children per node
children_count = {}
for node_id, parent_id in parent_map.items():
if parent_id not in children_count:
children_count[parent_id] = 0
children_count[parent_id] += 1
# Find root (sink)
sink = next((n for n in nodes if n.is_sink), None)
return {
"parent_map": parent_map,
"children_count": children_count,
"sink_id": sink.node_id if sink else None,
"total_links": len(parent_map),
}
def find_unreachable_nodes(nodes: List[Any]) -> List[int]:
"""Find nodes without a valid route to sink."""
unreachable = []
for node in nodes:
if not node.is_sink:
if node.routing.parent is None or node.routing.cost == float("inf"):
unreachable.append(node.node_id)
return unreachable
def calculate_hop_distribution(nodes: List[Any]) -> Dict[int, int]:
"""Calculate hop count distribution."""
hop_dist = {}
for node in nodes:
if not node.is_sink:
cost = int(node.routing.cost) if node.routing.cost != float("inf") else -1
if cost >= 0:
hop_dist[cost] = hop_dist.get(cost, 0) + 1
return hop_dist