Code Monkey home page Code Monkey logo

kicad-parasitics's Introduction

KiCad-Parasitics

... Documentation is still being created

Plugin to analyze the wires in the PCB editor. To use the plugin, two points must be marked on the board. This is best two pads that are connected with a wire. The tool then determines the DC resistance between the two points. A parasitic inductance wired also estimated. In future versions, the parasitic capacitance to the ground plane will be determined.

Example

First install Kicad-Parasitic from the Kicad "Plugin and Content Manager", then:

  • open Kicad
  • go to File -> Open Demo Project ...
  • select Stickhub folder
  • select StickHub.kicad_pro grafik
  • open StickHub.kicad_pcb
  • zoom in to the front layer, close to the USB connector
  • select the two D- vias
  • press on the "parasitic" icon
  • grafik

Tested until now

Operating systems

  • Windows
  • Linux
  • Mac

KiCad versions

  • KiCad 6 (will also not work in the future)
  • KiCad 7.0.8 (up to commit cd378574)
  • KiCad 7.99.0-unknow (up to commit 099e5dd9)

kicad-parasitics's People

Contributors

nopeppermint avatar steffen-w avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

kicad-parasitics's Issues

"You have to mark exactly two elements..."

Everything was working fine in the past, but for some reason I know always get the message "You have to mark exactly two elements..." even tough those two elements are already selected. Any idea what might be the cause? I have not changed anything

Fatal Error with little description

Hi there, I recently installed your plugin as I thought it would be nice to be able to calculate/view properties of my tracks on the PCB I'm currently working on. Today I wanted to try parasitics, but didn't get it to work. I have attached an image below that shows the error.

Some additional information:

  • My laptop runs Windows 11
  • I use KiCAD 7.0.10 (previously 7.0.5, I updated but that didn't make the plugin work)
  • I installed the latest version of this plugin inside the plugin manager of KiCAD.
  • My PCB Stackup in KiCAD is custom so it fits the one I use from JLCPCB.
  • My PCB design is unfinished and not all nets are connected.

Don't stress with finding a solution. I just thought I could report the error and help you out with development by reporting the bug.
If you tell me what to do I can help you debug for a solution or provide further information.

grafik

ERROR in Resistance Network calculation (ngspice)

Dear maintainer,

when calculating a connection, the results are displayed (--> Resistance (only short path) = xx.xxx mOhm) but followed by an error message, indicating that no ngspice installation could be found. As you can see below, ngspice is configured and available.

parasitic version: 2023.10.11 22 kB 67 kB ✔ stable

Application: KiCad PCB Editor x64 on x64

Version: 7.0.1, release build

Libraries:
wxWidgets 3.2.2
FreeType 2.12.1
HarfBuzz 5.0.1
FontConfig 2.14.1
libcurl/7.83.1-DEV Schannel zlib/1.2.13

Platform: Windows 10 (build 19044), 64-bit edition, 64 bit, Little endian, wxMSW

Build Info:
Date: Mar 11 2023 03:41:46
wxWidgets: 3.2.2 (wchar_t,wx containers)
Boost: 1.80.0
OCC: 7.6.2
Curl: 7.83.1-DEV
ngspice: 39
Compiler: Visual C++ 1934 without C++ ABI

Build settings:
KICAD_SPICE=ON

Any suggestions?
Is the error message the error itself as ngspice is working?

Regards,

Bassude

Intercompatibility with kicad 8

          Hi @Steffen-W ,

I am having same error, but I thought it was because I'm using the version 8 release 3. I did not have any issues when using version 7.10. Just this file is having the issue. Here is the error I'm getting...

Screenshot 2024-02-23 162721

Any help solving the issue would be greatly appreciated as I use this tool often.

Thanks,
Josh

Originally posted by @Joshc17m in #8 (comment)

Selection bug

Hello. Thanks for making this plugin! I had to tweak it a bit to get it running on my system but after I got it running I was really happy with it.

I was getting an error initially that said I had to select 2 items (pads or vias). Even when I had two selected. I tracked it down to GetItems not returning anything.

My system:

Windows 11

Kicad info

Application: KiCad x64 on x64

Version: 7.0.8, release build

Libraries:
wxWidgets 3.2.2
FreeType 2.12.1
HarfBuzz 6.0.0
FontConfig 2.14.1
libcurl/7.88.1-DEV Schannel zlib/1.2.13

Platform: Windows 11 (build 22621), 64-bit edition, 64 bit, Little endian, wxMSW

Build Info:
Date: Sep 29 2023 18:44:47
wxWidgets: 3.2.2 (wchar_t,wx containers)
Boost: 1.81.0
OCC: 7.7.1
Curl: 7.88.1-DEV
ngspice: 41
Compiler: Visual C++ 1936 without C++ ABI

Build settings:
KICAD_SPICE=ON

Mods I made:

I only changed Get_PCB_Elements.py

import numpy as np
import pcbnew


ToMM = pcbnew.ToMM


def SaveDictToFile(dict_name, filename):
    with open(filename, "w") as f:
        f.write("data = {\n")
        for uuid, d in list(dict_name.items()):
            f.write(str(uuid))
            f.write(":")
            f.write(str(d))
            f.write(",\n")
        f.write("}")


# Überprüfe, ob der Punkt sich innerhalb des Polygons befindet
def IsPointInPolygon(point_, polygon_):
    point = np.array(point_)
    polygon = np.array(polygon_)

    n = len(polygon)
    inside = False

    p1x, p1y = polygon[0]
    for i in range(n + 1):
        p2x, p2y = polygon[i % n]
        if point[1] > min(p1y, p2y):
            if point[1] <= max(p1y, p2y):
                if point[0] <= max(p1x, p2x):
                    if p1y != p2y:
                        x_intersect = (point[1] - p1y) * (p2x - p1x) / (p2y - p1y) + p1x
                    if p1x == p2x or point[0] <= x_intersect:
                        inside = not inside
        p1x, p1y = p2x, p2y

    return inside


# def getMember(obj, small=True):
#     import inspect
#     from pprint import pprint

#     members = inspect.getmembers(obj, predicate=inspect.ismethod)
#     if small:
#         for m in members:
#             print(m[0])
#     else:
#         pprint(members)


def getHash(obj):
    return obj.m_Uuid.Hash()


def getHashList(objlist):
    return [getHash(obj) for obj in objlist]


def getPolygon(obj):
    poly_obj = obj.GetEffectivePolygon()
    Polygon = [tuple(map(ToMM, poly_obj.CVertex(p))) for p in range(poly_obj.FullPointCount())]
    return Polygon


def getLayer(obj, PossibleLayer=set([0, 31])):
    return sorted(set(obj.GetLayerSet().CuStack()) & PossibleLayer)


def getConnections(track, connect):
    def getVectorLen(vector):
        return np.sqrt(vector.dot(vector))

    def getDistance(point1, point2):
        return getVectorLen(np.array(point2) - np.array(point1))

    def MoveToObjCenter(wirePos, width, objPos):
        objPos = np.array(objPos)
        wirePos = np.array(wirePos)

        diffVector = objPos - wirePos
        # if getVectorLen(diffVector) > width / 2:
        #     return wirePos + width / 2 * diffVector / getVectorLen(diffVector)
        # else:
        #     return wirePos

        x = np.sign(diffVector[0]) * min([abs(diffVector[0]), width / 2])
        y = np.sign(diffVector[1]) * min([abs(diffVector[1]), width / 2])
        return wirePos + np.array([x, y])

    ConnStart = []
    ConnEnd = []

    Start = tuple(map(ToMM, track.GetStart()))
    End = tuple(map(ToMM, track.GetEnd()))

    for con in connect.GetConnectedTracks(track):
        if 'pcbnew.PCB_VIA' in str(con):
            print(tuple(map(ToMM, con.GetWidth())))
            print(tuple(map(ToMM, con.GetPosition())))
        elif 'pcbnew.PCB_TRACK' in str(con):
            conStart = tuple(map(ToMM, con.GetStart()))
            conEnd = tuple(map(ToMM, con.GetEnd()))
            if Start == conStart:
                ConnStart.append(getHash(con))
            if Start == conEnd:
                ConnStart.append(getHash(con))
            if End == conStart:
                ConnEnd.append(getHash(con))
            if End == conEnd:
                ConnEnd.append(getHash(con))

            if getHash(con) not in ConnStart + ConnEnd:
                distance = [
                    getDistance(Start, conStart),
                    getDistance(Start, conEnd),
                    getDistance(End, conStart),
                    getDistance(End, conEnd),
                ]
                minDis = min(distance)

                if distance[0] == minDis or distance[1] == minDis:
                    ConnStart.append(getHash(con))
                else:
                    ConnEnd.append(getHash(con))

    for con in connect.GetConnectedPads(track):
        Polygon = getPolygon(con)
        Start_ = MoveToObjCenter(Start, ToMM(track.GetWidth()), tuple(map(ToMM, con.GetPosition())))
        End_ = MoveToObjCenter(End, ToMM(track.GetWidth()), tuple(map(ToMM, con.GetPosition())))

        if IsPointInPolygon(Start_, Polygon):
            ConnStart.append(getHash(con))
        if IsPointInPolygon(End_, Polygon):
            ConnEnd.append(getHash(con))

    return ConnStart, ConnEnd


def Get_PCB_Elements(board: pcbnew.BOARD, connect: pcbnew.CONNECTIVITY_DATA):
    # RunSimulation()

    DesignSettings = board.GetDesignSettings()
    BoardThickness = ToMM(DesignSettings.GetBoardThickness())
    print("BoardThickness", BoardThickness)
    PossibleLayer = set(DesignSettings.GetEnabledLayers().CuStack())

    print("GetTracks", len(board.GetTracks()))
    print("GetAreaCount", board.GetAreaCount())
    print("GetPads", len(board.GetPads()))
    print("AllConnectedItems", len(board.AllConnectedItems()))
    print("GetFootprints", len(board.GetFootprints()))
    print("GetDrawings", len(board.GetDrawings()))
    print("GetAllNetClasses", len(board.GetAllNetClasses()))

    ItemList = {}

    for track in board.GetTracks():
        temp = {"Layer": getLayer(track, PossibleLayer)}
        if 'pcbnew.PCB_VIA' in str(track):
            temp["type"] = "VIA"
            temp["Position"] = tuple(map(ToMM, track.GetStart()))
            temp["Drill"] = ToMM(track.GetDrill())
            temp["Width"] = ToMM(track.GetWidth())
            temp["connStart"] = sorted(
                getHashList(connect.GetConnectedPads(track))
                + getHashList(connect.GetConnectedTracks(track))
            )
            temp["Area"] = 0
        elif 'pcbnew.PCB_TRACK' in str(track):
            if track.GetLength() == 0:
                continue
            temp["type"] = "WIRE"
            temp["Start"] = tuple(map(ToMM, track.GetStart()))
            temp["End"] = tuple(map(ToMM, track.GetEnd()))
            temp["Width"] = ToMM(track.GetWidth())
            temp["Length"] = ToMM(track.GetLength())
            temp["Area"] = temp["Width"] * temp["Length"]
            temp["Layer"] = [track.GetLayer()]
            temp["connStart"], temp["connEnd"] = getConnections(track, connect)
        elif 'pcbnew.PCB_ARC' in str(track):
            temp["type"] = "WIRE"
            temp["Start"] = tuple(map(ToMM, track.GetStart()))
            temp["End"] = tuple(map(ToMM, track.GetEnd()))
            temp["Radius"] = ToMM(track.GetRadius())
            temp["Width"] = ToMM(track.GetWidth())
            temp["Length"] = ToMM(track.GetLength())
            temp["Area"] = temp["Width"] * temp["Length"]
            if track.GetLength() == 0:
                continue
            temp["Layer"] = [track.GetLayer()]
            temp["connStart"], temp["connEnd"] = getConnections(track, connect)
        else:
            print("type", type(track), "is not considered!")
            continue

        temp["Netname"] = track.GetNetname()
        temp["NetCode"] = track.GetNetCode()
        temp["id"] = getHash(track)
        temp["IsSelected"] = track.IsSelected()
        ItemList[temp["id"]] = temp

    for Pad in board.AllConnectedItems():
        temp = {"Layer": getLayer(Pad, PossibleLayer)}
        if 'pcbnew.PAD' in str(Pad):
            temp["type"] = "PAD"
            temp["Shape"] = Pad.GetShape()
            # temp["PadAttr"] = Pad.ShowPadAttr()
            # temp["IsFlipped"] = Pad.IsFlipped()
            temp["Position"] = tuple(map(ToMM, Pad.GetPosition()))
            temp["Size"] = tuple(map(ToMM, Pad.GetSize()))
            temp["Orientation"] = Pad.GetOrientation().AsDegrees()
            temp["DrillSize"] = tuple(map(ToMM, Pad.GetDrillSize()))
            temp["Drill"] = temp["DrillSize"][0]
            temp["Area"] = ToMM(ToMM(Pad.GetEffectivePolygon().Area()))
            temp["PadName"] = Pad.GetPadName()
            # temp["FootprintUUID"] = getHash(Pad.GetParent())
            # if Pad.GetParent():
            #     temp["FootprintReference"] = Pad.GetParent().GetReference()

        elif 'pcbnew.ZONE' in str(Pad):
            # pcbnew.ZONE().GetZoneName
            if "teardrop" in Pad.GetZoneName():
                continue
            temp["type"] = "ZONE"
            temp["Position"] = tuple(map(ToMM, Pad.GetPosition()))
            temp["Area"] = ToMM(ToMM(Pad.GetFilledArea()))
            temp["NumCorners"] = Pad.GetNumCorners()
            temp["ZoneName"] = Pad.GetZoneName()
        else:
            if not 'pcbnew.PCB_TRACK' in str(track):
                print("type", type(track), "is not considered!")
            continue

        temp["Netname"] = Pad.GetNetname()
        temp["NetCode"] = Pad.GetNetCode()
        temp["id"] = getHash(Pad)
        temp["IsSelected"] = Pad.IsSelected()
        temp["connStart"] = sorted(
            getHashList(connect.GetConnectedPads(Pad))
            + getHashList(connect.GetConnectedTracks(Pad))
        )
        ItemList[temp["id"]] = temp

    for uuid, d in list(ItemList.items()):  # TODO: WIRES still need to be considered
        if d["type"] == "ZONE":
            for item in d["connStart"]:
                if not "connEND" in ItemList[item]:
                    ItemList[item]["connStart"].append(uuid)

    return ItemList

If you want I can fork the project and create a PR.

Thanks again for the plugin

KeyError: "type"

This is a really cool project idea and I'm glad that I caught it in the plugin manager. I haven't been able to use it yet, though, because...

Traceback (most recent call last):
  File ".../kicad/7.0/3rdparty/plugins/com_github_Steffen-W_KiCad-Parasitics/__init__.py", line 51, in Run
    ItemList = Get_PCB_Elements(board, connect)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../kicad/7.0/3rdparty/plugins/com_github_Steffen-W_KiCad-Parasitics/Get_PCB_Elements.py", line 227, in Get_PCB_Elements
    if d["type"] == "ZONE":
       ~^^^^^^^^
KeyError: 'type'

Environment:

Debian bookworm, using Kicad 7.0 (installed via apt with sudo apt install kicad-libraries="7.0.7+dfsg-1~bpo12+1" from bookworm-backports.

Reproduction steps:

image
Two pads in the same net.

image
With nothing, selected, works as expected.

image
When two pads are selected, this happens. Not sure if this is the intended error message, but at least it's handled?

image
image
And activating the plugin, even with nothing selected, causes the error.

image
Same thing if the pads are selected, and again if all the traces in the middle are as well.

Thanks for looking into this, the idea looks promising.

Error after selecting two objects

I have selected two pads, but I still get the error to mark only two objects. This error doesn't change even if I select other pads or vias. Can you tell me what I'am doing wrong.

image

Platform: Windows
KiCad: 7.0.9
Plugin: 2023.10.27

unhandled Fatal Error

Hi,

Thanks for this Plugin.

I tried it out with Kicad and selected a track and got the following error:

grafik

This project I can not share.

But another fatal error is also available on kicads demo project stickhub:

  1. open demo project stickhub
  2. open pcb file
  3. select the track on the usb d+ line
  4. click on the parasitic icon of Kicad-Parasitics addon
  5. fatal error

grafik

Tested with Kicad 7.0.8 and also 7.99, doesn't matter, I get crashes on both.

Application: KiCad PCB Editor x86_64 on x86_64

Version: 7.0.8-rc1-202309282119~cd3785744c~ubuntu22.04.1, release build

Libraries:
	wxWidgets 3.2.1
	FreeType 2.11.1
	HarfBuzz 6.0.0
	FontConfig 2.13.1
	libcurl/7.81.0 OpenSSL/3.0.2 zlib/1.2.11 brotli/1.0.9 zstd/1.4.8 libidn2/2.3.2 libpsl/0.21.0 (+libidn2/2.3.2) libssh/0.9.6/openssl/zlib nghttp2/1.43.0 librtmp/2.3 OpenLDAP/2.5.16

Platform: Linux Mint 21.2, 64 bit, Little endian, wxGTK, cinnamon, x11

Build Info:
	Date: Sep 28 2023 21:19:16
	wxWidgets: 3.2.1 (wchar_t,wx containers) GTK+ 3.24
	Boost: 1.74.0
	OCC: 7.5.2
	Curl: 7.88.1
	ngspice: 38
	Compiler: GCC 11.4.0 with C++ ABI 1016

Build settings:
	KICAD_SPICE=ON

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.