Added Opamp Table and Sine Kreis to Schaltungstheorie
All checks were successful
Build Typst PDFs (Docker) / build-typst (push) Successful in 27s

This commit is contained in:
alexander
2026-02-04 21:07:39 +01:00
parent f73195234f
commit ea73769927
4 changed files with 781 additions and 20 deletions

View File

@@ -1,14 +1,18 @@
#import "@preview/mannot:0.3.1"
#import "@preview/zap:0.5.0"
#import "@preview/cetz:0.4.2" :*
#import "@preview/cetz:0.4.2" : *
#import "@preview/cetz-plot:0.1.3"
#import "../lib/circuit.typ" : *
#import "@preview/unify:0.7.1": num,qty,unit
#import "@preview/cetz-plot:0.1.3"
#import "../lib/schaltungstheorie/opampTable.typ" : *
#import "../lib/schaltungstheorie/tumCustomSymbols.typ" as tumSymbols
#import "../lib/circuit.typ" : *
#import "../lib/common_rewrite.typ" : *
#import "../lib/circuit.typ" : *
#set math.mat(delim: "[")
#show math.equation.where(block: true): it => math.inline(it)
#set math.mat(delim: "[")
@@ -260,7 +264,7 @@
wire("I0.in", "R1.in")
wire("R1.in", (rel: (0.5, 0)), i: (content: $i$, invert: true))
cetz.draw.content((0.62, -0.75), [$R$])
cetz.draw.content((0.62, -0.75), [$G_i$])
cetz.draw.set-style(mark: (end: ">", fill: black, scale: 0.6))
cetz.draw.content((1.7, -0.75), [$u$])
cetz.draw.line((1.5, -0.1), (1.5, -1.4), stroke: 0.5pt)
@@ -278,7 +282,7 @@
)
wire((0, -1.5), (1.75, -1.5))
cetz.draw.content((0.62, -0.75), [$R$])
cetz.draw.content((0.62, -0.75), [$R_i$])
cetz.draw.set-style(mark: (end: ">", fill: black, scale: 0.6))
cetz.draw.content((1.95, -0.75), [$u$])
cetz.draw.line((1.75, -0.1), (1.75, -1.4), stroke: 0.5pt)
@@ -286,23 +290,22 @@
),
[
$u = R_i i + u_0$ \
$u = R_i i + U_0$ \
],
[
$i = 1/R_i u - I_0$
$i = G_i u - I_0$
],
table.cell(colspan: 2)[
#align($-->$)
],
table.cell(colspan: 2)[
$<--$
],
align(center, text(size: 7mm, $-->$)),
[$G_i = 1/R_i \ I_0 = U_0 G_i$],
[$R_i = 1/G_i \ U_0 = I_0 R_i$],
align(center, text(size: 7mm, $<--$)),
)
]
// Quell Wandlung
/*// Quell Wandlung
#bgBlock(fill: colorEineTore)[
#subHeading(fill: colorEineTore)[Quelle Wandlung]
@@ -369,6 +372,8 @@
]
);
]
*/
// Bauelemente
#bgBlock(fill: colorEineTore)[
#subHeading(fill: colorEineTore)[Bauelemente]
@@ -1293,6 +1298,7 @@
#subHeading(fill: colorComplexAC)[Komplexe Komponent]
#table(
columns: (1fr, 2fr, 2fr, 2fr),
inset: (bottom: 2mm, top: 2mm),
fill: (x, y) => if calc.rem(y, 2) == 1 { tableFillLow } else { tableFillHigh },
[], [*$Y = U/I$*], [*$Z = I/U$*], [*$phi$*],
[], [*$Omega$*], [*$S$*], [*rad*],
@@ -1347,11 +1353,20 @@
#bgBlock(fill: colorAllgemein, [
#subHeading(fill: colorAllgemein, [Sin-Table])
#sinTable
#SineCircle()
])
]
#pagebreak()
#bgBlock(fill: colorZweiTore, width: 100%)[
#subHeading(fill: colorZweiTore)[OpAmp Schaltungen]
#scale(opampTable, 100%)
]
#bgBlock(fill: colorZweiTore, width: 100%)[
#subHeading(fill: colorZweiTore)[Zwei-Tor-Übersichts]
@@ -1579,12 +1594,12 @@
content((0.75, 0.75), "In")
})
]),
$bold(R)$,
$bold(G)$,
$bold(H)$,
$bold(H')$,
$bold(A)$,
$bold(A')$,
$bold(R) quad mat(Omega, Omega; Omega, Omega)$,
$bold(G) quad mat(S, S; S, S)$,
$bold(H) quad mat(Omega, 1; 1, S)$,
$bold(H') quad mat(S, 1; 1, Omega)$,
$bold(A) quad mat(S, 1; 1, Omega)$,
$bold(A') quad mat(S, 1; 1, Omega)$,
$bold(R)$,
$mat(r_11, r_12; r_21, r_22)$,

View File

@@ -1,3 +1,5 @@
#import "@preview/cetz:0.4.2"
#let bgBlock(body, fill: color, width: 100%) = block(body, fill:fill.lighten(80%), width: width, inset: (bottom: 2mm, left: 2mm, right: 2mm,))
#let SeperatorLine = line(length: 100%, stroke: (paint: black, thickness: 0.3mm))
@@ -66,8 +68,51 @@
$z^* = a - #i b = r e^(-#i phi)$
Konjungiert Erweitern:\
$(a + b #i)/(c + d #i) = ((a + b #i)(c - d #i))/(c^2 + d² )$
$r = abs(z) quad phi = cases(
+ arccos(a/r) space : space a >= 0,
- arccos(a/r) space : space a < 0,
)$
]
]
#let SineCircle() = {
align(center+horizon,
cetz.canvas({
import cetz.draw : *
line((-33mm, 0), (33mm, 0), stroke: (paint: rgb("#8e8e8e7f")))
line((0, -33mm), (0, 33mm), stroke: (paint: rgb("#8e8e8e7f")))
let labels = (
(0deg, $0°$, $0$),
(30deg, $30°$, $pi/6$),
(45deg, $45°$, $pi/4$),
(60deg, $60°$, $pi/3$),
(90deg, $90°$, $pi/2$),
(120deg, $120°$, $2pi/3$),
(135deg, $135°$, $3pi/4$),
(150deg, $150°$, $5pi/6$),
(180deg, $180°$, $pi$),
(210deg, $210°$, $7pi/6$),
(225deg, $2250°$, $5pi/4$),
(240deg, $240°$, $4pi/3$),
(270deg, $270°$, $3pi/2$),
(300deg, $300°$, $5pi/3$),
(315deg, $3150°$, $7pi/4$),
(330deg, $330°$, $11pi/6$),
)
circle((0, 0), radius: 25mm)
for (pos, label1, label2) in labels {
line((radius: 24mm, angle: pos), (radius: 26mm, angle: pos))
content((radius: 20.0mm, angle: pos), label1, anchor: "mid", angle: if(pos > 90deg and pos < 270deg) {pos + 180deg} else {pos})
content((radius: 29.5mm, angle: pos), label2, anchor: "mid")
}
})
)
}

View File

@@ -0,0 +1,271 @@
#import "@preview/zap:0.5.0"
#import "@preview/cetz:0.4.2"
#import "tumCustomSymbols.typ" as joham
#import "../common_rewrite.typ" : *
#let opampTable = table(
columns: (auto, auto, auto, auto, auto, auto),
align: center + horizon,
inset: (x, y) => if(y > 0) {3mm} else {2mm},
fill: (x, y) => if calc.rem(x, 2) == 1 { tableFillHigh } else { tableFillLow },
table.header(
[*Spannungsfolger*],
[*Invertierender Verstärker*],
[*Nicht invertierender Verstärker*],
[*Ideale Diode*],
[*NIK*],
[*Gyrator*]),
zap.circuit({
import zap: *
set-style(vsource: (radius: 0.3))
joham.ideal-opamp("O", (2, 0), scale: 0.4, invert: true)
node("MU", (rel: (0.2, 0), to: "O.out"))
cetz.draw.anchor("MM", (rel: (0, -0.65), to: "MU"))
node("MB", (2, -1))
node("A", (rel: (-0.7, 0), to: "O.plus"), fill: false)
node("C", (rel: (0.7, 0), to: "O.out"), fill: false)
node("D", (rel: (0.7, -1), to: "O.out"), fill: false)
node("B", ("A", "|-", "MB"), fill: false)
wire("O.ground", "MB")
wire("B", "MB")
wire("MB", "D")
wire("A", "O.plus")
wire("O.out", "C")
zwire("O.minus", "MM", ratio: -30%)
wire("MM", "MU")
joham.ground("G1", "MB", scale: 0.7)
joham.voltage("A", "B", $u_"in"$)
joham.voltage("C", "D", anchor: "west", $u_"out"$)
}),
zap.circuit({
import zap: *
set-style(vsource: (radius: 0.3))
let height = 2 / 3;
node("A", (0, height), fill: false)
node("B", (0, -height), fill: false)
node("C", (3, height), fill: false)
node("D", (3, -height), fill: false)
node("MU", (1.25, height))
node("MB", (1.25, -height))
node("OU", (2.5, height))
node("OB", (2, -height))
joham.ideal-opamp("O", (2, 0), scale: 0.4)
resistor("R1", "A", "MU", scale: 0.4, label: (content: $R_1$, distance: 3pt), fill: none)
wire("B", "MB")
zwire("MU", "O.minus", ratio: 0%)
zwire("MB", "O.plus", ratio: 0%)
resistor("R0", "MU", "OU", scale: 0.4, label: (content: $R_0$, distance: 3pt))
wire("OU", "C")
wire("O.ground", "OB")
wire("MB", "OB")
wire("OB", "D")
zwire("O.out", "OU", ratio: 100%)
joham.ground("G1", "MB", scale: 0.7)
joham.voltage("A", "B", $u_"in"$)
joham.voltage("C", "D", anchor: "west", $u_"out"$)
}),
zap.circuit({
import zap: *
set-style(vsource: (radius: 0.3))
joham.ideal-opamp("O", (2, 0), scale: 0.4, invert: true)
node("MU", (rel: (0.2, 0), to: "O.out"))
node("MM", (rel: (0, -1), to: "MU"))
node("MB", (rel: (0, -1), to: "MM"))
node("A", (rel: (-0.7, 0), to: "O.plus"), fill: false)
node("C", (rel: (1, 0), to: "O.out"), fill: false)
node("D", (rel: (1, -2), to: "O.out"), fill: false)
node("B", ("A", "|-", "MB"), fill: false)
node("G", (2, -2))
wire("O.ground", "G")
resistor("R0", "MU", "MM", scale: 0.4, label: (content: $R_0$, distance: 3pt), fill: none)
resistor("R1", "MM", "MB", scale: 0.4, label: (content: $R_1$, distance: 3pt), fill: none)
wire("MB", "D")
wire("A", "O.plus")
wire("O.out", "C")
wire("B", "MB")
zwire("O.minus", "MM", ratio: -30%)
joham.ground("G1", "G", scale: 0.7)
joham.voltage("A", "B", $u_"in"$)
joham.voltage("C", "D", anchor: "west", $u_"out"$)
}),
zap.circuit({
import zap: *
set-style(vsource: (radius: 0.3))
joham.ideal-opamp("O", (2, 0), scale: 0.4)
node("G", (2, -0.75))
node("MU", (rel: (-0.4, 0), to: "O.minus"))
node("MB", ("MU", "|-", "G"))
node("A", (rel: (-1.2, 0), to: "O.minus"), fill: false)
node("B", ("A", "|-", "G"), fill: false)
joham.diode("D1", (rel: (0, 0.5), to: "MU"), (rel: (1.4, 0)), scale: 0.6, type: "real")
wire("O.ground", "G")
wire("B", "G")
wire("A", "O.minus")
zwire("MB", "O.plus", ratio: 0%)
wire("D1.in", "MU")
zwire("D1.out", "O.out", ratio: 0%)
joham.ground("G1", "G", scale: 0.7)
joham.voltage("A", "B", $u$)
}),
zap.circuit({
import zap: *
node("A", (-1.4, 0), fill: false)
node("C", (1.4, 0), fill: false)
node("B", (-1.4, -1.4), fill: false)
node("D", (1.4, -1.4), fill: false)
node("E", (0.7, -1.4))
node("F", (0, 0))
joham.ideal-opamp("O", (0, -0.6), scale: 0.4, angle: 90deg)
wire("B", "E")
wire("D", "E")
node("G", (to: "A", rel: (0.4, 0)))
node("H", (to: "C", rel: (-0.4, 0)))
wire("A", "G", i: (content: $i_"in"$, distance: 3pt, scale: 0.7))
wire("C", "H")
resistor("R1", "G", "F", scale: 0.4, label: (content: $R$, anchor: "south", distance: 3pt), fill: none)
resistor("R2", "H", "F", scale: 0.4, label: (content: $R$, anchor: "north", distance: 3pt), fill: none)
zwire("G", "O.minus", ratio: 115%, axis: "y")
zwire("H", "O.plus", ratio: 115%, axis: "y")
wire("O.out", "F")
zwire("E", "O.ground", ratio: 0%)
joham.ground("G1", "E", scale: 0.7)
resistor("R3", (rel: (0.2, 0), to: "C"), (rel: (0.2, 0), to: "D"), scale: 0.4, label: (content: $R_L$, distance: 3pt), fill: none)
wire("R3.in", "C")
wire("R3.out", "D")
joham.voltage("A", "B", $u_"in"$)
}),
scale(80%, zap.circuit({
import zap: *
set-style(vsource: (radius: 0.3))
joham.ideal-opamp("O1", (-1, 0), scale: 0.4, angle: 90deg, invert: true)
joham.ideal-opamp("O2", (1, 0), scale: 0.4, angle: 90deg)
node("MM", (0, -0.6))
node("MB", (0, -0.9))
node("MBL", (rel: (-0.3, 0), to: "MB"))
node("MBR", (rel: (0.3, 0), to: "MB"))
node("MU", (0, 1))
node("RU", (1, 1))
node("LU", (-1, 1))
node("LLU", (rel: (-1, 0), to: "LU"))
node("RRU", (rel: (1.3, 0), to: "RU"))
node("A", (rel: (-0.5, 0), to: "LLU"), fill: false)
node("B", ("A", "|-", "MB"), fill: false)
node("D", (rel: (0.2, 0.4), to: "RU"), fill: false)
node("C", (rel: (-0.2, 0.4), to: "RRU"), fill: false)
resistor("R1", "MU", "LU", scale: 0.4, label: (content: $R$, distance: 3pt, anchor: "south"))
resistor("R2", "RU", "MU", scale: 0.4, label: (content: $R$, distance: 3pt, anchor: "south"))
resistor("R3", "LU", "LLU", scale: 0.4, label: (content: $R$, distance: 3pt, anchor: "south"))
resistor("R4", (rel: (0.3, 0), to: "RRU"), ((rel: (0.3, 0), to: "RRU"), "|-", "MB"), scale: 0.4, label: (content: $R$, distance: 3pt))
joham.ground("G", "MB", scale: 0.7)
wire("O1.out", (rel: (0, 0.2)), (rel: (0, -0.2), to: "RU"), "RU")
wire("O2.out", (rel: (0, 0.2)), (rel: (0, -0.2), to: "LU"), "LU")
wire("MM", "MU")
zwire("O1.minus", "MM", ratio: 0%)
zwire("O2.minus", "MM", ratio: 0%)
wire("O1.plus", ("O1.plus", "|-", "MM"), ("MM", "-|", "LLU"), "LLU")
wire("LLU", "A")
wire("MBL", "B")
wire("MBL", "MB")
wire("MBR", "MB")
zwire("O1.ground", "MBL", ratio: 100%)
zwire("O2.vcc", "MBR", ratio: 100%)
wire("O2.plus", ("O2.plus", "|-", "MM"), ("MM", "-|", "RRU"), "RRU")
wire("R4.in", "RRU")
wire("R4.out", "MBR")
zwire("D", "RU", ratio: 0%)
zwire("C", "RRU", ratio: 0%)
joham.voltage("A", "B", $u_"in"$)
joham.voltage("D", "C", anchor: "south", $u_"out"$)
})),
$u_"out" = u_"in"$,
$u_"out" = - R_0/R_1 u_"in"$,
$u_"out" = (1 + R_0 / R_1) u_"in"$,
$$,
$u_"in" = -R_L i_"in"$
)

View File

@@ -0,0 +1,430 @@
#import "@preview/zap:0.4.0": * // TODO: Using wrong version, because 5.0.0 breaks custom stuff
#import "@preview/cetz:0.4.2": draw
#import cetz.draw: *
#let norator(name, node, scale: 1.0, ..params) = {
let custom-style = (
width: 1.41 * scale,
height: 1.41 * scale
)
let draw(ctx, position, style) = {
interface((-custom-style.width / 2, -custom-style.height / 2), (custom-style.width / 2, custom-style.height / 2), io: position.len() < 2)
merge-path(close: true, {
arc((-custom-style.width / 2, 0), radius: custom-style.height / 5, start: 45deg, stop: 315deg, anchor: "arc-center", name: "right-arc")
arc((custom-style.width / 2, 0), radius: custom-style.height / 5, start: 135deg, stop: -135deg, anchor: "arc-center", name: "left-arc")
})
}
component("norator", name, node, draw: draw, ..params)
}
#let nullator(name, node, scale: 1.0, ..params) = {
let custom-style = (
width: 1.41 * scale,
height: 1.41 * scale
)
let draw(ctx, position, style) = {
interface((-custom-style.width / 2, -custom-style.height / 2), (custom-style.width / 2, custom-style.height / 2), io: position.len() < 2)
circle((0, 0), radius: (custom-style.width / 2, custom-style.height / 6))
}
component("nullator", name, node, draw: draw, ..params)
}
#let diode(name, node, type: none, ..params) = {
assert((type in ("ideal", "convex", "concave", "zener", "real") or type == none), message: "type must be ideal, convex, concave, zener, ...")
if type == none {
type = "ideal"
}
let custom-style = (
radius: 0.3,
width: 0.28,
)
let draw(ctx, position, style) = {
translate((-custom-style.radius / 4, 0))
interface((-custom-style.radius / 2, -custom-style.radius), (custom-style.radius, custom-style.radius), io: position.len() < 2)
polygon((0, 0), 3, radius: custom-style.radius, fill: if type in ("real", "zener") { black } else { auto })
if type == "zener" {
merge-path({
line((custom-style.radius, custom-style.width), (custom-style.radius, -custom-style.width))
line((custom-style.radius, custom-style.width), (custom-style.radius + custom-style.width / 3, custom-style.width))
})
} else { // ideal, convex, concave
line((custom-style.radius, custom-style.width), (custom-style.radius, -custom-style.width))
}
if type == "concave" {
arc((-custom-style.radius/10,0), radius: (custom-style.radius / 4, custom-style.radius / 3), start: 90deg, stop: -90deg, anchor: "chord-center")
} else if type == "convex" {
circle((0, 0), radius: custom-style.radius / 3.5)
}
}
component("custom-diode", name, node, draw: draw, ..params)
}
#let inductor(name, node, ..params) = {
let custom-style = (
width: 1,
height: 0.4
)
let draw(ctx, position, style) = {
interface((-custom-style.width / 2, -custom-style.height / 2), (custom-style.width / 2, custom-style.height / 2), io: position.len() < 2)
cetz.decorations.coil(line((-custom-style.width / 2, 0), (custom-style.width / 2, 0)), amplitude: custom-style.width / 3, segments: 5)
}
component("indcutor", name, node, draw: draw, ..params)
}
#let eintor(name, node, ..params) = {
let custom-style = (
width: 1,
height: 0.4
)
let draw(ctx, position, style) = {
interface((-custom-style.width / 2, -custom-style.height / 2), (custom-style.width / 2, custom-style.height / 2), io: position.len() < 2)
rect((-custom-style.width / 2, -custom-style.height / 2), (custom-style.width / 2, custom-style.height / 2), ..style)
rect((custom-style.width / 2, -custom-style.height / 2), (custom-style.width / 4, custom-style.height / 2), fill: black, ..style)
}
component("eintor", name, node, draw: draw, ..params)
}
#let controlled-source(name, node, scale: 1.0, type: none, ..params) = {
assert((type in ("voltage", "current")), message: "type must be voltage or current, ...")
let custom-style = (
radius: 0.3 * scale,
width: 0.28 * scale,
)
let draw(ctx, position, style) = {
interface((-custom-style.radius, -custom-style.radius), (custom-style.radius, custom-style.radius), io: position.len() < 2)
polygon((0, 0), 4, radius: custom-style.radius)
if type == "voltage" {
line((-custom-style.radius, 0), (custom-style.radius, 0))
} else {
line((0, -custom-style.radius), (0, custom-style.radius))
}
anchor("north", (0, custom-style.radius))
anchor("south", (0, -custom-style.radius))
}
component("custom-diode", name, node, draw: draw, ..params)
}
#let empty(name, node, ..params) = {
let draw(ctx, position, style) = {
interface((-0.5, -0.2), (0.5, 0.2), io: true)
}
component("empty", name, node, draw: draw, ..params)
}
#let blackbox(name, node, mirror: false, label: "", ..params) = {
assert(params.pos().len() == 0, message: "blackbox only supports one node")
let custom-style = (
width: 1,
height: 1,
length: 0.2,
)
let factor = if mirror { -1 } else { 1 }
let draw(ctx, position, style) = {
interface((-custom-style.width / 2, -custom-style.height / 2), (custom-style.width / 2, custom-style.height / 2), io: false)
rect((-custom-style.width / 2, -custom-style.height / 2), (custom-style.width / 2, custom-style.height / 2), ..style)
content((0, 0), label)
anchor("in", (factor * (custom-style.width / 2 + custom-style.length), custom-style.height / 3))
anchor("out", (factor * (custom-style.width / 2 + custom-style.length), -custom-style.height / 3))
wire("in", (rel: (-factor * custom-style.length, 0)))
wire("out", (rel: (-factor * custom-style.length, 0)))
}
component("blackbox", name, node, draw: draw, ..params)
}
#let zweitor(name, node, label: "", ..params) = {
assert(params.pos().len() == 0, message: "zweitor only supports one node")
// assert(type(label) == content, message: "label has to be content")
let custom-style = (
width: 1,
height: 1,
length: 0.2,
)
let draw(ctx, position, style) = {
interface((-custom-style.width / 2, -custom-style.height / 2), (custom-style.width / 2, custom-style.height / 2), io: false)
rect((-custom-style.width / 2, -custom-style.height / 2), (custom-style.width / 2, custom-style.height / 2), ..style)
content((0, 0), label)
anchor("11", (-custom-style.width / 2 - custom-style.length, custom-style.height / 3))
anchor("12", (-custom-style.width / 2 - custom-style.length, -custom-style.height / 3))
anchor("21", (custom-style.width / 2 + custom-style.length, custom-style.height / 3))
anchor("22", (custom-style.width / 2 + custom-style.length, -custom-style.height / 3))
wire("11", (rel: (custom-style.length, 0)))
wire("12", (rel: (custom-style.length, 0)))
wire("21", (rel: (-custom-style.length, 0)))
wire("22", (rel: (-custom-style.length, 0)))
}
component("zweitor", name, node, draw: draw, ..params)
}
#let gyrator(name, node, scale: 1.0, constant: $R_d$, invert: false, ..params) = {
assert(params.pos().len() == 0, message: "gyrator only supports one node")
let custom-style = (
width: 5 * scale,
height: 5 * scale,
length: 0.5 * scale,
)
let draw(ctx, position, style) = {
interface((-custom-style.width / 2, -custom-style.height / 2), (custom-style.width / 2, custom-style.height / 2), io: true)
anchor("11", (-custom-style.width / 2 - custom-style.length, custom-style.height / 3))
anchor("12", (-custom-style.width / 2 - custom-style.length, -custom-style.height / 3))
anchor("21", (custom-style.width / 2 + custom-style.length, custom-style.height / 3))
anchor("22", (custom-style.width / 2 + custom-style.length, -custom-style.height / 3))
wire("11", (rel: (custom-style.length + custom-style.width / 3, 0)), (to: "12", rel: (custom-style.length + custom-style.width / 3, 0)), "12")
wire("21", (rel: (-custom-style.length - custom-style.width / 3, 0)), (to: "22", rel: (-custom-style.length - custom-style.width / 3, 0)), "22")
arc((-custom-style.width / 6, 0), radius: custom-style.width / 9, start: 90deg, stop: -90deg, anchor: "chord-center")
arc((custom-style.width / 6, 0), radius: custom-style.width / 9, start: 90deg, stop: 270deg, anchor: "chord-center")
line(name: "dual", (to: "11", rel: (custom-style.length + custom-style.width / 3, 0.1)), (to: "21", rel: (-custom-style.length - custom-style.width / 3, 0.1)), mark: (end: if not invert { ">" }, start: if invert { ">" }, scale: 0.7), stroke: 0.5pt, fill: black)
content((to: "dual.centroid", rel: (0, 0.1)), constant, anchor: "south")
}
component("gyrator", name, node, draw: draw, ..params)
}
#let nullor(name, node, scale: 1.0, ..params) = {
assert(params.pos().len() == 0, message: "nullor only supports one node")
let custom-style = (
width: 5 * scale,
height: 5 * scale,
length: 0.5 * scale,
)
let draw(ctx, position, style) = {
interface((-custom-style.width / 2, -custom-style.height / 2), (custom-style.width / 2, custom-style.height / 2), io: true)
anchor("11", (-custom-style.width / 2 - custom-style.length, custom-style.height / 3))
anchor("12", (-custom-style.width / 2 - custom-style.length, -custom-style.height / 3))
anchor("21", (custom-style.width / 2 + custom-style.length, custom-style.height / 3))
anchor("22", (custom-style.width / 2 + custom-style.length, -custom-style.height / 3))
nullator("N1", scale: scale, (to: "11", rel: (custom-style.length + custom-style.width / 3, 0)), (to: "12", rel: (custom-style.length + custom-style.width / 3, 0)))
wire("11", "N1.in")
wire("12", "N1.out")
norator("N2", scale: scale, (to: "21", rel: (-custom-style.length - custom-style.width / 3, 0)), (to: "22", rel: (-custom-style.length - custom-style.width / 3, 0)))
wire("21", (rel: (-custom-style.length - custom-style.width / 3, 0)))
wire("22", (rel: (-custom-style.length - custom-style.width / 3, 0)))
}
component("nullor", name, node, draw: draw, ..params)
}
#let transformer(name, node, scale: 1.0, ..params) = {
assert(params.pos().len() == 0, message: "transformer only supports one node")
let custom-style = (
width: 5 * scale,
height: 5 * scale,
length: 0.5 * scale,
)
let draw(ctx, position, style) = {
interface((-custom-style.width / 2, -custom-style.height / 2), (custom-style.width / 2, custom-style.height / 2), io: true)
anchor("11", (-custom-style.width / 2 - custom-style.length, custom-style.height / 3))
anchor("12", (-custom-style.width / 2 - custom-style.length, -custom-style.height / 3))
anchor("21", (custom-style.width / 2 + custom-style.length, custom-style.height / 3))
anchor("22", (custom-style.width / 2 + custom-style.length, -custom-style.height / 3))
anchor("C1in", (to: "11", rel: (custom-style.length + custom-style.width / 3, -custom-style.height / 6)))
anchor("C1out", (to: "12", rel: (custom-style.length + custom-style.width / 3, custom-style.height / 6)))
cetz.decorations.coil(line("C1in", "C1out"), amplitude: custom-style.width / 10, segments: 5)
zwire("11", "C1in", ratio: 100%)
zwire("12", "C1out", ratio: 100%)
anchor("C2in", (to: "21", rel: (-custom-style.length - custom-style.width / 3, -custom-style.height / 6)))
anchor("C2out", (to: "22", rel: (-custom-style.length - custom-style.width / 3, custom-style.height / 6)))
cetz.decorations.coil(line("C2out", "C2in"), amplitude: custom-style.width / 10, segments: 5)
zwire("21", "C2in", ratio: 100%)
zwire("22", "C2out", ratio: 100%)
line((custom-style.width * 0.025, -custom-style.height / 5), (custom-style.width * 0.025, custom-style.height / 5))
line((-custom-style.width * 0.025, -custom-style.height / 5), (-custom-style.width * 0.025, custom-style.height / 5))
content((0, custom-style.height / 3), anchor: "south", text(size: 0.75em)[$ü : 1$])
}
component("transformer", name, node, draw: draw, ..params)
}
#let controlled-source(name, node, scale: 1.0, left: "VC", right: "VS", i: none, ..params) = {
assert(params.pos().len() == 0, message: "controlled source only supports one node")
let custom-style = (
width: 5 * scale,
height: 5 * scale,
length: 0.5 * scale,
)
let draw(ctx, position, style) = {
interface((-custom-style.width / 2, -custom-style.height / 2), (custom-style.width / 2, custom-style.height / 2), io: true)
anchor("11", (-custom-style.width / 2 - custom-style.length, custom-style.height / 3))
anchor("12", (-custom-style.width / 2 - custom-style.length, -custom-style.height / 3))
anchor("21", (custom-style.width / 2 + custom-style.length, custom-style.height / 3))
anchor("22", (custom-style.width / 2 + custom-style.length, -custom-style.height / 3))
if left == "VC" {
wire("11", (rel: (custom-style.length + custom-style.width / 3, 0)))
wire("12", (to: "12", rel: (custom-style.length + custom-style.width / 3, 0)))
} else if left == "CS" {
wire("11", (rel: (custom-style.length + custom-style.width / 3, 0)), (to: "12", rel: (custom-style.length + custom-style.width / 3, 0)), "12")
} else {
assert(false, message: "unknown value for left")
}
if right == "CS" {
// isource("source", (rel: (-custom-style.length - custom-style.width / 3, 0), to: "21"), (rel: (-custom-style.length - custom-style.width / 3, 0), to: "22"), scale: scale, dependent: true, i: i)
anchor("sp", (rel: (-custom-style.length - custom-style.width / 3, 0), to: "21"))
anchor("sn", (rel: (-custom-style.length - custom-style.width / 3, 0), to: "22"))
} else {
assert(false, message: "unknown value for right")
}
wire("21", "sp")
wire("22", "sn")
// arc((-custom-style.width / 6, 0), radius: custom-style.width / 9, start: 90deg, stop: -90deg, anchor: "chord-center")
// arc((custom-style.width / 6, 0), radius: custom-style.width / 9, start: 90deg, stop: 270deg, anchor: "chord-center")
}
component("gyrator", name, node, draw: draw, ..params)
}
#let ideal-opamp(name, node, invert: false, scale: 1.0, angle: 0deg, ..params) = {
assert(params.pos().len() == 0, message: "opamp supports only one node")
let custom-style = (
width: 1.8 * scale,
height: 1.75 * scale,
padding: .28 * scale,
sign-stroke: .55pt,
sign-size: .14 * scale,
sign-delta: .45 * scale,
)
let draw(ctx, position, style) = {
rotate(angle)
interface((-custom-style.width / 2, -custom-style.height / 2), (custom-style.width / 2, custom-style.height / 2), io: true)
let sgn = if invert { -1 } else { 1 }
anchor("minus", (-custom-style.width / 2, sgn * custom-style.sign-delta))
anchor("plus", (-custom-style.width / 2, -sgn * custom-style.sign-delta))
scope({
translate((-custom-style.width / 6, 0))
polygon((0, 0), 3, radius: custom-style.width * 2 / 3, name: "poly")
})
// This is horrendous, don't look at it
anchor("ground", ((rel: (0deg, custom-style.width * 2 / 3), to: "poly.default"), 50%, (rel: (-120deg, custom-style.width * 2 / 3), to: "poly.default")))
anchor("vcc", ((rel: (0deg, custom-style.width * 2 / 3), to: "poly.default"), 50%, (rel: (120deg, custom-style.width * 2 / 3), to: "poly.default")))
set-style(stroke: custom-style.sign-stroke)
line((rel: (custom-style.padding - custom-style.sign-size, 0), to: "minus"), (rel: (2 * custom-style.sign-size, 0)))
line((rel: (custom-style.padding - custom-style.sign-size, 0), to: "plus"), (rel: (2 * custom-style.sign-size, 0)))
line((rel: (custom-style.padding, -custom-style.sign-size), to: "plus"), (rel: (0, 2 * custom-style.sign-size)))
content((custom-style.width / 2, 0), text(size: 12pt * scale)[$ infinity $], anchor: "east", padding: .45 * scale, angle: angle)
}
component("ideal-opamp", name, node, draw: draw, ..params)
}
#let ground(name, node, ..params) = {
assert(params.pos().len() == 0, message: "ground supports only one node")
let custom-style = (
width: 0.46,
distance: 0.28,
)
let draw(ctx, position, style) = {
wire((0, 0), (0, -custom-style.distance))
let delta = custom-style.width / 2
line((-custom-style.width / 2, -custom-style.distance), (custom-style.width / 2, -custom-style.distance))
interface((-custom-style.width / 2, custom-style.distance), (custom-style.width / 2, -custom-style.distance))
anchor("default", (0, 0))
}
component("ground", name, node, draw: draw, ..params)
}
#let offset-line(from, to, dist, func) = {
import cetz: vector
get-ctx(ctx => {
let (_, from, to) = cetz.coordinate.resolve(ctx, from, to)
let line = vector.sub(to, from)
let normal = (-line.at(1), line.at(0))
let offset = vector.scale(vector.norm(normal), dist)
let c = vector.add(from, offset)
let d = vector.add(c, line)
func(c, d)
})
}
#let voltage(from, to, distance: 0, anchor: "east", label) = {
offset-line(from, to, distance, (from, to) => {
line((from, 15%, to), (from, 85%, to), stroke: 0.5pt, mark: (end: (symbol: ">", scale: 0.5, fill: black)), name: "V1")
content("V1.centroid", padding: 0.1, anchor: anchor, label)
})
}
#let element-voltage(from, to, distance: 0.5, anchor: "east", label) = {
voltage(from, to, anchor: anchor, distance: if anchor in ("east", "north") { -distance } else { distance }, label)
}