1 of 10

1

From team Blueberry, JAAM.

Just Another Antenna Modeller.

From NEC-2

to openEMS

to a language.

Primarily designed to speed up the development of RF antennas and other such equipment, the FOSS way.

Arecibo Observatory

2 of 10

JAAM

source: NEC-2 Part I, §§I–II

2

NEC-2: We used punch cards for this stuff?

NEC-2 is an integral-equation antenna solver built around currents on wires and conducting surfaces.

For wire antennas, that model is still excellent. The problem is what you have to feed it.

01

Wire-first geometry

Straight wire segments, plus surface patches where needed.

02

Frequency-domain solve

Accurate current and radiation analysis without filling all of free space.

03

Mature and inspectable

Sources, loads, grounds and radiation patterns are explicit.

The kind of structure NEC-2 likes: mostly wire.

Yes, those are indeed wires in a Yagi Antenna.

3 of 10

JAAM

source: NEC-2 User’s Guide, structure modelling guidelines

3

NEC-2: The geometry is numerical

You are not only describing an antenna. You are choosing a discretisation that keeps NEC inside its assumptions.

01

Segment everything

Curves become piecewise-linear wires. The guide recommends Δ < ~0.1λ, often smaller in critical regions.

02

Respect the thin-wire model

The classic approximation assumes radius ≪ wavelength and radius ≪ wire length.

03

Surface models need care

NEC can use patches, but the original docs explicitly warn that surface-field accuracy can vary.

04

Ground is another model choice

Perfect, Sommerfeld/Norton and reflection approximations each come with different costs and caveats.

Curved geometry is still ultimately a set of numerical choices.

4 of 10

JAAM

source: openEMS docs + JAAM docs/finale-demo.md

4

OPENEMS: A shift to 3D

openEMS gives us a full FDTD domain instead of a wire-first model.

That buys us CSXCAD geometry, PML boundaries, lumped ports, graded Cartesian meshes and NF2FF results in one open solver stack.

01

More general geometry

Wires, boxes, materials and volumetric structure live in the same domain.

02

Time-domain solve

One run can cover a frequency band instead of one frequency at a time.

03

Open output path

The generated model and solver artifacts remain inspectable.

The modelling target is no longer a “stick figure”.

5 of 10

JAAM

source: JAAM benchmarks/dipole_reference.py + docs/native-setup.md + openEMS mesh docs

5

openEMS: The Woes of Meshing and Cells

The solver is capable. The authoring surface is not small.

A hand-written run still has to sequence geometry calls, split feeds, reserve PML space, place fixed mesh lines, smooth them, run the solver, then post-process the result.

And the native Python bindings are compiled dependencies. On host they live in system Python, not the project venv.

Powerful solver. Bad place to encode intent.

6 of 10

JAAM

source: JAAM README.md

6

JAAM: Codify Intent, and let the Compiler do the rest.

JAAM is a declarative language and traced compiler in front of openEMS.

The source describes the antenna. The compiler owns units, topology, lowering, mesh construction and artifacts before arbitrary Python ever runs.

.jaam source files

→

ANTLR AST

→

typed IR

→

optimization passes

→

mesh plan

→

CSXCAD + openEMS

→

versioned artifact

The IR is the one true source.

Emitter, visualiser and runtime all consume the same resolved model.

7 of 10

JAAM

source: examples/dipole.jaam + benchmarks/dipole_reference.py

7

EXAMPLE: the same dipole

JAAM source

Hand-written openEMS reference

JAAM still emits a real openEMS model. It just moves feed splitting, PML reservation, units and mesh policy into compiler-owned code. So the code is reusable in normal Python as well!

8 of 10

JAAM

source: src/jaam/passes.py + JAAM README.md

8

OPTIMISATION: The compiler knows your model

Because JAAM owns a typed IR, it can simplify the numerical setup without rewriting the user’s antenna.

canonicalize-wire-vertices

remove exact/redundant points from the structure

merge-collinear-wires

collapse compatible straight runs to save time

graded-mesh-coarsening

coarsen away from geometry to reduce cells

mesh-anchor-pruning

experimental: fewer fixed coordinates for detailed curves

The pruning pass keeps the detailed curve vertices sent to CSXCAD. It only fixes fewer Cartesian mesh coordinates and lets CSXCAD insert intermediate lines.

opt-in until curved-antenna parity is proven

9 of 10

JAAM

source: JAAM README.md, Optimization evidence

9

BENCHMARKS: Grid complexity and size

Actual post-smoothing FDTD cells, measured from CSXCAD GetLines().

Yagi

66,816 → 66,816

0%

Helix

254,113 → 44,030

−82.7%

Parabolic arc

88,264 → 55,760

−36.8%

Straight concat

29,160 → 29,160

0%

The big win is curved geometry.

Something that NEC2 has historically struggled with, and equal in wire antennas.

10 of 10

JAAM

source: JAAM README.md + scripts/compare_dipole_reference.py

10

BENCHMARKS: Did we change the math?

Grid cells are expensive. We cut them down. Did we regress?

Hand-written openEMS dipole vs JAAM

on the same frozen mesh

0.0061 dB

max S11 difference

0.033%

impedance difference

0.00012 dB

max far-field cut difference

Experimental parabolic pruning

52.6 s → 24.2 s

but:

up to 1.24 dB cut drift

14.9% impedance drift

So mesh-anchor pruning stays opt-in.