Impedance targets before routing: profile table from the stackup, targetOhms per net, router sizes width and gap, Signals verifies

Drew Owens · ·closed by Colby Knox

What Quilter has

Impedance profiles per layer from the stackup (Apr 7 2026, Simbeor field solver), editable per-net targets (May 1) and any differential target (Jun 30). Their router sizes trace width and pair gap from the profile before routing.

What AI Flow has today

The SKILL.md says a board with differential pairs, impedance control or length matching is beyond the grid router, so the AI routes those nets by hand. Fields 0.4+ Signals gives a conservative microstrip estimate of a landed pair, refused on vias, arcs or layer changes, so the check exists only after the copper is down. This is the one Quilter feature that does something the flow cannot do at all today.

Proposal

  1. A profile table per layer from the spec's stackupMm and epsilonR: width to Z0 (single-ended) and width plus gap to Zdiff, using the closed-form microstrip and stripline formulas KiCad's calculator uses. Fields already holds the stackup, so the table can be a Fields output the flow reads, or a small crate in aiflow-router.
  2. Spec: targetOhms (and targetDiffOhms, tolerancePercent) on a net or pair.
  3. route picks width and gap for those nets from the table, keeps the pair coupled, and refuses a layer it cannot hit the target on.
  4. analyze runs the Fields Signals check on the landed copper and the gate fails when it is outside tolerance.

Closed forms are within a few percent on 2 to 4 layer FR4, enough for USB, CAN and Ethernet on Adom boards. No commercial solver; if a true field solve is ever needed, openEMS or a 2D FEM is the open route.

Done when

A USB pair on a real board routes to 90 ohms differential by the binary alone and the Signals check agrees within the tolerance the spec set.

Source: the Quilter assessment on the private page https://wiki.adom.inc/drew2/quilter-assessment (Oct 15 2026; Quilter facts are from their public changelog, https://www.quilter.ai/changelog). Filed by Drew's AI agent on Drew's behalf.

4 Replies

John Lauer ·

Thanks, Drew. This one is the largest of the four (an impedance table, router sizing of width and gap, and a Signals gate), so it gets its own release rather than riding in this batch. #53 and #54 shipped in 0.2.3. Leaving this open.

John Lauer ·

Most of this is in adom-aiflow 0.2.25. Leaving it open for the last part of your "done when": a run on a real board.

What shipped:

  1. Table per layer from the stackup (impedance table): width to Z0, and width plus gap to Zdiff.
    • Formulas: Hammerstad-Jensen microstrip, Wheeler stripline, offset stripline, Cohn coupled stripline, Garg-Bahl coupled microstrip.
    • Checked against an independent 2-D field solve. The error is under 0.3% on typical microstrip and pairs, and up to 3.4% on offset stripline (the table is in docs/impedance.md).
    • It refuses, and says why, for a layer under the fab's width or gap minimum, a target out of reach, or geometry where the formula's error grows (coupled microstrip with s/h under 0.2, offset stripline past 3:1).
    • It never guesses a missing stackup value; it names the key to add.
  2. Spec: impedanceTargets takes net + targetOhms or pair + targetDiffOhms, and tolerancePercent, plus optional layer, gapMm, widthMm, maxSkewMm and maxUncontrolledMm. It isn't called impedance, because adom-fields uses that key and refuses anything but numbers there. Fields' own map is read too.
  3. route sizes those nets from the table on one outer layer, with no vias.
    • The second net of a pair follows the first at the solved pitch.
    • It refuses before routing when no layer can reach the target.
    • After routing it prints each net's width, gap, impedance, coupled percentage and skew, with a WARNING when the pair was split.
  4. analyze impedance judges the landed copper sample by sample, and finish requires it to pass. With a same-input Fields report, it also compares against Signals and the 2-D cross-section solve. A Fields value outside tolerance fails the target.

Measured on a 4-layer JLC 7628 test board, 90 ohm differential:

  • A straight pair: 100% coupled, 90.0 ohm closed form; Fields Signals gave 86.4 (within target), the 2-D solve 85.2.
  • With a 5 mm jog: 92 to 96% coupled, skew up to 0.26 mm. Fields Signals refuses to estimate bends and fan-outs, so only the 2-D solve agrees there.

Not done:

  • No real board with a USB pair has gone through it yet. That's the run that closes this; a board of yours with USB would be ideal.
  • The router doesn't length-tune.
  • Pairs that cross, lane groups and layer changes stay with the AI (impedance table gives the widths and gaps for that work).

Upgrade: tell your AI "give me the latest adom-aiflow" (or adom-wiki pkg install adom/adom-aiflow); adom-aiflow --version says 0.2.25.

Colby Knox mentioned this in pull request #90 ·
Colby Knox ·

Drew, the "run on a real board" from your done-when found something. On StickHub (a USB hub, eight USB 2 pairs, 2 layers, 1.6 mm), 90 ohm differential solves to 1.38 mm wide traces on either outer layer, but the hub chip's pins are 0.30 mm. The grid router couldn't enter them at that width and landed no copper on any of the eight pairs.

In AI Flow 0.2.71, impedance table now says so for each target: it names the narrowest pin the solved width can't enter and what would work:

  • neck down to the pin within maxUncontrolledMm at each end, by routing the pair yourself;
  • a thinner dielectric under the outer layer (a 4-layer stackup);
  • a coplanar ground beside the pair.

route gives the same reason when a pair ends up with no copper.

Still open here: the grid router can't yet neck down at the pins itself or length-tune, and the formulas don't model a coplanar ground, which is what makes 90 ohm practical on a 2-layer board. I'm keeping this open for those.

Upgrade with adom-wiki pkg install adom/adom-aiflow; adom-aiflow --version then shows 0.2.71.

Colby Knox marked this in progress ·
Colby Knox mentioned this in pull request #92 ·
Colby Knox ·

Drew, the three things the StickHub run asked for are in AI Flow 0.2.73.

  • Neck-down at the pins. A target whose pins are narrower than its width is also routed at the rule width (a pair at its solved pitch), then widened back to the target wherever the router's clearance check passes. Only the necks at the pins stay narrow, and they count as uncontrolled length against maxUncontrolledMm. Raise that for a fine-pitch fan-out: the necks there run about 4 to 8 mm.
  • Length tuning. A pair whose nets differ by more than maxSkewMm gets 45° bumps on the shorter net, on the side away from its partner and only where they clear.
  • Grounded coplanar lines. Set coplanarGapMm on a target, or "coplanarGround": {"net": "GND", "gapMm": g} in the spec. These are conductor-backed coplanar formulas for a single line and a pair, within 0.6 to 4.1 % of a 2-D field solve over 200 cross-sections. A row outside the validated range is refused, never extrapolated. impedance table suggests the coplanar width when a microstrip width misses the pins. analyze impedance measures the ground pour beside the line once it's filled, and says when it's only assumed.

On StickHub's stackup (1.51 mm, er 4.5), 90 ohm differential with a GND pour beside the pair comes out at:

  • Pour 0.2 mm away, the grid router's pitch: width 0.85 mm, gap 0.35 mm.
  • Pour 0.15 mm away, routed by hand: width 0.38 mm, gap 0.15 mm, which fits the hub's 0.3 mm pins.

A fine-pitch test pair (0.3 mm pins, 30 mm apart, 2 layers, 1.6 mm, 90 ohm), which got no copper before, now:

  • routes;
  • has 0.99 mm of skew tuned to 0 with one bump;
  • passes the check at 90.0 ohm, 76 % coupled.

Limits:

  • The pours stage doesn't set its zone clearance to the coplanar gap yet; set the pour's clearance by hand.
  • Tuning matches the two nets of one pair, not a group of lanes.
  • StickHub itself still doesn't route end to end, because the grid router can't reach that hub chip's pins for any net. That isn't specific to impedance.

I'm closing this. Reopen it with a board that shows a gap.

Upgrade with adom-wiki pkg install adom/adom-aiflow; adom-aiflow --version then shows 0.2.73.

Colby Knox closed this ·

Log in to reply.