Integrated Capacitors

Capacitors are important in realizing most circuits.

A capacitor stores energy in an electric field between two “plates”. The basic equation for a capacitor is C=\epsilon\frac{A}{d}. As with most integrated devices, there are trade-offs between the desired aspects of the device and the undesired elements. Many different kinds of capacitors are available that make different trade-offs. The important properties we want in capacitors are:

  1. Cost
  2. Capacitor density: capacitance per unit area
  3. parasitic capacitance: capacitance to other nodes besides the two plates we are interested in
  4. parasitic resistance
  5. parasitic inductance
  6. leakage: appears as a parallel resistor
  7. Breakdown voltage

Metal-Oxide-Metal (MOM) Capacitors

MOM capacitors are the most straight forward capacitors available in an integrated circuit process. They are especially useful in advanced digital optimized CMOS processes with many layers of interconnects. Several geometries can be used (from lowest to highest density): parallel plate, interdigitated (with or without via stack), rotative, and fractal. Vertical bars or vertical parallel plates usually give the best capacitance density, with slightly different trade-offs for C vs Q (= \frac{1}{\omega RC}).

MOM capacitors can be inexpensive for small values: no extra masks are required. But the low density makes large capacitors quite expensive in silicon area. Modern processes actively try to reduce interconnect parasitics using low-K dielectrics, so cap density trend is probably going lower. Some low-K dielectrics can have low breakdown voltages. The parasitic inductance and resistance will depend on the geometry.

Pros: no extra masks, or process options needed, good linearity

Cons: moderate bottom plate parasitic, low density, high series inductance and resistance, possibly low breakdown voltage,


MIM Capacitors

MIM capacitors are formed by sandwiching a thin dielectric between two metal layers. Typically the dielectric thickness is much smaller than IMD thickness. This requires more masks for the top electrode as well as the dielectric.

Pros: lower bottom plate parasitic, high density, good linearity, low

Cons: extra mask cost (offset by potentially lower area)

Source: A new damascene architecture for high-performance metal–insulator–metal capacitors integration – Scientific Figure on ResearchGate. Available from: [accessed 26 Jun, 2017]


Every MOSFET has a capacitor at it’s heart. All one needs to do is connect the source and drain together to make bottom plate and the gate serves as top plate. This capacitor is available in every process, but suffers from a severe limitation: It’s highly non-linear as the effective gate thickness is dependent on the bias applied. The applied gate voltage can change the concentration of carriers (holes or electrons) in the channel. At some voltage, the channel can be depleted of all carriers and the capacitance reaches a minimum. Voltages higher or lower will collect carriers in the channel and create a capacitor of reasonable value.

C-V (or capacitance-voltage) profile curves
Saumitra Raj Mehrotra; Gerhard Klimeck (2010), “CV profile with different oxide thickness,”

Enhanced MOSCAP on highly-doped diffusion

The obvious way to improve the MOSCAP linearity is to make sure the channel cannot be depleted. This improves the linearity a lot, to about 2-5% total variation. It is usually done with NMOS device because it is naturally in accumulation mode. Adding an extra implant pushes it further into accumulation. One extra mask can help achieve a better trade-off of density and cost.


Depending on the process available, the density, cost and linearity requirements, one can use one or more of MOM, MIM, MOSCAP, or enhanced MOSCAP. MOM is cheap, lowest density, and most linear. MIM cap is the most expensive, good density, and very linear. MOSCAP is cheapest, high density, and very non-linear. Enhanced MOSCAP is cheap, high-density, and somewhat linear.

gm/Id method

The traditional circuit bias and sizing method using square law, as described in textbooks, is cumbersome and not very accurate in today’s sub-micron technologies. Unfortunately, the prevalent textbooks being rather old, still teach the square law method.

A more modern method using “gm/Id” of the transistor has been known since 1996 (Silviera, et. al. 1996), but hasn’t made its way into many designers’ toolkits. Instead of trying to explain it here, I suggest reading Bernhard E Boser’s (2011) lecture notes.

If you’d like to try this yourself, I have created an example testbench for ngspice using 45nm predictive technology models from ASU and a python script to post-process it.

If you find an error, have an idea for improving it, or just want to discuss this generally, please leave a reply or contact me.

Silveira, F., D. Flandre, and P. G.A Jespers. “A gm/ID Based Methodology for the Design of CMOS Analog Circuits and Its Application to the Synthesis of a Silicon-on-Insulator Micropower OTA.” IEEE Journal of Solid-State Circuits 31, no. 9 (September 1996): 1314–19. doi:10.1109/4.535416.
Boser, Bernhard E. “Analog Design Using gm/Id and Ft Metrics,” 2011.

ngspice raw and numpy

Numpy makes it almost trivial to read ngspice raw binary files into python:

# MIT license:
# See
# for a more complete library. Isotel's version is GPL licensed
from __future__ import division
import numpy as np
BSIZE_SP = 512 # Max size of a line of data; we don't want to read the
# whole file to find a line, in case file does not have
# expected structure.
MDATA_LIST = [b'title', b'date', b'plotname', b'flags', b'no. variables',
b'no. points', b'dimensions', b'command', b'option']
def rawread(fname: str):
"""Read ngspice binary raw files. Return tuple of the data, and the
plot metadata. The dtype of the data contains field names. This is
not very robust yet, and only supports ngspice.
>>> darr, mdata = rawread('')
>>> darr.dtype.names
>>> plot(np.real(darr['frequency']), np.abs(darr['v(out)']))
# Example header of raw file
# Title: rc band pass example circuit
# Date: Sun Feb 21 11:29:14 2016
# Plotname: AC Analysis
# Flags: complex
# No. Variables: 3
# No. Points: 41
# Variables:
# 0 frequency frequency grid=3
# 1 v(out) voltage
# 2 v(in) voltage
# Binary:
fp = open(fname, 'rb')
plot = {}
count = 0
arrs = []
plots = []
while (True):
mdata = fp.readline(BSIZE_SP).split(b':', maxsplit=1)
if len(mdata) == 2:
if mdata[0].lower() in MDATA_LIST:
plot[mdata[0].lower()] = mdata[1].strip()
if mdata[0].lower() == b'variables':
nvars = int(plot[b'no. variables'])
npoints = int(plot[b'no. points'])
plot['varnames'] = []
plot['varunits'] = []
for varn in range(nvars):
varspec = (fp.readline(BSIZE_SP).strip()
assert(varn == int(varspec[0]))
if mdata[0].lower() == b'binary':
rowdtype = np.dtype({'names': plot['varnames'],
'formats': [np.complex_ if b'complex'
in plot[b'flags']
else np.float_]*nvars})
# We should have all the metadata by now
arrs.append(np.fromfile(fp, dtype=rowdtype, count=npoints))
fp.readline() # Read to the end of line
return (arrs, plots)
if __name__ == '__main__':
arrs, plots = rawread('test.raw')
# Local Variables:
# mode: python
# End:
view raw hosted with ❤ by GitHub

Verilog-A and overall accuracy settings

Fast-spice, or multi-rate simulators use different time-steps for each partition in a circuit. This can have some interesting consequences when used along with Verilog-A models.

Verilog-A allows one to use model some aspects of the circuit behavior using events. Unfortunately, sometimes the containing partition of the Verilog-A model uses very aggressive optimization for reducing the number of time-steps evaluated. This can cause the simulator to never evaluate the Verilog-A event.

In this case one has to set fairly conservative settings for the containing block. So all the speed gain from the Verilog-A model is lost in the conservative settings for the next block. Watch out for the gotcha!