TraceMaker
C++ API of the engine
Loading...
Searching...
No Matches
return_path.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2#pragma once
3// Reference-return audit of high-speed nets (issue #7, docs/05-routing.md §42, D114).
4//
5// KiCad's DRC cannot tell whether a fast trace has continuous copper under it. A dogbone escape punches antipads through the reference
6// pour, a plane can be split, a layer change can come without a nearby stitch: the signal is DRC-clean and its return current still
7// walks around the void, which grows the loop area and the inductance. This pass answers a geometric question per net: does the trace
8// have copper under it on the adjacent reference layer, and where it does not, how far does the return detour?
9//
10// It is read-only (it adds nothing to the board) and it is a geometric model, not a field solver: the return of a signal over copper
11// is taken to be its mirror image on the reference layer, across a void it is the shortest path that stays on the remaining reference
12// copper (Dijkstra over the visibility graph of the reference polygon's vertices; Lee and Preparata 1984), and at a layer change it
13// closes through the nearest stitching via of the reference net, or the nearest capacitor between the two reference nets, within a
14// radius. The return does not close through "one assumed GND ball": at a footprint the nearest pad of the reference net is the
15// assumed return pad (the comment on the issue).
16#include <string>
17#include <utility>
18#include <vector>
19
20#include <nlohmann/json.hpp>
21
22#include "geom/point.hpp"
23#include "model/board.hpp"
24#include "model/rules.hpp"
25
26namespace tmk::analysis {
27
29 // Which nets: a signal is analysed if it matches any selector (default: none, the pass is off). Name patterns are KiCad wildcards.
30 std::vector<std::string> name_patterns;
31 std::vector<std::string> net_classes;
32 std::vector<std::pair<model::NetId, model::NetId>> pair_nets; // differential pairs, resolved by the caller (route::named_pairs)
33 bool diff_pairs = false; // analyse the halves of `pair_nets`
34 // "PATTERN=LAYER": the reference layer of the nets that match, instead of the adjacent layer with the most copper under the trace.
35 std::vector<std::pair<std::string, std::string>> reference_layers;
36 double stitch_radius_mm = 5.0; // how far a stitching via or a capacitor may be from a layer change
37 double sample_mm = 0.05; // spacing of the samples along a trace
38 double min_void_mm = 0.1; // a stretch without copper shorter than this is a sampling artefact, not a void
39 double warn_detour_mm = 2.0; // thresholds: warnings, not DRC errors
40 double warn_separation_mm = 1.0;
41 bool refill = true; // zones without fills are refilled first (the engine's refill, not KiCad's)
42 bool refill_always = false; // refill every zone: the fills in the file predate copper that was just routed
43};
44
45struct ReturnVoid {
46 int layer = 0; // signal layer (copper index)
47 geom::Point entry, exit; // where the trace leaves and regains copper under it
48 double signal_mm = 0; // the trace between them
49 double return_mm = 0; // the return path between them (the shortest path on the reference copper)
50 double detour_mm = 0; // return - signal, at least 0
51 double max_separation_mm = 0; // the farthest the return gets from the trace
53 bool no_path = false; // the reference copper does not connect the two ends (a split plane): no return on this layer
54 std::vector<geom::Point> path; // the return path, entry to exit
55};
56
58 geom::Point at; // the signal via
59 int from_layer = 0, to_layer = 0;
60 std::string ref_from, ref_to; // reference net names ("" = no reference copper under the via)
61 std::string closure; // "stitch via", "capacitor", "none", "no reference"
62 double distance_mm = -1; // to the closure
64 bool missing = false;
65};
66
67struct ReturnEnd { // a trace end at a pad: the assumed return pad
69 std::string pad; // "REF.NUM"
70 std::string ref_pad; // nearest pad of the reference net, "" = none within the radius
71 double distance_mm = -1;
73};
74
75struct NetReturn {
77 std::string name;
78 std::vector<int> layers; // signal layers
79 std::vector<int> reference_layers; // the reference layer of each signal layer, same order (-1 = none)
80 double signal_mm = 0;
81 double detour_mm = 0; // summed over the voids
83 int void_count = 0;
84 int split_count = 0; // voids with no return path
86 double uncovered_mm = 0; // trace length with no reference layer at all
87 std::vector<ReturnVoid> voids;
88 std::vector<ReturnLayerChange> changes;
89 std::vector<ReturnEnd> ends;
90 // For the viewer: the signal as polylines per layer, and the return along it (mirror over copper, the detour across a void).
91 std::vector<std::pair<int, std::vector<geom::Point>>> signal;
92 std::vector<std::pair<int, std::vector<geom::Point>>> ret;
93 std::vector<std::string> warnings;
94};
95
97 std::vector<NetReturn> nets;
98 std::vector<std::string> notes; // what the run could not do (arcs skipped, zones refilled, a net without a reference ...)
100};
101
102// Analyses the nets the options select on `b` as it stands (routed copper included). Deterministic.
104
105// The report as JSON (nanometres converted to millimetres), and one `return_path` viewer message per net (docs/13-viewer-protocol.md).
106nlohmann::json return_path_json(const model::Board& b, const ReturnPathReport& r);
107std::string return_path_message(const model::Board& b, const NetReturn& n);
108// A one-line text form per net and the lines under it that explain a warning.
109std::vector<std::string> return_path_lines(const model::Board& b, const ReturnPathReport& r);
110
111} // namespace tmk::analysis
The board model (design doc 02 §3): every object TraceMaker reads from a .kicad_pcb,...
std::string return_path_message(const model::Board &b, const NetReturn &n)
nlohmann::json return_path_json(const model::Board &b, const ReturnPathReport &r)
The report as JSON (nanometres converted to millimetres), and one return_path viewer message per net ...
ReturnPathReport analyse_return_paths(const model::Board &b, const model::DesignRules &rules, const ReturnPathOptions &opt)
Analyses the nets the options select on b as it stands (routed copper included). Deterministic.
std::vector< std::string > return_path_lines(const model::Board &b, const ReturnPathReport &r)
A one-line text form per net and the lines under it that explain a warning.
std::int32_t NetId
0 = no net
Definition board.hpp:21
Integer-nanometre points and KiCad-compatible rotation.
Design rules as KiCad defines them (design doc 08 §3–4): board minimums and net classes from the ....
std::vector< int > layers
signal layers
int split_count
voids with no return path
double detour_mm
summed over the voids
std::vector< ReturnLayerChange > changes
std::vector< std::pair< int, std::vector< geom::Point > > > ret
std::vector< ReturnEnd > ends
std::vector< std::pair< int, std::vector< geom::Point > > > signal
For the viewer: the signal as polylines per layer, and the return along it (mirror over copper,...
std::vector< int > reference_layers
the reference layer of each signal layer, same order (-1 = none)
std::vector< ReturnVoid > voids
std::vector< std::string > warnings
double uncovered_mm
trace length with no reference layer at all
geom::Point at
< a trace end at a pad: the assumed return pad
std::string ref_pad
nearest pad of the reference net, "" = none within the radius
std::string pad
"REF.NUM"
geom::Point at
the signal via
std::string ref_to
reference net names ("" = no reference copper under the via)
std::string closure
"stitch via", "capacitor", "none", "no reference"
double distance_mm
to the closure
double min_void_mm
a stretch without copper shorter than this is a sampling artefact, not a void
double warn_detour_mm
thresholds: warnings, not DRC errors
bool refill_always
refill every zone: the fills in the file predate copper that was just routed
double sample_mm
spacing of the samples along a trace
std::vector< std::string > name_patterns
Which nets: a signal is analysed if it matches any selector (default: none, the pass is off)....
double stitch_radius_mm
how far a stitching via or a capacitor may be from a layer change
std::vector< std::string > net_classes
std::vector< std::pair< model::NetId, model::NetId > > pair_nets
differential pairs, resolved by the caller (route::named_pairs)
bool refill
zones without fills are refilled first (the engine's refill, not KiCad's)
std::vector< std::pair< std::string, std::string > > reference_layers
"PATTERN=LAYER": the reference layer of the nets that match, instead of the adjacent layer with the m...
bool diff_pairs
analyse the halves of pair_nets
std::vector< std::string > notes
what the run could not do (arcs skipped, zones refilled, a net without a reference ....
std::vector< NetReturn > nets
double return_mm
the return path between them (the shortest path on the reference copper)
geom::Point farthest
where
std::vector< geom::Point > path
the return path, entry to exit
int layer
signal layer (copper index)
double detour_mm
return - signal, at least 0
bool no_path
the reference copper does not connect the two ends (a split plane): no return on this layer
double signal_mm
the trace between them
double max_separation_mm
the farthest the return gets from the trace
geom::Point exit
where the trace leaves and regains copper under it