实验结果与结论

This commit is contained in:
2026-05-21 01:56:53 +08:00
parent 49761cf843
commit 7e6c369f9d
25 changed files with 665 additions and 47 deletions

View File

@@ -13,6 +13,8 @@ from matplotlib.lines import Line2D
OVERSEAS_CITIES = {"迪拜", "法兰克福", "雅加达", "开普敦"}
OVERSEAS_COLOR = "#4285F4"
DOMESTIC_COLOR = "#EA4335"
BASE_FONT_SIZE = 20
CELL_FONT_SIZE = BASE_FONT_SIZE - 5
def leading_group_size(labels: list[str], group: set[str]) -> int:
@@ -43,11 +45,11 @@ def configure_fonts() -> None:
plt.rcParams["axes.unicode_minus"] = False
plt.rcParams.update(
{
"font.size": 15,
"axes.titlesize": 19,
"axes.labelsize": 17,
"xtick.labelsize": 15,
"ytick.labelsize": 15,
"font.size": BASE_FONT_SIZE,
"axes.titlesize": BASE_FONT_SIZE + 4,
"axes.labelsize": BASE_FONT_SIZE + 2,
"xtick.labelsize": BASE_FONT_SIZE,
"ytick.labelsize": BASE_FONT_SIZE,
"figure.dpi": 150,
}
)
@@ -114,7 +116,7 @@ def plot_heatmap(csv_path: Path, output_path: Path) -> None:
ax.legend(
handles=legend_handles,
loc="lower center",
bbox_to_anchor=(0.5, 1.15),
bbox_to_anchor=(0.5, 1.2),
ncol=2,
frameon=False,
columnspacing=1.4,
@@ -130,7 +132,7 @@ def plot_heatmap(csv_path: Path, output_path: Path) -> None:
value = float(matrix[row_index, col_index])
text = "0" if value == 0 else f"{value:.2f}".rstrip("0").rstrip(".")
color = "white" if value > 0.55 * vmax else "#222222"
ax.text(col_index, row_index, text, ha="center", va="center", color=color, fontsize=11)
ax.text(col_index, row_index, text, ha="center", va="center", color=color, fontsize=CELL_FONT_SIZE)
sender_split = leading_group_size(senders, OVERSEAS_CITIES)
receiver_split = leading_group_size(receivers, OVERSEAS_CITIES)
@@ -144,8 +146,8 @@ def plot_heatmap(csv_path: Path, output_path: Path) -> None:
ax.tick_params(which="minor", bottom=False, left=False)
colorbar = fig.colorbar(image, ax=ax, shrink=0.88)
colorbar.set_label("平均丢包率", fontsize=14)
colorbar.ax.tick_params(labelsize=12)
colorbar.set_label("平均丢包率", fontsize=BASE_FONT_SIZE)
colorbar.ax.tick_params(labelsize=BASE_FONT_SIZE)
output_path.parent.mkdir(parents=True, exist_ok=True)
fig.savefig(output_path, bbox_inches="tight")

163
scripts/plot_thpt.py Normal file
View File

@@ -0,0 +1,163 @@
from __future__ import annotations
import argparse
import csv
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import font_manager
BASE_FONT_SIZE = 25
TITLE_FONT_SIZE = BASE_FONT_SIZE + 1
AXIS_LABEL_FONT_SIZE = BASE_FONT_SIZE
TICK_FONT_SIZE = BASE_FONT_SIZE - 2
LEGEND_FONT_SIZE = BASE_FONT_SIZE - 2
BAR_LABEL_FONT_SIZE = BASE_FONT_SIZE - 4
MAX_LOSS = 0.02
def configure_fonts() -> None:
preferred_fonts = [
"Microsoft YaHei",
"SimHei",
"Noto Sans CJK SC",
"Source Han Sans SC",
"PingFang SC",
"WenQuanYi Micro Hei",
"Arial Unicode MS",
]
installed_fonts = {font.name for font in font_manager.fontManager.ttflist}
for font in preferred_fonts:
if font in installed_fonts:
plt.rcParams["font.sans-serif"] = [font]
break
plt.rcParams["axes.unicode_minus"] = False
plt.rcParams.update(
{
"font.size": BASE_FONT_SIZE,
"axes.titlesize": TITLE_FONT_SIZE,
"axes.labelsize": AXIS_LABEL_FONT_SIZE,
"xtick.labelsize": TICK_FONT_SIZE,
"ytick.labelsize": TICK_FONT_SIZE,
"legend.fontsize": LEGEND_FONT_SIZE,
"figure.dpi": 150,
}
)
def read_throughput(csv_path: Path) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
losses: list[float] = []
cubic: list[float] = []
fec: list[float] = []
with csv_path.open("r", encoding="utf-8-sig", newline="") as file:
reader = csv.DictReader(file)
for row in reader:
losses.append(float(row["loss"]))
cubic.append(float(row["cubic_thpt_mbps"]))
fec.append(float(row["fec_thpt_mbps"]))
return np.array(losses), np.array(cubic), np.array(fec)
def format_loss_label(loss: float) -> str:
if loss == 0:
return "0"
percent = loss * 100
return f"{percent:g}%"
def filter_results(
losses: np.ndarray,
cubic: np.ndarray,
fec: np.ndarray,
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
keep = losses <= MAX_LOSS
return losses[keep], cubic[keep], fec[keep]
def plot_absolute_throughput(losses: np.ndarray, cubic: np.ndarray, fec: np.ndarray, output_path: Path) -> None:
labels = [format_loss_label(loss) for loss in losses]
fig, ax = plt.subplots(figsize=(5.6, 5.0), constrained_layout=True)
ax.plot(losses, cubic, marker="o", linewidth=2.4, markersize=7, label="直接转发", color='#4285F4')
ax.plot(losses, fec, marker="s", linewidth=2.4, markersize=7, label="本文方法", color='#EA4335')
ax.set_xlabel("丢包率")
ax.set_ylabel("吞吐量Mbps")
ax.set_xticks(losses, labels)
plt.setp(ax.get_xticklabels(), rotation=-35, ha="left", rotation_mode="anchor")
ax.grid(axis="y", linestyle="--", alpha=0.35)
ax.grid(axis="x", linestyle="--", alpha=0.22)
ax.legend(frameon=False)
output_path.parent.mkdir(parents=True, exist_ok=True)
fig.savefig(output_path, bbox_inches="tight")
plt.close(fig)
def plot_speedup(losses: np.ndarray, cubic: np.ndarray, fec: np.ndarray, output_path: Path) -> None:
speedup = fec / cubic
labels = [format_loss_label(loss) for loss in losses]
category_x = np.arange(len(labels))
fig, ax = plt.subplots(figsize=(5.6, 5.0), constrained_layout=True)
bars = ax.bar(category_x, speedup, color="#4285F4", width=0.62)
ax.axhline(1.0, color="#444444", linewidth=1.2, linestyle="--")
ax.set_xlabel("丢包率")
ax.set_ylabel("相对吞吐提升")
ax.set_xticks(category_x, labels)
ax.grid(axis="y", linestyle="--", alpha=0.35)
ax.set_ymargin(0.1)
for bar, value in zip(bars, speedup):
ax.text(
bar.get_x() + bar.get_width() / 2,
bar.get_height(),
f"{value:.1f}x",
ha="center",
va="bottom",
fontsize=BAR_LABEL_FONT_SIZE,
)
output_path.parent.mkdir(parents=True, exist_ok=True)
fig.savefig(output_path, bbox_inches="tight")
plt.close(fig)
def plot_throughput(csv_path: Path, absolute_output_path: Path, speedup_output_path: Path) -> None:
configure_fonts()
losses, cubic, fec = read_throughput(csv_path)
losses, cubic, fec = filter_results(losses, cubic, fec)
plot_absolute_throughput(losses, cubic, fec, absolute_output_path)
plot_speedup(losses, cubic, fec, speedup_output_path)
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Plot throughput comparison under different loss rates.")
parser.add_argument("--input", type=Path, default=Path("scripts/thpt.csv"), help="Path to throughput CSV.")
parser.add_argument(
"--absolute-output",
type=Path,
default=Path("figures/thpt_absolute.pdf"),
help="Output path for the absolute throughput figure.",
)
parser.add_argument(
"--speedup-output",
type=Path,
default=Path("figures/thpt_speedup.pdf"),
help="Output path for the relative speedup figure.",
)
return parser.parse_args()
def main() -> None:
args = parse_args()
plot_throughput(args.input, args.absolute_output, args.speedup_output)
if __name__ == "__main__":
main()

9
scripts/thpt.csv Normal file
View File

@@ -0,0 +1,9 @@
loss,cubic_thpt_mbps,fec_thpt_mbps
0,92.1,90.9
0.002,42.5,61.7
0.005,27.9,59.8
0.01,18.9,54.8
0.02,12.7,45.3
0.05,7.58,21.5,
0.1,4.78,6.25
0.2,0.624,5.61
1 loss,cubic_thpt_mbps,fec_thpt_mbps
2 0,92.1,90.9
3 0.002,42.5,61.7
4 0.005,27.9,59.8
5 0.01,18.9,54.8
6 0.02,12.7,45.3
7 0.05,7.58,21.5,
8 0.1,4.78,6.25
9 0.2,0.624,5.61