mirror of
https://github.com/atomic14/kicad-coil-plugins.git
synced 2024-10-18 09:06:57 +00:00
Refactor common functions out from notebooks
This commit is contained in:
parent
95abe5c798
commit
f11f403e9f
6 changed files with 407 additions and 561 deletions
|
@ -9,10 +9,27 @@
|
||||||
"import pandas as pd\n",
|
"import pandas as pd\n",
|
||||||
"import numpy as np\n",
|
"import numpy as np\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# import matplotlib as plt\n",
|
|
||||||
"import matplotlib.pyplot as plt\n",
|
"import matplotlib.pyplot as plt\n",
|
||||||
"import scipy\n",
|
|
||||||
"from skspatial.objects import LineSegment, Line, Vector\n",
|
"from skspatial.objects import LineSegment, Line, Vector\n",
|
||||||
|
"\n",
|
||||||
|
"# some helper functions\n",
|
||||||
|
"from helpers import (\n",
|
||||||
|
" get_arc_point,\n",
|
||||||
|
" draw_arc,\n",
|
||||||
|
" rotate,\n",
|
||||||
|
" translate,\n",
|
||||||
|
" flip_y,\n",
|
||||||
|
" flip_x,\n",
|
||||||
|
" create_via,\n",
|
||||||
|
" create_pad,\n",
|
||||||
|
" create_track,\n",
|
||||||
|
" create_silk,\n",
|
||||||
|
" create_silk,\n",
|
||||||
|
" optimize_points,\n",
|
||||||
|
" chaikin,\n",
|
||||||
|
")\n",
|
||||||
|
"from pcb_json import dump_json, plot_json\n",
|
||||||
|
"\n",
|
||||||
"from enum import Enum\n",
|
"from enum import Enum\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Layer = Enum(\"Layer\", \"FRONT BACK\")"
|
"Layer = Enum(\"Layer\", \"FRONT BACK\")"
|
||||||
|
@ -26,98 +43,29 @@
|
||||||
"source": [
|
"source": [
|
||||||
"VIA_DIAM = 0.8\n",
|
"VIA_DIAM = 0.8\n",
|
||||||
"VIA_DRILL = 0.4\n",
|
"VIA_DRILL = 0.4\n",
|
||||||
|
"# this is for a 1.27mm pitch pin\n",
|
||||||
|
"PAD_DIAM = 1.0\n",
|
||||||
|
"PAD_DRILL = 0.65\n",
|
||||||
|
"\n",
|
||||||
|
"# PCB Edge size\n",
|
||||||
|
"STATOR_RADIUS = 18\n",
|
||||||
"STATOR_HOLE_RADIUS = 5\n",
|
"STATOR_HOLE_RADIUS = 5\n",
|
||||||
|
"\n",
|
||||||
|
"# Track width and spacing\n",
|
||||||
"TRACK_WIDTH = 0.127\n",
|
"TRACK_WIDTH = 0.127\n",
|
||||||
"TRACK_SPACING = 0.127\n",
|
"TRACK_SPACING = 0.127\n",
|
||||||
|
"\n",
|
||||||
|
"# Coil params\n",
|
||||||
"TURNS = 9\n",
|
"TURNS = 9\n",
|
||||||
"STATOR_RADIUS = 18\n",
|
|
||||||
"PIN_DIAM = 1.7\n",
|
|
||||||
"COIL_CENTER_RADIUS = 11.5\n",
|
"COIL_CENTER_RADIUS = 11.5\n",
|
||||||
"COIL_VIA_RADIUS = 12.5\n",
|
"COIL_VIA_RADIUS = 12.5\n",
|
||||||
|
"\n",
|
||||||
"# where to place the pins\n",
|
"# where to place the pins\n",
|
||||||
"CONNECTION_PINS_RADIUS = 16\n",
|
"CONNECTION_PINS_RADIUS = 16.5\n",
|
||||||
|
"\n",
|
||||||
"USE_SPIRAL = False"
|
"USE_SPIRAL = False"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# get the point on an arc at the given angle\n",
|
|
||||||
"def get_arc_point(angle, radius):\n",
|
|
||||||
" return (\n",
|
|
||||||
" radius * np.cos(np.deg2rad(angle)),\n",
|
|
||||||
" radius * np.sin(np.deg2rad(angle)),\n",
|
|
||||||
" )\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# draw an arc\n",
|
|
||||||
"def draw_arc(start_angle, end_angle, radius, step=10):\n",
|
|
||||||
" points = []\n",
|
|
||||||
" for angle in np.arange(start_angle, end_angle + step, step):\n",
|
|
||||||
" x = radius * np.cos(np.deg2rad(angle))\n",
|
|
||||||
" y = radius * np.sin(np.deg2rad(angle))\n",
|
|
||||||
" points.append((x, y))\n",
|
|
||||||
" return points\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# roate the points by the required angle\n",
|
|
||||||
"def rotate(points, angle):\n",
|
|
||||||
" return [\n",
|
|
||||||
" [\n",
|
|
||||||
" x * np.cos(np.deg2rad(angle)) - y * np.sin(np.deg2rad(angle)),\n",
|
|
||||||
" x * np.sin(np.deg2rad(angle)) + y * np.cos(np.deg2rad(angle)),\n",
|
|
||||||
" ]\n",
|
|
||||||
" for x, y in points\n",
|
|
||||||
" ]\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# move the points out to the distance at the requited angle\n",
|
|
||||||
"def translate(points, distance, angle):\n",
|
|
||||||
" return [\n",
|
|
||||||
" [\n",
|
|
||||||
" x + distance * np.cos(np.deg2rad(angle)),\n",
|
|
||||||
" y + distance * np.sin(np.deg2rad(angle)),\n",
|
|
||||||
" ]\n",
|
|
||||||
" for x, y in points\n",
|
|
||||||
" ]\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# flip the y coordinate\n",
|
|
||||||
"def flip_y(points):\n",
|
|
||||||
" return [[x, -y] for x, y in points]\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def flip_x(points):\n",
|
|
||||||
" return [[-x, y] for x, y in points]\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def create_pad(radius, angle, name):\n",
|
|
||||||
" return {\n",
|
|
||||||
" \"x\": radius * np.cos(np.deg2rad(angle)),\n",
|
|
||||||
" \"y\": radius * np.sin(np.deg2rad(angle)),\n",
|
|
||||||
" \"name\": name,\n",
|
|
||||||
" }\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def create_silk(point, text):\n",
|
|
||||||
" return {\n",
|
|
||||||
" \"x\": point[0],\n",
|
|
||||||
" \"y\": point[1],\n",
|
|
||||||
" \"text\": text,\n",
|
|
||||||
" }\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def create_via(point):\n",
|
|
||||||
" return {\"x\": point[0], \"y\": point[1]}\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def create_track(points):\n",
|
|
||||||
" return [{\"x\": x, \"y\": y} for x, y in points]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
|
@ -222,46 +170,7 @@
|
||||||
" coil_points.append(coil_point2)\n",
|
" coil_points.append(coil_point2)\n",
|
||||||
"\n",
|
"\n",
|
||||||
" template_index = template_index + 1\n",
|
" template_index = template_index + 1\n",
|
||||||
" return coil_points\n",
|
" return coil_points"
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def optimize_points(points):\n",
|
|
||||||
" # follow the line and remove points that are in the same direction as the previous poin\n",
|
|
||||||
" # keep doing this until the direction changes significantly\n",
|
|
||||||
" # this is a very simple optimization that removes a lot of points\n",
|
|
||||||
" # it's not perfect but it's a good start\n",
|
|
||||||
" optimized_points = []\n",
|
|
||||||
" for i in range(len(points)):\n",
|
|
||||||
" if i == 0:\n",
|
|
||||||
" optimized_points.append(points[i])\n",
|
|
||||||
" else:\n",
|
|
||||||
" vector1 = np.array(points[i]) - np.array(points[i - 1])\n",
|
|
||||||
" vector2 = np.array(points[(i + 1) % len(points)]) - np.array(points[i])\n",
|
|
||||||
" length1 = np.linalg.norm(vector1)\n",
|
|
||||||
" length2 = np.linalg.norm(vector2)\n",
|
|
||||||
" if length1 > 0 and length2 > 0:\n",
|
|
||||||
" dot = np.dot(vector1, vector2) / (length1 * length2)\n",
|
|
||||||
" # clamp dot between -1 and 1\n",
|
|
||||||
" dot = max(-1, min(1, dot))\n",
|
|
||||||
" angle = np.arccos(dot)\n",
|
|
||||||
" if angle > np.deg2rad(5):\n",
|
|
||||||
" optimized_points.append(points[i])\n",
|
|
||||||
" print(\"Optimised from {} to {} points\".format(len(points), len(optimized_points)))\n",
|
|
||||||
" return optimized_points\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def chaikin(points, iterations):\n",
|
|
||||||
" if iterations == 0:\n",
|
|
||||||
" return points\n",
|
|
||||||
" l = len(points)\n",
|
|
||||||
" smoothed = []\n",
|
|
||||||
" for i in range(l - 1):\n",
|
|
||||||
" x1, y1 = points[i]\n",
|
|
||||||
" x2, y2 = points[i + 1]\n",
|
|
||||||
" smoothed.append([0.95 * x1 + 0.05 * x2, 0.95 * y1 + 0.05 * y2])\n",
|
|
||||||
" smoothed.append([0.05 * x1 + 0.95 * x2, 0.05 * y1 + 0.95 * y2])\n",
|
|
||||||
" smoothed.append(points[l - 1])\n",
|
|
||||||
" return chaikin(smoothed, iterations - 1)"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -270,83 +179,28 @@
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"if not USE_SPIRAL:\n",
|
"template_f = []\n",
|
||||||
" template_f = []\n",
|
"for i in range(len(template)):\n",
|
||||||
" for i in range(len(template)):\n",
|
" template_f.append(template[len(template) - i - len(template) // 2])\n",
|
||||||
" template_f.append(template[len(template) - i - len(template) // 2])\n",
|
"template_f = flip_x(template_f)\n",
|
||||||
" template_f = flip_x(template_f)\n",
|
"points_f = chaikin(\n",
|
||||||
" points_f = chaikin(\n",
|
" optimize_points(flip_x(get_points(template_f, TURNS, TRACK_SPACING + TRACK_WIDTH))),\n",
|
||||||
" optimize_points(\n",
|
" 2,\n",
|
||||||
" flip_x(get_points(template_f, TURNS, TRACK_SPACING + TRACK_WIDTH))\n",
|
")\n",
|
||||||
" ),\n",
|
"points_b = chaikin(\n",
|
||||||
" 2,\n",
|
" optimize_points(get_points(template, TURNS, TRACK_SPACING + TRACK_WIDTH)), 2\n",
|
||||||
" )\n",
|
")\n",
|
||||||
" points_b = chaikin(\n",
|
|
||||||
" optimize_points(get_points(template, TURNS, TRACK_SPACING + TRACK_WIDTH)), 2\n",
|
|
||||||
" )\n",
|
|
||||||
"\n",
|
"\n",
|
||||||
" points_f = [(COIL_VIA_RADIUS - COIL_CENTER_RADIUS, 0)] + points_f\n",
|
"points_f = [(COIL_VIA_RADIUS - COIL_CENTER_RADIUS, 0)] + points_f\n",
|
||||||
" points_b = [(COIL_VIA_RADIUS - COIL_CENTER_RADIUS, 0)] + points_b\n",
|
"points_b = [(COIL_VIA_RADIUS - COIL_CENTER_RADIUS, 0)] + points_b\n",
|
||||||
"\n",
|
"\n",
|
||||||
" df = pd.DataFrame(points_f, columns=[\"x\", \"y\"])\n",
|
"df = pd.DataFrame(points_f, columns=[\"x\", \"y\"])\n",
|
||||||
" ax = df.plot.line(x=\"x\", y=\"y\", color=\"blue\")\n",
|
"ax = df.plot.line(x=\"x\", y=\"y\", color=\"blue\")\n",
|
||||||
" ax.axis(\"equal\")\n",
|
"ax.axis(\"equal\")\n",
|
||||||
" df = pd.DataFrame(points_b, columns=[\"x\", \"y\"])\n",
|
"df = pd.DataFrame(points_b, columns=[\"x\", \"y\"])\n",
|
||||||
" ax = df.plot.line(x=\"x\", y=\"y\", color=\"red\", ax=ax)\n",
|
"ax = df.plot.line(x=\"x\", y=\"y\", color=\"red\", ax=ax)\n",
|
||||||
"\n",
|
"\n",
|
||||||
" print(\"Track points\", len(points_f), len(points_b))\n",
|
"print(\"Track points\", len(points_f), len(points_b))"
|
||||||
"else:\n",
|
|
||||||
" print(\"Using spiral\")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Basic Spiral Coil Generation"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def get_spiral(turns, start_radius, thickness, layer=Layer.FRONT):\n",
|
|
||||||
" points = []\n",
|
|
||||||
" # create a starting point in the center\n",
|
|
||||||
" for angle in np.arange(0, turns * 360, 1):\n",
|
|
||||||
" radius = start_radius + thickness * angle / 360\n",
|
|
||||||
" if layer == Layer.BACK:\n",
|
|
||||||
" x = radius * np.cos(np.deg2rad(angle + 180))\n",
|
|
||||||
" y = radius * np.sin(np.deg2rad(angle + 180))\n",
|
|
||||||
" points.append((x, -y))\n",
|
|
||||||
" else:\n",
|
|
||||||
" x = radius * np.cos(np.deg2rad(angle))\n",
|
|
||||||
" y = radius * np.sin(np.deg2rad(angle))\n",
|
|
||||||
" points.append((x, y))\n",
|
|
||||||
" return points"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"if USE_SPIRAL:\n",
|
|
||||||
" points_f = get_spiral(\n",
|
|
||||||
" TURNS, VIA_DIAM / 2 + TRACK_SPACING, TRACK_SPACING + TRACK_WIDTH, Layer.FRONT\n",
|
|
||||||
" )\n",
|
|
||||||
" points_b = get_spiral(\n",
|
|
||||||
" TURNS, VIA_DIAM / 2 + TRACK_SPACING, TRACK_SPACING + TRACK_WIDTH, Layer.BACK\n",
|
|
||||||
" )\n",
|
|
||||||
"\n",
|
|
||||||
" points_f = [(COIL_VIA_RADIUS - COIL_CENTER_RADIUS, 0)] + points_f\n",
|
|
||||||
" points_b = [(COIL_VIA_RADIUS - COIL_CENTER_RADIUS, 0)] + points_b\n",
|
|
||||||
" print(\"Track points\", len(points_f), len(points_b))\n",
|
|
||||||
"else:\n",
|
|
||||||
" print(\"Using template\")"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -517,14 +371,16 @@
|
||||||
"vias.append(create_via(get_arc_point(8 * 360 / 12, outer_connection_radius_C)))\n",
|
"vias.append(create_via(get_arc_point(8 * 360 / 12, outer_connection_radius_C)))\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# create pads for the input\n",
|
"# create pads for the input\n",
|
||||||
"pin_radius = STATOR_RADIUS - TRACK_SPACING - PIN_DIAM / 2\n",
|
"for angle in range(0, 360, 15):\n",
|
||||||
"pads.append(create_pad(pin_radius, 0, \"A\"))\n",
|
" pads.append(create_pad(CONNECTION_PINS_RADIUS, angle, \"A\"))\n",
|
||||||
"pads.append(create_pad(pin_radius, 1 * 360 / 12, \"B\"))\n",
|
|
||||||
"pads.append(create_pad(pin_radius, 2 * 360 / 12, \"C\"))\n",
|
|
||||||
"\n",
|
"\n",
|
||||||
"coils_f[0].append(get_arc_point(0, pin_radius))\n",
|
"# coils_f[0].append(get_arc_point(0, CONNECTION_PINS_RADIUS))\n",
|
||||||
"coils_f[1].append(get_arc_point(1 * 360 / 12, pin_radius))\n",
|
"# coils_f[1].append(get_arc_point(1 * 360 / 12, CONNECTION_PINS_RADIUS))\n",
|
||||||
"coils_f[2].append(get_arc_point(2 * 360 / 12, pin_radius))"
|
"# coils_f[2].append(get_arc_point(2 * 360 / 12, CONNECTION_PINS_RADIUS))\n",
|
||||||
|
"\n",
|
||||||
|
"# coils_f[0].append(get_arc_point(15, CONNECTION_PINS_RADIUS))\n",
|
||||||
|
"# coils_f[1].append(get_arc_point(15 + 1 * 360 / 12, CONNECTION_PINS_RADIUS))\n",
|
||||||
|
"# coils_f[2].append(get_arc_point(15 + 2 * 360 / 12, CONNECTION_PINS_RADIUS))"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -533,122 +389,32 @@
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"# dump out the results to json\n",
|
"# dump out the json version\n",
|
||||||
"json_result = {\n",
|
"json_result = dump_json(\n",
|
||||||
" \"parameters\": {\n",
|
" \"coils_12.json\",\n",
|
||||||
" \"trackWidth\": TRACK_WIDTH,\n",
|
" STATOR_RADIUS,\n",
|
||||||
" \"statorHoleRadius\": STATOR_HOLE_RADIUS,\n",
|
" STATOR_HOLE_RADIUS,\n",
|
||||||
" \"statorRadius\": STATOR_RADIUS,\n",
|
" TRACK_WIDTH,\n",
|
||||||
" \"viaDiameter\": VIA_DIAM,\n",
|
" PAD_DIAM,\n",
|
||||||
" \"viaDrillDiameter\": VIA_DRILL,\n",
|
" PAD_DRILL,\n",
|
||||||
" },\n",
|
" VIA_DIAM,\n",
|
||||||
" \"vias\": vias,\n",
|
" VIA_DRILL,\n",
|
||||||
" \"pads\": pads,\n",
|
" vias,\n",
|
||||||
" \"silk\": silk,\n",
|
" pads,\n",
|
||||||
" \"tracks\": {\n",
|
" silk,\n",
|
||||||
" \"f\": [create_track(points) for points in tracks_f],\n",
|
" tracks_f,\n",
|
||||||
" \"b\": [create_track(points) for points in tracks_b],\n",
|
" tracks_b,\n",
|
||||||
" },\n",
|
")"
|
||||||
"}\n",
|
]
|
||||||
"\n",
|
},
|
||||||
"import json\n",
|
{
|
||||||
"\n",
|
"cell_type": "code",
|
||||||
"json.dump(json_result, open(\"coil.json\", \"w\"))\n",
|
"execution_count": null,
|
||||||
"\n",
|
"metadata": {},
|
||||||
"\n",
|
"outputs": [],
|
||||||
"# df = pd.DataFrame(coil_A_f, columns=[\"x\", \"y\"])\n",
|
"source": [
|
||||||
"# ax = df.plot.line(x=\"x\", y=\"y\", label=\"Coil A\", color=\"blue\")\n",
|
"# plot the json\n",
|
||||||
"# ax.axis(\"equal\")\n",
|
"plot_json(json_result)"
|
||||||
"# df = pd.DataFrame(coil_A_b, columns=[\"x\", \"y\"])\n",
|
|
||||||
"# ax = df.plot.line(x=\"x\", y=\"y\", label=\"Coil B\", color=\"green\")\n",
|
|
||||||
"# ax.axis(\"equal\")\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# plot the back tracks\n",
|
|
||||||
"ax = None\n",
|
|
||||||
"for track in json_result[\"tracks\"][\"b\"]:\n",
|
|
||||||
" df = pd.DataFrame(track, columns=[\"x\", \"y\"])\n",
|
|
||||||
" ax = df.plot.line(x=\"x\", y=\"y\", color=\"blue\", ax=ax)\n",
|
|
||||||
" ax.axis(\"equal\")\n",
|
|
||||||
"\n",
|
|
||||||
"# plot the front tracks\n",
|
|
||||||
"for track in json_result[\"tracks\"][\"f\"]:\n",
|
|
||||||
" df = pd.DataFrame(track, columns=[\"x\", \"y\"])\n",
|
|
||||||
" ax = df.plot.line(x=\"x\", y=\"y\", color=\"red\", ax=ax)\n",
|
|
||||||
" ax.axis(\"equal\")\n",
|
|
||||||
"\n",
|
|
||||||
"# hide the legend\n",
|
|
||||||
"ax.legend().set_visible(False)\n",
|
|
||||||
"# make the plot bigger\n",
|
|
||||||
"ax.figure.set_size_inches(10, 10)\n",
|
|
||||||
"\n",
|
|
||||||
"# plot the vias\n",
|
|
||||||
"for via in json_result[\"vias\"]:\n",
|
|
||||||
" ax.add_patch(\n",
|
|
||||||
" plt.Circle(\n",
|
|
||||||
" (via[\"x\"], via[\"y\"]),\n",
|
|
||||||
" radius=VIA_DIAM / 2,\n",
|
|
||||||
" fill=True,\n",
|
|
||||||
" color=\"black\",\n",
|
|
||||||
" )\n",
|
|
||||||
" )\n",
|
|
||||||
" ax.add_patch(\n",
|
|
||||||
" plt.Circle(\n",
|
|
||||||
" (via[\"x\"], via[\"y\"]),\n",
|
|
||||||
" radius=VIA_DRILL / 2,\n",
|
|
||||||
" fill=True,\n",
|
|
||||||
" color=\"white\",\n",
|
|
||||||
" )\n",
|
|
||||||
" )\n",
|
|
||||||
"\n",
|
|
||||||
"# plot the edge cuts\n",
|
|
||||||
"ax.add_patch(\n",
|
|
||||||
" plt.Circle(\n",
|
|
||||||
" (0, 0),\n",
|
|
||||||
" radius=STATOR_RADIUS,\n",
|
|
||||||
" fill=False,\n",
|
|
||||||
" color=\"yellow\",\n",
|
|
||||||
" )\n",
|
|
||||||
")\n",
|
|
||||||
"ax.add_patch(\n",
|
|
||||||
" plt.Circle(\n",
|
|
||||||
" (0, 0),\n",
|
|
||||||
" radius=STATOR_HOLE_RADIUS,\n",
|
|
||||||
" fill=False,\n",
|
|
||||||
" color=\"yellow\",\n",
|
|
||||||
" )\n",
|
|
||||||
")\n",
|
|
||||||
"\n",
|
|
||||||
"# plot the pads\n",
|
|
||||||
"for pad in json_result[\"pads\"]:\n",
|
|
||||||
" ax.add_patch(\n",
|
|
||||||
" plt.Circle(\n",
|
|
||||||
" (pad[\"x\"], pad[\"y\"]),\n",
|
|
||||||
" radius=1.7 / 2,\n",
|
|
||||||
" fill=True,\n",
|
|
||||||
" color=\"yellow\",\n",
|
|
||||||
" )\n",
|
|
||||||
" )\n",
|
|
||||||
" ax.add_patch(\n",
|
|
||||||
" plt.Circle(\n",
|
|
||||||
" (pad[\"x\"], pad[\"y\"]),\n",
|
|
||||||
" radius=1.0 / 2,\n",
|
|
||||||
" fill=True,\n",
|
|
||||||
" color=\"white\",\n",
|
|
||||||
" )\n",
|
|
||||||
" )\n",
|
|
||||||
"\n",
|
|
||||||
"# plot the silk\n",
|
|
||||||
"for silk in json_result[\"silk\"]:\n",
|
|
||||||
" ax.text(\n",
|
|
||||||
" silk[\"x\"],\n",
|
|
||||||
" silk[\"y\"],\n",
|
|
||||||
" silk[\"text\"],\n",
|
|
||||||
" horizontalalignment=\"center\",\n",
|
|
||||||
" verticalalignment=\"center\",\n",
|
|
||||||
" color=\"black\",\n",
|
|
||||||
" fontsize=50,\n",
|
|
||||||
" )"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -11,8 +11,24 @@
|
||||||
"\n",
|
"\n",
|
||||||
"# import matplotlib as plt\n",
|
"# import matplotlib as plt\n",
|
||||||
"import matplotlib.pyplot as plt\n",
|
"import matplotlib.pyplot as plt\n",
|
||||||
"import scipy\n",
|
|
||||||
"from skspatial.objects import LineSegment, Line, Vector\n",
|
"from skspatial.objects import LineSegment, Line, Vector\n",
|
||||||
|
"\n",
|
||||||
|
"# some helper functions\n",
|
||||||
|
"from helpers import (\n",
|
||||||
|
" get_arc_point,\n",
|
||||||
|
" draw_arc,\n",
|
||||||
|
" rotate,\n",
|
||||||
|
" translate,\n",
|
||||||
|
" flip_y,\n",
|
||||||
|
" flip_x,\n",
|
||||||
|
" optimize_points,\n",
|
||||||
|
" chaikin,\n",
|
||||||
|
" create_pad,\n",
|
||||||
|
" create_silk,\n",
|
||||||
|
" create_via,\n",
|
||||||
|
")\n",
|
||||||
|
"from pcb_json import dump_json, plot_json\n",
|
||||||
|
"\n",
|
||||||
"from enum import Enum\n",
|
"from enum import Enum\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Layer = Enum(\"Layer\", \"FRONT BACK\")"
|
"Layer = Enum(\"Layer\", \"FRONT BACK\")"
|
||||||
|
@ -26,72 +42,27 @@
|
||||||
"source": [
|
"source": [
|
||||||
"VIA_DIAM = 0.8\n",
|
"VIA_DIAM = 0.8\n",
|
||||||
"VIA_DRILL = 0.4\n",
|
"VIA_DRILL = 0.4\n",
|
||||||
|
"# this is for a 1.27mm pitch pin\n",
|
||||||
|
"PAD_DIAM = 1.0\n",
|
||||||
|
"PAD_DRILL = 0.65\n",
|
||||||
|
"\n",
|
||||||
|
"# PCB Edge size\n",
|
||||||
|
"STATOR_RADIUS = 18\n",
|
||||||
"STATOR_HOLE_RADIUS = 5\n",
|
"STATOR_HOLE_RADIUS = 5\n",
|
||||||
|
"\n",
|
||||||
|
"# Track width and spacing\n",
|
||||||
"TRACK_WIDTH = 0.127\n",
|
"TRACK_WIDTH = 0.127\n",
|
||||||
"TRACK_SPACING = 0.127\n",
|
"TRACK_SPACING = 0.127\n",
|
||||||
|
"\n",
|
||||||
|
"# Coil params\n",
|
||||||
"TURNS = 18\n",
|
"TURNS = 18\n",
|
||||||
"STATOR_RADIUS = 18\n",
|
|
||||||
"COIL_CENTER_RADIUS = 11.5\n",
|
"COIL_CENTER_RADIUS = 11.5\n",
|
||||||
"# where to place the pins\n",
|
"# where to place the pins\n",
|
||||||
"CONNECTION_PINS_RADIUS = 16\n",
|
"CONNECTION_PINS_RADIUS = 16.5\n",
|
||||||
|
"\n",
|
||||||
"USE_SPIRAL = False"
|
"USE_SPIRAL = False"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# get the point on an arc at the given angle\n",
|
|
||||||
"def get_arc_point(angle, radius):\n",
|
|
||||||
" return (\n",
|
|
||||||
" radius * np.cos(np.deg2rad(angle)),\n",
|
|
||||||
" radius * np.sin(np.deg2rad(angle)),\n",
|
|
||||||
" )\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# draw an arc\n",
|
|
||||||
"def draw_arc(start_angle, end_angle, radius, step=10):\n",
|
|
||||||
" points = []\n",
|
|
||||||
" for angle in np.arange(start_angle, end_angle + step, step):\n",
|
|
||||||
" x = radius * np.cos(np.deg2rad(angle))\n",
|
|
||||||
" y = radius * np.sin(np.deg2rad(angle))\n",
|
|
||||||
" points.append((x, y))\n",
|
|
||||||
" return points\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# roate the points by the required angle\n",
|
|
||||||
"def rotate(points, angle):\n",
|
|
||||||
" return [\n",
|
|
||||||
" [\n",
|
|
||||||
" x * np.cos(np.deg2rad(angle)) - y * np.sin(np.deg2rad(angle)),\n",
|
|
||||||
" x * np.sin(np.deg2rad(angle)) + y * np.cos(np.deg2rad(angle)),\n",
|
|
||||||
" ]\n",
|
|
||||||
" for x, y in points\n",
|
|
||||||
" ]\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# move the points out to the distance at the requited angle\n",
|
|
||||||
"def translate(points, distance, angle):\n",
|
|
||||||
" return [\n",
|
|
||||||
" [\n",
|
|
||||||
" x + distance * np.cos(np.deg2rad(angle)),\n",
|
|
||||||
" y + distance * np.sin(np.deg2rad(angle)),\n",
|
|
||||||
" ]\n",
|
|
||||||
" for x, y in points\n",
|
|
||||||
" ]\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# flip the y coordinate\n",
|
|
||||||
"def flip_y(points):\n",
|
|
||||||
" return [[x, -y] for x, y in points]\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def flip_x(points):\n",
|
|
||||||
" return [[-x, y] for x, y in points]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
|
@ -198,46 +169,7 @@
|
||||||
" coil_points.append(coil_point2)\n",
|
" coil_points.append(coil_point2)\n",
|
||||||
"\n",
|
"\n",
|
||||||
" template_index = template_index + 1\n",
|
" template_index = template_index + 1\n",
|
||||||
" return coil_points\n",
|
" return coil_points"
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def optimize_points(points):\n",
|
|
||||||
" # follow the line and remove points that are in the same direction as the previous poin\n",
|
|
||||||
" # keep doing this until the direction changes significantly\n",
|
|
||||||
" # this is a very simple optimization that removes a lot of points\n",
|
|
||||||
" # it's not perfect but it's a good start\n",
|
|
||||||
" optimized_points = []\n",
|
|
||||||
" for i in range(len(points)):\n",
|
|
||||||
" if i == 0:\n",
|
|
||||||
" optimized_points.append(points[i])\n",
|
|
||||||
" else:\n",
|
|
||||||
" vector1 = np.array(points[i]) - np.array(points[i - 1])\n",
|
|
||||||
" vector2 = np.array(points[(i + 1) % len(points)]) - np.array(points[i])\n",
|
|
||||||
" length1 = np.linalg.norm(vector1)\n",
|
|
||||||
" length2 = np.linalg.norm(vector2)\n",
|
|
||||||
" if length1 > 0 and length2 > 0:\n",
|
|
||||||
" dot = np.dot(vector1, vector2) / (length1 * length2)\n",
|
|
||||||
" # clamp dot between -1 and 1\n",
|
|
||||||
" dot = max(-1, min(1, dot))\n",
|
|
||||||
" angle = np.arccos(dot)\n",
|
|
||||||
" if angle > np.deg2rad(5):\n",
|
|
||||||
" optimized_points.append(points[i])\n",
|
|
||||||
" print(\"Optimised from {} to {} points\".format(len(points), len(optimized_points)))\n",
|
|
||||||
" return optimized_points\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def chaikin(points, iterations):\n",
|
|
||||||
" if iterations == 0:\n",
|
|
||||||
" return points\n",
|
|
||||||
" l = len(points)\n",
|
|
||||||
" smoothed = []\n",
|
|
||||||
" for i in range(l - 1):\n",
|
|
||||||
" x1, y1 = points[i]\n",
|
|
||||||
" x2, y2 = points[i + 1]\n",
|
|
||||||
" smoothed.append([0.9 * x1 + 0.1 * x2, 0.9 * y1 + 0.1 * y2])\n",
|
|
||||||
" smoothed.append([0.1 * x1 + 0.9 * x2, 0.1 * y1 + 0.9 * y2])\n",
|
|
||||||
" smoothed.append(points[l - 1])\n",
|
|
||||||
" return chaikin(smoothed, iterations - 1)"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -369,15 +301,6 @@
|
||||||
"angle_B = 120\n",
|
"angle_B = 120\n",
|
||||||
"angle_C = 240\n",
|
"angle_C = 240\n",
|
||||||
"\n",
|
"\n",
|
||||||
"\n",
|
|
||||||
"def create_pad(radius, angle, name):\n",
|
|
||||||
" return {\n",
|
|
||||||
" \"x\": radius * np.cos(np.deg2rad(angle)),\n",
|
|
||||||
" \"y\": radius * np.sin(np.deg2rad(angle)),\n",
|
|
||||||
" \"name\": name,\n",
|
|
||||||
" }\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# create the pads at CONNECTION_PINS radius - 2 for each of the coils, A, B and C\n",
|
"# create the pads at CONNECTION_PINS radius - 2 for each of the coils, A, B and C\n",
|
||||||
"pads.append(create_pad(CONNECTION_PINS_RADIUS, angle_A - 30, \"A\"))\n",
|
"pads.append(create_pad(CONNECTION_PINS_RADIUS, angle_A - 30, \"A\"))\n",
|
||||||
"pads.append(create_pad(CONNECTION_PINS_RADIUS, angle_A + 30, \"A\"))\n",
|
"pads.append(create_pad(CONNECTION_PINS_RADIUS, angle_A + 30, \"A\"))\n",
|
||||||
|
@ -388,11 +311,6 @@
|
||||||
"pads.append(create_pad(CONNECTION_PINS_RADIUS, angle_C - 30, \"C\"))\n",
|
"pads.append(create_pad(CONNECTION_PINS_RADIUS, angle_C - 30, \"C\"))\n",
|
||||||
"pads.append(create_pad(CONNECTION_PINS_RADIUS, angle_C + 30, \"C\"))\n",
|
"pads.append(create_pad(CONNECTION_PINS_RADIUS, angle_C + 30, \"C\"))\n",
|
||||||
"\n",
|
"\n",
|
||||||
"\n",
|
|
||||||
"def create_via(point):\n",
|
|
||||||
" return {\"x\": point[0], \"y\": point[1]}\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# the main coils\n",
|
"# the main coils\n",
|
||||||
"coil_A_f = translate(rotate(points_f, angle_A), COIL_CENTER_RADIUS, angle_A)\n",
|
"coil_A_f = translate(rotate(points_f, angle_A), COIL_CENTER_RADIUS, angle_A)\n",
|
||||||
"coil_A_b = translate(rotate(points_b, angle_A), COIL_CENTER_RADIUS, angle_A)\n",
|
"coil_A_b = translate(rotate(points_b, angle_A), COIL_CENTER_RADIUS, angle_A)\n",
|
||||||
|
@ -527,7 +445,13 @@
|
||||||
"\n",
|
"\n",
|
||||||
"vias.append(create_via(a_connection_f[-1]))\n",
|
"vias.append(create_via(a_connection_f[-1]))\n",
|
||||||
"vias.append(create_via(b_connection_f[-1]))\n",
|
"vias.append(create_via(b_connection_f[-1]))\n",
|
||||||
"vias.append(create_via(c_connection_f[-1]))"
|
"vias.append(create_via(c_connection_f[-1]))\n",
|
||||||
|
"\n",
|
||||||
|
"silk = [\n",
|
||||||
|
" create_silk(get_arc_point(angle_A, COIL_CENTER_RADIUS), \"A\"),\n",
|
||||||
|
" create_silk(get_arc_point(angle_B, COIL_CENTER_RADIUS), \"B\"),\n",
|
||||||
|
" create_silk(get_arc_point(angle_C, COIL_CENTER_RADIUS), \"C\"),\n",
|
||||||
|
"]"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -536,130 +460,32 @@
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"def create_track(points):\n",
|
"# dump out the json version\n",
|
||||||
" return [{\"x\": x, \"y\": y} for x, y in points]\n",
|
"json_result = dump_json(\n",
|
||||||
"\n",
|
" \"coils_6.json\",\n",
|
||||||
"\n",
|
" STATOR_RADIUS,\n",
|
||||||
"# dump out the results to json\n",
|
" STATOR_HOLE_RADIUS,\n",
|
||||||
"json_result = {\n",
|
" TRACK_WIDTH,\n",
|
||||||
" \"parameters\": {\n",
|
" PAD_DIAM,\n",
|
||||||
" \"trackWidth\": TRACK_WIDTH,\n",
|
" PAD_DRILL,\n",
|
||||||
" \"statorHoleRadius\": STATOR_HOLE_RADIUS,\n",
|
" VIA_DIAM,\n",
|
||||||
" \"statorRadius\": STATOR_RADIUS,\n",
|
" VIA_DRILL,\n",
|
||||||
" \"viaDiameter\": VIA_DIAM,\n",
|
" vias,\n",
|
||||||
" \"viaDrillDiameter\": VIA_DRILL,\n",
|
" pads,\n",
|
||||||
" },\n",
|
" silk,\n",
|
||||||
" \"vias\": vias,\n",
|
" tracks_f,\n",
|
||||||
" \"pads\": pads,\n",
|
" tracks_b,\n",
|
||||||
" \"silk\": [\n",
|
")"
|
||||||
" {\n",
|
]
|
||||||
" \"x\": COIL_CENTER_RADIUS * np.cos(np.deg2rad(angle_A)),\n",
|
},
|
||||||
" \"y\": COIL_CENTER_RADIUS * np.sin(np.deg2rad(angle_A)),\n",
|
{
|
||||||
" \"text\": \"A\",\n",
|
"cell_type": "code",
|
||||||
" },\n",
|
"execution_count": null,
|
||||||
" {\n",
|
"metadata": {},
|
||||||
" \"x\": COIL_CENTER_RADIUS * np.cos(np.deg2rad(angle_B)),\n",
|
"outputs": [],
|
||||||
" \"y\": COIL_CENTER_RADIUS * np.sin(np.deg2rad(angle_B)),\n",
|
"source": [
|
||||||
" \"text\": \"B\",\n",
|
"# plot the json\n",
|
||||||
" },\n",
|
"plot_json(json_result)"
|
||||||
" {\n",
|
|
||||||
" \"x\": COIL_CENTER_RADIUS * np.cos(np.deg2rad(angle_C)),\n",
|
|
||||||
" \"y\": COIL_CENTER_RADIUS * np.sin(np.deg2rad(angle_C)),\n",
|
|
||||||
" \"text\": \"C\",\n",
|
|
||||||
" },\n",
|
|
||||||
" ],\n",
|
|
||||||
" \"tracks\": {\n",
|
|
||||||
" \"f\": [create_track(points) for points in tracks_f],\n",
|
|
||||||
" \"b\": [create_track(points) for points in tracks_b],\n",
|
|
||||||
" },\n",
|
|
||||||
"}\n",
|
|
||||||
"\n",
|
|
||||||
"import json\n",
|
|
||||||
"\n",
|
|
||||||
"json.dump(json_result, open(\"coil.json\", \"w\"))\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# df = pd.DataFrame(coil_A_f, columns=[\"x\", \"y\"])\n",
|
|
||||||
"# ax = df.plot.line(x=\"x\", y=\"y\", label=\"Coil A\", color=\"blue\")\n",
|
|
||||||
"# ax.axis(\"equal\")\n",
|
|
||||||
"# df = pd.DataFrame(coil_A_b, columns=[\"x\", \"y\"])\n",
|
|
||||||
"# ax = df.plot.line(x=\"x\", y=\"y\", label=\"Coil B\", color=\"green\")\n",
|
|
||||||
"# ax.axis(\"equal\")\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# plot the back tracks\n",
|
|
||||||
"ax = None\n",
|
|
||||||
"for track in json_result[\"tracks\"][\"b\"]:\n",
|
|
||||||
" df = pd.DataFrame(track, columns=[\"x\", \"y\"])\n",
|
|
||||||
" ax = df.plot.line(x=\"x\", y=\"y\", color=\"blue\", ax=ax)\n",
|
|
||||||
" ax.axis(\"equal\")\n",
|
|
||||||
"\n",
|
|
||||||
"# plot the front tracks\n",
|
|
||||||
"for track in json_result[\"tracks\"][\"f\"]:\n",
|
|
||||||
" df = pd.DataFrame(track, columns=[\"x\", \"y\"])\n",
|
|
||||||
" ax = df.plot.line(x=\"x\", y=\"y\", color=\"red\", ax=ax)\n",
|
|
||||||
" ax.axis(\"equal\")\n",
|
|
||||||
"\n",
|
|
||||||
"# hide the legend\n",
|
|
||||||
"ax.legend().set_visible(False)\n",
|
|
||||||
"# make the plot bigger\n",
|
|
||||||
"ax.figure.set_size_inches(10, 10)\n",
|
|
||||||
"\n",
|
|
||||||
"# plot the vias\n",
|
|
||||||
"for via in json_result[\"vias\"]:\n",
|
|
||||||
" ax.add_patch(\n",
|
|
||||||
" plt.Circle(\n",
|
|
||||||
" (via[\"x\"], via[\"y\"]),\n",
|
|
||||||
" radius=VIA_DIAM / 2,\n",
|
|
||||||
" fill=True,\n",
|
|
||||||
" color=\"black\",\n",
|
|
||||||
" )\n",
|
|
||||||
" )\n",
|
|
||||||
" ax.add_patch(\n",
|
|
||||||
" plt.Circle(\n",
|
|
||||||
" (via[\"x\"], via[\"y\"]),\n",
|
|
||||||
" radius=VIA_DRILL / 2,\n",
|
|
||||||
" fill=True,\n",
|
|
||||||
" color=\"white\",\n",
|
|
||||||
" )\n",
|
|
||||||
" )\n",
|
|
||||||
"\n",
|
|
||||||
"# plot the edge cuts\n",
|
|
||||||
"ax.add_patch(\n",
|
|
||||||
" plt.Circle(\n",
|
|
||||||
" (0, 0),\n",
|
|
||||||
" radius=STATOR_RADIUS,\n",
|
|
||||||
" fill=False,\n",
|
|
||||||
" color=\"yellow\",\n",
|
|
||||||
" )\n",
|
|
||||||
")\n",
|
|
||||||
"ax.add_patch(\n",
|
|
||||||
" plt.Circle(\n",
|
|
||||||
" (0, 0),\n",
|
|
||||||
" radius=STATOR_HOLE_RADIUS,\n",
|
|
||||||
" fill=False,\n",
|
|
||||||
" color=\"yellow\",\n",
|
|
||||||
" )\n",
|
|
||||||
")\n",
|
|
||||||
"\n",
|
|
||||||
"# plot the pads\n",
|
|
||||||
"for pad in json_result[\"pads\"]:\n",
|
|
||||||
" ax.add_patch(\n",
|
|
||||||
" plt.Circle(\n",
|
|
||||||
" (pad[\"x\"], pad[\"y\"]),\n",
|
|
||||||
" radius=1.7 / 2,\n",
|
|
||||||
" fill=True,\n",
|
|
||||||
" color=\"yellow\",\n",
|
|
||||||
" )\n",
|
|
||||||
" )\n",
|
|
||||||
" ax.add_patch(\n",
|
|
||||||
" plt.Circle(\n",
|
|
||||||
" (pad[\"x\"], pad[\"y\"]),\n",
|
|
||||||
" radius=1.0 / 2,\n",
|
|
||||||
" fill=True,\n",
|
|
||||||
" color=\"white\",\n",
|
|
||||||
" )\n",
|
|
||||||
" )"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
|
@ -44,6 +44,8 @@ class CoilPlugin(pcbnew.ActionPlugin):
|
||||||
track_width = coil_data["parameters"]["trackWidth"]
|
track_width = coil_data["parameters"]["trackWidth"]
|
||||||
stator_hole_radius = coil_data["parameters"]["statorHoleRadius"]
|
stator_hole_radius = coil_data["parameters"]["statorHoleRadius"]
|
||||||
stator_radius = coil_data["parameters"]["statorRadius"]
|
stator_radius = coil_data["parameters"]["statorRadius"]
|
||||||
|
pad_diameter = coil_data["parameters"]["padDiameter"]
|
||||||
|
pad_drill = coil_data["parameters"]["padDrillDiameter"]
|
||||||
via_diameter = coil_data["parameters"]["viaDiameter"]
|
via_diameter = coil_data["parameters"]["viaDiameter"]
|
||||||
via_drill_diameter = coil_data["parameters"]["viaDrillDiameter"]
|
via_drill_diameter = coil_data["parameters"]["viaDrillDiameter"]
|
||||||
|
|
||||||
|
@ -86,11 +88,11 @@ class CoilPlugin(pcbnew.ActionPlugin):
|
||||||
module.SetPosition(pcbnew.wxPointMM(pad["x"], pad["y"]))
|
module.SetPosition(pcbnew.wxPointMM(pad["x"], pad["y"]))
|
||||||
board.Add(module)
|
board.Add(module)
|
||||||
pcb_pad = pcbnew.PAD(module)
|
pcb_pad = pcbnew.PAD(module)
|
||||||
pcb_pad.SetSize(pcbnew.wxSizeMM(1.7, 1.7))
|
pcb_pad.SetSize(pcbnew.wxSizeMM(pad_diameter, pad_diameter))
|
||||||
pcb_pad.SetShape(pcbnew.PAD_SHAPE_CIRCLE)
|
pcb_pad.SetShape(pcbnew.PAD_SHAPE_CIRCLE)
|
||||||
pcb_pad.SetAttribute(pcbnew.PAD_ATTRIB_PTH)
|
pcb_pad.SetAttribute(pcbnew.PAD_ATTRIB_PTH)
|
||||||
pcb_pad.SetLayerSet(pcb_pad.PTHMask())
|
pcb_pad.SetLayerSet(pcb_pad.PTHMask())
|
||||||
pcb_pad.SetDrillSize(pcbnew.wxSizeMM(1.0, 1.0))
|
pcb_pad.SetDrillSize(pcbnew.wxSizeMM(pad_drill, pad_drill))
|
||||||
pcb_pad.SetPosition(pcbnew.wxPointMM(pad["x"], pad["y"]))
|
pcb_pad.SetPosition(pcbnew.wxPointMM(pad["x"], pad["y"]))
|
||||||
pcb_pad.SetNetCode(net.GetNetCode())
|
pcb_pad.SetNetCode(net.GetNetCode())
|
||||||
module.Add(pcb_pad)
|
module.Add(pcb_pad)
|
||||||
|
|
112
helpers.py
Normal file
112
helpers.py
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
# get the point on an arc at the given angle
|
||||||
|
def get_arc_point(angle, radius):
|
||||||
|
return (
|
||||||
|
radius * np.cos(np.deg2rad(angle)),
|
||||||
|
radius * np.sin(np.deg2rad(angle)),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# draw an arc
|
||||||
|
def draw_arc(start_angle, end_angle, radius, step=10):
|
||||||
|
points = []
|
||||||
|
for angle in np.arange(start_angle, end_angle + step, step):
|
||||||
|
x = radius * np.cos(np.deg2rad(angle))
|
||||||
|
y = radius * np.sin(np.deg2rad(angle))
|
||||||
|
points.append((x, y))
|
||||||
|
return points
|
||||||
|
|
||||||
|
|
||||||
|
# roate the points by the required angle
|
||||||
|
def rotate(points, angle):
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
x * np.cos(np.deg2rad(angle)) - y * np.sin(np.deg2rad(angle)),
|
||||||
|
x * np.sin(np.deg2rad(angle)) + y * np.cos(np.deg2rad(angle)),
|
||||||
|
]
|
||||||
|
for x, y in points
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# move the points out to the distance at the requited angle
|
||||||
|
def translate(points, distance, angle):
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
x + distance * np.cos(np.deg2rad(angle)),
|
||||||
|
y + distance * np.sin(np.deg2rad(angle)),
|
||||||
|
]
|
||||||
|
for x, y in points
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# flip the y coordinate
|
||||||
|
def flip_y(points):
|
||||||
|
return [[x, -y] for x, y in points]
|
||||||
|
|
||||||
|
|
||||||
|
def flip_x(points):
|
||||||
|
return [[-x, y] for x, y in points]
|
||||||
|
|
||||||
|
|
||||||
|
def create_pad(radius, angle, name):
|
||||||
|
return {
|
||||||
|
"x": radius * np.cos(np.deg2rad(angle)),
|
||||||
|
"y": radius * np.sin(np.deg2rad(angle)),
|
||||||
|
"name": name,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def create_silk(point, text):
|
||||||
|
return {
|
||||||
|
"x": point[0],
|
||||||
|
"y": point[1],
|
||||||
|
"text": text,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def create_via(point):
|
||||||
|
return {"x": point[0], "y": point[1]}
|
||||||
|
|
||||||
|
|
||||||
|
def create_track(points):
|
||||||
|
return [{"x": x, "y": y} for x, y in points]
|
||||||
|
|
||||||
|
|
||||||
|
def optimize_points(points):
|
||||||
|
# follow the line and remove points that are in the same direction as the previous poin
|
||||||
|
# keep doing this until the direction changes significantly
|
||||||
|
# this is a very simple optimization that removes a lot of points
|
||||||
|
# it's not perfect but it's a good start
|
||||||
|
optimized_points = []
|
||||||
|
for i in range(len(points)):
|
||||||
|
if i == 0:
|
||||||
|
optimized_points.append(points[i])
|
||||||
|
else:
|
||||||
|
vector1 = np.array(points[i]) - np.array(points[i - 1])
|
||||||
|
vector2 = np.array(points[(i + 1) % len(points)]) - np.array(points[i])
|
||||||
|
length1 = np.linalg.norm(vector1)
|
||||||
|
length2 = np.linalg.norm(vector2)
|
||||||
|
if length1 > 0 and length2 > 0:
|
||||||
|
dot = np.dot(vector1, vector2) / (length1 * length2)
|
||||||
|
# clamp dot between -1 and 1
|
||||||
|
dot = max(-1, min(1, dot))
|
||||||
|
angle = np.arccos(dot)
|
||||||
|
if angle > np.deg2rad(5):
|
||||||
|
optimized_points.append(points[i])
|
||||||
|
print("Optimised from {} to {} points".format(len(points), len(optimized_points)))
|
||||||
|
return optimized_points
|
||||||
|
|
||||||
|
|
||||||
|
def chaikin(points, iterations):
|
||||||
|
if iterations == 0:
|
||||||
|
return points
|
||||||
|
l = len(points)
|
||||||
|
smoothed = []
|
||||||
|
for i in range(l - 1):
|
||||||
|
x1, y1 = points[i]
|
||||||
|
x2, y2 = points[i + 1]
|
||||||
|
smoothed.append([0.95 * x1 + 0.05 * x2, 0.95 * y1 + 0.05 * y2])
|
||||||
|
smoothed.append([0.05 * x1 + 0.95 * x2, 0.05 * y1 + 0.95 * y2])
|
||||||
|
smoothed.append(points[l - 1])
|
||||||
|
return chaikin(smoothed, iterations - 1)
|
140
pcb_json.py
Normal file
140
pcb_json.py
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
import json
|
||||||
|
import pandas as pd
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
|
||||||
|
def create_track(points):
|
||||||
|
return [{"x": x, "y": y} for x, y in points]
|
||||||
|
|
||||||
|
|
||||||
|
def dump_json(
|
||||||
|
filename,
|
||||||
|
stator_radius,
|
||||||
|
stator_hole_radius,
|
||||||
|
track_width,
|
||||||
|
pad_diam,
|
||||||
|
pad_drill,
|
||||||
|
via_diam,
|
||||||
|
via_drill,
|
||||||
|
vias,
|
||||||
|
pads,
|
||||||
|
silk,
|
||||||
|
tracks_f,
|
||||||
|
tracks_b,
|
||||||
|
):
|
||||||
|
# dump out the results to json
|
||||||
|
json_result = {
|
||||||
|
"parameters": {
|
||||||
|
"trackWidth": track_width,
|
||||||
|
"statorHoleRadius": stator_hole_radius,
|
||||||
|
"statorRadius": stator_radius,
|
||||||
|
"viaDiameter": via_diam,
|
||||||
|
"viaDrillDiameter": via_drill,
|
||||||
|
"padDiameter": pad_diam,
|
||||||
|
"padDrillDiameter": pad_drill,
|
||||||
|
},
|
||||||
|
"vias": vias,
|
||||||
|
"pads": pads,
|
||||||
|
"silk": silk,
|
||||||
|
"tracks": {
|
||||||
|
"f": [create_track(points) for points in tracks_f],
|
||||||
|
"b": [create_track(points) for points in tracks_b],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
json.dump(json_result, open(filename, "w"))
|
||||||
|
return json_result
|
||||||
|
|
||||||
|
|
||||||
|
def plot_json(json_result):
|
||||||
|
stator_radius = json_result["parameters"]["statorRadius"]
|
||||||
|
stator_hole_radius = json_result["parameters"]["statorHoleRadius"]
|
||||||
|
pad_diam = json_result["parameters"]["padDiameter"]
|
||||||
|
pad_drill = json_result["parameters"]["padDrillDiameter"]
|
||||||
|
# track_width = json_result["parameters"]["trackWidth"]
|
||||||
|
via_dim = json_result["parameters"]["viaDiameter"]
|
||||||
|
via_drill = json_result["parameters"]["viaDrillDiameter"]
|
||||||
|
# plot the back tracks
|
||||||
|
ax = None
|
||||||
|
for track in json_result["tracks"]["b"]:
|
||||||
|
df = pd.DataFrame(track, columns=["x", "y"])
|
||||||
|
ax = df.plot.line(x="x", y="y", color="blue", ax=ax)
|
||||||
|
ax.axis("equal")
|
||||||
|
|
||||||
|
# plot the front tracks
|
||||||
|
for track in json_result["tracks"]["f"]:
|
||||||
|
df = pd.DataFrame(track, columns=["x", "y"])
|
||||||
|
ax = df.plot.line(x="x", y="y", color="red", ax=ax)
|
||||||
|
ax.axis("equal")
|
||||||
|
|
||||||
|
# hide the legend
|
||||||
|
ax.legend().set_visible(False)
|
||||||
|
# make the plot bigger
|
||||||
|
ax.figure.set_size_inches(10, 10)
|
||||||
|
|
||||||
|
# plot the vias
|
||||||
|
for via in json_result["vias"]:
|
||||||
|
ax.add_patch(
|
||||||
|
plt.Circle(
|
||||||
|
(via["x"], via["y"]),
|
||||||
|
radius=via_dim / 2,
|
||||||
|
fill=True,
|
||||||
|
color="black",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ax.add_patch(
|
||||||
|
plt.Circle(
|
||||||
|
(via["x"], via["y"]),
|
||||||
|
radius=via_drill / 2,
|
||||||
|
fill=True,
|
||||||
|
color="white",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# plot the edge cuts
|
||||||
|
ax.add_patch(
|
||||||
|
plt.Circle(
|
||||||
|
(0, 0),
|
||||||
|
radius=stator_radius,
|
||||||
|
fill=False,
|
||||||
|
color="yellow",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ax.add_patch(
|
||||||
|
plt.Circle(
|
||||||
|
(0, 0),
|
||||||
|
radius=stator_hole_radius,
|
||||||
|
fill=False,
|
||||||
|
color="yellow",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# plot the pads
|
||||||
|
for pad in json_result["pads"]:
|
||||||
|
ax.add_patch(
|
||||||
|
plt.Circle(
|
||||||
|
(pad["x"], pad["y"]),
|
||||||
|
radius=pad_diam / 2,
|
||||||
|
fill=True,
|
||||||
|
color="yellow",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ax.add_patch(
|
||||||
|
plt.Circle(
|
||||||
|
(pad["x"], pad["y"]),
|
||||||
|
radius=pad_drill / 2,
|
||||||
|
fill=True,
|
||||||
|
color="white",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# plot the silk
|
||||||
|
for silk in json_result["silk"]:
|
||||||
|
ax.text(
|
||||||
|
silk["x"],
|
||||||
|
silk["y"],
|
||||||
|
silk["text"],
|
||||||
|
horizontalalignment="center",
|
||||||
|
verticalalignment="center",
|
||||||
|
color="black",
|
||||||
|
fontsize=50,
|
||||||
|
)
|
|
@ -3,4 +3,4 @@ jupyter
|
||||||
numpy
|
numpy
|
||||||
pandas
|
pandas
|
||||||
scikit-spatial
|
scikit-spatial
|
||||||
scipy
|
pre-commit
|
Loading…
Reference in a new issue