Files
MCM/A题/ZJ_v2/fig05_radio_tail.py
2026-02-16 21:52:26 +08:00

122 lines
4.4 KiB
Python

"""
Fig 5: Radio Tail Energy Illustration
Shows the tail effect in network power consumption
"""
import os
import numpy as np
import matplotlib.pyplot as plt
from plot_style import set_oprice_style, save_figure
def make_figure(config):
"""Generate Fig 5: Radio Tail Energy Illustration"""
set_oprice_style()
# Time axis
t = np.linspace(0, 10, 1000)
# Data burst events (brief pulses)
burst_times = [1.0, 4.5, 7.0]
burst_duration = 0.2
data_activity = np.zeros_like(t)
for bt in burst_times:
mask = (t >= bt) & (t < bt + burst_duration)
data_activity[mask] = 1.0
# Power state with tail effect
# After each burst, power decays exponentially
power_state = np.zeros_like(t)
tau_tail = 2.0 # Tail decay time constant
for i, ti in enumerate(t):
# Find most recent burst
recent_bursts = [bt for bt in burst_times if bt <= ti]
if recent_bursts:
t_since_burst = ti - max(recent_bursts)
if t_since_burst < burst_duration:
# During burst: high power
power_state[i] = 1.0
else:
# After burst: exponential decay (tail)
power_state[i] = 1.0 * np.exp(-(t_since_burst - burst_duration) / tau_tail)
# Create figure with two subplots
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 7), sharex=True)
# Top: Data activity
ax1.fill_between(t, 0, data_activity, alpha=0.6, color='#2ca02c', label='Data Transmission')
ax1.set_ylabel('Data Activity', fontsize=11)
ax1.set_ylim(-0.1, 1.2)
ax1.set_yticks([0, 1])
ax1.set_yticklabels(['Idle', 'Active'])
ax1.grid(True, alpha=0.3, axis='x')
ax1.legend(loc='upper right')
ax1.set_title('Network Radio Tail Effect Illustration', fontsize=12, fontweight='bold')
# Annotate burst durations
for bt in burst_times:
ax1.annotate('', xy=(bt + burst_duration, 1.1), xytext=(bt, 1.1),
arrowprops=dict(arrowstyle='<->', color='black', lw=1))
ax1.text(bt + burst_duration/2, 1.15, f'{int(burst_duration*1000)}ms',
ha='center', fontsize=8)
# Bottom: Power state
ax2.fill_between(t, 0, power_state, alpha=0.6, color='#ff7f0e', label='Radio Power State')
ax2.plot(t, power_state, 'r-', linewidth=1.5)
ax2.set_xlabel('Time (seconds)', fontsize=11)
ax2.set_ylabel('Power State', fontsize=11)
ax2.set_ylim(-0.1, 1.2)
ax2.set_yticks([0, 0.5, 1])
ax2.set_yticklabels(['Idle', 'Mid', 'High'])
ax2.grid(True, alpha=0.3)
ax2.legend(loc='upper right')
# Highlight tail regions
for bt in burst_times:
tail_start = bt + burst_duration
tail_end = tail_start + 3 * tau_tail
ax2.axvspan(tail_start, min(tail_end, 10), alpha=0.2, color='yellow')
# Add annotation explaining the tail
ax2.text(0.98, 0.95,
'Tail Effect:\nPower remains elevated\nafter data transmission\n' +
r'$P(t) = P_{high} \cdot e^{-t/\tau}$',
transform=ax2.transAxes,
fontsize=9, verticalalignment='top', horizontalalignment='right',
bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.8))
# Add decay time constant annotation
bt = burst_times[0]
t_tau = bt + burst_duration + tau_tail
idx_tau = np.argmin(np.abs(t - t_tau))
ax2.plot([bt + burst_duration, t_tau], [1.0, power_state[idx_tau]],
'k--', linewidth=1, alpha=0.5)
ax2.text(t_tau, power_state[idx_tau] + 0.05, r'$\tau$ = 2s',
fontsize=9, ha='left')
plt.tight_layout()
# Save
figure_dir = config.get('global', {}).get('figure_dir', 'figures')
os.makedirs(figure_dir, exist_ok=True)
output_base = os.path.join(figure_dir, 'Fig05_Radio_Tail')
save_figure(fig, output_base, dpi=config.get('global', {}).get('dpi', 300))
plt.close()
# Compute tail energy waste
total_burst_energy = np.sum(data_activity) * (t[1] - t[0])
total_power_energy = np.sum(power_state) * (t[1] - t[0])
tail_waste_ratio = (total_power_energy - total_burst_energy) / total_power_energy
return {
"output_files": [f"{output_base}.pdf", f"{output_base}.png"],
"computed_metrics": {
"tail_waste_ratio": float(tail_waste_ratio),
"tau_seconds": tau_tail
},
"validation_flags": {},
"pass": True
}