Creator: Kreijstal
Source follower (common-drain amplifier) built from an N-channel MOSFET (NMOS) . The input drives the gate through , the drain is tied to the supply , and the output is taken at the source, which is loaded by the resistor and the capacitance to ground. The bulk is grounded, so the body effect lowers the voltage gain below one. Related to the course "Advanced Analog Integrated Circuits and Systems (AAIC)" (#41178, TU Berlin).
#import "@preview/cetz:0.5.3": canvas, draw
#import draw: anchor, circle, content, group, line, rotate, set-origin
#set page(width: auto, height: auto, margin: 8pt, fill: none)
#set text(size: 12pt)
// === Circuit symbol toolkit ===
// Each symbol is a named cetz group carrying its own terminal anchors, so the schematic
// below can be wired up purely by anchor name (e.g. "M1.G" to "R1.R").
// Wire two anchors with a single right-angle bend, running vertically first.
#let wire(from, to, ..styling) = line(from, (from, "|-", to), to, ..styling)
// Draw `body` at `position` inside a named group, register `anchors`, then place `label`.
#let symbol(
position,
name,
body,
anchors,
label: none,
label-pos: "center",
label-anchor: "center",
label-offset: (0, 0),
rotate-by: 0deg,
..styling,
) = {
group(name: name, ..styling, {
set-origin(position)
rotate(rotate-by)
body(..styling)
for (anchor-name, pos) in anchors { anchor(anchor-name, pos) }
if label != none {
content((rel: label-offset, to: label-pos), label, anchor: label-anchor)
}
})
}
// Horizontal two-terminal part with terminals L/R and label positions T/B, labeled below by default
#let two-terminal(position, name, body, left, right, half-height, ..opts) = symbol(
position,
name,
body,
(L: (left, 0), R: (right, 0), T: (0, half-height), B: (0, -half-height)),
label-pos: "B",
label-anchor: "north",
label-offset: (0, -0.1),
..opts,
)
#let resistor(position, name, width: 0.8, height: 0.3, zigs: 3, lead: 0.3, ..opts) = {
let (half-w, half-h) = (width / 2, height / 2)
let (left, right) = (-half-w - lead, half-w + lead)
let segments = zigs * 2
let seg-w = width / segments
let body(..styling) = {
// one flat lead, then `segments` alternating half-height zigs, then the other lead
let sign = 1
line(
(left, 0),
(-half-w, 0),
(rel: (seg-w / 2, half-h)),
..for _ in range(segments - 1) {
sign *= -1
((rel: (seg-w, half-h * 2 * sign)),)
},
(rel: (seg-w / 2, half-h)),
(right, 0),
..styling,
)
}
two-terminal(position, name, body, left, right, half-h, ..opts)
}
#let capacitor(position, name, plate-height: 0.6, gap: 0.2, lead: 0.5, ..opts) = {
let (half-gap, half-h) = (gap / 2, plate-height / 2)
let (left, right) = (-half-gap - lead, half-gap + lead)
let body(..styling) = {
line((left, 0), (-half-gap, 0), ..styling)
line((-half-gap, -half-h), (-half-gap, half-h), ..styling)
line((half-gap, half-h), (half-gap, -half-h), ..styling)
line((half-gap, 0), (right, 0), ..styling)
}
two-terminal(position, name, body, left, right, half-h, ..opts)
}
#let nmos-transistor(position, name, width: 0.9, height: 1.2, arrow-scale: 0.8, ..opts) = {
let mid-y = height / 2
let (gate-x, channel-x) = (0.3 * width, 0.4 * width)
let reach = 0.35 * height // half-length of the vertical gate and channel bars
let (gate, drain, source) = ((-0.3 * width, mid-y), (width, height), (width, 0))
let bulk = (1.3 * width, mid-y)
let body(..styling) = {
for x in (channel-x, gate-x) {
line((x, mid-y - reach), (x, mid-y + reach), ..styling, thickness: 1.2pt)
}
line(gate, (gate-x, mid-y), ..styling)
line((channel-x, mid-y), bulk, ..styling)
line(drain, (width, mid-y + reach), ..styling)
line((width, mid-y + reach), (channel-x, mid-y + reach), ..styling)
line((width, mid-y - reach), source, ..styling)
line(
(channel-x, mid-y - reach),
(width, mid-y - reach),
..styling,
mark: (end: "stealth", fill: black, scale: arrow-scale),
)
}
symbol(
position,
name,
body,
(G: gate, D: drain, S: source, B: bulk, east: (width, mid-y)),
label-pos: "D",
label-anchor: "north-west",
label-offset: (0.05, 0.05),
..opts,
)
}
// Three stacked bars of shrinking width below a short lead.
#let gnd-symbol(position, name, lead: 0.3, bar-width: 0.5, spacing: 0.05, ..opts) = {
let widths = (1.0, 0.7, 0.4).map(factor => bar-width * factor / 2)
let body(..styling) = {
line((0, 0), (0, -lead), ..styling)
for (idx, half-w) in widths.enumerate() {
line((-half-w, -lead - idx * spacing), (half-w, -lead - idx * spacing), ..styling)
}
}
symbol(position, name, body, (T: (0, 0)), ..opts)
}
// Supply rail: a short stem capped by a horizontal bar.
#let vdd-symbol(position, name, stem: 0.3, bar-width: 0.5, ..opts) = {
let half-w = bar-width / 2
let body(..styling) = {
line((0, 0), (0, stem), ..styling)
line((-half-w, stem), (half-w, stem), ..styling)
}
symbol(
position,
name,
body,
(B: (0, 0), T: (0, stem)),
label-pos: "T",
label-anchor: "south",
label-offset: (0, 0.1),
..opts,
)
}
// Circle with leads top and bottom, annotated by a voltage arrow to its left.
#let voltage-source(
position,
name,
label: none,
radius: 0.3,
lead: 0.3,
arrow-offset: 0.7,
..opts,
) = {
let arrow-x = -radius * (1 + arrow-offset)
let body(..styling) = {
circle((0, 0), radius: radius, ..styling)
line((0, radius), (0, radius + lead), ..styling)
line((0, -radius), (0, -radius - lead), ..styling)
// the voltage arrow spans the circle's diameter
line(
(arrow-x, radius),
(arrow-x, -radius),
..styling,
mark: (end: "stealth", scale: 0.4, fill: black, stroke: (paint: black, thickness: 0.6pt)),
)
if label != none {
content((rel: (-0.1, 0), to: (arrow-x, 0)), label, anchor: "east", offset: (-0.05, 0))
}
}
symbol(position, name, body, (T: (0, radius + lead), B: (0, -radius - lead)), ..opts)
}
#let node(position, name, radius: 0.05, fill: rgb("#cdd3da"), ..opts) = symbol(
position,
name,
(..styling) => circle((0, 0), radius: radius, ..styling, fill: fill),
(center: (0, 0), default: (0, 0)),
..opts,
)
// === Source follower (common-drain amplifier) schematic ===
#canvas({
let thin = (stroke: (thickness: .6pt))
let x-vin = 0
let x-m1 = 1.9
let x-out = x-m1 + 0.9
let x-cl = x-out + 2.0
let y-source = 1.0
let y-mid = y-source + 0.6 // height of M1's gate and bulk terminals
let y-gnd = -1.0
voltage-source((x-vin, y-mid - 1), "Vin", label: $V_"in"$, radius: 0.4, lead: 0.2, ..thin)
resistor(
(x-vin + 1.0, y-mid),
"R1",
label: $R_1$,
label-pos: "T",
label-offset: (0, 0.4),
width: 1.0,
..thin,
)
nmos-transistor(
(x-m1, y-source),
"M1",
label: $M_1$,
label-pos: "east",
label-anchor: "west",
label-offset: (0.3, 0.3),
..thin,
)
vdd-symbol((rel: (0, 1.5), to: "M1.D"), "Vdd", label: $V_"DD"$, ..thin)
resistor(
(rel: (0, -1), to: "M1.S"),
"R2",
rotate-by: 90deg,
label: $R_2$,
label-pos: "L",
label-offset: (0.5, 0.5),
..thin,
)
capacitor(
(x-cl, y-source - 0.95),
"CL",
rotate-by: 90deg,
label: $C_L$,
label-pos: "R",
label-offset: (0.1, -0.55),
..thin,
)
node(
(x-cl + 1.0, y-mid),
"VoutNode",
label: $V_"out"$,
label-offset: (0.15, 0),
label-anchor: "west",
..thin,
)
for (name, pos) in (
("GND_Vin", (x-vin, y-gnd)),
("GND_M1B", (rel: (0.1, 0), to: "M1.B")),
("GND_R2", (x-out, y-gnd)),
("GND_CL", (x-cl, y-gnd)),
) {
gnd-symbol(pos, name, ..thin)
}
for (from, to) in (
("Vin.T", "R1.L"),
("Vin.B", "GND_Vin.T"),
("R1.R", "M1.G"),
("M1.D", "Vdd.B"),
("M1.B", "GND_M1B.T"),
("M1.S", "R2.R"),
("GND_R2.T", "R2.L"),
("GND_CL.T", "CL.L"),
("CL.R", "M1.S"),
("VoutNode", "M1.S"),
) {
wire(from, to, ..thin)
}
})