Piecewise Linear Models in SPICE

EE461g — Implementing PWL Diode and Zener Models with Behavioral Sources

1. Why Piecewise Linear Models?

Real diode behavior follows the Shockley equation, which is nonlinear and can make hand analysis difficult. Piecewise linear (PWL) models approximate the I-V curve using straight-line segments, making circuit analysis tractable while retaining the essential behavior.

In SPICE, we can implement PWL models using behavioral sources (the B element), which let us define current as an arbitrary function of voltage. This gives us direct control over the model, unlike the built-in .model D(...) which always uses the exponential Shockley equation.

2. Review: PN Diode PWL Models

We build up diode models in three levels of complexity:

ModelForward BiasReverse BiasParameters
Model 1 — Ideal Short circuit (VD = 0) Open circuit (ID = 0) None
Model 2 — Constant Vf VD = Vf Open circuit Vf
Model 3 — Vf + rd VD = Vf + ID·rd Open circuit Vf, rd

Model 3 in SPICE (Vf + Rs)

The most useful PN model uses a forward voltage drop plus a series (dynamic) resistance. In lecture notes this resistance is often called rd; in SPICE models it is typically called Rs. They represent the same thing: the slope of the I-V curve in the conducting region. Implemented as a behavioral current source:

* PWL PN Diode subcircuit
.subckt PWL_DIODE anode cathode
* If V(anode,cathode) > Vf:  I = (V - Vf)/Rs    (on, linear slope)
* Otherwise:                 I = V/Roff           (off, tiny leakage)
B1 anode cathode I = (V(anode,cathode) > 0.7) ?
+   (V(anode,cathode) - 0.7)/5.0 + V(anode,cathode)/1e6
+   : V(anode,cathode)/1e6
.ends PWL_DIODE
Key idea: The B element defines a behavioral source. The syntax B1 n+ n- I = <expression> creates a current source whose value is computed from node voltages at each simulation step. The ternary operator condition ? value_if_true : value_if_false implements the piecewise breakpoints.

3. The Zener Diode PWL Model

A Zener diode behaves like a regular diode in forward bias, but also conducts in reverse breakdown at a well-defined voltage VZ. The PWL model therefore has three regions:

Zener diode I-V characteristic illustrated as a piecewise-linear curve with forward, off, and breakdown regions.
Figure 1: Zener diode I-V characteristic (PWL model)
RegionConditionCurrentBehavior
Forward VAK > Vf I = (VAK − Vf) / Rs Same as regular diode
Off −VZ ≤ VAK ≤ Vf I ≈ 0  (VAK / Roff) Both junctions off
Reverse breakdown VAK < −VZ I = (VAK + VZ) / Rs Zener conduction

where VAK = V(anode) − V(cathode).

SPICE Subcircuit

* PWL Zener Diode subcircuit
* Parameters: VF=0.7V, VZ=5.1V, RS=5ohm, Roff=1Mohm
.subckt PWL_ZENER anode cathode

B1 anode cathode I =
+   (V(anode,cathode) > 0.7) ?
+       (V(anode,cathode) - 0.7)/5.0 + V(anode,cathode)/1e6
+   : ( (V(anode,cathode) < -5.1) ?
+       (V(anode,cathode) + 5.1)/5.0 + V(anode,cathode)/1e6
+   :   V(anode,cathode)/1e6 )

.ends PWL_ZENER

Reading the Expression

The behavioral source uses nested ternary operators. Written as pseudocode:

if V(anode,cathode) > 0.7:              # Forward bias
    I = (V - 0.7) / 5.0 + V / 1e6
elif V(anode,cathode) < -5.1:            # Reverse breakdown
    I = (V + 5.1) / 5.0 + V / 1e6
else:                                    # Off region
    I = V / 1e6
Why Roff? The V/1e6 term adds a tiny leakage current in all regions. This serves two purposes: (1) it models real-world leakage, and (2) it prevents numerical convergence problems in SPICE by ensuring the device always has a finite (though very high) impedance.

4. Parameters

ParameterSymbolMeaningTypical Value
Forward voltageVfTurn-on voltage in forward bias0.7 V (Si)
Zener voltageVZReverse breakdown voltage3.3, 5.1, 12 V, etc.
On-state resistanceRsInverse slope of I-V in conducting region (smaller Rs = steeper curve)1–20 Ω
Off-state resistanceRoffLeakage resistance when off100 kΩ–1 MΩ

5. Complete Example: Zener Voltage Regulator

A classic application: using a Zener diode to regulate voltage. The Zener is reverse-biased, so it clamps the output at approximately VZ.

Circuit

Zener voltage regulator schematic with V_in, series resistor R_S, and Zener diode.

Full ngspice Netlist

Save the code below to a file (e.g., regulator.cir) and run it with:

ngspice -b regulator.cir
* Zener Voltage Regulator - PWL Model
* Demonstrates piecewise linear Zener in a regulator circuit

* --- Zener subcircuit definition ---
.subckt PWL_ZENER anode cathode
B1 anode cathode I =
+   (V(anode,cathode) > 0.7) ?
+       (V(anode,cathode) - 0.7)/5.0 + V(anode,cathode)/1e6
+   : ( (V(anode,cathode) < -5.1) ?
+       (V(anode,cathode) + 5.1)/5.0 + V(anode,cathode)/1e6
+   :   V(anode,cathode)/1e6 )
.ends PWL_ZENER

* --- Circuit ---
Vin in 0 DC 0
Rs  in out 100

* Zener: pin order matches .subckt definition (anode cathode)
*   first pin  (0)   -> anode   = GND
*   second pin (out)  -> cathode = Vout
* This puts the Zener in reverse bias for regulation.
Xz1 0 out PWL_ZENER

* --- DC sweep ---
.dc Vin -15 15 0.01

* --- Output ---
.control
run
set gnuplot_terminal=png
gnuplot zener_regulator v(out) v(in)
+   title 'Zener Regulator: Vout vs Vin'
+   xlabel 'Input Voltage (V)'
+   ylabel 'Output Voltage (V)'
quit
.endc

.end
Watch the polarity! In the regulator circuit, the Zener anode connects to ground and the cathode connects to Vout. This means V(anode,cathode) = 0 − Vout = −Vout. When Vout exceeds VZ, V(anode,cathode) < −VZ, activating the breakdown region and clamping the output.

What happens for negative Vin?

When Vin goes negative, Vout also goes negative. Now V(anode,cathode) = −Vout becomes positive. Once it exceeds Vf (i.e., Vout < −Vf), the Zener is forward-biased and conducts like a regular diode. This clamps Vout near −Vf ≈ −0.7V. The three operating regions of this circuit are:

Input RangeZener StateVout
Vin > VZReverse breakdown≈ VZ (clamped, slight slope from Rs)
−Vf ≤ Vin ≤ VZOff≈ Vin (passes through)
Vin < −VfForward-biased≈ −Vf (clamped, slight slope from Rs)

6. Interactive Simulation

Adjust the parameters below and click Simulate to see the Zener regulator response computed in your browser. The simulation sweeps Vin from −Vmax to +Vmax and solves the circuit at each step using Newton-Raphson iteration.

Zener Regulator Parameters

Vout vs Vin
V_out versus V_in plot for the Zener regulator. Live values reported in the status text below.
Circuit Current I vs Vin
Circuit current I versus V_in.
Vout vs Vin — PWL Model vs Ideal
V_out versus V_in comparing PWL model to ideal Zener.

Ideal (orange) assumes Rs = 0 and Roff = ∞: Vout = Vin when off, Vout = VZ when regulating, Vout = −Vf when forward-biased. PWL (blue) includes finite Rs so Vout has a small slope in the regulating region.

Zener I-V Characteristic
Zener I-V characteristic from the simulation.

Standalone I-V curve of the Zener subcircuit (not the regulator circuit). Shows the three PWL regions with your chosen VZ, Vf, and Rs.

Things to Try

  1. Increase Rs to 50 Ω. Notice how the Vout slope in the regulating region gets steeper — the regulation is worse because more voltage drops across the Zener's internal resistance.
  2. Increase Rseries to 500 Ω. The regulation actually gets better (flatter Vout). Why? Because Rseries absorbs more of the input variation.
  3. Set VZ to 3.3 V to model a common low-voltage Zener. Watch how the clamp level changes in both the positive (breakdown) and negative (forward) directions.
  4. Set Vf to 0.3 V to model a Schottky-like forward drop. Observe the asymmetry: the negative clamp moves closer to 0 V while the positive clamp stays at VZ.
  5. Compare with the ideal model (orange line). As Rs → 0, the blue PWL curve should approach the orange ideal curve. Try Rs = 0.1 to verify.

7. Tips for Students

  1. Always define the subcircuit first. Place .subckt ... .ends before the main circuit so ngspice can resolve X instance references.
  2. Check polarity. The B source convention: positive current flows from the first node to the second. V(anode,cathode) is the voltage across the device in the expected direction.
  3. Use Roff for convergence. A pure open circuit (I = 0) in the off region can cause SPICE convergence failures. A small leakage term V/Roff fixes this.
  4. Nested ternary syntax: cond1 ? val1 : (cond2 ? val2 : val3) — parentheses around the inner ternary improve readability but are optional in ngspice.
  5. Continuation lines in SPICE use a + at the start of the next line.
  6. To change the Zener voltage, just change the -5.1 and +5.1 values in the expression to your desired VZ.

8. Extending the Model

Back-to-Back Zener Limiter

Two Zener diodes connected cathode-to-cathode clip both positive and negative peaks:

* Back-to-back Zener Limiter - Complete Netlist

* --- Zener subcircuit (same as before) ---
.subckt PWL_ZENER anode cathode
B1 anode cathode I =
+   (V(anode,cathode) > 0.7) ?
+       (V(anode,cathode) - 0.7)/5.0 + V(anode,cathode)/1e6
+   : ( (V(anode,cathode) < -5.1) ?
+       (V(anode,cathode) + 5.1)/5.0 + V(anode,cathode)/1e6
+   :   V(anode,cathode)/1e6 )
.ends PWL_ZENER

* --- Circuit ---
Vin in 0 SIN(0 10 1k)
Rs  in out 100

* Cathode-to-cathode configuration:
* Positive swing: Xz1 forward + Xz2 breakdown -> clips at Vz + Vf
* Negative swing: Xz1 breakdown + Xz2 forward -> clips at -(Vz + Vf)
Xz1 out mid PWL_ZENER
Xz2 0   mid PWL_ZENER

.tran 1u 3m

.control
run
plot v(in) v(out)
.endc

.end

Different Forward and Reverse Resistances

You can use separate Rs,fwd and Rs,rev values for more accurate modeling. Here the forward resistance is 2.6 Ω and the reverse (breakdown) resistance is 10 Ω:

.subckt PWL_ZENER_ASYM anode cathode
B1 anode cathode I =
+   (V(anode,cathode) > 0.7) ?
+       (V(anode,cathode) - 0.7)/2.6 + V(anode,cathode)/1e6
+   : ( (V(anode,cathode) < -5.1) ?
+       (V(anode,cathode) + 5.1)/10.0 + V(anode,cathode)/1e6
+   :   V(anode,cathode)/1e6 )
.ends PWL_ZENER_ASYM