Skip to content

Releases: king-aj3/EMStudioFree

v1.12.0 — validated against published works: 172 anchors traced, 144 primary-confirmed

Choose a tag to compare

@king-aj3 king-aj3 released this 30 Aug 19:12

Someone put it to me plainly that being able to re-create this project's tutorials proves nothing — if a tutorial anchors on a wrong number, everyone faithfully reproduces the error. That is correct: consistency is not correctness. So this release's headline is not a feature. It is an audit of my own foundations.

  • Every reference value, traced to its primary source. Every number the validation gates anchor on was traced back to the original paper, standard, report or manufacturer datasheet, and compared digit by digit — under strict rules of evidence: only the original document (or an official scan) can CONFIRM a value; restatements merely corroborate; anything that could not be re-read in a fetched document is recorded as unverifiable rather than assumed right; and every suspected mismatch was re-verified against the source itself before being believed. Result: 172 anchors traced — 144 confirmed digit-for-digit against primary sources (the NIST scan of NBS TN-688, the compumag TEAM-7 specification, Lyn's J. Fluid Mech. experiment, the Huynh thesis chamber column, Belden datasheets, the ITU-R Recommendation texts, Balanis — measured from the PDF's embedded vector geometry where the source is a chart — and NIST CODATA), 13 corroborated only, 8 honestly unverifiable, and 7 real mismatches in my own numbers, every one corrected in this release and published beside its correction. The full record: https://ajj3.us/apps/emstudio/validation — and machine-readable in this repository as docs/validation/anchors.json, so the claim and the record cannot drift apart.
  • The seven corrections (none touched a solved result): the LPDA low-sigma table re-measured from Balanis Fig 11.13's embedded vector paths — the hand-read values were off by up to 0.010 in τ, and the 8.5 dB contour never reaches σ = 0.06 at all, so that row is now labelled the extrapolation it is; the 0.469 sphere constant's citation corrected (the constant was always right — it is Churchill's sphere correlation; the cited equation prints the 0.492 plate function); the vendored ITU-R P.1812 engine relabelled -8, the revision actually vendored and the one in force; "64 per-dataset logs" → 63; the horn phase-error docstring s = 1/8 → 1/4; the horn aspect-ratio derivation claim; and NBS TN-688's own 2.16 dB rounding of the dBd offset documented beside the exact 2.15 the code keeps.
  • A second horn design mode — the true Balanis optimum. design_pyramidal_optimum solves the ch. 13 chain for the shortest horn at a target gain, with the realizability condition p_e = p_h as the equation being solved and the feed guide included; the Element Designer gains a Design-mode choice beside the symmetric-beam default. Verified on identities from fetched sources: p_e/p_h = 1 to 1e-9 with and without a WR-90 throat, gain round-trip within 0.015 dB.
  • The symmetric-beam horn synthesis now prints one buildable horn. The old read-out quoted both per-plane optimum flares beside a 1.5 aspect ratio — a pair whose flares meet the axis 1.5× apart, which no single pyramidal horn can have. The E-plane flare now derives from the shared apex, and the "independent gain cross-check" is relabelled the same-model consistency figure it is.
  • The NEC2 pattern parsers select the requested frequency's block. On a swept file the old single-block parsers returned the band-start block under whatever label the caller asked for (latent — no shipped path passes one today). One shared block walker now serves all three parsers; a data row must lead with a number, so the card-echo trailer can never be ingested as data. Proven on real nec2c output.

Pre-tag proof: the full solver battery ran complete on the release commit itself — 115 ok, 0 failed, 0 skipped, 21,409.8 s (5.95 hours), 3,535 executed checks across 105 gates — and nothing moved during the run, so the proved tree and this tag differ by the proof paragraph alone.

97 automated validation gates in this repository. Full details in CHANGELOG.md.

v1.11.1 — the audit release: 38 fixes, 32 repaired gates, honest coverage

Choose a tag to compare

@king-aj3 king-aj3 released this 30 Aug 11:13

This is the audit release. Every change in it comes from a three-round, 209-agent audit of the entire codebase — every validation gate, every public function, and every published claim — with each finding adversarially refuted before being accepted, and each fix proven by a before/after control with real numbers rather than inspection.

  • 38 product defects fixed across the engines and dialogs. The ones most likely to have touched a number you read: the reference impedance is now per-frequency end to end (a waveguide port's modal impedance was truncated to its first sweep value — checked against Pozar eq. 3.22, the column now matches the analytic TE10 impedance across WR-28, and the worst-case normalising error at the top of the band falls from +40 % to +10 %; nothing moves for lumped, coax or microstrip ports). Every Palace solve started from the GUI had been running on one core — the MPI-ranks property was attached to the wrong solver's property block, so the parallel speedup released in v1.5.0 never reached the GUI path until now. Reported wind drag was four to five orders of magnitude low (it rendered as 0.000 N/m) from a doubled area term, and mislabelled Pa when it is newtons. The Smith tab's caption now uses the solver's own S11, so its VSWR and return loss can no longer disagree with the VSWR tab. Nine Element Designer inputs (horn/IFA/PIFA) were wired to nothing — the predicted panel and the PDF described the design from before your edit while Accept & Generate built the edited one. Also fixed: intermodulation levels above third order (wrong by tens of dB), a material change that silently coarsened the FDTD mesh at metal edges, open-conductor inductance, reversed-coil sign handling, assistant answers fabricated beyond the sweep edge, P.1546 optional corrections returning NaN, and a licence path that could lock out a paying customer during a Gumroad outage.
  • 32 validation gates could pass while checking nothing — a skip path that returned success when a backend was absent, a bare except-clause that relabelled real regressions as "backend unavailable", checks whose passing condition was a constant, and one gate that asserted against a stub it had installed itself. Each repair was proven by sabotage (gate goes red) then revert (green), and independently re-verified. If you run a gate by hand without its backend now, it says SKIPPED and exits non-zero instead of printing a pass it did not earn.
  • The battery now reports coverage, not just exit codes. Each gate's line ends with the number of checks it actually executed, and the summary totals them — because a green run used to discard the only evidence separating a gate that checked 118 things from one that checked none.
  • Six published claims were corrected on their live surfaces — including a stale check count, an overstated GPU-agreement tolerance, and a claim that two Pro-only gates ship in this repository's CI. The corrections are in the storefront, the site and the forum threads, with the changes acknowledged in place.
  • Two known issues are documented rather than half-fixed (CHANGELOG "Known and deliberately NOT fixed"): a latent NEC2 multi-block parser selection no shipped caller currently reaches, and the pyramidal horn's circular gain cross-check — the candidate fix changed a validated, published anchor's geometry and is held for an explicit design decision.

Pre-tag proof: the full solver battery ran complete on the fix commit itself — 115 ok, 0 failed, 0 skipped, 21,557.2 s (5.99 hours), 3,524 executed checks across 105 gates — with per-gate check counts recorded for the first time. The difference between the proved tree and this tag is version stamps and the CHANGELOG entry.

97 automated validation gates in this repository. Full details in CHANGELOG.md.

v1.11.0 — a Smith chart, and the measured anchor becomes a measured trend

Choose a tag to compare

@king-aj3 king-aj3 released this 29 Aug 05:01
  • ⭐ A Smith chart — Results ▸ the new "Smith" tab. The impedance locus on the unit disc with the constant-R/X grid, VSWR 2 / 1.5 / 1.2 rings, start and end markers so the direction of increasing frequency is readable, and a star on the best match. The title states Z, VSWR, return loss and whether the load is inductive or capacitive. Tutorial 37 teaches reading it — leading on the distinction the chart exists to make and an S11 dip cannot show: resonant (the locus crosses the real axis) is not matched (it crosses it at the centre). The chart is normalised to the port, and says so in the title: on a 75 Ω or 100 Ω port an unlabelled chart is actively misleading.
  • It is hand-rolled, with no new dependency, and the reason is recorded in the source. All three Smith packages on PyPI — pysmithchart, scikit-rf, mpl-smithchart — are absent from FreeCAD's bundled Python, so any of them becomes an install-time dependency on three platforms whose bundles differ, and scikit-rf pulls pandas in to draw a chart. Against that, the mathematics is a Möbius transform and two circle formulas. The deciding argument was gateability: you cannot mutation-test someone else's projection. docs/PLAN.md named scikit-rf for "S-params/Smith" at the start of this project and it was never adopted; emstudio/post/smith.py now says why, so nobody re-litigates it.
  • ⚠⚠ Gating a Smith chart is hard because almost every true statement about one is an identity — satisfied by construction, and therefore worthless as the only check. So the load-bearing tests are cross checks against numbers derived independently: the circle geometry is verified by sampling thousands of real impedances, mapping each through Γ and confirming the images land on the circle the closed form predicts (to 1e-12); VSWR is checked against SweepResult.vswr(), the number the VSWR tab has shown since v0.8.0; and return loss must be the exact negation of s11_db(), because both sign conventions are in circulation. Mutation-proven four ways — and the wrong-circle-radius mutation is caught by only the cross-check.
  • ⚠ The new GUI check for it was itself vacuous, and that is why it is worth telling you about. Its first version read ax.lines[0] — which is the real-axis rule, not the data — and reported "2 locus points, max |Γ| 1.000" for a 41-point sweep. Green, asserting nothing. It now finds the locus by label and asserts the point count equals the sweep. It was caught only because the check prints its coverage instead of just PASS, which is the habit that has now caught four hollow checks in one week.
  • ⭐⭐ The measured radiating anchor is now a measured TREND. The published anchor PIFA is solved on four ground-plane sizes and each is checked against the anechoic-chamber column of Huynh's Table 5-1: 20 mm +0.75 %, 40 mm +1.84 %, 80 mm +0.22 %, 100 mm −0.65 % — with resonance moving +29 % across the shrink, and the non-monotonic turn reproduced. ⚠ The closed form returns 1873.7 MHz for every one of them; it has no ground-size term at all. "On a handset the chassis is part of the antenna" stops being a warning printed beside a number and becomes a checked fact.
  • ⚠⚠ Two corrections that came only from reading the source, either of which would have shipped a wrong gate. The +18.3 % ground-plane shift this project has quoted since A2 is Table 5-1's computed (IE3D) column, not its measured one — and our own de-risk note claimed the table "measures" three numbers of which none came from the measured column (it publishes no measured gain at all). The measured pair is both stronger and larger: +29.0 %. And the trend is not monotonic — resonance falls as the ground grows only to a minimum near L = 100 mm and then rises again. "Bigger ground, lower resonance" is exactly what a reasonable person writes from a summary, and it is false. A summary of a source is not the source.
  • ⚠ The obvious cheap version of this gate would have measured noise. The 80 mm and 100 mm rows differ by 6 MHz, while this gate's own mesh spread across MeshResolution 20–90 is about 30 MHz — five times larger. The 20 mm rung moves 548 MHz, roughly 18× the spread, which is why the ladder is anchored there and carries an explicit floor. The ladder asserts resonance only, never match depth: the published rows re-match the probe at every ground size while the model holds the feed fixed, so comparing S11 across it would be comparing two different experiments.
  • Every GUI command is now documented, and a gate keeps it that way. Seven of the fifty registered commands had no row in HELP.md's command table, and none was described anywhere else in it either. Two were recent headline features: Solve Wind Loading, the feature v1.9.0 was named for — the file's five "wind" hits were every one coil winding — and the Filter & Diplexer Designer, which had only the word "diplexers" in a blurb and no user-manual section, so it had no user-facing command reference at all. All seven now have rows, and doc_counts now requires every "MenuText" in commands.py to be a row or to be named in a declared allow-list for rows that deliberately cover several commands.
  • ⭐ Why two documentation sweeps missed that. The previous release ran 157 subagents over the docs and confirmed 97 findings; none was this. Both rounds hunted claims that were wrong — stale versions, stale counts, tier errors. A missing row makes no false claim, so a staleness sweep is structurally blind to it. Absence is visible only against an inventory, never against a diff with reality.
  • Fixed: the gate that watches your installed copy could not see a Windows or macOS install. Its directories and its battery prerequisite both hard-coded the Linux path, so on any other platform it skipped — silently, and exit 0. Measured on a Windows box: the installed copy was at v1.0.0, ten releases behind, with every gate on that machine green. It now resolves the FreeCAD user Mod directory per platform — three branches, because os.name is "posix" on macOS and Linux — through one function that the gate, the requirement and the check tool all share, so the layout lives in a single line.

Pre-tag proof: the full SOLVER battery ran complete on this release's code — 115 ok, 0 failed, 0 skipped, 22,007.2 s (6.11 hours) — the first complete run at 115 gates. It is also the first release whose proved tree needs no argument: the only commit that landed while it ran changed a single handoff document that no gate reads, so every executable byte the battery touched is a byte in this tag.

97 automated validation gates in this repository. Full details in CHANGELOG.md.

v1.10.0 — a PIFA measured against real hardware, and Palace radiating end to end

Choose a tag to compare

@king-aj3 king-aj3 released this 27 Aug 08:38
  • The project's first radiating anchor against MEASURED hardware. A printed PIFA — the antenna in most handsets — solves at 1.8962 GHz against a published anechoic-chamber measurement of 1.892 GHz, +0.22 %, and every mesh from λ/20 to λ/90 lands within 1.3 % of it. Every other radiating gate here is checked against something computed: a published geometry, an analytic vendor curve, our own synthesis. This one is checked against an antenna somebody built and measured, which is the strongest form of claim this project can make.
  • ⚠ And the finding that came with it: the shorting plate's POSITION is worth 7.6 %, and no closed form can see it. The standard PIFA equations have no term for where along the edge the short sits. Centred solves at 2.0370 GHz, at the edge at 1.8930 GHz, and the formula returns 1873.7 MHz for both. A PIFA built to exactly the right dimensions with the short in the wrong place is wrong by more than the formula's own stated accuracy, with nothing analytic to warn you. Found by chasing a discrepancy instead of tuning it away.
  • The handset pair, and a 5G worked example. A printed inverted-F rebuilt from openEMS's own published example (2.3934 GHz, −26.5 dB, 211 MHz of −10 dB bandwidth covering the whole 2.4 GHz ISM band) joins the PIFA, both with Element Designer pages, examples and tutorials. Separately, the 5G NR band n78 patch at 3.5 GHz puts the same patch on the same board as the 2.4 GHz example so frequency is the only variable between the two documents — and gates the honest limitation, that its −10 dB bandwidth does not cover n78's 500 MHz.
  • The Element Designer now has eight families. The Ka-band pyramidal horn had a gate, a template and a tutorial since v1.5.0 while the designer contained zero horn references — a validated capability nobody could reach from the tool meant to reach it. It is now a family: frequency and target gain in, the optimum-flare aperture out, with two independent gain routes cross-checked on screen.
  • Palace radiates, end to end. Its far field is read back as a pattern like any other backend's, and the radiating domain that feeds it is meshed from geometry EMStudio builds itself — checked against the closed form for a half-wave dipole (broadside +1.821 dBi against 2.151 analytic, a 19.4 dB axial null). ⚠ Reachable from the API and its gate, not yet from a menu, and the docs say exactly that.
  • Corrections you should know about, because they were wrong in ways that mattered. The user manual described two Pro dialogs as "part of the free EMStudio core" — so this repository shipped a manual telling you a dialog you cannot open should be there. Both issue forms linked "what is deliberately not planned" to a file that isn't in this repository, giving every reader a 404. And several places still said openEMS had no one-click Windows install, which stopped being true in v1.8.0.

Pre-tag proof: the full SOLVER battery ran complete on this release's code — 114 ok, 0 failed, 0 skipped, 6.05 hours — the first complete run at 114 gates and the first with nothing skipped.

96 automated validation gates in this repository. Full details in CHANGELOG.md.

v1.9.0 — the wind engine gets its door, and it refuses what no anchor covers

Choose a tag to compare

@king-aj3 king-aj3 released this 25 Aug 19:37
  • The wind engine finally has its door — Analysis ▸ Solve Wind Loading… Type a section width, a wind speed and a member length; the dialog chooses the solve method from the Reynolds number the way the thermal dialogs choose their turbulence model: steady below the shedding onset, transient laminar to Re 200, and above that the kOmegaSST square-section configuration validated against the Lyn (1995) experiment / Tian (2013) URANS study at Re 21,400 — carried to Re 1.5×10⁵ on the square's flat measured drag plateau. The choice and its honest runtime are shown before you press Solve, and configurations no anchor covers are refused with the engine's own explanation instead of a disclaimer after the fact: a circular mast above the shedding regime cannot be run, only explained — its drag crisis is transition physics a single-Re anchor doesn't cover. Cancel actually stops the solve.
  • The licence dialog's Remove button heals instead of dying silently when Pro vanishes mid-session, and the free tier's one-line Pro hint is now asserted as a rendered widget, so it can't silently disappear.
  • The free tier's convection advice matches Pro's rule for rule, gated by a parity check that compares fired warning conditions — including the NEC double-derating warning and the implausible-factor band.
  • Release hygiene you can see: this release's pre-tag proof was the first complete run of the entire 109-gate battery — 109 ok, 0 failed, 0 skipped, 5.5 hours — and the project now reads its own installed copies against the release ladder (that reader found them six releases stale on its first run, which is exactly why it exists).

91 automated validation gates in this repository. Full details in CHANGELOG.md.

v1.8.0 — turbulent wind loading validated against the measured anchor; openEMS one-click on native Windows

Choose a tag to compare

@king-aj3 king-aj3 released this 24 Aug 01:49
  • Turbulent wind loading is validated — transient kOmegaSST on the sharp-edged square section, to Re 1.5×10⁵. The new openfoam_wind_ras gate solves the published anchor (the square cylinder at Re 21,400 — Lyn's 1995 LDV experiment, and Tian 2013, the same case in OpenFOAM 2-D URANS SST) through EMStudio's own writer and runner: Cd 2.14 against the experiment's 2.1, St 0.136 against the measured 0.132 with the documented URANS bias, lift amplitude beside the DNS value. Every tolerance is the published spread, not our own measurement. Circular sections above the shedding regime still refuse honestly — the drag crisis is transition-location physics no single-Re anchor covers, and the validity note says so instead of shipping a plausible number. The domain is part of the benchmark: the case reproduces the sources' ~5 % tunnel blockage, because a more "generous" domain legitimately reads Cd a few percent low (measured, and recorded).
  • openEMS on native Windows: a one-click Install button, proven before it was offered. Solver Setup downloads the official upstream build (sha256-pinned), builds the Python environment the run pipeline needs from the zip's own wheels, heals the measured DLL-closure failure (the wheels bundle no DLLs, and Python ≥3.8 ignores PATH for extension-module dependencies), and refuses before the download if no wheel-compatible Python (3.13/3.14) exists — instead of leaving a "found" solver that cannot run. Verified live on Windows through the unmodified runner first: the patch gate reproduces its published −29 dB S11 reference at 2.435 GHz, and the microstrip notch matches the stored cross-platform reference to the digit (3.6623 GHz).
  • The openEMS progress bar now actually reports progress: the live console prints Timestep: with a colon, which the shipped pattern could never match — on any platform, ever. Fixed against a captured live run, and the deck now flushes its total-timesteps line so the bar learns its denominator before the FDTD output floods the pipe.
  • The wind RAS startup crashes recorded on 2026-08-23 were never the turbulence model: a dev-harness potentialFoam init (which the product never runs) and a too-small domain, both root-caused with field-dump forensics and both recorded in docs/WIND_TURBULENCE_ANCHOR.md.

91 automated validation gates in this repository. Full details in CHANGELOG.md.

v1.7.0 — turbulent RAS chosen by Rayleigh number, and its anchor gate settles where laminar cannot

Choose a tag to compare

@king-aj3 king-aj3 released this 23 Aug 23:31
  • The thermal dialogs now choose kOmegaSST above Ra 1e8 and name the model in every result. Both writers take turbulence="kOmegaSST" — the CHT writer with the v2512 tree's own compressible wall functions — and laminar cases are byte-identical when the switch is off (sha256-proven). §8a chooses on a flux/Churchill fixed point because Ra is an output of its flux boundary condition; §8c on its nominal Ra. Below Ra 1e8 nothing changes.
  • openfoam_ras_solid — the turbulent-regime anchor gate: a kOmegaSST sphere at resulting Ra 2.08e9 through the product's own writer and runner lands at Nu 107.65 vs Churchill 99.03 (+8.7 %) and settles (drift 3.4e-4); the laminar mutation reads −10.9 % and never settles — both deltas fit the correlation's ±15 % scatter, so the settle requirement is the stated discriminator. Proved end to end twice; the two runs agreed to every printed digit.
  • The Array Designer pattern overlay now sits ON the array: "Show in 3-D view" rebuilds the verified wires through the same constructor the solve used, so display cannot drift from solved, and centres the balloon on the array's own frame.
  • --all now exercises the FreeCAD halves of the battery: 11 gates route through freecadcmd when it is present, and 8 self-skippers that had printed vacuous "ok"s under python3 are honestly tiered.
  • Wind turbulence machinery is built but refused: its Re-21 400 anchor solve diverges at startup, and method_is_valid keeps refusing the path until a green gate exists — a validity claim may not precede its evidence.

90 automated validation gates in this repository. Full details in CHANGELOG.md.

v1.6.0 — CPU-vs-GPU agreement gated; kOmegaSST validated against a measured experiment

Choose a tag to compare

@king-aj3 king-aj3 released this 23 Aug 19:52
  • CPU-vs-GPU agreement is enforced, not remembered: palace_gpu_agreement solves the same cavity on CPU and GPU through the product on the same GPU-linked binary (probed by linkage, never names), proves which device actually ran from Palace's own banner, and requires every eigenmode to agree to 1e-6. Measured margins: /gpu/hip/shared agrees to 2.2e-9; the broken /gpu/hip/gen fails at 4.0e-2.
  • Turbulent natural convection validated against a measured experiment: the cavity writer takes turbulence="kOmegaSST" and openfoam_ras_cavity solves the Betts & Bokhari tall cavity (Ra 8.6e5) through EMStudio's own writer and runner against the digitised measured profiles that ship in the ESI v2512 tree — worst temperature profile 4.8 % of span, worst velocity 8.7 %. The laminar mutation at the same Ra never converges and reads 17.2 % / 50.6 %. Laminar cases are byte-identical with the switch off; the dialogs still run laminar and say so.
  • Prism boundary layers on both snappyHexMesh paths (wall_layers, default 3): every quoted reference re-measured on the layered mesh with the move stated in the CHANGELOG — the sphere anchor's Churchill agreement improved from +4.3 % to +2.9 %.
  • run_battery.py --all fixed (it had been dying mid-run on an unhandled requirement kind) — and its first complete run's findings fixed with it: ten FreeCAD-importing gates now route through freecadcmd, three CFD gates carry measured timeouts, and the wind gate asserts its validity note's content instead of a reworded literal.
  • README's Status line is now gated by the smoke test alongside the three source version strings.

89 automated validation gates in this repository. Full details in CHANGELOG.md.

v1.4.0 — results correctness, a material library, and ITU-R reachable

Choose a tag to compare

@king-aj3 king-aj3 released this 22 Aug 12:26

Read this first — results correctness

Four defects were found together and fixed. Every one of them made numbers optimistic. If you have quoted an EMStudio figure anywhere, check it against this list.

openEMS reported DIRECTIVITY as GAIN. The pattern column headed gain_dbi was built from openEMS's Dmax, and the results layer documented that column as gain. They are equal only for a lossless antenna, and EMStudio emits lossy dielectrics — so the figure overstated gain by the radiation efficiency.

Measured on the shipped 2.4 GHz patch template: directivity 6.6350 dBi, radiation efficiency 96.24 %, true gain 6.4686 dBi. The published number was 0.166 dB high. Gain is now D x eta, with eta = P_radiated / P_accepted — both were already produced by the run and nothing read them. Directivity, efficiency and the power budget are now reported alongside the pattern.

NEC2 silently discarded "Conductor" geometry. The wire builder skipped every material category that did not begin with "Metal", so choosing Conductor and entering a conductivity produced a deck with no wires from that material at all — not a lossless answer, an absent structure, reported as a result.

NEC2 reported 100.00 % efficiency for every antenna, because no LD card was ever emitted. Finite-conductivity materials now emit LD 5, so ohmic loss is real. This matters most where it is largest: small loops and short verticals can sit tens of dB below their lossless directivity.

openEMS discarded the conductivity you typed, folding Conductor into AddMetal (PEC). It now emits AddConductingSheet.

PEC-only models are unaffected. A perfect conductor emits no LD card and no conducting sheet, so decks are byte-identical and every previous PEC result stands. Confirmed by the dipole, monopole, LPDA and array gates passing unchanged.

All four are pinned by tests/validation/material_loss.py, which runs in the fast battery with no solver and no FreeCAD required.

Added

A named material library, 31 entries, in the spirit of CST/HFSS/FEKO — pick a material by name and its properties and category come with it. Copper, silver, gold, aluminium, brass, bronze, zinc, tin, solder, tungsten, titanium, nickel, mild steel, stainless 304, graphite, seawater; PTFE, PE, PS, RT/duroid 5880, RO4003C, FR-4, polycarbonate, ABS, nylon, glass, alumina. Conductors carry conductivity, temperature coefficient and relative permeability, with ferromagnetics flagged because a high mu_r collapses skin depth.

Perfect conductor (PEC) leads the list and remains the default for an unspecified material — an idealised lossless metal is a legitimate and often correct modelling choice, not a placeholder.

Library values are nominal at 20 C. FR-4 is a class of laminates rather than a material; for anything you will build, use the vendor's number and Custom.

ITU-R P.452-18 and P.2001-6 are reachable from the GUI for the first time. Both engines shipped validated — 595 and 4,430 official ITU validation cases replayed, worst basic-transmission-loss deviation 5.0e-09 dB and 1.2e-12 dB — but nothing in the product could call them. Point-to-Point Link Budget now offers both, with time percentage, terminal coordinates and a radio-zone picker that maps to each Recommendation's own (different) zone numbering.

Four new tutorials: LPDA over NEC2, LF/MF ground-wave coverage, P.452 and P.2001.

Fixed — macOS

A keg-only Homebrew library read as "provably missing", blocking guided source builds behind prerequisites already installed. _lib_present() globbed only <prefix>/lib; Homebrew keeps openblas and lapack keg-only under <prefix>/opt/<name>/lib. Verified on an arm64 host.

Verified

Pro battery 45/0, free battery 36/0, smoke under python and freecadcmd, offscreen gui_smoke, export drift 0.

EMStudio v1.3.0 — wave ports from your own selection, and a silent S-parameter bug fixed

Choose a tag to compare

@king-aj3 king-aj3 released this 21 Aug 14:21

Install or update through the FreeCAD Add-on Manager — it installs from master, so you may already have this.

What's new

N-port is reachable from the GUI. Select the faces you want as ports and use Analysis ▸ Wave Ports from Selection — port 1 is the first face you click, because only you know which physical connector that is. A live 3-port WR-90 T-junction now solves end to end: passivity 0.9996, losslessness 2.9985 against an ideal 3.0, and a genuine .s3p written with one matrix row per line.

Every capability has a tutorialdocs/TUTORIALS.md, 28 of them. Each ends in a checkable number and names the automated gate that pins it, and each quotes the range the gate allows rather than a single value, because your mesh will not reproduce ours exactly.

Solver Setup shows a version you can trust. ElmerSolver --version carries a run timestamp, so that column used to change every time you pressed Re-detect. Now gated.

Correctness fixes — read this part

openEMS silently accepted more than one excited port. Every port created through the GUI carries Excited=True, and the guard tested "any" while the S-parameter contract says exactly one. Adding a second port the obvious way produced a deck driving both, which openEMS accepts — and then s11 = uf_ref/uf_inc treats port 1 as the only source, so the incident wave is contaminated and the S-parameters are silently wrong. No exception, no warning, a plausible answer. Now refused, with the offending ports named. Shipped templates were never affected, and FullSMatrix was never affected.

The litz proximity fallback used the wrong asymptote. On a build without SciPy, _proximity_h returned 0.166 · x where the true large-x limit is (x−1)/833 % high even at x = 512, and 5.92× just above the x = 2 join. Proximity loss is the number litz wire exists to control. Corrected; x ≥ 4 is now within 1.6 %. If you have SciPy installed you were never affected.

Guided source builds were blocked on macOS. _lib_present() shelled out to ldconfig, which is glibc-only, and reported every library prerequisite missing on macOS — often ones Homebrew had already installed. A probe that cannot run now answers "present", because unprovable must not masquerade as proven-missing.

Also: shell quoting in the OpenFOAM command builder, and a SHA256 pin on the Windows OpenFOAM installer.

Verify it yourself

git clone https://github.com/king-aj3/EMStudioFree
python3 tests/validation/run_battery.py

82 validation gates in this tree. The fast tier needs only numpy and scipy — no solver install. --all adds the benchmark tier, which does need the solvers present. The tests and the reference data they check against are both in the repo, so you can read what they assert before running anything.

Known limits

Nothing radiating is gated above 2.435 GHz — the patch. Palace is gated to 39 and 57 GHz on closed structures (waveguide, cavity), and openEMS to 3.68 GHz on a microstrip notch filter, which is not a radiator. Treat higher-frequency antenna work as unproven here until there is a gate for it.