TraceMaker
C++ API of the engine
Loading...
Searching...
No Matches
impedance_rules.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2#pragma once
3// Impedance and current rules on a real board (design doc 15 §5.3-5.4, P4): the board stackup gives, per routing
4// layer, the line structure and the dielectric to the nearest reference layer; the closed forms of impedance.hpp
5// turn a rule's target (z0_ohm / zdiff_ohm) into a width and gap. Report-only: nothing here changes routing.
6//
7// Assumption (dev/assumptions-m13.md, P4): the copper layer adjacent to a routing layer is its reference plane.
8// Outer layers are microstrip over the next copper layer; inner layers are stripline between the copper layers
9// above and below. A zone on the reference layer is reported as confirmation; without one the report says the
10// plane is assumed. Boards without a stackup get nothing computed (doc 15 §3.6; CLAUDE.md rule 6).
11#include <optional>
12#include <string>
13#include <vector>
14
15#include <nlohmann/json.hpp>
16
17#include "crules/catalogue.hpp"
18#include "crules/impedance.hpp"
19#include "model/board.hpp"
20#include "model/rules.hpp"
21
22namespace tmk::crules {
23
24// One copper layer's line geometry from the stackup.
26 int copper = -1;
27 std::string layer;
28 bool routing = true; // false for KiCad "power" (plane) layers
29 imp::Structure structure = imp::Structure::Microstrip; // outer: microstrip; inner: stripline
30 int ref_a = -1, ref_b = -1; // reference copper layers (microstrip: ref_a only; stripline: above, below)
31 std::string ref_a_note, ref_b_note; // "zone GND" or "no zone: assumed plane"
32 Coord h1 = 0, h2 = 0; // dielectric to ref_a (microstrip) / to the planes above and below (stripline)
33 Coord t = 0; // copper thickness of this layer
34 double er = 0; // dielectric permittivity (stripline: series combination of both sides)
35 bool ok = false;
36 std::string why; // when !ok
37};
38std::vector<LayerGeometry> stackup_geometry(const model::Board& b);
39
40// The width (and gap) that meets one target on one layer.
42 std::string layer, ref; // "F.Cu", "In1.Cu (zone GND)"
44 bool differential = false;
45 double target = 0; // ohm
46 bool ok = false;
47 std::string why; // when !ok
48 Coord width = 0, gap = 0; // gap: pair gap (differential) or coplanar ground gap (GCPW); 0 otherwise
49 double z = 0; // achieved impedance at the integer-nm solution
50 double eps_eff = 0, ps_per_mm = 0; // differential: odd mode
51 double error_pct = 0; // stated formula error
52 Coord h = 0, h2 = 0; // dielectric to the reference (stripline: above, below)
53 double er = 0;
54 std::string note; // e.g. "gap raised: width at the board minimum"
55};
56
58 bool computed = false; // false: `why` says why (no stackup, no target, ...)
59 std::string why;
60 double z0 = 0, zdiff = 0, tol_pct = 0;
61 std::string structure; // rule parameter, "" = microstrip/stripline by layer
62 Coord min_width = 0, pair_gap = 0, coplanar_gap = 0; // the bounds used, and where they came from
63 std::string bounds_note;
64 std::vector<LineSolution> lines;
65};
66
67// Board bounds used for solving: the narrowest width and the pair / coplanar gap (see impedance_rules.cpp).
69std::string impedance_text(const ImpedancePlan& p);
70// Differential impedance of an existing width/gap on a copper layer (to compare a board net class with the target);
71// < 0 when the layer has no complete stackup geometry.
72double pair_impedance(const model::Board& b, int copper, Coord width, Coord gap);
73nlohmann::json impedance_json(const ImpedancePlan& p);
74
75// Width for a rule that names a current (doc 15 §5.4, IPC-2221).
77 bool computed = false;
78 std::string why;
79 double amps = 0, delta_t_c = 0;
80 Coord outer_copper = 0, inner_copper = 0; // inner 0: no inner layers
82 bool copper_assumed = false; // no stackup: 35 um (1 oz) assumed
83};
85std::string current_text(const CurrentPlan& p);
86nlohmann::json current_json(const CurrentPlan& p);
87
88// Propagation delay per copper layer used to turn ps skew budgets into mm (doc 15 §4): from the stackup (eps_eff
89// of a 50 ohm line on outer layers, er on inner layers) or the catalogue's FR-4 defaults.
90struct LayerDelay {
91 std::string layer;
92 double ps_per_mm = 0;
93 bool from_stackup = false;
94};
95std::vector<LayerDelay> prop_delays(const model::Board& b, const Catalogue& cat);
96// One line for the report header: the stackup summary and the delays, or why defaults are used.
97std::string stackup_summary(const model::Board& b, const Catalogue& cat);
98nlohmann::json stackup_json(const model::Board& b, const Catalogue& cat);
99
100} // namespace tmk::crules
The board model (design doc 02 §3): every object TraceMaker reads from a .kicad_pcb,...
Component-rule catalogue (design doc 15 §6.1): categories of components with their detectors,...
Closed-form transmission-line impedance for PCB traces (design doc 15 §5.3) and the IPC-2221 width fo...
nlohmann::json current_json(const CurrentPlan &p)
double pair_impedance(const model::Board &b, int copper, Coord width, Coord gap)
Differential impedance of an existing width/gap on a copper layer (to compare a board net class with ...
std::vector< LayerDelay > prop_delays(const model::Board &b, const Catalogue &cat)
nlohmann::json impedance_json(const ImpedancePlan &p)
CurrentPlan plan_current(const model::Board &b, const RuleSpec &r)
nlohmann::json stackup_json(const model::Board &b, const Catalogue &cat)
std::vector< LayerGeometry > stackup_geometry(const model::Board &b)
std::string stackup_summary(const model::Board &b, const Catalogue &cat)
One line for the report header: the stackup summary and the delays, or why defaults are used.
ImpedancePlan plan_impedance(const model::Board &b, const model::DesignRules *rules, const RuleSpec &r)
Board bounds used for solving: the narrowest width and the pair / coplanar gap (see impedance_rules....
std::string impedance_text(const ImpedancePlan &p)
std::string current_text(const CurrentPlan &p)
std::int64_t Coord
Engine coordinate: signed 64-bit nanometres.
Definition units.hpp:12
Design rules as KiCad defines them (design doc 08 §3–4): board minimums and net classes from the ....
Width for a rule that names a current (doc 15 §5.4, IPC-2221).
bool copper_assumed
no stackup: 35 um (1 oz) assumed
Coord inner_copper
inner 0: no inner layers
std::vector< LineSolution > lines
bool computed
false: why says why (no stackup, no target, ...)
std::string structure
rule parameter, "" = microstrip/stripline by layer
Coord coplanar_gap
the bounds used, and where they came from
Propagation delay per copper layer used to turn ps skew budgets into mm (doc 15 §4): from the stackup...
One copper layer's line geometry from the stackup.
Coord h2
dielectric to ref_a (microstrip) / to the planes above and below (stripline)
imp::Structure structure
outer: microstrip; inner: stripline
std::string ref_b_note
"zone GND" or "no zone: assumed plane"
Coord t
copper thickness of this layer
int ref_b
reference copper layers (microstrip: ref_a only; stripline: above, below)
bool routing
false for KiCad "power" (plane) layers
double er
dielectric permittivity (stripline: series combination of both sides)
The width (and gap) that meets one target on one layer.
double error_pct
stated formula error
Coord h2
dielectric to the reference (stripline: above, below)
std::string ref
"F.Cu", "In1.Cu (zone GND)"
Coord gap
gap: pair gap (differential) or coplanar ground gap (GCPW); 0 otherwise
double ps_per_mm
differential: odd mode
std::string note
e.g. "gap raised: width at the board minimum"
double z
achieved impedance at the integer-nm solution