mirror of
https://github.com/NawfalMotii79/PLFM_RADAR.git
synced 2026-09-12 02:56:04 +00:00
40d352ee68f48d95569a9274b0f4e045b3aeeb47
15
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
40d352ee68 |
chore(sim): prune superseded antenna scripts — keep edge-fed-row v3 path
Drop 5 antenna sims that were either dead-end topologies or got superseded
by validated v3 designs. The kept set documents the path the project
actually took: edge-fed series-fed row on 0.508 mm RO4350B (drop-in
old-Gerber replacement, 100 MHz BW), with the single-element edge-fed
inset and probe-fed comparators kept as design-space reference points,
and production_beams_verify retained as the D-series audit artifact for
the ADAR1000 setBeamAngle() dead-code finding.
Removed:
Quartz_Waveguide.py
openems_quartz_slotted_wg_10p5GHz.py
Early waveguide explorations, abandoned when the project moved
to a planar patch array.
aperture_coupled_aeris10_v2.py
First openEMS attempt at the AERIS-10 design point. Achieved
60 MHz BW with residual reactance; superseded by the v3 paths
(probe-fed 180 MHz BW, edge-fed-inset 180 MHz BW, edge-fed
series-fed row 100 MHz BW) that landed shortly after.
array_factor_adar1000_aeris10.py
Pure-numpy ADAR1000 phase-quantization sim used to find that
setBeamAngle()'s 4-elem broadcast produces grating lobes and
that the function is dead in production (replaced by
initializeBeamMatrices + setCustomBeamPattern16). Findings
already actioned in commit
|
||
|
|
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.
|
||
|
|
acfbbb1d4d |
sim(antenna): probe_fed_array v3 — multi-port DRIVEN_PORTS env override
Previously the array sim only excited a single inner element (DRIVEN_X / DRIVEN_Y). Adds DRIVEN_PORTS env var accepting a comma/semicolon-separated list of "i,j" pairs that are all excited in-phase with equal amplitude — models a perfect 1:N corporate splitter feeding an N-patch sub-array. Example: DRIVEN_PORTS="0,0;1,0;2,0;3,0;0,1;1,1;2,1;3,1" excites a 4-cols × 2-rows sub-array anchored in the corner. S-parameter post-processing reframed for the multi-driven case: each excited port reports active-S11 (uf_ref/uf_inc with all driven ports active); each non-excited port reports S relative to a representative driven port's incident wave (all driven ports have equal amplitude so any reference works). Backwards-compatible: empty DRIVEN_PORTS reverts to single-port DRIVEN_X / DRIVEN_Y behaviour. |
||
|
|
38ee73a05c |
sim(antenna): verify production beam tables — setBeamAngle() is dead code
Audit of how the ADAR1000 is actually steered in production. Reproduces
main.cpp:initializeBeamMatrices() (PHASE_DIFFERENCES, matrix1, matrix2,
vector_0) verbatim in Python and runs the patterns through the same array-
factor pipeline used for the firmware-vs-correct comparison.
Key findings — context for fixing the setBeamAngle() bug without regression:
1) setBeamAngle() is DEAD CODE in production. grep for callers across the
whole tree returns only the definition itself (ADAR1000_Manager.cpp:215),
the header declaration (line 58), and one comment in ADAR1000_AGC.cpp
referencing the sign convention. main.cpp does NOT call it. The 4-phase
broadcast bug exposed in commit
|
||
|
|
2f4d45caa7 |
sim(antenna): nf2ff far-field + ADAR1000 array-factor verification
PART 1 — edge_fed_row_nf2ff_aeris10_v3.py:
Far-field analysis of the 1x8 series-fed row at 10.520 GHz to discriminate
broadside from scanned operation. Adds an nf2ff probe box to the verified
TX-centered design point (CONN_LEN=8.15) and computes the radiation pattern.
Result: E-plane (along array y) main lobe at θ=0.0°, BW3dB=14°
H-plane (perpendicular) main lobe at θ=0.0°, BW3dB=44°
First sidelobe -12 dB at ±18° (theoretical N=8 uniform: -13 dB)
→ BROADSIDE CONFIRMED at the operating mode.
openEMS NF2FF API notes baked into the script:
- CalcNF2FF expects theta/phi in DEGREES, converts internally.
- Prad/Dmax are sign-buggy in this version; pattern shape (E_norm) is
what we use for broadside identification.
- EndCriteria is 10·log10 energy ratio (so -40 dB → EndCriteria=1e-4).
PART 2 — array_factor_adar1000_aeris10.py:
Phased-array beam-forming verification using the ADAR1000 firmware's actual
phase-shifter codes. Combines the cached single-row embedded-element pattern
with a 16-element x-axis array factor at d=λ/2=14.286 mm pitch (matches
firmware's `element_spacing = wavelength/2` constant).
Replicates ADAR1000_Manager.cpp:714-729 (calculatePhaseSettings) and the
setBeamAngle() loop that broadcasts the 4-phase pattern to all 4 chips.
Compares against the correct 16-element progressive phasing.
CRITICAL FIRMWARE BUG SURFACED BY THE SIM:
setBeamAngle(angle) computes only 4 phases (one per chip channel), then
applies the same 4-phase pattern to all 4 chips. The intended 16-element
beam-steering never actually happens.
At cmd 15°, the firmware writes: [0, 17, 33, 50] × 4 = repeating pattern
Correct 16-elem progression: [0, 17, 33, 50, 66, 83, 99, 116, 5, 21,
38, 54, 71, 87, 104, 120]
Sim consequences (H-plane peak vs commanded):
cmd +0° → fw peaks +0° (correct) / correct +0°
cmd +5° → fw peaks +0° (NO STEERING) / correct -4°
cmd +10° → fw peaks +0° (NO STEERING) / correct -10°
cmd +15° → fw peaks +0° (NO STEERING) / correct -14°
cmd +20° → fw peaks -28° (locked grating) / correct -20°
cmd +30° → fw peaks -30° (coincidence) / correct -30°
cmd +45° → fw peaks -30° (locked) / correct -44°
Why: the same 4-elem pattern broadcast to 4 chips = effective super-pitch
d_super = 4d = 2λ, which generates grating lobes at sin(θ_g)=±0.5±sin(θ_0).
For |cmd|<18° those grating lobes coincide with the fixed broadside peak,
so the array radiates broadside regardless of commanded angle. For larger
commands the beam jumps to ±30° (the grating-lobe direction), not the
intended target.
The proper function setCustomBeamPattern16() (ADAR1000_Manager.cpp:636)
exists but isn't called by setBeamAngle(); fix is to either route through
it from a host-computed 16-element table, or extend calculatePhaseSettings
to produce 16 phases. Tracking under a separate beam-forming PR (not
antenna sim).
Other radar-engineer checks (all PASS for the antenna with proper phasing):
- Phase quantization: 7-bit (2.8125°/LSB) adds <0.2 dB SLL degradation
- Grating lobes: d=λ/2 → none in real space at any scan angle 0..90°
- Scan loss: matches cos(θ) ideal up to ~45°, then EEP roll-off dominates
- Beam pointing: sign-flipped cmd↔peak (cmd +X° peaks at -X°) — wiring
convention; either negate phase_shift in firmware or invert in host
- Null steering: phase-only synthesis places -30 dB null at θ=20° while
keeping main beam at broadside — confirmed feasible
|
||
|
|
abc7e3c66b |
sim(antenna): center 1x8 row dip on radar TX 10.520 GHz (CONN_LEN 8.0->8.15)
Sweep CONN_LEN at PROFILE=balanced to land the operating-mode dip on the chirp-band center instead of 60 MHz above it. Sensitivity is df/dCONN ≈ -0.20 GHz/mm (longer line → lower op freq). CONN=8.00 → dip 10.560 GHz, S11@10.520 = -12.6 dB (above TX) CONN=8.15 → dip 10.520 GHz, S11@10.520 = -18.8 dB (TX-centered) CONN=8.20 → dip 10.510 GHz, S11@10.510 = -18.4 dB (TX low edge) CONN=8.25 → dip 10.500 GHz, S11@10.500 = -18.4 dB (LO-centered) CONN_LEN=8.15 wins because the radar TX 10.510-10.530 GHz sees -17 to -19 dB symmetrically across the band, with -15 dB margin at the LO frequency. -10 dB BW spans 10.470-10.580 GHz (110 MHz). Pitch 15.10 mm vs old Gerber 15.01 mm. |
||
|
|
087a0563c0 |
sim(antenna): add 1x8 series-fed row — covers radar TX 10.51-10.53 GHz at -10 to -14 dB
Daisy-chain validation for 2-layer 0.508 mm RO4350B stackup. Row of 8 patches edge-connected via 8.0 mm microstrip segments (pitch 14.95 mm matches old Gerber). With direct edge feed on patch 0 (no inset; inset would drop the row input Z to ~6 Ω), the natural input impedance at the operating mode is ~80 Ω, close enough to 50 Ω for direct match without a quarter-wave transformer. Topology behaves as a finite periodic resonator with N=8 modes (~0.5 GHz spacing) and a stopband centered on the patch self-resonance. Operating point is the top-below-stopband mode at 10.56 GHz: S11 = -22.5 dB, Zin = 79.9 - j3 Ω. -10 dB BW spans 10.51-10.61 GHz (100 MHz), covering the 10.510-10.530 GHz chirp band with S11 = -10.4 to -14.6 dB across that interval. Mesh sensitivity: sanity profile (lambda/18) gave a misleading deepest-dip at 11.4 GHz; balanced (lambda/25) is required to land the operating-mode characterization correctly. PROFILE=balanced is now the documented run mode. |
||
|
|
178cb26abd |
sim(antenna): add edge-fed (inset) single-element on 0.508 mm RO4350B — 180 MHz BW
Validates the "Option C" hardware path: keep the old 8x16 Gerber's series-fed edge-fed topology, just thicken the patch substrate from 0.102 mm to 0.508 mm RO4350B. Single-element edge-fed with inset notch matched to 50 Ω microstrip. Verified at PROFILE=balanced (λ/25 mesh): W = 7.854 mm (preserved from old Gerber → array compatible) L = 6.95 mm (tuned for f_res = 10.5 GHz on 0.508 mm sub) inset_depth = 3.40 mm (~49 % of L) inset_gap = 0.30 mm (each side of feed line, in the inset notch) feed_W = 1.16 mm (50 Ω microstrip on 0.508 mm RO4350B) feed_lead = 15.5 mm (= 1·λ_g at 10.5 GHz → port sees true antenna Z) Result: f_res = 10.509 GHz, S11 @ 10.5 = -18.5 dB, VSWR = 1.27 Z @ 10.5 = 61.8 + j3.2 Ω -10 dB BW = 180 MHz (10.41-10.59 GHz, 1.71 %) This is identical BW to probe_fed_v3 — confirming BW is set by substrate thickness alone, not feed method. Edge-fed Option C is therefore the simpler 2-layer hardware path: same series-fed-row architecture as the old Gerber, single PCB stackup, no probe vias / antipads / back-board splitter complexity. Next step: extend to a 1x8 series-fed row to verify the daisy-chain topology still gives in-phase feeding at the new substrate's λ_g. |
||
|
|
eb9be337b1 |
sim(antenna): add 4x4 probe-fed array model — mutual coupling characterisation
Single-port-driven, 15-port-terminated FDTD sim built on the same v3 patch
design point (W=7.854, L=6.56, FEED_OFFSET=2.14) at the Gerber pitch
(14.27 mm X / 15.01 mm Y). Reads out S_jd for all elements when port
(DRIVEN_X, DRIVEN_Y) is excited. Configurable array size + driven port via
env vars; default = 4x4, drive inner element (1,1).
Result at PROFILE=balanced, drive (1,1):
Active S11 @ 10.5 GHz : -16.7 dB, Z = 45.7 + j13.5 Ω
Active -10 dB BW : 190 MHz (10.44-10.63 GHz; ≈ single-element 180)
Nearest-neighbour coupling:
-x edge neighbour (0,1): -18.3 dB (strongest — edge element loads less)
-y/+y in-array : -22 dB
+x interior neighbour : -24.7 dB
Diagonal : -32 dB
Far corners : -45 to -53 dB
Outputs: coupling_grid.png heatmap + S_matrix.csv (all S_jd full sweep) +
S11_data.csv (driven-port only).
Known limitation: port box must align with mesh lines; SmoothMeshLines may
sub-cell-shift seed lines, causing some DRIVEN_X/DRIVEN_Y choices to give
"Unused primitive" warning + zero excitation. Default (1,1) is verified;
other choices are best-effort. Documented inline.
|
||
|
|
3f3846b514 |
sim(antenna): add probe-fed 2-layer patch model — 180 MHz BW vs aperture-coupled 60 MHz
Single-element OpenEMS sim for a 2-layer probe-fed patch on 0.508 mm RO4350B. Verified at PROFILE=balanced (λ/25 mesh): f_res = 10.51 GHz, S11 = -21.8 dB, VSWR 1.18, -10 dB BW = 180 MHz (10.40-10.58 GHz). Direct 50 Ω match — no port matching cap needed. Design point baked into defaults: PATCH_W = 7.854 mm (preserved from old 8x16 Gerber → array compatible) PATCH_L = 6.56 mm (tuned for f_res = 10.5 GHz at 0.508 mm sub) FEED_OFFSET = 2.14 mm (probe via, from -y radiating edge) Why probe-fed: aperture-coupled v2 (4-layer Stack_Hybrid) capped at ~60 MHz BW because the 0.11 mm L4 acts as a near-short reflector — beneficial for slot coupling but creates an L2-L4 cavity that's the BW ceiling. Tested removing L4 (open-back aperture-coupled): coupling collapsed, R stayed >1000 Ω regardless of patch tuning. Probe-fed has no slot bottleneck; physics BW = 1.7% on h=0.508 matches sim 180 MHz directly. Hardware change required to deploy: 2-layer stackup (patch on top, ground on bottom, probe vias with antipads). Old 8x16 Gerber was edge-fed; v3 is probe- fed → top-layer feed network goes away, ADAR1000 carrier on a separate board with SMP RF launches. Stackup signoff with antenna designer needed before PCB. aperture_coupled_v2 retained as the 4-layer fallback (with the 0.043 pF cap) if 2-layer redesign isn't approved. |
||
|
|
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.
|
||
|
|
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
|
||
|
|
2106e24952 |
fix: enforce strict ruff lint (17 rule sets) across entire repo
- Expand ruff config from E/F to 17 rule sets (B, RUF, SIM, PIE, T20, ARG, ERA, A, BLE, RET, ISC, TCH, UP, C4, PERF) - Fix 907 lint errors across all Python files (GUI, FPGA cosim, schematics scripts, simulations, utilities, tools) - Replace all blind except-Exception with specific exception types - Remove commented-out dead code (ERA001) from cosim/simulation files - Modernize typing: deprecated typing.List/Dict/Tuple to builtins - Fix unused args/loop vars, ambiguous unicode, perf anti-patterns - Delete legacy GUI files V1-V4 - Add V7 test suite, requirements files - All CI jobs pass: ruff (0 errors), py_compile, pytest (92/92), MCU tests (20/20), FPGA regression (25/25) |
||
|
|
11aa590cf2 |
fix: full-repo ruff lint cleanup and CI migration to uv
Resolve all 374 ruff errors across 36 Python files (E501, E702, E722, E741, F821, F841, invalid-syntax) bringing `ruff check .` to zero errors repo-wide with line-length=100. Rewrite CI workflow to use uv for dependency management, whole-repo `ruff check .`, py_compile syntax gate, and merged python-tests job. Add pyproject.toml with ruff config and uv dependency groups. CI structure proposed by hcm444. |
||
|
|
4b7eb54ee8 | Add files via upload |