michea

Using Python for Implementing Parameter Extraction in IC-CAP

Blog Post created by michea on Jul 13, 2018

While IC-CAP is equipped with a powerful library of transforms and examples for performing model parameter extraction, we may extend this power using the built-in Python support in IC-CAP to access external Python libraries, especially when developing new behavioral models or implementing custom analysis routines.

 

In my previous article, I showed how to implement a quasi-static measurement in a series of IC-CAP transforms, demonstrating the flexibility of the data handling capabilities in IC-CAP.  Python modules like pyvisawrapper.py and dataparser.py modules extended the data parsing using external libraries. In this article, I will show you how you can also easily implement custom parameter extraction routines using Python in IC-CAP. Leveraging the work I presented in my previous blog entitled "Measuring Sub-Threshold MOSFET Characteristics Using a Quasi-Static I-V Method", I'll discuss a custom Python transform for extracting the Vth parameter (gate threshold voltage) on the quasi-static Id vs. Vg sweep data of a p-channel MOSFET.

 

We will be implementing the ICON (constant current) method for extracting Gate Threshold Voltage (Vth) from the Id vs. Vg data. This is a popular method due to its simplicity. Other popular methods ( i.e. Id_sat or Max_Gm methods ) can be similarly implemented using custom Python classes and functions.

 

Prerequisites

 

Depending on whether you happen to have an E5270B (or B1500A) or an older 4156C, you might prefer to download the complete IC-CAP model file py_new_api_basic_demo_5270.mdl or py_new_api_basic_demo_4156.mdl attached at the end of this post.

E5270BAgilent 4156C

 

Each model file contains the complete Python source code used to implement the quasi-static measurement. I recommend saving these *.mdl files to C:\Keysight\ICCAP_2018\examples\python, as I described in my previous article Measuring Sub-Threshold MOSFET Characteristics Using a Quasi-Static I-V Method. In these .mdl files we previously created the global arrays vvalue[ ] and ivalue[ ] in the _run transform for storing our forced voltage and measured current data values. In the _calc_vth transform we will access these arrays to extract the Vth value by calling an external Python script extract_vth_cc.py also attached below. You should copy the extract_vth_cc.py to your C:\Users\<username>\iccap\python directory or the directory specified by the environment variable ICCAP_USER_PYTHON_PATH.

 

Load the IC-CAP Model File

 

Assuming you saved the model file to the examples folder (C:\Keysight\ICCAP_2018\examples\python), click 'File/Examples...' and select: python\py_api_new_basic_demo_5270.mdl. (or *_4156.mdl).

 

Select the idvg_quasi Setup, go to the 'Extract / Optimize' tab and then select the _run transform.

The following arrays are defined to store the local I-V measured data:

 

# global list of values
vvalue = []
ivalue = []

...

 

Notice that the global namespace is set in the Function field by selecting PythonGlobal. This gives us access to the ivalue[] and vvalue[] along with vg_points (from the vgpts Setup Variable) which will be used in the extract_vth_cc function _calc_vth() below.

Go to the end of the _run transform and uncomment the following lines of code:

 

# calculate vth
if bOk: iccap_func("_calc_vth","execute")

...

 

Select the idvg_quasi Setup, go to the 'Extract / Optimize' tab and then select the _calc_vth transform.

 

from extract_vth_cc import * 
#################################################################
# _calc_vth.py
#
# Calculate Threshold voltage for IdVg measurement

# Uses _extract_vth which implement Icon method (IdVg@Vb=0)
#
# Device parameters

# W = channel width (um)
# L = channel length (um)
# M = channel mask multiplier
# deltaW = channel width variation
# deltaL = channel length variation 
#
################################################################# 
# get W, L from Model Variables
W = float(MVar("W").get_val())
L = float(MVar("L").get_val())
M = 1.0
icon = 1E-8
deltaW = 0
deltaL = 0
if debug: print "W = {} L = {} M = {} icon = {}
                 deltaW = {} deltaL = {}\n".format(W,L,M,icon,deltaW,deltaL)

if polarity == "PMOS":
   icon *= -1
 
# get Id[] Vg[] from _run
ids = ivalue[:vg_points]
vgs = vvalue[:vg_points] 

# get Id_Vg @ Vb=0
evt = extract_vth_cc(ids, vgs, W, L, M, deltaW, deltaL, icon)
vth = evt.calculate() 

print "vth = ", vth

 

The _calc_vth transform instantiates the extract_vth_cc class and initializes it by passing the measured data arrays ids and vgs along with the device geometry W, L, deltaW, deltaL and icon parameter (constant current value for extracting the gate threshold voltage). Once the extract_vth_cc instance is created, the calculate() function (or method) is called to return the Vgs that gives the current closest to the icon value.

 

Open the Python source code in your favorite editor.

 

Review the implementation of the extract_vth_cc class and calculate method.

 

extract_vth_cc.py source code listing

import numpy as np
from iccap import MVar
##############################################################################
#
# Global variables
#
##############################################################################
# enable/disable debug prints
debug = int(MVar("debug").get_val()) 

# extract_vth_cc script for extracting threshold voltage
class extract_vth_cc:    
   def __init__(self,id,vg,W,L,M,deltaW,deltaL,icon):
       """
       Initialize extract_vth_cc class.

       This function initializes the class used to extract Vth using
       the ICON method.

       Args:
          self:      This instance of the extract_vth_cc class.
           id:        Drain current array values.
           vg:        Gate voltage array values.
           W:         Device channel width.
           L:         Device channel length.
           M:         Channel mask multiplier.
          deltaW:    Channel width variation.
           deltaL:    Channel length variation.
           icon:      Constant current to extract Vth.

       Kwargs:
       Returns:       instance of class

       Raises:
       """
       self.id = id  # a list []
       self.vg = vg  # a list []
       self.W = W
       self.L = L
       self.M = M
       self.deltaW = deltaW
       self.deltaL = deltaL
       self.icon = icon
      
       # calculate and return Vth
       def calculate(self):
          """
          Calculates the gate threshold voltage.

          This function extracts the extrapolated Vth value by using
          the ICON method.

          Args:
             self:      This instance of the extract_vth_cc class.

          Kwargs:

          Returns:
             Vth:       Interpolated gate threshold voltage at icon.

          Raises:
          """
        
        # initialize local variables 
        vth =1E-30
        type = 1       # nmos        
        vg = self.vg
        id = self.id

        # create numpy array and initialize
        nid = np.zeros([len(id),1])
        
        # copy id to numpy array and flatten
        nid.flat[:] = id

        # compute the id reference value from device geometry
        iref = self.icon * self.M * (self.W - self.deltaW)/(self.L - self.deltaL)
        if debug: print "iref = {}".format(iref)
        
        # return the index closest to the reference value
        idx = (np.abs(nid - iref)).argmin()
        if debug: print "idx = {} id = {}".format(idx, id[idx])        
        
        # check if vg is negative - PMOS device type
        if vg[idx] < 0:
             type = -1   # pmos
        
        # return vg @ iref
        Vth = vg[idx]
        return Vth

 

Notice the use of Numpy arrays in the code above. The Numpy python module provides very convenient methods for processing array variables. (You'll never go back to PEL...) The zeros method creates a new Numpy array the length of the data ("len(id)") and initializes all values to 0.  Once the Numpy array is created and initialized, the flat method is used to iterate the 1D array while copying the id array values to the local nid array. The algorithm scales the constant current icon based on device geometry to calculate a reference current iref. Using this iref value, the index of the data point is returned which is closest to our target. This resulting index is used to return the value of the element of the vg array which is the Vth value.

 

Conclusion

 

You can quickly create reusable custom extractions or analysis routines using Python to start building your own modeling library. I hope this quick example of extracting gate threshold voltage will serve as a starting point for developing your own custom routines for use in IC-CAP. In follow on articles, I will demonstrate additional features of IC-CAP to streamline and customize your Python transforms using the IC-CAP's built-in user interface elements and TableVars to allow using parameter inputs in the Measure / Simulate tab to provide user-entered data to your Python transforms.

 

Related Links

 

Measuring Sub-Threshold MOSFET Characteristics Using a Quasi-Static I-V Method

How to Extract Threshold Voltage of MOSFETs

Python Programming Integration with IC-CAP

Outcomes