Engineering 77 Final
Project
30 November 2005
Tyler Strombom, Aron Dobos
Numerical Simulation of MOSFETs
using MATLAB
Abstract
The purpose of our project was to extend the numerical techniques learned in Lab 2 to simulate simple MOSFET circuits. A Newton-Raphsen non-linear equation solver program was written in MATLAB, and used to simulate a resistive load inverter circuit. The result was verified by a SPICE simulation.
Resistive Load Inverter
The circuit is shown below in Figure 1.
Figure 1. Resistive Load Inverter
The equations used in the MATLAB solver were developed by summing currents at the output node. The level 1 MOSFET equations were used including the channel length modulation parameter λ, but the substrate (Body) effect was ignored. Since the transistor Q1 may be operating in any three regions, the circuit had to be solved for each of the operating regions, and the result that was consistent with the initial assumptions was then chosen as the correct result. For reference, the equations governing the operation of an NMOS transistor are reproduced below.
The code consists of 3 files. Nmos_resistive.m sets the various transistor parameters such as Kn, VT0, and λ, and calls the functions nmos_newton_linear_t.m and nmos_newton_saturation_t.m to calculate the output voltage VDS at each input voltage from 0 to VDD. Each function returns both the calculated output voltage as well as whether the Newton-Raphsen solver converged. From these results it is determined which of the two results to use. Note that for VGS < VT0, the current is 0 and the solution is trivial. The DC transfer characteristic of the inverter circuit is shown below in Figure 2.
Figure 2. Resistive Load Inverter Transfer Characteristic (MATLAB)
Below the SPICE netlist used for verifying the MATLAB result is included. The SPICE generated transfer characteristic is included in Figure 3.
*e77 final project
Vdd 5 0 dc 5
R1 5 4 10k
M1 4 3 0 0 MNMOSIS L=3u
W=6u
* M1 DRAIN GATE SOURCE BULK
.MODEL MNMOSIS NMOS LEVEL=1 VTO=1 KP=40E-06
LAMBDA=2e-02
V1 3 0 dc 1
.control
dc v1 0 5 0.01
plot V(4)
.endc
.end
SPICE Netlist for Resistive Load Inverter
Simulation
Figure 3. Resistive Load Inverter Transfer Characteristic (SPICE)
A comparison of the two transfer characteristics indicates that indeed the MATLAB solver is working as expected. The MATLAB code is reproduced below for reference.
Depletion-load NMOS
Inverter
The general inverter circuit is shown in Figure 4.
Figure 4: Depletion Load Inverter
As in Task 1, Iload and Idriver were set equal to each other for the four possible NMOS mode combinations to determine the equations and their derivatives necessary for the Newton Raphsen technique.
The MATLAB code calculates the output voltage for each of the four combinations, and then tries to determine which of the four results is the correct one. The calculated voltages must be consistent with the assumed operating region for the each device, and of course the Newton-Raphson solver must have converged also.
The MATLAB simulation result is given below in Figure 5.
Figure 5. MATLAB Simulation for Depletion Mode Inverter
The discontinuity experienced at Vin=2.4V has not been explained yet. Despite this error, the simulation agrees nicely with the SPICE result generated with the following netlist.
Vdd 5 0 dc
5
M0 5 4 4 0 MNDEPL L=3u W=6u
M1 4 3 0 0 MNMOSIS L=3u W=6u
* M1 DRAIN GATE SOURCE
BULK
.MODEL MNMOSIS NMOS
LEVEL=1 VTO=1 KP=40E-06 LAMBDA=2e-02
.MODEL MNDEPL NMOS
LEVEL=1 VTO=-3 KP=8E-06 LAMBDA=2e-02
V1 3 0 dc 1
.control
dc v1 0 5
0.01
plot V(4)
.endc
.end
Figure 6. SPICE Result for Depletion Load Inverter
Appendix A. MATLAB
Code for Resistive Load Inverter
%% resistive load inverter
clc
DV=0.5e-1;
VDD=5;
VGS=0:DV:VDD;
Kn = 40e-6*2; % 40
uA/V^2, (W/L)=2
Rload = 10000;
Vt = 1;
lambda = 0.02;
Vout = zeros(size(VGS));
state = zeros(size(VGS));
guess = 5; %initial guess for vout
for i=1:length(VGS)
if (i > 1)
guess
= Vout(i-1); % use previous VDS as guess for
next one
end
if (VGS(i) <= Vt)
Vout(i)
= VDD;
state(i) = 0;
else
[VDS1, converged1] =
nmos_newton_linear_t(VGS(i), VDD, lambda, Rload, Kn, Vt,
-100, 100, guess);
[VDS2, converged2] =
nmos_newton_saturation_t(VGS(i), VDD, lambda, Rload, Kn, Vt,
-100, 100, guess);
if (converged1 ==
0 && converged2 == 0)
display(sprintf('vgs=%g neither function converged: error', VGS(i)));
VGS(i)
return;
elseif (converged1 == 1 && VDS1 <=
VGS(i)-Vt) % lin succeeded
Vout(i) = VDS1;
state(i) = 1; % lin
elseif (converged2 == 1 && VDS2 >
VGS(i)-Vt) % sat
succeeded
Vout(i) = VDS2;
state(i) = 2; % sat;
else
display('Error: inconsistent solution');
if (converged1==1)
display(sprintf('-> linear converged, but VDS(%g) < VGS(%g)
- Vt(%g) failed.', VDS1, VGS(i),
Vt));
end
if (converged2==1)
display(sprintf('-> saturation converged, but VDS(%g) >
VGS(%g) - Vt(%g) failed.', VDS2, VGS(i), Vt));
end
end
end
end
plot(VGS, Vout,
VGS, state);
legend('curve1');
title('Resistive load NMOS inverter');
xlabel('Vin');
ylabel('Vout');
function [VDS, converged] = nmos_newton_linear_t(VGS,
VDD, lambda, Rload, Kn, Vt, vmin, vmax,
guess)
threshold = 0.00001; % accuracy
of VDS result
max_iter = 50; % maximum number of iterations
VDS = guess; % start
with a reasonable guess
converged = 2;
for i=1:max_iter
flag
= 0;
f = Kn*((VGS-Vt)*VDS-VDS^2/2)*(1+lambda*VDS)
- (VDD-VDS)/Rload;
df = Kn*(VGS-Vt) - Kn*VDS + 2*lambda*Kn*(VGS-Vt)*VDS - 3*VDD^2/2*Kn*lambda + 1/Rload;
dx = f/df;
VDS = VDS - dx; % x1 = x - f(x)/df(x)
if (VDS < vmin || VDS > vmax)
display(sprintf('vgs=%g linear equation
out of bounds', VGS));
return;
end
% if
change from previous Vd
value was smaller than
% the
accuracy threshold, we're done, so return.
if (abs(dx) < threshold)
converged
= 1;
display(sprintf('vgs=%g linear equation
converged', VGS));
return;
end
end
return;
function [VDS, converged] = nmos_newton_saturation_t(VGS,
VDD, lambda, Rload, Kn, Vt, vmin, vmax,
guess)
threshold = 0.00001; % accuracy
of VDS result
max_iter = 50; % maximum number of iterations
VDS = guess; % start
with a reasonable guess
converged = 0;
for i=1:max_iter
flag
= 0;
f = Kn/2*((VGS-Vt)^2)*(1+lambda*VDS) - (VDD-VDS)/Rload;
df = Kn/2*lambda*(VGS-Vt)^2
+ 1/Rload;
dx = f/df;
VDS = VDS - dx; % x1 = x - f(x)/df(x)
if (VDS < vmin || VDS > vmax)
display(sprintf('vgs=%g saturation
equation out of bounds', VGS));
return;
end
% if
change from previous Vd
value was smaller than
% the
accuracy threshold, we're done, so return.
if (abs(dx) < threshold)
converged
= 1;
display(sprintf('vgs=%g saturation
equation converged', VGS));
return;
end
end
return;
Appendix B. MATLAB Code for Depletion Load Inverter
%% depletion-mode nmos load
inverter
clc
DV=0.05;
VDD=5;
VGS=0:DV:VDD;
Kn = 40e-6*2; % 40
uA/V^2, (W/L)=2
Kndepl = 8e-6*2; % 8
uA/V^2, (W/L)=2
Vt = 1;
Vtdepl = -3;
lambda = 0.02;
Vout = zeros(size(VGS));
state = zeros(size(VGS));
guess = 5; %initial guess for vout
for i=1:length(VGS)
if (i > 1)
guess
= Vout(i-1); % use previous VDS as guess for next
one
end
if (VGS(i) <= Vt)
Vout(i)
= VDD;
state(i) = 0;
else
[VDS1, converged1] =
newton_depl_lin_nmos_lin(VGS(i), VDD, lambda, Kn,
[VDS2, converged2] =
newton_depl_sat_nmos_sat(VGS(i), VDD, lambda, Kn,
[VDS3, converged3] =
newton_depl_sat_nmos_lin(VGS(i), VDD, lambda, Kn,
[VDS4, converged4] =
newton_depl_lin_nmos_sat(VGS(i), VDD, lambda, Kn,
disp(sprintf('** vgs=%g convergance results:(%d %d
%d %d)', VGS(i), converged1, converged2,
converged3, converged4));
if (converged1 ==
0 && converged2 == 0 && converged3 == 0 && converged4
== 0)
disp(sprintf('vgs=%g neither function
converged: error', VGS(i)));
VGS(i)
return;
% depl(lin) nmos(lin)
elseif (converged1 == 1 && VDS1 <
VGS(i)-Vt &&
(VDD-VDS1) < -Vtdepl)
VDD-VDS1
-Vtdepl
Vout(i) = VDS1;
state(i) = 1;
disp(sprintf('** vgs=%g chose result
1: depl(lin) nmos(lin) VDS=%g',VGS(i), VDS1));
% depl(sat)
nmos(sat)
elseif (converged2 ==
1 && VDS2 >= VGS(i)-Vt
&& (VDD-VDS2) >= -Vtdepl)
Vout(i) = VDS2;
state(i) = 2;
disp(sprintf('** vgs=%g chose result
2: depl(sat) nmos(sat)
VDS=%g',VGS(i),VDS2));
% depl(sat)
nmos(lin)
elseif (converged3 == 1 && VDS3 <
VGS(i)-Vt &&
(VDD-VDS3) >= -Vtdepl)
Vout(i) = VDS3;
state(i) = 3;
disp(sprintf('** vgs=%g chose result
3: depl(sat) nmos(lin) VDS=%g',VGS(i),VDS3));
% depl(lin)
nmos(sat)
elseif (converged4 == 1 && VDS4 >=
VGS(i)-Vt &&
(VDD-VDS4) < -Vtdepl)
Vout(i) = VDS4;
state(i) = 4;
disp(sprintf('** vgs=%g chose result
4: depl(lin) nmos(sat) VDS=%g',VGS(i),VDS4));
%disp(sprintf('vgs=%g nmos saturation solution used (VDS=%g) consistent', VGS(i), VDS2));
else
disp('Error:
inconsistent solution!');
if (converged1==1)
disp(sprintf('->1 depl:lin nmos:lin converged,
but VDS(%g) < VGS(%g) - Vt(%g) failed.', VDS1, VGS(i), Vt));
end
if (converged2==1)
disp(sprintf('->2 depl:sat nmos:sat converged,
but VDS(%g) > VGS(%g) - Vt(%g) failed.', VDS2, VGS(i), Vt));
end
if (converged3==1)
disp(sprintf('->3 depl:sat nmos:lin converged,
but VDS(%g) < VGS(%g) - Vt(%g) failed.', VDS3, VGS(i), Vt));
end
if (converged4==1)
disp(sprintf('->4 depl:lin nmos:sat converged,
but VDS(%g) > VGS(%g) - Vt(%g) failed.', VDS4, VGS(i), Vt));
end
end
end
end
plot(VGS, Vout,
VGS, state);
legend('curve1');
title('Depletion-mode NMOS load inverter');
xlabel('Vin');
ylabel('Vout');
function [F, DF] = ID_nmos_sat(VGS,
VDS, VDD, lambda, Kn, Vt)
F = Kn/2*((VGS-Vt)^2)*(1+lambda*VDS);
DF = 1/2*Kn*(VGS-Vt)^2*lambda;
function [F, DF] = ID_nmos_lin(VGS,
VDS, VDD, lambda, Kn, Vt)
F = Kn*((VGS-Vt)*VDS-VDS^2/2)*(1+lambda*VDS);
DF = Kn*(VGS-Vt-VDS)*(1+lambda*VDS)+Kn*((VGS-Vt)*VDS-1/2*VDS^2)*lambda;
function [F, DF] = ID_depl_sat(VDS,
VDD, lambda, Kn, Vt)
VGS = 0;
F = Kn/2*(VGS-Vt)^2*(1+lambda*(VDD-VDS));
DF = -1/2*Kn*(VGS-Vt)^2*lambda;
function [F, DF] = ID_depl_lin(VDS,
VDD, lambda, Kn, Vt)
VGS = 0;
F = Kn*((VGS-Vt)*(VDD-VDS)-(VDD-VDS)^2/2)*(1+lambda*(VDD-VDS));
DF = Kn*(-abs(-VGS+Vt)+VDD-VDS)*(1+lambda*(VDD-VDS))-Kn*(abs(-VGS+Vt)*(VDD-VDS)-1/2*(VDD-VDS)^2)*lambda;
function [VDS, converged] = newton_depl_lin_nmos_lin(VGS,
VDD, lambda, Kn,
threshold = 0.00001; % accuracy
of VDS result
max_iter = 50; % maximum number of iterations
VDS = guess; % start
with a reasonable guess
converged = 0;
for i=1:max_iter
%
calculate the functions and the derivatives
% function
ID_depl_lin(VDS, VDD, lambda, Kn, Vt)
[f_depl
df_depl] = ID_depl_lin(VDS, VDD, lambda, Kndepl, Vtdepl);
% function
ID_nmos_lin(VGS, VDS, VDD, lambda, Kn, Vt)
[f_nmos
df_nmos] = ID_nmos_lin(VGS, VDS, VDD, lambda, Kn, Vt);
f = f_depl
- f_nmos;
df = df_depl - df_nmos;
dx = f/df;
VDS = VDS - dx; % x1 = x - f(x)/df(x)
if (VDS < vmin || VDS > vmax)
disp(sprintf('vgs=%g linear equation out of bounds', VGS));
return;
end
% if
change from previous Vd
value was smaller than
% the
accuracy threshold, we're done, so return.
if (abs(dx) < threshold)
converged
= 1;
return;
end
end
return;
function [VDS, converged] = newton_depl_sat_nmos_sat(VGS,
VDD, lambda, Kn,
threshold = 0.00001; % accuracy
of VDS result
max_iter = 50; % maximum number of iterations
VDS = guess; % start
with a reasonable guess
converged = 0;
for i=1:max_iter
%
calculate the functions and the derivatives
[f_depl
df_depl] = ID_depl_sat(VDS, VDD, lambda, Kndepl, Vtdepl);
[f_nmos
df_nmos] = ID_nmos_sat(VGS, VDS, VDD, lambda, Kn, Vt);
f = f_depl
- f_nmos;
df = df_depl - df_nmos;
dx = f/df;
VDS = VDS - dx; % x1 = x - f(x)/df(x)
if (VDS < vmin || VDS > vmax)
disp(sprintf('vgs=%g saturation equation out of bounds', VGS));
return;
end
% if
change from previous Vd
value was smaller than
% the
accuracy threshold, we're done, so return.
if (abs(dx) < threshold)
converged
= 1;
return;
end
end
return;
function [VDS, converged] = newton_depl_sat_nmos_lin(VGS,
VDD, lambda, Kn,
threshold = 0.00001; % accuracy
of VDS result
max_iter = 50; % maximum number of iterations
VDS = guess; % start
with a reasonable guess
converged = 0;
for i=1:max_iter
% calculate
the functions and the derivatives
[f_depl
df_depl] = ID_depl_sat(VDS, VDD, lambda, Kndepl, Vtdepl);
[f_nmos
df_nmos] = ID_nmos_lin(VGS, VDS, VDD, lambda, Kn, Vt);
f = f_depl
- f_nmos;
df = df_depl - df_nmos;
dx = f/df;
VDS = VDS - dx; % x1 = x - f(x)/df(x)
if (VDS < vmin || VDS > vmax)
disp(sprintf('vgs=%g linear equation out of bounds', VGS));
return;
end
% if
change from previous Vd
value was smaller than
% the
accuracy threshold, we're done, so return.
if (abs(dx) < threshold)
converged
= 1;
return;
end
end
return;
function [VDS, converged] = newton_depl_lin_nmos_sat(VGS,
VDD, lambda, Kn,
threshold = 0.00001; % accuracy
of VDS result
max_iter = 50; % maximum number of iterations
VDS = guess; % start
with a reasonable guess
converged = 0;
for i=1:max_iter
%
calculate the functions and the derivatives
% function
ID_depl_lin(VDS, VDD, lambda, Kn, Vt)
[f_depl
df_depl] = ID_depl_lin(VDS, VDD, lambda, Kndepl, Vtdepl);
% function
ID_nmos_sat(VGS, VDS, VDD, lambda, Kn, Vt)
[f_nmos
df_nmos] = ID_nmos_sat(VGS, VDS, VDD, lambda, Kn, Vt);
f = f_depl
- f_nmos;
df = df_depl - df_nmos;
dx = f/df;
VDS = VDS - dx; % x1 = x - f(x)/df(x)
if (VDS < vmin || VDS > vmax)
disp(sprintf('vgs=%g saturation equation out of bounds', VGS));
return;
end
% if
change from previous Vd
value was smaller than
% the
accuracy threshold, we're done, so return.
if (abs(dx) < threshold)
converged
= 1;
return;
end
end
return;