Commit Graph

3 Commits

Author SHA1 Message Date
Jason 0728d931c4 chore(repo): PR-H — G-series close-out (regression infra + lint sweep)
Closeout pass for the G-series 3-ladder chirp + adaptive-escalation work.
Cleanup, watchdog/fallback, lint, full regression — final sign-off.

Cleanup + watchdog/fallback: already wired during earlier audit waves
(track watchdog in chirp_scheduler RP_DEF_TRACK_WATCHDOG_FRAMES, RESERVED
fallback in plfm_chirp_controller_v2, range-decim watchdog in
radar_system_top with gpio_dig7 surfacing, F-3.* MCU error path).
Verified — no residual TODO/FIXME in production RTL or MCU.

Regression infra: tb/cosim/compare_independent.py SKIP-detection bug —
importlib.util.find_spec("scipy.signal") raises ModuleNotFoundError when
the parent scipy package is itself absent (instead of returning None as
the surrounding logic assumed). Wrap in try/except so the regression
runner gets the intended rc=2 SKIP marker rather than a crash that masks
the rest of the script.

Lint sweep: ruff full-repo → 0 errors. Two changes:
  - pyproject.toml broadens 5_Simulations/Antenna/**.py exemption from
    just T20+ERA to the full set of script-ergonomics rules
    (RUF001/002/003 Greek µ/λ/π/θ in physical-units strings, E501 long
    matplotlib/numpy lines, RUF005/015/046, E70x one-line setup, B007
    tuple-unpack loop vars, B905, BLE001 diag try/except, C401, RET504,
    SIM118, PERF40x, ARG001, E402). These are sim/analysis scripts, not
    production code — keep substantive bug rules (F unused, B core
    bugbears) but drop stylistic noise.
  - Auto-fix sweep: 31x F541 (f-string-no-placeholder), 3x F401 (unused
    sys import), 2x F841 (dead leftover ref_pat / phases_quant in
    array_factor_adar1000_aeris10.py).

.gitignore: cover 9_Firmware/9_2_FPGA/tb/cosim/mf_chain_autocorr.csv
(matched_filter cosim writes here now; was already covered for tb/ but
not tb/cosim/).

Regression baseline (radar_venv):
  FPGA  : 42/43 — 1 pre-existing T-6 drift cosim fail surfaced by the
          SKIP fix above. Three sub-checks now red because PR-O moved
          xFFT/MF chain to LogiCORE v9.1 *Scaled* mode (1/2 per stage,
          1/2^11 total for N=2048) but compare_independent.py's invariants
          (FFT-impulse uniform-spectrum, MF peak-at-injected-delay, MF
          peak/median ≥ 5) were written assuming UNSCALED FFT. Not
          introduced by this PR — was hidden by the SKIP-detection crash.
          Defer to PR-M.4: redesign T-6 invariants (or input amplitudes)
          to match scaled-mode arithmetic.
  MCU   : 34/34 binary suites pass.
  GUI   : test_v7 150/150 pass.

uv.lock: scipy resolution catch-up (declared in pyproject dev group all
along; lock just hadn't been refreshed after pyproject edits landed).

Bench-side checks: none — this PR is repo hygiene, no firmware/RTL
behaviour change.
2026-05-05 10:39:57 +05:45
Jason e01c2ae424 sim(antenna): tune aperture-coupled v2 to design point — R matched, X residual documented
10-iteration analytic-tune sweep (no DE optimizer — that was a wrong
direction for this topology) on the Stack_Hybrid 4-layer stackup. Key
findings from the sweep are baked into the script defaults and header.

Best design point @ 10.5 GHz (now the env-var defaults):
  patch  W=9.55 mm  L=7.77 mm
  slot   L=3.00 mm  W=0.50 mm  (centered under patch)
  stub   L=4.16 mm  (= λ_g/4 in feed sub at f0)
  feed   lead=12.34 mm  W=0.25 mm
         total feed length = 1·λ_g at 10.5 GHz, line transparent at f0

Result: Z ≈ R + j350 Ω at 10.5 GHz, R = 33–51 across reruns (sanity-profile
convergence drift; X is stable). R is within matching range; the +j350
inductive residual is fundamental to the topology (L4 backshort under the
antenna footprint), not a tuning artifact. Two production-grade fixes:
  (a) Series cap at port C ≈ 0.043 pF — drops S11 to ≈ -40 dB
  (b) Open L4 backshort under antenna — restores standard open-back
      aperture-coupled, stub naturally tunes X

Three real bugs fixed in the underlying sim (without these, the baseline
script was measuring artifacts, not the antenna):

1. Z mesh under-density. Default SmoothMeshLines at λ/18 gave the 0.11 mm
   feed substrate ~0.1 cells vertically — microstrip Z0 was a pure mesh
   artifact. Now built explicitly with ≥5 substrate-interior lines per
   dielectric (bypassing SmoothMeshLines collapse for z-axis only). Fine
   substrate cells visible via MESH_DEBUG=1.

2. SLOT_Y_OFF_MM env var was read but never applied to the L2 slot box,
   silently making the parameter inert. Slot is now correctly offset in y.

3. FEED_LEAD_L was hardcoded at 14.0 mm, making total feed length 18.16 mm
   = exactly 1·λ_g at 9.5 GHz (in feed substrate). This created a parasitic
   feed-line full-wave standing wave in-band that masked the patch as a
   persistent "9.4 GHz resonance" regardless of patch dimensions. Now
   parameterized via FEED_LEAD_L_MM with default 12.34 mm so total feed =
   1·λ_g at 10.5 GHz instead — line is transparent at the operating freq
   and sim measures the actual antenna impedance at the port.

Sweep grids updated to span ±1 step around the iter #6 design point.
2026-05-03 00:26:41 +05:45
Jason 42056b8331 sim(antenna): add OpenEMS aperture-coupled patch model for Stack_Hybrid v2
Re-simulation infrastructure for the new 4-layer aperture-coupled antenna
stackup (Stack_Hybrid.png, committed 1de2296). Renders the full multilayer
geometry (L1 patch / L2 slot ground / L3 microstrip feed / L4 backplane)
on the actual substrate stack (RO4350B 0.508 mm + RO4450F 1.2 mm + RO4350B
0.11 mm) and runs FDTD via openEMS to characterize S11 vs frequency.

Geometry interpolated from existing 2-layer Gerber:
  patch W from Gerber (7.854 mm, set by εr only)
  patch L re-tunable for new substrate (env var PATCH_L_MM, default 7.25 mm)
  slot/feed/stub fully parameterized via env vars

Run modes:
  PROFILE=sanity    : single run, λ/18 mesh, ~30 s
  PROFILE=balanced  : single run, λ/25 mesh, ~60 s
  PROFILE=sweep     : 5×5 grid over slot_L × stub_L, ~25 min

Env overrides for parametric exploration:
  PATCH_W_MM, PATCH_L_MM, SLOT_L_MM, SLOT_W_MM, STUB_L_MM, SLOT_Y_OFF_MM

Setup: openEMS Python bindings built from source against /opt/openEMS for
Python 3.12 in radar_venv; run with
  DYLD_LIBRARY_PATH=~/opt/openEMS/lib ~/radar_venv/bin/python
under cwd != openEMS-Project/openEMS/python (avoids CSXCAD shadow import).

Status: simulation infrastructure verified end-to-end; patch resonates at
10.4 GHz with W=9.0 / L=5.5–6.0 mm. Full 50 Ω impedance match not yet
converged — the L4 backplane (non-standard for aperture-coupled) reduces
slot coupling vs textbook formulas; needs proper EM optimizer (scipy
wrapping or CST/HFSS handoff) to fully tune. ~150 MHz baseline BW
predicted from substrate physics; 30/40 MHz chirp target comfortably
under any plausible match outcome.
2026-05-02 22:37:25 +05:45