Getting gm by Id vs Id by W by L graphs in Cadence

14 January 2026 Link



The following steps need to be done for getting the gm/Id vs Id/(W/L) graphs in Cadence for a MOS transistor.

Create the schematic

The schematic is a simple transistor schematic. The schematic below shows an example:



The above schematic shows that the drain current(di), vgd, vbs, W and L are parameterized and they are sweeped in the simulation script (except vbs) to get the graphs for a wide range of conditions and check the variation of the graph for them.

Save Operating Point Info

Create a text file called mysaves_t18.scs and add the following line in it:

save MN0_PSP.m0:oppoint


Now add this file with path in ADE->Setup->Simulation Files->Definition Files
Note that the .m0 is only needed because this model is implemented as s Sub Circuit in the models file. If the model is not a subcircuit and something direct like a BSIM model then .m0 would not be needed.

Setup simulation in ADE

Setup the DC sweep simulation in ADE by DC sweeping di from a low value to a high value for a typical vgd, W and L. Set the sweep to be logarithmic with 50 points per decade. Also setup expressions to calculate
  1. gm/Id = gm/di expression: (getData("MNO_PSP.m0:gm" ?result "dc-dc")/IS("/V1/PLUS"))
  2. Id/(W/L) expression: (IS("/V1/PLUS")/(5e-6/180e-9))

Run the Simulation and see the results.

Create the Ocean Script

Save the Ocean Script from the ADE environment and modify it to look like the following:

  1. ; Select the waveform tool
  2. ocnWaveformTool( 'wavescan )
  3.  
  4. ; Select the simulator
  5. simulator( 'spectre )
  6.  
  7. ; Specify the Design Netlist
  8. design( "/sim/mgupta/nch_char_1/spectre/schematic/netlist/netlist")
  9.  
  10. ; Specify the Results Directory
  11. resultsDir( "/sim/mgupta/nch_char_1/spectre/schematic" )
  12.  
  13. ; Specify the model files set
  14. modelFile(
  15. '("/home/tekcad/cds4_4/lib/models.scs" "tt_res")
  16. '("/home/tekcad/cds4_4/lib/models.scs" "tt_mim")
  17. '("/home/tekcad/cds4_4/lib/models.scs" "tt")
  18. )
  19.  
  20. ; Specify the Definition file created to save the operating point
  21. definitionFile(
  22. "/home/mgupta/Cadence/mysaves_t18.scs"
  23. )
  24.  
  25. ; Convert the main run steps to a procedure 'mysim' and convert width, length, vgd, istart, istop
  26. ; etc as variables to be passed along with the filehandle where to write the results
  27. procedure(mysim(istart istop length width vgd fileHandle)
  28. analysis('dc ?param "di" ?start istart ?stop istop ?dec "50" )
  29. desVar( "l" length )
  30. desVar( "vgd" vgd )
  31. desVar( "di" 5u )
  32. desVar( "w" width )
  33. save( 'i "/V1/PLUS" )
  34. temp( 27 )
  35. run()
  36. gm_by_Ids = (getData("MN0_PSP.m0:gm" ?result "dc-dc") / IS("/V1/PLUS"))
  37. id_by_w_l = IS("/V1/PLUS")*length/width
  38.  
  39. ;Comment out the plot statement
  40. ;plot( gm_by_Ids ?expr '( "gm_by_Ids" ) )
  41.  
  42. ; Write the results in the filehandle
  43. ocnPrint( ?output fileHandle ?numberNotation 'engineering ?numSpaces 10 id_by_w_l gm_by_Ids)
  44. )
  45.  
  46. ; Create file for writing the results
  47. resultFile = outfile( "./Curves/gmByIdCurves.csv" "w")
  48. ; Close the file
  49. close(resultFile)
  50.  
  51. ; Lists for iterating the simulation
  52.  
  53. length_list = list(180e-9 500e-9 1e-6 1.5e-6 2e-6 2.5e-6 3e-6 3.5e-6 4e-6 4.5e-6 5e-6 5.5e-6 6e-6 6.5e-6 7e-6 7.5e-6 8e-6 8.5e-6 9e-6 9.5e-6 10e-6)
  54. ;length_list = list(180e-9 500e-9)
  55. width_list = list(2e-6 4e-6 6e-6 8e-6 10e-6 15e-6 20e-6)
  56. ;width_list = list(2e-6 4e-6)
  57. vgd_list = list(0.3 0 -0.3 -0.6 -0.9)
  58. ;vgd_list = list(0.3 0)
  59.  
  60. min_IdbyWL = 1e-9
  61. max_IdbyWL = 200e-6
  62.  
  63. ; Loop through all the lists
  64. foreach( vgd vgd_list
  65. foreach( width width_list
  66. foreach(length length_list
  67. ; Calculate istart, istop so that Id/(W/L) starts and stops the same for every W/L combination
  68. istart = min_IdbyWL*width/length
  69. istop = max_IdbyWL*width/length
  70. ; Write the data in a temp File
  71. tempFile = outfile("./Curves/gmByIdtmp.out" "w")
  72. mysim(istart istop length width vgd tempFile)
  73. ; Close the file
  74. close(tempFile)
  75. ; Combine the data file and temp file to an intermediate file
  76. ; Create the intermediate file
  77. system(sprintf(nil "pr -mr -t -s\\ %s %s > %s" "./Curves/gmByIdCurves.csv" "./Curves/gmByIdtmp.out" "./Curves/gmByIdinter.out"))
  78. ; remove the Curves data file
  79. system(sprintf(nil "rm -rf ./Curves/gmByIdCurves.csv"))
  80. ; rename intermediate file to Curves file
  81. system(sprintf(nil "mv ./Curves/gmByIdinter.out ./Curves/gmByIdCurves.csv"))
  82. )
  83. )
  84. )
  85.  
  86. ; Remove the temporary File
  87. system(sprintf(nil "rm -rf ./Curves/gmByIdtmp.out"))


Save this ocean script (say 'gmByIdScript.ocn') and load it from the CIW window by typing:

load("gmByIdScript.ocn")


This would start the simulations and at the end we would have the file gmByIdCurves.csv with all the simulation results.

Draw the Graph using MATLAB

Finally create the following script in MATLAB and name it mergeGraphs.m and run it to create the graphs in a figure:
  1. % Script to read gmbyId.txt and merge the readings to just 1 graph
  2. % 1st column is taken as Current, 2nd column as Id/(W/L), 3rd column as
  3. % gm/Id
  4. % Remove the 1st 2 lines as the header lines
  5.  
  6. arr = textread('gmByIdCurves.csv','',-1,'headerlines',2,'headercolumns',0);
  7.  
  8. figure(1);
  9. for count = 2:3:size(arr,2)
  10. semilogx(arr([1:size(arr,1)],count),arr([1:size(arr,1)],count+1),'r');
  11. hold on;
  12. end
  13. grid on;
  14.  
  15. xlabel('Id/(W/L)')
  16. ylabel('gm/Id')
  17. title('gm/Id vs Id/(W/L) for 2V NMOS TSMC 0.18\mum RF; 180nm \leq L \leq 10\mum, 2\mum \leq W \leq 20\mum, 0.3V \leq Vgd \leq -0.9V')


Drawing the Graph using gsl-shell

Use the following script. The script can be loaded in gsl-shell using the command dofile('script_path_and_name').
  1. csv = require 'csv'
  2. t=csv.read('MyScripts/gmByIdCurves.csv')
  3. -- Convert it to a 2D numeric array since the csv is space separated and not "," separated
  4. curves = {}
  5. for i = 4,#t do
  6. curves[#curves+1] = {}
  7. for n in string.gmatch(t[i][1],"%S+") do
  8. curves[#curves][#curves[#curves]+1] = tonumber(n)
  9. end
  10. end
  11.  
  12. -- Now all the data table is in Curves:
  13. -- 1st column is drain current
  14. -- 2nd column is Id/(W/L)
  15. -- 3rd column is gm/Id
  16. -- And it repeats
  17. p = graph.plot()
  18.  
  19. for i = 2,#curves[1],3 do
  20. -- Create the line here
  21. ln = graph.path(math.log10(curves[1][i]),curves[1][i+1])
  22. for j = 2,#curves do
  23. ln:line_to(math.log10(curves[j][i]),curves[j][i+1])
  24. end
  25. p:addline(ln)
  26. end
  27. p:show()


Sample Graph

Shown below is a sample graph from the above steps:



NOTE This graph was taken with a linear sweep a better graph will result of the sweep is set to logarithmic especially with no discontinuity in the slope as it seems in this one.

References