Integrate ImpedenceFinder closed-form Z0 into the project Impedance tab.

Use the vendored Hammerstad-Jensen/Cohn engine for microstrip, stripline, and coupled-diff advice. Skip OpenEMS/pcbnew and refuse CPWG rather than inventing a number.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-10 23:14:57 +02:00
co-authored by Cursor
parent 3e43bb6ecb
commit 6fc2ac583d
30 changed files with 2219 additions and 2 deletions
+75
View File
@@ -0,0 +1,75 @@
from __future__ import annotations
from impedancefinder import planes
from impedancefinder.model import Point2D, SamplePoint, ZonePolygon
from .conftest import rect
def _sample_at(x_mm: float, width_mm: float = 0.2) -> SamplePoint:
return SamplePoint(
net="SIG", layer="F.Cu", distance_along_net_mm=x_mm, position=Point2D(x_mm, 0), width_mm=width_mm
)
def test_full_coverage_has_no_flags(full_ground_plane):
sample = _sample_at(2.0)
coverage = planes.coverage_at(sample, (full_ground_plane,), "In1.Cu")
assert coverage.is_covered
assert planes._flags_for(coverage, sample.width_mm) == ()
def test_void_directly_under_trace_flags_broken(split_ground_plane):
sample = _sample_at(5.0) # inside the 4..6mm gap
coverage = planes.coverage_at(sample, (split_ground_plane,), "In1.Cu")
assert not coverage.is_covered
assert planes._flags_for(coverage, sample.width_mm) == ("plane_broken",)
def test_void_near_but_not_under_trace_flags_proximity_only(split_ground_plane):
sample = _sample_at(3.9, width_mm=0.5) # covered, close to the gap edge at x=4
coverage = planes.coverage_at(sample, (split_ground_plane,), "In1.Cu")
assert coverage.is_covered
assert planes._flags_for(coverage, sample.width_mm) == ("plane_split_nearby",)
def test_far_from_void_has_no_proximity_flag(split_ground_plane):
sample = _sample_at(0.0)
coverage = planes.coverage_at(sample, (split_ground_plane,), "In1.Cu")
assert coverage.is_covered
assert planes._flags_for(coverage, sample.width_mm) == ()
def test_missing_plane_layer_reports_uncovered_not_a_crash():
sample = _sample_at(0.0)
coverage = planes.coverage_at(sample, (), "In1.Cu")
assert not coverage.is_covered
assert coverage.distance_to_void_mm is None
def test_resolve_reference_planes_outer_layer_has_only_below(stackup_4layer, full_ground_plane):
sample = _sample_at(2.0)
context = planes.resolve_reference_planes(stackup_4layer, (full_ground_plane,), sample)
assert context.above is None
assert context.below is not None
assert context.reference_plane_count == 1
def test_resolve_reference_planes_inner_layer_has_both(stackup_4layer):
top_plane = ZonePolygon(net="GND", layer="F.Cu", outlines_mm=(rect(-5, -5, 50, 5),))
bottom_plane = ZonePolygon(net="GND", layer="In2.Cu", outlines_mm=(rect(-5, -5, 50, 5),))
sample = SamplePoint(
net="SIG", layer="In1.Cu", distance_along_net_mm=0, position=Point2D(0, 0), width_mm=0.15
)
context = planes.resolve_reference_planes(stackup_4layer, (top_plane, bottom_plane), sample)
assert context.above is not None and context.above.is_covered
assert context.below is not None and context.below.is_covered
assert context.reference_plane_count == 2
def test_exclude_net_ignores_the_traces_own_copper():
own_net_pour = ZonePolygon(net="SIG", layer="F.Cu", outlines_mm=(rect(-5, -5, 50, 5),))
sample = _sample_at(0.0)
coverage = planes.coverage_at(sample, (own_net_pour,), "F.Cu", exclude_net="SIG")
assert not coverage.is_covered
assert coverage.distance_to_void_mm is None