Resources Numerical accuracy Calculation policy

Magnetics add-on: template shapes and hand formulas

Builds ready-made magnet study cross-sections and the textbook value each result is compared with.

How the precision is kept

Each hand value is one closed-form 64-bit expression from the template's sizes in mm (converted with × 1e-3) and the study's currents and permeabilities. μ0 is written as 4π × 10⁻⁷. The formulas are idealizations, and the file stores an acceptance tolerance with each.

Calculations under this policy

7 calculations in 1 source file. The code is read from the released app when this page loads. It is the calculation people run, not a copy kept for this page.

addons/magnetics/lib/templates.js PartCraft 0.8.1 64-bit 7 calculations Reviewed

Tests tools/addons-test/browser-magnetics.mjs

Permeability of free space

64-bit

The constant μ0 used in every hand formula.

μ0 = 4 × 10⁻⁷ × π

4e-7 × Math.PI in 64-bit. This is the pre-2019 defined value; the measured value differs at about the tenth significant digit, far inside the templates' tolerances.

  • addons/magnetics/lib/templates.js
  • lines 2 to 19
  • PartCraft 0.8.1
/**
 * templates.js — ready-made magnet studies (the Magnetics add-on, 0.8 SG.7+; DOM-free). Each one is the cross-section of a long device, in mm,
 * as closed polygons with a role per polygon (air, iron, magnet, coil: the shapes of PartCraft's magnet-study.js), so a study can be set up and
 * solved without drawing sketches first. Five of them, three with a hand formula the result is compared against:
 *
 *   ccore   C-core electromagnet: an iron C with an air gap, a coil round its back leg (go and return)        hand: μ0·NI / (g + l/μr) in the gap
 *   frame   a permanent magnet in one leg of a closed iron frame                                             hand: Br·(lm/μrm) / (lm/μrm + L/μr)
 *   keeper  a holding magnet: U yoke with a magnet in its base, a keeper across the poles over a small gap   (no hand formula; force through a thin gap is rough)
 *   wire    one round conductor in air                                                                      hand: B = μ0·I / 2πr at r = 2a
 *   wires   two parallel conductors with opposite currents                                                  hand: F = μ0·I² / 2πd per metre
 *
 *   TEMPLATES                 { id → { params: [{ key, def, min, max }], pad? (the air box margin it wants), build(p) → { loops, specs, names }, hand?(p, specs) → { kind, … } } }
 *   build(id, params)         → { loops: [[[x, y] …] …] (mm), specs: [spec], names: [language key], hand: … | null, params (clamped) }
 *   circle(cx, cy, r, n)      → a polygon with n corners (counter-clockwise)
 * A spec is magnet-study.js's: { role, mur, curve, br, angle, murMag, current (total A through the profile), force }.
 * Every material number here is an example (iron μr 1000–2000, magnet Br 1.2 T, μr 1.05), not a data sheet.
 */
export const MU0 = 4e-7 * Math.PI;

Round conductor as a polygon

64-bit

The corners of the polygon that stands for a round wire.

pᵢ = (cx + r cos(2πi ÷ n), cy + r sin(2πi ÷ n)), n = 48

Corners lie on the circle, so the polygon's area is slightly less than the circle's. Angles are 2π × i ÷ n with Math.cos and Math.sin.

  • addons/magnetics/lib/templates.js
  • line 23
  • PartCraft 0.8.1
export const circle = (cx, cy, r, n = 48) => Array.from({ length: n }, (_, i) => [cx + r * Math.cos(2 * Math.PI * i / n), cy + r * Math.sin(2 * Math.PI * i / n)]);

C-core gap field

64-bit

The flux density in the air gap of a C-core electromagnet by the magnetic circuit formula.

B = μ0 × NI ÷ ((g + l ÷ μr) × 10⁻³), l = 2(w − tk) + 2(h − tk) − g

Sizes are in mm; the path length g + l ÷ μr is multiplied by 1e-3 once. NI and μr are read with Number(); a missing μr becomes 1.

  • addons/magnetics/lib/templates.js
  • lines 40 to 41
  • PartCraft 0.8.1
const { w, h, tk } = p, g = Math.min(p.gap, h - 2 * tk - 2), l = 2 * (w - tk) + 2 * (h - tk) - g, NI = Math.abs(Number(specs[1]?.current) || 0), mur = Number(specs[0]?.mur) || 1;
return { kind: 'meanB', box: [w - tk, h / 2 - g / 2, w, h / 2 + g / 2], value: MU0 * NI / ((g + l / mur) * 1e-3), what: 'hand.ccore', tol: 0.15 };

Magnet in a closed iron frame

64-bit

The flux density in a permanent magnet set in one leg of a closed frame.

B = Br × (lm ÷ μrm) ÷ (lm ÷ μrm + L ÷ μr), L = 2(w − tk) + 2(h − tk) − lm

Lengths appear in a ratio, so no unit factor is needed. A missing magnet or iron permeability becomes 1.

  • addons/magnetics/lib/templates.js
  • lines 56 to 57
  • PartCraft 0.8.1
const { w, h, tk } = p, lm = h - 2 * tk, L = 2 * (w - tk) + 2 * (h - tk) - lm, Br = Number(specs[2]?.br) || 0, murm = Number(specs[2]?.murMag) || 1, mur = Number(specs[0]?.mur) || 1;
return { kind: 'meanB', region: 3, value: Br * (lm / murm) / (lm / murm + L / mur), what: 'hand.frame', tol: 0.02 };

Field round one wire

64-bit

The flux density at two radii from the center of a round conductor.

B = μ0 × I ÷ (2π × r × 10⁻³), r = 2a

r is twice the wire radius in mm, converted with × 1e-3 inside the denominator. The result is compared over a ring from 1.8 to 2.2 radii.

  • addons/magnetics/lib/templates.js
  • lines 76 to 77
  • PartCraft 0.8.1
const I = Math.abs(Number(specs[0]?.current) || 0), r = 2 * p.r;
return { kind: 'ringB', at: [0, 0], r0: 1.8 * p.r, r1: 2.2 * p.r, r, value: MU0 * I / (2 * Math.PI * r * 1e-3), what: 'hand.wire', tol: 0.02 };

Force between two wires

64-bit

The force per meter between two parallel conductors.

F = μ0 × |I₁ × I₂| ÷ (2π × d × 10⁻³)

The absolute value of the product of the two currents is used; d is in mm, converted with × 1e-3.

  • addons/magnetics/lib/templates.js
  • lines 93 to 94
  • PartCraft 0.8.1
const I1 = Number(specs[0]?.current) || 0, I2 = Number(specs[1]?.current) || 0;
return { kind: 'force', body: 1, value: MU0 * Math.abs(I1 * I2) / (2 * Math.PI * p.d * 1e-3), what: 'hand.wires', tol: 0.06, perMetre: true };

Template sizes within their ranges

64-bit

Clamps each size a person types to the template's allowed range.

Each size is clamped to its range; a value that is not a finite number falls back to the default. The wall thickness is limited to (min(w, h) − 6) ÷ 2.

  • addons/magnetics/lib/templates.js
  • lines 100 to 106
  • PartCraft 0.8.1
export function cleanParams(id, params = {}) {
  const T = TEMPLATES[id];
  const out = {};
  for (const q of T.params) { const v = Number(params[q.key]); out[q.key] = Number.isFinite(v) ? Math.min(q.max, Math.max(q.min, v)) : q.def; }
  if (id === 'ccore' || id === 'frame' || id === 'keeper') { out.tk = Math.min(out.tk, (Math.min(out.w, out.h) - 6) / 2); }
  return out;
}

In detail

Method
C-core: B = μ0·NI ÷ (g + l ÷ μr). Frame: B = Br·(lm ÷ μrm) ÷ (lm ÷ μrm + L ÷ μr), for which the file cites P. Campbell, Permanent Magnet Materials and their Application (1994). Wire: B = μ0·I ÷ (2πr). Two wires: F = μ0·I₁I₂ ÷ (2πd) per meter.
Number types
64-bit numbers.
Tolerances
Acceptance tolerances stored with the formulas: 15 % (C-core), 2 % (frame), 2 % (wire), 6 % (two wires).
Limits
μ0 = 4π × 10⁻⁷ is the value that was fixed by definition before the 2019 SI revision; the measured value recommended since differs from it at about the tenth significant digit. The C-core comment says the formula has no fringing and no leakage.

Approach: 64-bit, direct

Every value is a 64-bit number from input to result. Formulas are closed form or a direct solve, and every comparison uses a stated tolerance.

Every policy that takes this approach