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:
@@ -0,0 +1,75 @@
|
||||
"""Standalone impedance calculator (no PCB, no findings)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import asdict
|
||||
from typing import Literal
|
||||
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from pydantic import BaseModel
|
||||
|
||||
from backend.pinscopex.impedance import (
|
||||
GeometryError,
|
||||
TraceGeometry,
|
||||
coupled_diff_z,
|
||||
cpw_z0,
|
||||
export_kicad_dru,
|
||||
microstrip_z0,
|
||||
solve_width,
|
||||
stackup_targets,
|
||||
stripline_z0,
|
||||
)
|
||||
|
||||
router = APIRouter(tags=["impedance"])
|
||||
|
||||
|
||||
class ImpedanceRequest(BaseModel):
|
||||
mode: Literal["trace", "stackup"] = "trace"
|
||||
kind: Literal["microstrip", "stripline", "cpw", "diff"] | None = None
|
||||
h: float
|
||||
er: float
|
||||
t: float = 0.035
|
||||
w: float | None = None
|
||||
s: float | None = None
|
||||
target_z: float | None = None
|
||||
|
||||
|
||||
def _z_for_kind(kind: str, geo: TraceGeometry) -> dict:
|
||||
if kind == "microstrip":
|
||||
return {"z0": microstrip_z0(geo), "w_mm": geo.w, "s_mm": geo.s, "kind": kind}
|
||||
if kind == "stripline":
|
||||
return {"z0": stripline_z0(geo), "w_mm": geo.w, "s_mm": geo.s, "kind": kind}
|
||||
if kind == "cpw":
|
||||
return {"z0": cpw_z0(geo), "w_mm": geo.w, "s_mm": geo.s, "kind": kind}
|
||||
if kind == "diff":
|
||||
zodd, zeven, zdiff = coupled_diff_z(geo)
|
||||
return {
|
||||
"z0": None,
|
||||
"zodd": zodd,
|
||||
"zeven": zeven,
|
||||
"zdiff": zdiff,
|
||||
"w_mm": geo.w,
|
||||
"s_mm": geo.s,
|
||||
"kind": kind,
|
||||
}
|
||||
raise GeometryError(f"unknown kind {kind}")
|
||||
|
||||
|
||||
@router.post("/impedance")
|
||||
def compute_impedance(body: ImpedanceRequest):
|
||||
try:
|
||||
if body.mode == "stackup":
|
||||
s = body.s if body.s is not None else 0.2
|
||||
targets = stackup_targets(h=body.h, er=body.er, t=body.t, s=s)
|
||||
return {
|
||||
"targets": {k: asdict(v) for k, v in targets.items()},
|
||||
"kicad_dru": export_kicad_dru(targets),
|
||||
}
|
||||
kind = body.kind or "microstrip"
|
||||
w = body.w
|
||||
if body.target_z is not None:
|
||||
w = solve_width(kind, body.target_z, body.h, body.er, body.t, s=body.s)
|
||||
geo = TraceGeometry(h=body.h, er=body.er, t=body.t, w=w, s=body.s)
|
||||
return _z_for_kind(kind, geo)
|
||||
except GeometryError as exc:
|
||||
raise HTTPException(400, str(exc)) from exc
|
||||
Reference in New Issue
Block a user