# Transducer
<!-- MICROSIMGEN:BEGIN v1.7 — generated by g08_place_microsims.py; three.js first (§15); do not hand-edit inside -->
## Microsims — p5.js
### Transducer (p5.js) · `energy convert`
<div class="microsim-player">
<iframe src="https://editor.p5js.org/sciencenibber/full/kMi3GOmq5" width="100%" height="480" frameborder="0" loading="lazy" sandbox="allow-scripts allow-same-origin" title="Transducer — p5.js microsim"></iframe>
</div>
*Any device that turns one form of energy into another — microphone, speaker, antenna, sensor.*
**Open in the editor:** [▶ fork this sketch](https://editor.p5js.org/sciencenibber/sketches/kMi3GOmq5) · movement *VIII · Imaging, audio & sensors* · library `p5js`
### Related microsims
Live sims on neighbouring articles — 1 of them inside this article's own Wikipedia link tree:
- [[Sensor]] *(in tree)*
- [[Decibel]]
- [[Digital_image_processing]]
- [[Distortion]]
- [[Magnetic_resonance_imaging]]
- [[Analog_signal]]
*Sim hosted off-article; the article owns the reference, not the runtime (WIKI_RULES §10.4). Placed by `g08_place_microsims.py`.*
<!-- g09-shelf-note -->
> **Also on this page:** 1 further p5.js sketch already published for this article live further down. Per WIKI_RULES §5 a collision promotes rather than forks — they are one shelf, not rivals; this block is the §10.4 *current best* reference.
<!-- MICROSIMGEN:END -->
## Microsim
<iframe src="https://editor.p5js.org/sciencenibber/full/Cb_IFki6B" width="100%" height="620" frameborder="0" sandbox="allow-scripts allow-same-origin"></iframe>
<img src="../SPINTRONICS Images/Transducer.png" alt="Transducer microsim">
*Live sketch: [open in the p5.js editor](https://editor.p5js.org/sciencenibber/sketches/Cb_IFki6B). The poster image above is a placeholder pending an attended or server-side canvas capture.*
### p5.js source
```js
// =====================================================================
// Transducer - Wikitube MicroSim (SPINTRONICS hub, branch T - Transducers)
// Slug/ARTICLE: "Transducer" -> en.wikitube.io/wiki/Transducer
// ---------------------------------------------------------------------
// CONCEPT
// A transducer converts a measurand x(t) into an electrical output V(t).
// Four characteristics - the same four used to RATE real transducers -
// decide how faithfully it does so, and each is a control here:
// * Sensitivity S : slope of the transfer characteristic V = S*x
// * Range/sat. Vsat : output saturates (clips) at +/-Vsat
// * Bandwidth fc : first-order roll-off; gain G(f) and lag phi(f)
// * Noise floor sigma: RMS additive output noise; sets dynamic range
//
// MODEL (steady-state sinusoidal / frequency-response view)
// x(t) = A*sin(2*pi*f*t)
// G(f) = 1/sqrt(1 + (f/fc)^2) // amplitude gain (<= 1)
// phi(f) = -atan(f/fc) // phase lag (rad)
// V(t) = clamp( S*A*G*sin(2*pi*f*t + phi), -Vsat, +Vsat ) + noise(sigma)
// The dynamic operating point (x(t), V(t)) traces a Lissajous loop that
// opens from a line into a lagging ellipse as f -> fc (= visible bandwidth).
//
// A-V PATTERN: composition - a G block-diagram strip (measurand -> transducer
// -> output) over a quantitative transfer-characteristic chart (left) and an
// H signals-over-time scrolling-scope pair of traces (right).
//
// GOLDEN-RULES COMPLIANCE
// * createCanvas(720,520) + pixelDensity(2); layout from width/height.
// * Controls use real symbols + meaningful ranges; Reset restores ALL state.
// * HUD watermark drawn last: title | URL | hints | live equation footer.
// * ASCII only in every string/text(); Unicode (pi, sigma, phi) only in comments.
// * Frame-rate independent: dt = min(deltaTime/1000, 0.05). The model is
// closed-form (not an energy-conserving ODE) -> velocity-Verlet is N/A.
// * Default noLoop()+redraw() (input-driven); Run toggles a LIGHT loop().
// Per-frame work = a few hundred polyline vertices; static scaffolding is
// baked once into an offscreen buffer; setup() is cheap. No per-pixel /
// per-atom inner loops -> does not trip the editor loop-protect.
// * p5.disableFriendlyErrors = true; no allocation inside draw().
// =====================================================================
p5.disableFriendlyErrors = true; // quiet the FES (perf + clean console)
const ARTICLE = "Transducer"; // single source of truth (HUD/URL/save)
const WIKI = "en.wikitube.io/wiki/Transducer";
// ---- fixed axis full-scales (kept constant so readouts don't rescale) -------
const AXMAX = 10; // input axis: x in [-10, +10] units
const VAXMAX = 400; // output axis: V in [-400, +400] mV
// ---- layout (all derived from the 720x520 canvas; no magic coords in draw) --
const FOOTY = 326; // y where the live-equation footer sits
const PTOP = 84; // panels top
// left panel (transfer characteristic)
const LX0 = 52, LX1 = 348, LY0 = PTOP, LY1 = 322;
// right panel (time traces) split into input (top) + output (bottom)
const RX0 = 396, RX1 = 704;
const RIN0 = PTOP, RIN1 = 198; // input sub-panel y-range
const ROUT0 = 208, ROUT1 = 322; // output sub-panel y-range
// ---- control defaults (also used by Reset) ----------------------------------
const DEF = { S: 20, A: 7, f: 2, fc: 6, Vsat: 200, sig: 0 };
// ---- DOM controls -----------------------------------------------------------
let sldS, sldA, sldF, sldFc, sldVsat, sldSig; // six sliders
let btnRun, btnReset; // two buttons
// ---- animation state --------------------------------------------------------
let running = false; // paused by default (noLoop)
let tsec = 0; // elapsed model time (s), advanced by dt
// ---- baked static scenery ---------------------------------------------------
let scene; // p5.Graphics drawn once in setup()
// =====================================================================
// setup
// =====================================================================
function setup() {
createCanvas(720, 520);
pixelDensity(2);
textFont("Helvetica");
// -- sliders: (min, max, value, step) then .position(pageX,pageY).size(w) ---
// the canvas sits at page (0,0) so page coords line up with canvas coords.
const w = 130;
sldS = createSlider(5, 60, DEF.S, 1); sldS.position(120, 378); sldS.size(w);
sldA = createSlider(0, 10, DEF.A, 0.1); sldA.position(120, 416); sldA.size(w);
sldF = createSlider(0.2, 20, DEF.f, 0.1); sldF.position(120, 454); sldF.size(w);
sldFc = createSlider(0.5, 20, DEF.fc, 0.1); sldFc.position(476, 378); sldFc.size(w);
sldVsat = createSlider(50, 400, DEF.Vsat, 5); sldVsat.position(476, 416); sldVsat.size(w);
sldSig = createSlider(0, 20, DEF.sig, 0.5); sldSig.position(476, 454); sldSig.size(w);
// redraw on any slider change so the PAUSED view updates live while dragging
for (const s of [sldS, sldA, sldF, sldFc, sldVsat, sldSig]) s.input(redraw);
// -- buttons --------------------------------------------------------------
btnRun = createButton("Run");
btnRun.position(120, 490); btnRun.size(80, 22);
btnRun.mousePressed(toggleRun);
btnReset = createButton("Reset");
btnReset.position(210, 490); btnReset.size(80, 22);
btnReset.mousePressed(resetAll);
buildScene(); // bake panels, axes, ticks, block diagram ONCE
noLoop(); // input-driven by default; Run switches to loop()
}
// =====================================================================
// buildScene - bake everything static into the offscreen buffer once
// =====================================================================
function buildScene() {
scene = createGraphics(720, 520);
const g = scene;
g.pixelDensity(2);
g.background("#0f1420");
g.textFont("Helvetica");
// ---- header caption + block diagram: measurand -> TRANSDUCER -> output ----
g.noStroke(); g.fill("#7f8aa3"); g.textSize(9);
g.textAlign(CENTER, TOP);
g.text("sensor: x -> V actuator: V -> x (reciprocal)", 360, 6);
g.textAlign(CENTER, CENTER);
drawBox(g, 18, 30, 150, 34, "#16203a", "#3d5a9a");
g.fill("#cfe0ff"); g.textSize(11);
g.text("measurand x(t)", 18 + 75, 30 + 17);
drawBox(g, 285, 26, 170, 42, "#1d2a17", "#5a8a3d");
g.fill("#dfffcf"); g.textSize(12);
g.text("TRANSDUCER", 285 + 85, 26 + 13);
g.textSize(10); g.fill("#bfe6a8");
g.text("V = S * x (clamped)", 285 + 85, 26 + 30);
drawBox(g, 552, 30, 150, 34, "#2a1717", "#9a5a5a");
g.fill("#ffd9d9"); g.textSize(11);
g.text("output V(t)", 552 + 75, 30 + 17);
arrow(g, 168, 47, 285, 47); // x -> transducer
arrow(g, 455, 47, 552, 47); // transducer -> V
// ---- LEFT panel: transfer characteristic V(x) ----
panelFrame(g, LX0, LY0, LX1, LY1, "transfer characteristic V vs x");
const cx = mapX(0), cyz = mapY(0); // zero axes inside left panel
g.stroke("#2b3550"); g.strokeWeight(1);
g.line(LX0 + 1, cyz, LX1 - 1, cyz); // V = 0 horizontal axis
g.line(cx, LY0 + 14, cx, LY1 - 1); // x = 0 vertical axis
// x ticks (units)
g.textSize(8); g.fill("#7f8aa3");
g.textAlign(CENTER, TOP);
for (let xv = -10; xv <= 10; xv += 5) {
const px = mapX(xv);
g.stroke("#243049"); g.line(px, cyz - 3, px, cyz + 3); g.noStroke();
if (xv !== 0) g.text(xv, px, cyz + 4);
}
// V ticks (mV)
g.textAlign(RIGHT, CENTER);
for (let vv = -400; vv <= 400; vv += 200) {
const py = mapY(vv);
g.stroke("#243049"); g.line(cx - 3, py, cx + 3, py); g.noStroke();
if (vv !== 0) g.text(vv, cx - 6, py);
}
g.fill("#9aa6c2"); g.textSize(9);
g.textAlign(LEFT, BOTTOM); g.text("x (units)", LX1 - 58, LY1 - 4);
g.textAlign(LEFT, TOP); g.text("V (mV)", LX0 + 5, LY0 + 16);
// ---- RIGHT panel: input + output trace sub-panels ----
panelFrame(g, RX0, RIN0, RX1, RIN1, "input x(t)");
panelFrame(g, RX0, ROUT0, RX1, ROUT1, "output V(t)");
g.stroke("#2b3550"); // zero line in each sub-panel
g.line(RX0 + 1, (RIN0 + RIN1) / 2, RX1 - 1, (RIN0 + RIN1) / 2);
g.line(RX0 + 1, (ROUT0 + ROUT1) / 2, RX1 - 1, (ROUT0 + ROUT1) / 2);
g.noStroke(); g.fill("#9aa6c2"); g.textSize(9);
g.textAlign(RIGHT, BOTTOM);
g.text("t (window = 3 periods, scrolling)", RX1 - 4, ROUT1 - 3);
}
// small helper: filled+stroked rounded box (baked use only)
function drawBox(g, x, y, w, h, fillc, strokec) {
g.stroke(strokec); g.strokeWeight(1.5); g.fill(fillc);
g.rect(x, y, w, h, 6);
}
// small helper: arrow with a head (baked use only)
function arrow(g, x1, y1, x2, y2) {
g.stroke("#6f7ea8"); g.strokeWeight(2); g.line(x1, y1, x2, y2);
g.noStroke(); g.fill("#6f7ea8");
g.triangle(x2, y2, x2 - 8, y2 - 4, x2 - 8, y2 + 4);
}
// small helper: panel frame + caption
function panelFrame(g, x0, y0, x1, y1, label) {
g.noFill(); g.stroke("#33405f"); g.strokeWeight(1.2);
g.rect(x0, y0, x1 - x0, y1 - y0, 4);
g.noStroke(); g.fill("#aebbd9"); g.textSize(10);
g.textAlign(LEFT, TOP);
g.text(label, x0 + 6, y0 + 3);
}
// =====================================================================
// coordinate maps (use p5 map(); these names do NOT shadow p5's map)
// =====================================================================
function mapX(x) { return map(x, -AXMAX, AXMAX, LX0 + 8, LX1 - 6); } // left x-axis
function mapY(v) { return map(v, -VAXMAX, VAXMAX, LY1 - 6, LY0 + 16); } // left V-axis
function mapInY(x) { return map(x, -AXMAX, AXMAX, RIN1 - 6, RIN0 + 16); } // input trace
function mapOutY(v) { return map(v, -VAXMAX, VAXMAX, ROUT1 - 6, ROUT0 + 16); } // output trace
function mapT(t, t0, win) { return map(t, t0, t0 + win, RX0 + 6, RX1 - 6); } // scrolling time
// cheap deterministic gaussian (Box-Muller) via p5 random() -> obeys randomSeed
function gaussv() {
return sqrt(-2 * log(random() + 1e-9)) * cos(TWO_PI * random());
}
// dynamic output for an input phase ph (clamped, pre-noise)
function outAt(ph, A, S, G, phi, Vsat) {
return constrain(S * A * G * sin(ph + phi), -Vsat, Vsat);
}
// =====================================================================
// draw
// =====================================================================
function draw() {
// -- read every control ONCE into named locals -----------------------------
const S = sldS.value(); // mV per unit (sensitivity = slope)
const A = sldA.value(); // units (input half-span)
const f = sldF.value(); // Hz (drive frequency)
const fc = sldFc.value(); // Hz (-3 dB bandwidth)
const Vsat = sldVsat.value(); // mV (saturation / range)
const sig = sldSig.value(); // mV (RMS noise floor)
// -- derived frequency-response quantities ---------------------------------
const G = 1 / sqrt(1 + (f / fc) * (f / fc)); // amplitude gain <= 1
const phi = -atan(f / fc); // phase lag (rad)
const peak = S * A * G; // ideal output peak (mV)
// -- advance model time only while running (frame-rate independent) ---------
if (running) {
const dt = min(deltaTime / 1000, 0.05); // clamp big frame gaps
tsec += dt;
if (tsec > 1e6) tsec = 0; // guard against unbounded growth
}
image(scene, 0, 0); // blit baked panels/axes/diagram
drawTransfer(S, A, f, G, phi, Vsat, sig);
drawTraces(S, A, f, G, phi, Vsat, sig);
drawHUD(S, A, f, fc, Vsat, sig, G, phi, peak);
}
// ---------------------------------------------------------------------
// LEFT panel: static characteristic line + dynamic Lissajous operating loop
// ---------------------------------------------------------------------
function drawTransfer(S, A, f, G, phi, Vsat, sig) {
// noise band: +/- sigma around the ideal characteristic (faint fill)
if (sig > 0) {
noStroke(); fill(120, 150, 220, 40);
beginShape();
for (let xv = -AXMAX; xv <= AXMAX; xv += 1)
vertex(mapX(xv), mapY(constrain(S * xv, -Vsat, Vsat) + sig));
for (let xv = AXMAX; xv >= -AXMAX; xv -= 1)
vertex(mapX(xv), mapY(constrain(S * xv, -Vsat, Vsat) - sig));
endShape(CLOSE);
}
// static transfer characteristic V = clamp(S*x): sloped line + flat plateaus
stroke("#7fe08a"); strokeWeight(2.5); noFill();
beginShape();
for (let xv = -AXMAX; xv <= AXMAX; xv += 0.5)
vertex(mapX(xv), mapY(constrain(S * xv, -Vsat, Vsat)));
endShape();
// highlight the saturation plateaus in red where the line has flattened
const xSat = Vsat / S; // |x| beyond which output clips
if (xSat < AXMAX) {
stroke("#ff6b6b"); strokeWeight(2.5);
line(mapX(xSat), mapY(Vsat), mapX(AXMAX), mapY(Vsat));
line(mapX(-xSat), mapY(-Vsat), mapX(-AXMAX), mapY(-Vsat));
}
// dynamic operating loop: one period back from the current phase.
// f<<fc -> collapses onto the line; near/above fc -> opens to a lagging ellipse.
const ph0 = TWO_PI * f * tsec;
const NT = 72;
stroke(255, 210, 120, 150); strokeWeight(1.5); noFill();
beginShape();
for (let k = 0; k <= NT; k++) {
const ph = ph0 - TWO_PI * (k / NT);
vertex(mapX(A * sin(ph)), mapY(outAt(ph, A, S, G, phi, Vsat)));
}
endShape();
// current operating point (with a noisy output sample)
randomSeed(running ? floor(frameCount / 2) : 7);
const xNow = A * sin(ph0);
const vNow = outAt(ph0, A, S, G, phi, Vsat) + sig * gaussv();
const px = mapX(xNow), py = mapY(constrain(vNow, -VAXMAX, VAXMAX));
stroke(150, 165, 200, 120); strokeWeight(1); // guide lines to the axes
line(px, mapY(0), px, py);
line(mapX(0), py, px, py);
noStroke(); fill("#ffffff");
circle(px, py, 8);
// slope annotation (sensitivity)
noStroke(); fill("#7fe08a"); textSize(10); textAlign(LEFT, BOTTOM);
text("slope = S", mapX(AXMAX) - 70,
mapY(constrain(S * AXMAX, -Vsat, Vsat)) - 4);
}
// ---------------------------------------------------------------------
// RIGHT panel: scrolling input (top) + output (bottom), newest at right edge
// ---------------------------------------------------------------------
function drawTraces(S, A, f, G, phi, Vsat, sig) {
const Twin = 3 / f; // window = 3 periods regardless of f
const t0 = tsec - Twin; // window start (newest sample at tsec)
const N = 300; // light sample count across the panel
// input x(t) (cyan)
stroke("#5fd0ff"); strokeWeight(2); noFill();
beginShape();
for (let i = 0; i <= N; i++) {
const t = t0 + (i / N) * Twin;
vertex(mapT(t, t0, Twin), mapInY(A * sin(TWO_PI * f * t)));
}
endShape();
// output V(t) (amber): clamped, lagged, noisy. Seed for a stable paused frame.
randomSeed(running ? floor(frameCount / 2) + 1 : 11);
stroke("#ffb347"); strokeWeight(2); noFill();
beginShape();
for (let i = 0; i <= N; i++) {
const t = t0 + (i / N) * Twin;
const v = constrain(S * A * G * sin(TWO_PI * f * t + phi), -Vsat, Vsat)
+ sig * gaussv();
vertex(mapT(t, t0, Twin), mapOutY(constrain(v, -VAXMAX, VAXMAX)));
}
endShape();
// dashed saturation guides on the output sub-panel when peaks would clip
if (S * A * G > Vsat) {
stroke(255, 107, 107, 130); strokeWeight(1);
drawingContext.setLineDash([4, 4]);
line(RX0 + 6, mapOutY(Vsat), RX1 - 6, mapOutY(Vsat));
line(RX0 + 6, mapOutY(-Vsat), RX1 - 6, mapOutY(-Vsat));
drawingContext.setLineDash([]);
}
// "now" marker at the right edge of both sub-panels (newest sample)
const xEnd = A * sin(TWO_PI * f * tsec);
const vEnd = constrain(S * A * G * sin(TWO_PI * f * tsec + phi), -Vsat, Vsat);
noStroke(); fill("#5fd0ff"); circle(RX1 - 6, mapInY(xEnd), 6);
fill("#ffb347"); circle(RX1 - 6, mapOutY(vEnd), 6);
}
// ---------------------------------------------------------------------
// HUD watermark (drawn LAST): title | URL | hints | live equation footer
// + the six control labels/values + a 3-mode status flag.
// ---------------------------------------------------------------------
function drawHUD(S, A, f, fc, Vsat, sig, G, phi, peak) {
// ---- control labels + live values (next to each slider) ----
noStroke(); textSize(11);
fill("#cfe0ff"); textAlign(LEFT, CENTER);
text("S", 14, 389); text("A", 14, 427); text("f", 14, 465);
text("fc", 372, 389); text("Vsat", 372, 427); text("sigma", 372, 465);
fill("#9fe6b0");
text(nf(S, 0, 0) + " mV/u", 256, 389);
text(nf(A, 0, 1) + " u", 256, 427);
text(nf(f, 0, 1) + " Hz", 256, 465);
text(nf(fc, 0, 1) + " Hz", 612, 389);
text(nf(Vsat, 0, 0) + " mV", 612, 427);
text(nf(sig, 0, 1) + " mV", 612, 465);
// ---- HUD part 1: title (top-left) ----
fill("#ffffff"); textSize(13); textAlign(LEFT, TOP);
text("Transducer - input measurand to electrical output", 12, 8);
// ---- HUD part 2: URL (top-right) ----
fill("#8fa0c8"); textSize(10); textAlign(RIGHT, TOP);
text(WIKI, 708, 10);
// ---- HUD part 3: control hints ----
fill("#7f8aa3"); textSize(9); textAlign(LEFT, CENTER);
text("drag sliders | Run/Pause animates the drive | Reset", 300, 501);
// ---- live status: which of the 3 failure modes is active ----
textAlign(RIGHT, CENTER); textSize(10);
let flag = "in range", col = "#7fe08a";
if (peak > Vsat) { flag = "CLIPPING (range)"; col = "#ff6b6b"; }
else if (f > fc) { flag = "LAG (bandwidth)"; col = "#ffb347"; }
else if (sig > 0 && peak < 3 * sig) { flag = "BURIED (noise)"; col = "#c08bff"; }
fill(col); text(flag, 708, 501);
// ---- HUD part 4: live equation footer (above the control band) ----
const dr = (sig > 0) ? (20 * log(Vsat / sig) / log(10)) : Infinity;
const drStr = (sig > 0) ? (nf(dr, 0, 1) + " dB") : "inf";
noStroke(); fill("#0b0f18"); rect(0, FOOTY, width, 28);
fill("#aab6d6"); textSize(11); textAlign(LEFT, CENTER);
text("V = clamp(S*A*G*sin(2pi f t + phi), +/-Vsat) + noise", 10, FOOTY + 14);
textAlign(RIGHT, CENTER); fill("#cfe0ff");
text("G=" + nf(G, 0, 2) + " phi=" + nf(degrees(phi), 0, 0) +
" deg DR=" + drStr, 712, FOOTY + 14);
}
// =====================================================================
// controls
// =====================================================================
function toggleRun() {
running = !running;
btnRun.html(running ? "Pause" : "Run");
if (running) loop(); else { noLoop(); redraw(); }
}
function resetAll() {
sldS.value(DEF.S); sldA.value(DEF.A); sldF.value(DEF.f);
sldFc.value(DEF.fc); sldVsat.value(DEF.Vsat); sldSig.value(DEF.sig);
tsec = 0;
running = false; btnRun.html("Run");
noLoop(); redraw();
}
```
<!-- REAL-GENERATIVE-MEDIA:START -->
## The model this MicroSim animates
However different two transducers look, they share the same input-output description. Drive an input
**measurand** `x(t)` and the transducer returns an electrical output `V(t)`. Four characteristics -
the same four used to *rate* real transducers - decide how faithfully it does so. This sketch makes
each one a control you can move.
**1. Sensitivity / the transfer characteristic.** The output is a function of the input,
`V = f(x)`. Near an operating point the curve is locally a straight line whose slope is the
**sensitivity** `S = dV/dx` (output per unit input - e.g. mV per unit, mV/V for a load cell, uV/K
for a thermocouple). The left panel draws this **transfer characteristic**: a line of slope `S`.
**2. Range / saturation.** No real characteristic is a line forever; beyond the full-scale output it
**saturates**, flattening into plateaus at `+/-Vsat`. Drive the input past the point where
`|S * x| > Vsat` and the output **clips** - the peaks of the waveform are shorn flat.
**3. Bandwidth / dynamic response.** A transducer cannot follow an input instantly. Modelled as a
first-order [[System|system]] with a `-3 dB` cutoff `fc`, its sinusoidal **gain** rolls off and its output
**lags** the input:
```
G(f) = 1 / sqrt(1 + (f/fc)^2) (amplitude gain, <= 1)
phi(f) = -atan(f/fc) (phase lag, radians)
```
Below `fc` the output rides faithfully on the characteristic line; as `f` approaches and passes
`fc` the amplitude shrinks and the operating point opens from a line into a lagging **ellipse**
(a Lissajous loop) on the transfer plot - the visual signature of finite bandwidth.
**4. Noise floor / dynamic range.** Every transducer adds random **noise** to its output (in
electrical transducers, the thermal motion of charge). Noise of RMS value `sigma` corrupts *small*
signals far more than large ones. The ratio of the largest faithfully translated signal to the
smallest sets the **dynamic range**:
```
DR = 20 * log10(Vsat / sigma) dB
```
Putting it together, the output the sketch plots is the steady-state sinusoidal response
```
V(t) = clamp( S * A * G(f) * sin(2*pi*f*t + phi(f)), -Vsat, +Vsat ) + noise(sigma)
x(t) = A * sin(2*pi*f*t)
```
The "aha" is that **one input can fail to convert in three different ways**: it can be *clipped*
(too big for the range), *attenuated and delayed* (too fast for the bandwidth), or *buried* (too
small for the noise floor) - and the transfer characteristic shows you which is happening.
## Links (Wikipedia order)
<!-- injected from _registry/childlinks/Transducer.json (2026-07-30T02:09:12Z) -->
`Accelerometer` · `Actuator` · [[Alternating_current]] · `Amplifier` · `Amplitude` · `Antenna_(radio)` · `Audio_signal` · `Automation` · `Backlash_(engineering)` · [[Communications_system]] · [[Control_system]] · [[Cybernetics]] · `Disk_read-and-write_head` · [[Dynamic_range]] · `Electrical_conductor` · `Electro-galvanic_oxygen_sensor` · `Electroactive_polymer` · `Electrometer` · [[Electronics]] · [[Energy_transformation]] · `Finite-state_transducer` · `Fluorescent_lamp` · `Galvanometer` · `Gear_train` · `Geophone` · `Hall_effect_sensor` · `Human` · `Hydrophone` · `Hysteresis` · `Laser_diode` · `Light-emitting_diode` · `Linear_motor` · `Linear_variable_differential_transformer` · `List_of_sensors` · `Load_cell` · [[Loudspeaker]] · `Magnetic_cartridge` · `Magnetic_field` · `Microphone` · `Motion` · `Noise_(signal_processing)` · `Photodetector` · `Photodiode` · `Photomultiplier` · `Photoresistor` · `Pickup_(music_technology)` · `Piezoelectric_sensor` · `Potentiometer` · `Radio_receiver` · `Radio_wave` · [[Repeatability]] · `Robot` · `Rotary_variable_differential_transformer` · [[Sensor]] · [[Signal]] · `Software` · `Sound` · `Strain_gauge` · `Tactile_sensor` · `Tape_head` · `Thermistor` · `Thermocouple` · `Thermophone` · `Transceiver` · `Transmitter` · `Ultrasound` · `Vibrating_structure_gyroscope` · `Voice_coil` · [[Voltage]] · `Wireless`
## From the Real GENERATIVE library

*Transducer — placed from the Real G.E.N.E.R.A.T.I.V.E. course library (Energy room). Source: Wikimedia Commons (via Wikipedia article media). [Details & license](https://commons.wikimedia.org/wiki/File:Mechanical_transducer._-_DPLA_-_cfb11a91bbe9ab7384f897fb55faf74c_%28page_4%29.jpg).*
> A transducer is a device that converts energy from one form to another. Usually a transducer converts a signal in one form of energy to a signal in another.[1] Transducers are often employed at the boundaries of automation, measurement, and control systems, where electrical signals are converted to and from other physical quantities (energy, force, torque, l ([Wikipedia](https://en.wikipedia.org/wiki/Transducer))
<!-- REAL-GENERATIVE-MEDIA:END -->
## Overview
A **transducer** is a device that usefully converts [[Energy|energy]] from one form to another - most often a
**[[Signal|signal]]** carried in one form of energy into a signal carried in another. The conversion itself is
called **transduction**. Transducers live at the boundaries of measurement, automation, and control
systems, where physical quantities ([[Force|force]], pressure, temperature, light, position, sound, magnetic
field) are turned into electrical signals and back again.
Transducers are classified by the direction [[Information|information]] flows through them:
- A **sensor** is an *input* transducer: it responds to a stimulus from the physical world and
produces a signal that represents it (a thermocouple turning a temperature difference into a small
[[Voltage|voltage]]; an LVDT turning displacement into an AC signal; a load cell turning force into mV/V).
- An **actuator** is an *output* transducer: it takes a signal from a [[Control_system|control system]] and converts a
source of energy into motion, sound, light, or heat (a [[Loudspeaker|loudspeaker]], a motor, an LED).
- A **bidirectional** transducer works both ways. An antenna converts radio waves to a current and a
current to radio waves; a voice coil is a loudspeaker run forwards and a dynamic microphone run
backwards. This **reciprocity** is a defining feature of the family.
A second axis is the power source: **passive** transducers need an external **excitation** signal
that they modulate (a thermistor only reveals its resistance when a current is passed through it),
while **active** (self-generating) transducers produce their own output directly from the stimulus
(a photodiode, a thermocouple, a piezoelectric crystal).
## Parameter table (each control -> real symbol + range)
| Control | Symbol | Physical meaning | Range | Default |
|---|---|---|---|---|
| Sensitivity | `S` | transfer ratio = slope of the characteristic, output per unit input | 5 - 60 mV/unit | 20 mV/unit |
| Input amplitude | `A` | half-span of the driven measurand `x(t)` | 0 - 10 units | 7 units |
| Drive frequency | `f` | frequency of the input measurand | 0.2 - 20 Hz | 2 Hz |
| Bandwidth | `fc` | -3 dB cutoff of the first-order dynamic response | 0.5 - 20 Hz | 6 Hz |
| Range (saturation) | `Vsat` | full-scale output limit (+/-) where the curve flattens | 50 - 400 mV | 200 mV |
| Noise floor | `sigma` | RMS additive output noise | 0 - 20 mV | 0 mV |
Derived and shown live in the HUD: gain `G = 1/sqrt(1+(f/fc)^2)`, phase lag
`phi = -atan(f/fc)` (degrees), and dynamic range `DR = 20 log10(Vsat/sigma)` dB.
Controls: six sliders, plus **Run/Pause** (animate the drive) and **Reset** (restore every value,
phase, and the paused state).
## Learning objective
Explain how a transducer's **sensitivity, range, bandwidth, and noise floor** together determine
which inputs it can faithfully convert - and predict, by reading the transfer characteristic and the
input/output traces, **when the output will clip, when it will lag and shrink, and when it will
vanish into noise**.
## A-V pattern
A composition: a **G** system block-diagram strip (measurand -> transducer -> output) over a
quantitative **transfer-characteristic chart** (output vs input, left) and an **H** signals-over-time
pair of traces (input and output waveforms, right). The dynamic operating point traces a Lissajous
loop on the chart to expose bandwidth lag.
## Sources
- Transducer - Wikipedia: https://en.wikipedia.org/wiki/Transducer
<!-- CRAFT-LINK:START g12 -->
*Built to the [[WT!P5_js_Microsim_Master_Class|p5.js Master Class]].*
<!-- CRAFT-LINK:END -->
## Wikipedia : Wikitube
**Strict pair:** [Wikipedia](https://en.wikipedia.org/wiki/Transducer) : [Wikitube](https://en.wikitube.io/wiki/Transducer)
## Previous hub tags
Tree parent: [[Hydrogen]].
Legacy hubs: none.
---
*Sources: 1 legacy note. Minted wave 1, 2026-07-30 (v1.6 order).*