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, Kndepl, Vt, Vtdepl, -10, 10, guess);

        [VDS2, converged2] = newton_depl_sat_nmos_sat(VGS(i), VDD, lambda, Kn, Kndepl, Vt, Vtdepl, -10, 10, guess); 

        [VDS3, converged3] = newton_depl_sat_nmos_lin(VGS(i), VDD, lambda, Kn, Kndepl, Vt, Vtdepl, -10, 10, guess);

        [VDS4, converged4] = newton_depl_lin_nmos_sat(VGS(i), VDD, lambda, Kn, Kndepl, Vt, Vtdepl, -10, 10, guess); 

       

        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, Kndepl, Vt, Vtdepl, 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

    % 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, Kndepl, Vt, Vtdepl, 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

    % 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, Kndepl, Vt, Vtdepl, 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

    % 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, Kndepl, Vt, Vtdepl, 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

    % 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;