#!/usr/bin/env python3 """ combine.py -- build combined.csv from the three per-architecture correlated CSVs (correlate_doe.py's output), decoding Q48.16 fixed-point fields to plain floats and jitter_bits' IEEE754 bit pattern to a real jitter_ns value, since R has no convenient native uint64/bit-punning story worth using here. Usage (from this directory, after running correlate_doe.py for each architecture against ../results-20260912-with-heartbeat-csv/*-doe-raw.log to produce amd64-correlated.csv / aarch64-correlated.csv / riscv64-correlated.csv): python3 combine.py amd64-correlated.csv aarch64-correlated.csv riscv64-correlated.csv combined.csv """ import csv import struct import sys Q48 = 65536.0 def main(): if len(sys.argv) < 3: print("usage: combine.py [in2.csv ...] ", file=sys.stderr) sys.exit(1) *in_paths, out_path = sys.argv[1:] fields = ["arch", "run_id", "id_idx", "id_label", "rep", "tick_number", "elapsed_ns", "tick_interval_ns", "hot_word_count", "avg_word_heat", "window_width", "actual_window_size", "predicted_label_hits", "jitter_ns", "apic_ticks", "time_trust", "variance", "vm_call_depth_max", "hera_heat", "hermes_heat", "artemis_heat"] out_rows = [] for path in in_paths: arch = path.split("-correlated.csv")[0].split("/")[-1] with open(path) as f: for row in csv.DictReader(f): jitter_bits = int(row["jitter_bits"]) jitter_ns = struct.unpack('