MOSFET I-V curves
Device Characterization — SPICE Level-1 model, computed
Example from the compendium of canonical charts
Python Code
"""Device Characterization — MOSFET I-V curves (SPICE Level-1 model, computed)."""
import numpy as np
import plotly.graph_objects as go
def generate():
# SPICE Level-1 MOSFET parameters
k = 1e-3 # process gain (A/V²)
Vth = 1.0 # threshold voltage (V)
lam = 0.02 # channel-length modulation (V⁻¹)
VGS_vals = [1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0]
VDS = np.linspace(0, 5, 200)
colors = [
"#845EEE", "#55B685", "#E9A23B", "#DA5597", "#52B3D0",
"#a07fd6", "#3d9c6e", "#c87c22",
]
fig = go.Figure()
for idx, vgs in enumerate(VGS_vals):
ID = np.zeros_like(VDS)
vov = vgs - Vth # overdrive voltage
if vov <= 0:
# Cutoff: ID = 0 everywhere
pass
else:
for j, vds in enumerate(VDS):
if vds < vov:
# Triode (linear) region
ID[j] = k * (vov * vds - vds**2 / 2)
else:
# Saturation region
ID[j] = (k / 2) * vov**2 * (1 + lam * vds)
# Convert A → mA
ID_mA = ID * 1e3
fig.add_trace(go.Scatter(
x=VDS,
y=ID_mA,
mode="lines",
name=f"V<sub>GS</sub> = {vgs:.1f} V",
line=dict(color=colors[idx % len(colors)], width=2),
hovertemplate=f"VGS={vgs:.1f}V<br>VDS=%{{x:.2f}}V<br>ID=%{{y:.2f}}mA<extra></extra>",
))
# Boundary between triode and saturation: VDS = VGS - Vth
vgs_arr = np.array(VGS_vals)
vds_sat = vgs_arr - Vth
id_sat_mA = (k / 2) * (vgs_arr - Vth)**2 * 1e3
# Only show for VGS > Vth
mask = vgs_arr > Vth
fig.add_trace(go.Scatter(
x=vds_sat[mask],
y=id_sat_mA[mask],
mode="lines",
line=dict(color="gray", width=1.5, dash="dot"),
name="Saturation boundary",
hovertemplate="VDS<sub>sat</sub>=%{x:.2f}V<br>ID=%{y:.2f}mA<extra></extra>",
))
# Annotations for regions
fig.add_annotation(
x=0.5, y=6.5,
text="Triode",
showarrow=False,
font=dict(size=11, color="gray"),
)
fig.add_annotation(
x=3.0, y=6.5,
text="Saturation",
showarrow=False,
font=dict(size=11, color="gray"),
)
fig.update_layout(
xaxis=dict(title="V<sub>DS</sub> (V)", range=[0, 5]),
yaxis=dict(title="I<sub>D</sub> (mA)", range=[0, None]),
legend=dict(
x=1.02, y=1.0,
xanchor="left",
font=dict(size=10),
),
margin=dict(t=20, b=60, l=70, r=140),
)
return fig
if __name__ == "__main__":
generate()
Made with Plotly