File size: 3,151 Bytes
48c3baa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
"""Render side-by-side comparison plots for JS vs Python benchmark runs.

Two columns × three rows: each row is a channel (left antenna, right
antenna, head Y); left column is the JS run, right column is the Python
run. Same y range per row so the comparison is honest.
"""

import csv
import sys
from pathlib import Path

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt


def load(path):
    rows = []
    with open(path) as f:
        for r in csv.DictReader(f):
            rows.append({k: float(v) if v else None for k, v in r.items()})
    return rows


def col(rows, key):
    return [r[key] for r in rows]


def plot_pair(ax, time, cmd, act, title, ylabel, ylim=None):
    ax.plot(time, cmd, color="C0", linestyle="--", linewidth=1.2, label="commanded")
    ax.plot(time, act, color="C3", linewidth=1.2, label="measured")
    ax.set_title(title, fontsize=10)
    ax.set_xlabel("t (s)", fontsize=9)
    ax.set_ylabel(ylabel, fontsize=9)
    ax.grid(True, alpha=0.3)
    if ylim is not None:
        ax.set_ylim(*ylim)
    ax.legend(fontsize=8, loc="upper right")
    ax.tick_params(labelsize=8)


def main(js_csv, py_csv, out_png):
    js = load(js_csv)
    py = load(py_csv)

    js_t = col(js, "t_s")
    py_t = col(py, "t_s")

    # Shared y ranges (per row), computed across BOTH runs.
    def span(*lists, pad=3):
        vals = [v for lst in lists for v in lst if v is not None]
        return min(vals) - pad, max(vals) + pad

    yl_l = span(col(js, "left_commanded_deg"),  col(js, "left_actual_deg"),
                col(py, "left_commanded_deg"),  col(py, "left_actual_deg"))
    yl_r = span(col(js, "right_commanded_deg"), col(js, "right_actual_deg"),
                col(py, "right_commanded_deg"), col(py, "right_actual_deg"))
    yl_h = span(col(js, "head_y_commanded_cm"), col(js, "head_y_actual_cm"),
                col(py, "head_y_commanded_cm"), col(py, "head_y_actual_cm"), pad=0.5)

    fig, axes = plt.subplots(3, 2, figsize=(13, 9))
    plot_pair(axes[0, 0], js_t, col(js, "left_commanded_deg"),  col(js, "left_actual_deg"),
              "Left antenna — JS",  "deg", yl_l)
    plot_pair(axes[0, 1], py_t, col(py, "left_commanded_deg"),  col(py, "left_actual_deg"),
              "Left antenna — Python", "deg", yl_l)
    plot_pair(axes[1, 0], js_t, col(js, "right_commanded_deg"), col(js, "right_actual_deg"),
              "Right antenna — JS", "deg", yl_r)
    plot_pair(axes[1, 1], py_t, col(py, "right_commanded_deg"), col(py, "right_actual_deg"),
              "Right antenna — Python", "deg", yl_r)
    plot_pair(axes[2, 0], js_t, col(js, "head_y_commanded_cm"), col(js, "head_y_actual_cm"),
              "Head Y — JS", "cm", yl_h)
    plot_pair(axes[2, 1], py_t, col(py, "head_y_commanded_cm"), col(py, "head_y_actual_cm"),
              "Head Y — Python", "cm", yl_h)

    fig.suptitle("Streaming benchmark: JS (browser) vs Python (script)",
                 fontsize=12, fontweight="bold")
    fig.tight_layout(rect=(0, 0, 1, 0.97))
    fig.savefig(out_png, dpi=140)
    print(f"Wrote {out_png}")


if __name__ == "__main__":
    main(sys.argv[1], sys.argv[2], sys.argv[3])