The Seebeck effect creates a voltage across a conductor or semiconductor subjected to a temperature gradient. In this thermoelectric generator, electrons in the n-type leg and holes in the p-type leg both diffuse from the hot heat source to the cold heat sinks. Carriers piling up at the cold end charge it negatively in the n leg and positively in the p leg, so the internal electric fields, pointing from + to −, are opposite in the two legs and their voltages add up in series and drive a current through the load resistor. This effect enables thermoelectric devices that measure temperature and generate electricity from waste heat.
#import "@preview/cetz:0.5.3": canvas, decorations, draw
#import draw: circle, content, line, on-layer, rect
#set page(width: auto, height: auto, margin: 4pt, fill: none)
#set text(size: 12pt)
#let dy = 0.45
#let pillar-dx = 0.66
#let pillar-w = 2.45
#let pillar-h = 5.35
#let edge-stroke = (paint: black, thickness: 0.6pt)
#let circuit-stroke = (paint: black, thickness: 1.1pt)
#let field-color = black.transparentize(10%)
#let pillar-grad = gradient.linear(rgb("#d20a17"), rgb("#5660d4"), angle: 90deg)
// Box with front, right and top faces, receding by (depth-x, depth-y).
#let draw-prism(x0, y0, w, h, depth-x, front-fill, right-fill, top-fill, depth-y: dy) = {
rect((x0, y0), (x0 + w, y0 + h), fill: front-fill, stroke: edge-stroke)
line(
(x0 + w, y0),
(x0 + w + depth-x, y0 + depth-y),
(x0 + w + depth-x, y0 + h + depth-y),
(x0 + w, y0 + h),
close: true,
fill: right-fill,
stroke: edge-stroke,
)
line(
(x0, y0 + h),
(x0 + w, y0 + h),
(x0 + w + depth-x, y0 + h + depth-y),
(x0 + depth-x, y0 + h + depth-y),
close: true,
fill: top-fill,
stroke: edge-stroke,
)
}
// Charge carrier drifting down from the hot to the cold end.
#let charge-marker(x, y, sign, fill) = {
circle((x, y), radius: 0.2, fill: fill, stroke: none)
content((x, y + 0.03), text(weight: "light")[#sign])
line(
(x, y - 0.22),
(x, y - 0.72),
stroke: (paint: black, thickness: 1.3pt),
mark: (end: "stealth", fill: black, scale: 0.7),
)
}
#let sink-block(x0, y0, w: 2.9, h: 0.85) = {
let sink-side-blue = rgb("#0606cf")
draw-prism(
x0,
y0,
w,
h,
0.84,
rgb("#0b0bff"),
sink-side-blue,
sink-side-blue.lighten(20%),
depth-y: 0.58,
)
content((x0 + w / 2, y0 + h / 2), text(size: 14pt, fill: white)[heat sink])
}
#let pillar-block(x0, y0, label, carriers) = {
let (w, h) = (pillar-w, pillar-h)
rect((x0, y0), (x0 + w, y0 + h), fill: pillar-grad, stroke: none)
line(
(x0 + w, y0),
(x0 + w + pillar-dx, y0 + dy),
(x0 + w + pillar-dx, y0 + h + dy),
(x0 + w, y0 + h),
close: true,
fill: pillar-grad,
stroke: none,
)
circle((x0 + w / 2, y0 + h * 0.58), radius: 0.38, name: "badge", stroke: (
paint: white.transparentize(25%),
thickness: 0.7pt,
))
content("badge", text(size: 16pt, fill: white.transparentize(25%))[#label])
content((x0 + w / 2, y0 + h * 0.43), text(size: 14pt, fill: white)[#carriers])
}
// The internal field points from the positively (+) to the negatively (−) charged end of a leg.
#let field-arrow(x, y-plus, y-minus, label-side) = {
let mark = (end: "stealth", fill: field-color, scale: 0.55)
line((x, y-plus), (x, y-minus), stroke: (paint: field-color, thickness: 1.0pt), mark: mark)
let x-offset = if label-side == "west" { 0.18 } else { -0.18 }
for (y, label) in ((y-plus, [+]), (y-minus, [−])) {
content((x + x-offset, y), text(fill: field-color)[#label], anchor: label-side)
}
}
#canvas({
let left-sink-x = 1.05
let right-sink-x = 7.9
let sink-y = 0.8
let pillar-y = sink-y + 0.95
let left-field-x = left-sink-x + 0.35 + pillar-w + pillar-dx + 0.25
let right-field-x = right-sink-x + 0.35 - 0.25
// Electrons (N) and holes (P) both diffuse to the cold end, so the two fields point oppositely.
for (sink-x, label, carriers, sign, fill, field-x, field-ys, label-side, charge-offsets) in (
(
left-sink-x,
[N],
[electrons],
[−],
rgb("#11b7ef"),
left-field-x,
(pillar-y + pillar-h - 0.6, pillar-y + 0.6),
"west",
((1.05, 5.2), (2.25, 5.2), (1.05, 2.3), (2.35, 2.45)),
),
(
right-sink-x,
[P],
[holes],
[+],
rgb("#ffa300"),
right-field-x,
(pillar-y + 0.55, pillar-y + pillar-h - 0.55),
"east",
((1.02, 5.2), (2.2, 5.2), (1.02, 2.3), (2.32, 2.45)),
),
) {
sink-block(sink-x, sink-y)
pillar-block(sink-x + 0.35, pillar-y, label, carriers)
field-arrow(field-x, ..field-ys, label-side)
for (dx-offset, dy-offset) in charge-offsets {
charge-marker(sink-x + dx-offset, sink-y + dy-offset, sign, fill)
}
}
content(
((left-field-x + right-field-x) / 2, pillar-y + pillar-h * 0.55),
text(size: 15pt, fill: field-color)[electric field],
)
// Top heat source bar resting on the pillars (foreground so it occludes pillars/charges)
let (bar-x, bar-y) = (left-sink-x - 0.05, pillar-y + pillar-h - 0.1)
on-layer(20, {
draw-prism(bar-x, bar-y, 9.95, 0.9, 0.66, rgb("#ef1313"), rgb("#de1313"), rgb("#ff2222"))
content((bar-x + 5.05, bar-y + 1.16), text(size: 15pt, fill: white)[heat source])
content((bar-x + 4.68, bar-y + 0.4), text(size: 20pt, fill: white)[current $J arrow.r$])
})
// Bottom wire closing the electric circuit through a central load resistor.
let wire-y = 0.12
let left-wire-x = left-sink-x + 0.2
let right-wire-x = right-sink-x + 2.55
let (zig-left-x, zig-right-x) = (4.65, 5.85)
line(
(right-wire-x, sink-y),
(right-wire-x, wire-y),
(zig-right-x, wire-y),
stroke: circuit-stroke,
)
line((zig-left-x, wire-y), (left-wire-x, wire-y), (left-wire-x, sink-y), stroke: circuit-stroke)
// Resistor zigzag, with arrow tips along the path showing the current direction.
let circuit-mark = (symbol: "stealth", fill: black, scale: 0.5, shorten-to: none)
decorations.zigzag(
line(
(zig-right-x, wire-y),
(zig-left-x, wire-y),
stroke: circuit-stroke,
mark: (end: (20%, 50%, 80%).map(pos => (pos: pos, ..circuit-mark))),
),
amplitude: 0.12,
segment-length: 0.2,
)
content(((zig-left-x + zig-right-x) / 2, wire-y - 0.25), [load], anchor: "north")
})