#usage "This ULP calculates and place a coil."
"Depending from where you are starting the ULP, places pads (library) or vias (board).
"
"The calculation of coils or inductivities depends on a lot of "
"different factors, like
"
" -- basic material of the board
"
" -- thickness of the board
"
" -- number of layers
"
" -- thickness of the layers
"
" -- distances between elements
"
" -- tracks
"
" -- copper areas / ground plains
"
" -- thickness of the copper layers
"
" -- track width
"
" -- distances between tracks
"
" -- surface of tracks (tin?)
"
" -- the signal's frequency
"
" -- ...
"
"All these factors should be taken into consideration for the formula !
"
"used below to calculate an exact value for a coil. Nevertheless it !
"
"is necessary to check the result by a practical measurement. It is !
"
"very difficult to generate coils with exact values this way.
"
"Generally one can say that printed coils can be used in the MHz range only.
"
"Author: support@cadsoft.de,
";
// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND,
// EXPRESSED OR IMPLIED.
#require 4.1106
string Help = usage;
// **************----- german description -------------***************
// ----------------------------------------------------------------
string deHelp =
"Dieses ULP berechnet eine Spiralspule." +
"Dieses ULP kann in der Libary ebenso wie im Board benutzt werden.
" +
"Je nachdem ob Sie es von einer Library oder von einem Borad aus "
"starten, werden Pads bzw. Vias plaziert.
" +
"
" +
"Die Berechnung der Windungen bzw. der Induktivitaet haengt von vielen Faktoren ab, wie z.B.:
" +
" - Basismaterial
" +
" - Staerke der Leiterplatte
" +
" - Anzahl der Lagen
" +
" - Dicke der Lagen
" +
" - Abstand zu benachbarten Bauteilen, Leitungen, Kupferflaechen, Masseflaechen etc.
" +
" - Dicke der Kupferbeschichtung
" +
" - Breite der Leiterbahn (unteraetzen)
" +
" - Abstand zwischen den Leiterbahnen (Spiralkreise / Ätzgenauigkeit)
" +
" - Oberflaeche der Leiterbahn (Verzinnt)
" +
" - Signal-Frequenz
" +
" - ...
" +
"Um daraus einen einigermassen genauen Wert zu berechnen, muessten alle oben genannten Faktoren
" +
"als Korrekturwerte in die Formael einfliessen.
" +
"Was aber in jedem Fall durch entspechende Messungen nachgeprueft werden muesste.
" +
"In der Praxis sind Printspulen mit genau definierten Werten und in engen Toleranzen " +
"nur sehr schwer herzustellen.
" +
"Im Allgemeinen kann man davon ausgehen, dass Printspulen nur im MHz Bereich " +
"einigermassen Nutzbar sind.
" +
"Author: support@cadsoft.de,
";
if (language() == "de") Help = deHelp;
// 05.06.2002 alf@cadsoft.de
// 24.01.2005 alf@cadsoft.de
// ******************************************************************
// Parameterliste -- parameter section
real n = 4.0; // number of turns
real Wirewidth_mm = 0.2; // track width
real Wiredistance_mm = 0.2; // min. distance between tracks
real Diameter = 0.6; // pad/via diameter
real Drill = 0.4; // drill diameter
real offx = 0.0;
real offy = 0.0;
real UserArc;
int windn;
int wind1; // count of total turns
real windlast; // reminder Turn
real Ndist; // distance between turns
string Shape = "ROUND"; // Pad/Via-Form nicht veraendern
string direction = "CCW"; // *** Drehrichtung der Spirale nicht veraendern ***
// *** Direction do not change ***
string solderpoint;
string cmd = "";
string s;
int Layer = 1;
/* calculate X coordinate by Radius */
real Xneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserArc) {
real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin)));
real NewArc; /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */
{
if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */
NewArc = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserArc;
real rad = PI / 180 * NewArc;
return (RADIUS * cos(rad));
}
if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */
NewArc = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserArc;
real rad = PI / 180 * NewArc;
return (RADIUS * cos(rad));
}
if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */
NewArc = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserArc;
real rad = PI / 180 * NewArc;
return (RADIUS * cos(rad));
}
if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */
NewArc = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserArc;
real rad = PI / 180 * NewArc;
return (RADIUS * cos(rad));
}
if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */
NewArc = (Xalt - Xorigin) + UserArc;
real rad = PI / 180 * NewArc;
return (RADIUS * cos(rad));
}
if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90° */
NewArc = (Xalt - Xorigin + 90) + UserArc;
real rad = PI / 180 * NewArc;
return (RADIUS * cos(rad));
}
if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270° */
NewArc = (Xalt - Xorigin + 270)+ UserArc;
real rad = PI / 180 * NewArc;
return (RADIUS * cos(rad));
}
}
}
/* calculate Y coordinate by Radius */
real Yneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserArc) {
real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin)));
real NewArc; /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */
{
if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */
NewArc = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserArc;
real rad = PI / 180 * NewArc;
return (RADIUS * sin(rad));
}
if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */
NewArc = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserArc;
real rad = PI / 180 * NewArc;
return (RADIUS * sin(rad));
}
if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */
NewArc = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserArc;
real rad = PI / 180 * NewArc;
return (RADIUS * sin(rad));
}
if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */
NewArc = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserArc;
real rad = PI / 180 * NewArc;
return (RADIUS * sin(rad));
}
if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */
NewArc = (Xalt - Xorigin) + UserArc;
real rad = PI / 180 * NewArc;
return (RADIUS * sin(rad));
}
if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90° */
NewArc = (Xalt - Xorigin + 90) + UserArc;
real rad = PI / 180 * NewArc;
return (RADIUS * sin(rad));
}
if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270° */
NewArc = (Xalt - Xorigin + 270)+ UserArc;
real rad = PI / 180 * NewArc;
return (RADIUS * sin(rad));
}
}
}
/* place a Pad (Via) on startpoint */
void PadViaS(real x1, real x2, real w, real g) {
real p = x1 + (Wirewidth_mm / 2) - (Diameter / 2); //
sprintf( s, "%s (%4.2f %4.2f);\n", solderpoint , p + offx , 0.0 + offy);
cmd += s;
}
/* place a Pad (Via) on endpoint */
void PadViaE(real x1, real x2, real w, real g) {
real pRadius = x2 + ((x1 - x2) / 180 * g) + (Diameter / 2) - (Wirewidth_mm / 2) ;
real px = Xneu(pRadius, 0, 0, 0, w);
real py = Yneu(pRadius, 0, 0, 0, w);
sprintf( s, "%s (%4.2f %4.2f);\n", solderpoint, px + offx, py + offy);
cmd += s;
}
void doit(void) {
Ndist = (Wiredistance_mm + Wirewidth_mm ) ; // distance ARC to ARC
windn = round(n); // liefert x gerundet auf den nächsten Integer-Wert.
wind1 = trunc(n); // liefert den ganzzahligen Teil von n.
windlast = n - wind1; // rest der letzten Windung
UserArc = 360 * windlast;
real startarc = 0;
real endarc = 0;
real end2arc = 0;
real Y = 0;
int x = 0;
real ewx ;
real ewy ;
sprintf( s, "GRID mm;\n");
cmd += s;
sprintf( s, "Change dia %4.2f;\n", Diameter);
cmd += s;
sprintf( s, "Change shape %s;\n", Shape);
cmd += s;
sprintf( s, "Change drill %4.2f;\n", Drill);
cmd += s;
PadViaS( Ndist, Ndist, 0, 0);
sprintf( s, "change width %4.3f;\n", Wirewidth_mm);
cmd += s;
sprintf( s, "Change layer %d;\n", Layer);
cmd += s;
// full turns
for (x = 1; x <= wind1; x++) {
// first ARC -|- erster Halbbogen
startarc = x * Ndist;
endarc = -(x * Ndist + (Ndist / 2));
sprintf( s, "ARC '%s' (%6.3f %6.3f) (%6.3f %6.3f) (%6.3f %6.3f);\n",
direction, startarc + offx, Y + offy, endarc + offx, Y + offy, endarc + offx, Y + offy);
cmd += s;
// second ARC -|- zweiter Halbbogen
end2arc = (x + 1) * Ndist;
sprintf( s, "ARC (%6.3f %6.3f) (%6.3f %6.3f) (%6.3f %6.3f);\n",
endarc + offx, Y + offy, end2arc + offx, Y + offy, end2arc + offx, Y + offy);
cmd += s;
}
// last turn
if (UserArc >= 270) { // ***** 270° - 359°
// first ARC -|- erster Halbbogen
startarc = (x ) * Ndist;
endarc = -((x * Ndist) + (Ndist / 2));
sprintf( s, "ARC (%6.3f %6.3f) (%6.3f %6.3f) (%6.3f %6.3f);\n",
startarc + offx, Y + offy, endarc + offx, Y + offy, endarc + offx, Y + offy);
cmd += s;
// finish ARC -|- letzter Halbbogen
end2arc = (x + 1) * Ndist + (Ndist / 8);
ewx = Xneu(end2arc, 0, 0, 0, UserArc);
ewy = Yneu(end2arc, 0, 0, 0, UserArc);
sprintf( s, "ARC (%6.3f %6.3f) (%6.3f %6.3f) (%6.3f %6.3f);\n",
endarc + offx, Y + offy, end2arc + offx, Y + offy, ewx + offx, ewy + offy);
cmd += s;
PadViaE( end2arc, -endarc, UserArc, UserArc - 180);
UserArc = 0;
}
else if (UserArc >= 180) { // ***** 180° - 270°
// finish ARC -|- letzter Halbbogen
startarc = (x ) * Ndist;
endarc = -((x * Ndist) + (Ndist / 2));
sprintf( s, "ARC (%6.3f %6.3f) (%6.3f %6.3f) (%6.3f %6.3f);\n",
startarc + offx, Y + offy, endarc + offx, Y + offy, endarc + offx, Y + offy);
cmd += s;
// finish ARC -|- letzter Halbbogen
end2arc = (x + 1) * Ndist + (Ndist / 2);
ewx = Xneu(end2arc, 0, 0, 0, UserArc);
ewy = Yneu(end2arc, 0, 0, 0, UserArc);
sprintf( s, "ARC (%6.3f %6.3f) (%6.3f %6.3f) (%6.3f %6.3f);\n",
endarc + offx, Y + offy, end2arc + offx, Y + offy, ewx + offx, ewy + offy);
cmd += s;
PadViaE(end2arc, -endarc, UserArc, UserArc - 180);
UserArc = 0;
}
else if (UserArc >= 90) { // ***** 90° - 180°
// finish ARC -|- letzter Halbbogen
startarc = (x ) * Ndist;
endarc = -((x * Ndist) + (Ndist / 2));
ewx = Xneu(startarc, 0, 0, 0, UserArc);
ewy = Yneu(startarc, 0, 0, 0, UserArc);
sprintf( s, "ARC (%6.3f %6.3f) (%6.3f %6.3f) (%6.3f %6.3f);\n",
startarc + offx, Y + offy, endarc + offx, Y + offy, ewx + offx, ewy + offy);
cmd += s;
PadViaE(-endarc, startarc , UserArc, UserArc);
UserArc = 0;
}
else if (UserArc > 0) { // ***** 0° - 90°
// finish ARC -|- letzter Halbbogen
startarc = (x ) * Ndist;
endarc = -((x * Ndist) + (Ndist / 2));
ewx = Xneu(startarc, 0, 0, 0, UserArc);
ewy = Yneu(startarc, 0, 0, 0, UserArc);
sprintf( s, "ARC (%6.3f %6.3f) (%6.3f %6.3f) (%6.3f %6.3f);\n",
startarc + offx, Y + offy, endarc + offx, Y + offy, ewx + offx, ewy + offy);
cmd += s;
PadViaE(-endarc, startarc ,UserArc, UserArc );
}
else if (UserArc == 0) {
startarc = (x ) * Ndist;
endarc = -((x * Ndist) + (Ndist / 2));
PadViaE(-endarc, startarc ,UserArc, UserArc );
}
sprintf( s, "Change Layer tPlace;\n");
sprintf( s, "window (%6.3f %6.3f);\n", offx, offy);
cmd += s;
exit (cmd);
}
// *** main ***
if (board) board(B) { solderpoint = "VIA"; };
if (library) library(L) {solderpoint = "PAD"; };
string ulp_path = filedir(argv[0]);
string Spiral_H = "";
dlgDialog("Copper Spiral") {
dlgHBoxLayout {
dlgVBoxLayout {
dlgHBoxLayout {
dlgLabel("&Turns"); // number of turns (Windungen)
dlgRealEdit( n, 1.0, 100.0);
dlgStretch(1);
}
dlgLabel(Spiral_H);
dlgHBoxLayout {
}
}
dlgVBoxLayout {
dlgGridLayout {
dlgCell(1, 1) dlgLabel("wire &width 'w'"); // track width
dlgCell(1, 2) dlgRealEdit(Wirewidth_mm, 0.01, 25.0);
dlgCell(2, 1) dlgLabel("wire &distance 'd'"); // min. distance between tracks
dlgCell(2, 2) dlgRealEdit(Wiredistance_mm, .01, 25.0);
dlgCell(3, 1) dlgLabel("Via/Pad di&ameter"); // pad/via diameter
dlgCell(3, 2) dlgRealEdit(Diameter, 0.1, 10.0);
dlgCell(4, 1) dlgLabel("Via/Pad d&rill"); // drill diameter
dlgCell(4, 2) dlgRealEdit(Drill, .1, 10.0);
dlgCell(5, 1) dlgLabel("&Layer"); // Layer number
dlgCell(5, 2) dlgIntEdit(Layer, 1, 255);
dlgCell(6, 1) dlgLabel("
");
dlgCell(6, 2) dlgLabel("
");
dlgCell(7, 1) dlgLabel("offset &X"); // place with offset X
dlgCell(7, 2) dlgRealEdit( offx );
dlgCell(8, 1) dlgLabel("offset &Y"); // place with offset Y
dlgCell(8, 2) dlgRealEdit( offy );
}
dlgStretch(1);
}
}
dlgLabel("All measures in mm");
dlgHBoxLayout {
dlgPushButton("+&OK") { dlgAccept(); doit(); }
dlgPushButton("-&Cancel") { dlgReject(); exit(0); }
dlgStretch(1);
dlgPushButton("&Help") dlgMessageBox(Help, "Ok");
}
};