CALC-142
The beamforming teaching model checked: steering by a delay step, beam width and peak against row length, extra-beam onset, and the reversed reply
What this is
This is the project's own arithmetic, published in full so it can be checked rather than taken on trust. It is not a source. Every input it uses is cited to a record, and the conclusion it reaches only carries as far as those inputs do.
REGISTERED 2026-10-17. Drafted for CLM-1463 to CLM-1466 (lessons records draft BF, commit da08c9b2), checked by an independent reader (check BF: FIX, 13 findings applied, round 2 PASS), landed by the lessons-records session at coord's request. Script: beamform-model-check.py. verified: VER-2505 CONFIRMED 2026-10-17.
Feeds CLM-1463, CLM-1464, CLM-1465 and CLM-1466. Basis: lengths in wavelengths, delays in wave periods, so the wave speed is 1; angles from the row's normal. A teaching model, not a design.
Script. beamform-model-check.py, run with python -I; it runs the page model in node and recomputes
every number in Python.
Why it was needed. The beamforming lesson page shows numbers from a generic model (site figures model.mjs and scenes.mjs): a swing angle per delay, a beam width and strength per row length, an extra-beam limit per swing, and how closely the reversed replies arrive together. The model's maths had no check independent of its own code. CLM-1463 to CLM-1465 also need a worked derivation.
Inputs.
| Quantity | Value | Source | Stated or assumed |
|---|---|---|---|
| Model code | model.mjs, scenes.mjs at 3fb374f0 | page model | STATED (code) |
| Element | point source, equal in every direction in the plane | page model | ASSUMED (teaching) |
| Row | straight, even spacing d, N elements, equal amplitudes | page model | ASSUMED |
| Far-field sum | sum over n of exp(i 2 pi (x_n sin theta - tau_n)) | page model; closed form below | DERIVED |
| Pilot step | 12 elements at 0.5, bent 1.2, pilot at (6, 14); one element moved 0.37 | scenes.mjs | STATED (code); the move is CHOSEN |
Working. Independent route: the closed form for an even row, |AF|^2 = sin^2(N psi / 2) / sin^2(psi / 2) with psi = 2 pi (d sin theta - s), and bisection for every root. No line of the page model is reused. The steer root and the extra-beam directions are the same laws the model states, solved separately; the comparisons that share no law are the model's sampled peaks, widths and lobes against them.
1. *Steering.* Elements at x_n = n d, delay tau_n = n s. In direction theta the phase step between neighbours is psi = 2 pi (d sin theta - s). All add in full where psi is a whole number of turns; the main beam (m = 0) is at sin theta = s / d. In metres and seconds, s periods is s lambda / c seconds and d wavelengths is d lambda metres, so sin theta = c dt / d. 2. *Width and peak.* At psi = 0 the sum is N, so the power is N^2. Half power where sin(N x) / (N sin x) = 1 / sqrt 2 with x = psi / 2. For large N, N x = 1.392, so the full width in sin theta is 0.886 / (N d). 3. *Extra beams.* Other whole numbers m give sin theta = sin theta0 + m / d. For theta0 > 0 the m = -1 beam is visible when sin theta0 - 1 / d >= -1, that is d >= 1 / (1 + sin theta0). 4. *Reversed reply.* Element k at distance r_k from the pilot hears it at r_k (periods). It replies at max(r) - r_k, and its reply reaches the pilot at max(r), the same for every k, whatever r_k is.
Script output, transcribed (run 2026-10-17).
1. steer, 8 elements: law and sampled peak against the root of d sin(theta) = s d 0.5: s 0.05 5.73917, 0.1 11.537, 0.25 30, 0.4 53.1301 deg; all PASS (diff <= 2e-7 deg) d 0.85: s 0.05 3.37229, 0.1 6.75633, 0.25 17.1046, 0.4 28.0725 deg; law PASS NOTE d 0.85 s 0.4: model peakAngle returns -44.9009, a grating lobe of equal strength (64 = N^2); the page readout uses the law, not peakAngle step d slider end (d 0.5, delay 0.5): main beam 90.0, a second beam at -90.0 CONTROL wrong law sin = s/(2d): 14.4775 against 30, fired 2. width at d 0.5, model against closed form (deg): N2 60.0001/60.0000, N4 26.3331/26.3230, N8 12.8113/12.8025, N16 6.35983/6.35873; all 15 PASS (diff <= 0.011); peaks N^2 exactly, 15 PASS width x N d: N2 1.047, N4 0.919, N8 0.894, N16 0.888, N64 0.886, N1024 0.886 3. swung 30 deg, 8 elements: extra beams by model formula, model sampling (>= half peak), closed form 0.50 none; 0.60 none; 0.66 formula none, sampled -90, closed none; 0.67 -83.0; 0.70 -68.21; 0.85 -42.57; 1.00 -30.0; counts 7 PASS, angles 4 PASS (diff <= 1.5e-14) power towards -90 / main beam: d 0.50 0.000, 0.60 0.057, 0.62 0.317, 0.64 0.709, 0.65 0.877, 0.66 0.979, 0.6667 1.000 onset by bisection on d: 0 deg 1.0000, 10 0.8520, 30 0.6667, 45 0.5858, 60 0.5359, 90 0.5000 (1/(1+sin) the same to 4 places); model gratingLimit at 30 deg 0.666667, PASS 4. pilot: end state 1.000000 in step (PASS); moved element, model 1.000000 against numpy 1.000000; reply times max diff 7.1e-15 (PASS) CONTROL straight-row timing on the bent row: 0.258, fired 5. shown on the page: static d 30 deg and phase 0.25 (PASS); static e limit 0.666667 and 1 extra beam at -42.57 deg (PASS); static c, 16 antennas 6.36 deg, readout rounds to 6 (PASS) 6. polar plot beyond the readouts: step d far-edge power passes half the main beam at delay 0.444 (swing 62.7 deg); far-edge / main: 0.40 0.057, 0.44 0.443, 0.46 0.709, 0.48 0.920, 0.50 1.000; mirror beam at delay 0.25: 150 deg 1.000000, 30 deg 1.000000 of N^2 TOTAL PASS 66 FAIL 0
Result. Every number the page model shows agrees with the independent route: the steer law (to 1e-14 degrees), the beam widths (to 0.011 degrees), the N^2 peaks (exactly), the extra-beam directions and counts, the onset of 0.667 wavelengths at 30 degrees, and replies fully in step at the pilot for a bent row with a moved element. Both negative controls fire.
Where this fails. - It checks the maths of a teaching model, not a transmitter: point elements in a plane, equal amplitudes, no coupling between elements, a single frequency. Real numbers need a real design's records. - Near the onset, the polar plot and the readout can disagree. The readout counts extra beams by the formula, which counts a beam only once its peak is in view. In the 8-element model swung 30 degrees, the far-edge lobe is above half the main beam's power from about 0.63 wavelengths, so a reader dragging the spacing will see it before the readout names it (0.66: sampled, not counted). - At the step d slider's ends (delay +/-0.5 on half-wavelength spacing) the model makes two equal beams at the two edges, and the readout says the beam swings 90 degrees. The page sentence that half-wavelength spacing gives no extra beam at any angle is true for every swing short of 90 degrees. - Near those ends the far-edge lobe of the 8-element model is already large: it passes half the main beam's power at a delay of about 0.44 periods (a swing of about 63 degrees) and is 0.92 of it at 0.48. The polar plot shows it from there, so the page sentence holds for the formula's peaks, not for what a reader sees near the slider's ends. - The model's elements send equally in every direction in the plane, so the row also sends a mirror beam of equal strength behind it (the power at 150 degrees equals that at 30). The polar plot draws the whole circle; the readouts and CLM-1463 to CLM-1465 count the front half only. - The model's peakAngle picks whichever equal-strength lobe it samples first. It is used by the model's own test, not by any readout. - The width readout steps in 1e-4 radian increments and so runs up to 0.011 degrees wide; it prints whole degrees, so no shown figure changes. - The 0.886 / (N d) comment in model.mjs is the long-row limit; at N = 2 the true width is 1.047 / (N d).
Cite this
energyaperture.com/calc/calc-142
CALC-142. The working above, not a source document.