122 lines
4.4 KiB
Python
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
|
|
}
|