Transient example

Introduction

This is an example of transient simulation, featuring the well-known Colpitts oscillator.

../_images/colpitts.png

Bias:

\(V_{dd}=2.5V\), \(V_{bias}=2V\).

Passives:

\(L_1 = 5 nH\), \(R_0=3.14 k\Omega\) (\(Q_L=33\) @ 3 GHz)

\(C_1 = C_2 = 1.012 pF\) (resulting in \(n = C_1/(C_1 + C_2) = 0.5\))

\(C_2\) has a \(Q\) greater than 10 for every \(I_b\) less than \((w_0 C_2)^2/(2 K 10^2)\) = 4.8 mA.

Under such condition, the minimum transconductance required for oscillation can be calculated considering the MOS transistor an ideal voltage probe. The presence of the MOS has to be taken into account when evaluating the overall \(Q\) of the tank.

Under such hypothesis: \(g_{m,min} = 1/(n(1-n)R0)\), \(I_{b,min} = 1.27\) mA. In the following we use \(I_b\) = 1.3mA.

Netlist-based simulation

Netlist

MOS COLPITTS OSCILLATOR

vdd dd 0 type=vdc vdc=2.5

* Ql = 33 at 3GHz
l1 dd nd 5n ic=-1n
r0 nd dd 3.5k

* n = 0.5, f0 = 3GHz
c1 nd ns 1.12p ic=2.5
c2 ns 0  1.12p *ic=.01

m1 nd1 bias ns ns nmos w=200u l=1u
vtest nd nd1 type=vdc vdc=0 *read current

* Bias
vbias bias 0 type=vdc vdc=2
ib ns 0 type=idc idc=1.3m

.model ekv nmos TYPE=n VTO=.4 KP=10e-6

.op
.tran tstop=150n tstep=.1n method=trap uic=2
.plot tran v(nd)

The voltage generator Vtest has been added to the circuit in series with M1’s drain to add the drain current to the variables.

We need to simulate the circuit for roughly \(T \approx 10Q_L/f_0\) = 110ns to approach the steady state solution. The simulation above stops at \(t\) = 150ns.

Running the simulation

Save the netlist in a file and start ahkab with:

$ ahkab colpitts_mos.spc -o colpitts_graph

The simulation takes 70s on my laptop. Set tstop to a lower value to make it faster.

Results

Operating point (.OP)

The operating point is shown in this section of the program output:

2015-02-23 15:28:37
ahkab v. 0.13 (c) 2006-2015 Giuseppe Venturini

Operating Point (OP) analysis

Netlist: colpitts_mos.ckt
Title: MOS colpitts oscillator
At 300.00 K
Options:
    vea = 1.000000e-06
    ver = 0.001000
    iea = 1.000000e-09
    ier = 0.001000
    gmin = 0.000000e+00

Convergence reached in 42 iterations.

========
RESULTS:
========

Variable        Value         Error  (%)      Units
----------  ---------  ------------  -------  -------
VDD          2.5       -2.5e-12      (-0.00)  V
VND          2.5       -2.5e-12      (-0.00)  V
VNS         -0.116201   2.48567e-10  (-0.00)  V
VND1         2.5       -2.50951e-10  (-0.00)  V
VBIAS        2         -2e-12        (-0.00)  V
I(VDD)      -0.0013     0            (-0.00)  A
I(L1)        0.0013     0            (0.00)   A
I(VTEST)     0.0013     0            (0.00)   A
I(VBIAS)     0          0            (0.00)   A

========================
ELEMENTS OP INFORMATION:
========================

Part ID      V(n1-n2) [V]         Q [C]        E [J]
---------  --------------  ------------  -----------
C1               2.6162     2.93015e-12  3.83292e-12
C2              -0.116201  -1.30145e-13  7.56149e-15

Part ID      V(n1-n2) [V]    I [A]         P [W]
---------  --------------  -------  ------------
IB              -0.116201   0.0013  -0.000151061

Part ID      ϕ(n1,n2) [Wb]    I(n1->n2) [A]      E [J]
---------  ---------------  ---------------  ---------
L1                 6.5e-12           0.0013  4.225e-15

----  --------  -----------------  ----  ----  -----------------  -----  --------  -------------------------  ----  --------  -----------------
m1    N ch      STRONG INVERSION               LINEAR
beta  [A/V^2]:  0.000746574470194  Weff  [m]:  0.0002 (0.0002)    Leff   [m]:      1.33945110625e-06 (1e-06)  M/N:            1/1
Vdb   [V]:      2.616200987        Vgb   [V]:  2.116200987        Vsb    [V]:      0.0                        Vp    [V]:      1.18126783831
VTH   [V]:      0.4                VOD   [V]:  1.61188671993      nq:              1.44011732737              VA    [V]:      1.99917064176
Ids   [A]:      0.00129999988445   nv:         1.36453957998      Ispec  [A]:      3.84987888131e-06          TEF:            0.063129029685
gmg   [S]:      0.00184989038878   gms   [S]:  -0.00317451824956  rob    []:      1537.82370727
if:             475.729938341      ir:         23.4335578457      Qf     [C/m^2]:  0.00111108138735           Qr    [C/m^2]:  0.000227594358407
----  --------  -----------------  ----  ----  -----------------  -----  --------  -------------------------  ----  --------  -----------------

Part ID      R []    V(n1,n2) [V]    I(n1->n2) [A]    P [W]
---------  -------  --------------  ---------------  -------
R0            3500               0                0        0

Part ID      V(n1,n2) [V]    I(n1->n2) [A]     P [W]
---------  --------------  ---------------  --------
VDD                   2.5          -0.0013  -0.00325
VTEST                 0             0.0013   0
VBIAS                 2             0        0

Transient simulation (.TRAN)

The oscillation builds up quickly, as shown in this plot of \(V_{nd}\):

../_images/plot.png

From inspection, the circuit oscillates at 3.002 GHz with an oscillation amplitude of roughly 4V.

The next plot shows the oscillation starting off from the very beginning in a phase plane:

../_images/colpitts_phase_plane.png

API-based simulation

As an exercise, we will show here also how to perform a similar simulation taking advantage of the Python API.

Python script

import ahkab
import pylab

osc = ahkab.Circuit('MOS COLPITTS OSCILLATOR')

# models need to be defined before the devices that use them
osc.add_model('ekv', 'nmos', dict(TYPE='n', VTO=.4, KP=10e-6))

osc.add_vsource('vdd', n1='dd', n2=osc.gnd, dc_value=3.3)

# Ql = 33 at 3GHz
osc.add_inductor('l1', n1='dd', n2='nd', value=5e-9, ic=-1e-9)
osc.add_resistor('r0', n1='nd', n2='dd', value=3.5e3)

# n = 0.5, f0 = 3GHz
osc.add_capacitor('c1', n1='nd', n2='ns', value=1.12e-12)
osc.add_capacitor('c2', n1='ns', n2=osc.gnd, value=1.12e-12)

osc.add_mos('m1', nd='nd1', ng='bias', ns='ns', nb='ns',
            model_label='nmos', w=600e-6, l=100e-9)
# voltage source as a current probe
osc.add_vsource('vtest', n1='nd', n2='nd1', dc_value=0)

# Bias
osc.add_vsource('vbias', n1='bias', n2=osc.gnd, dc_value=2.)
osc.add_isource('ib', n1='ns', n2=osc.gnd, dc_value=1.3e-3)

# calculate an Operating Point (OP) to initialize the transient
# analysis
op = ahkab.new_op()
res = ahkab.run(osc, op)

# modify the OP to give the circuit a little kick to start the
# oscillation
x0 = res['op'].asmatrix()
l1vdei = osc.find_vde_index('l1')
l1i = len(osc.nodes_dict) - 1 + l1vdei
x0[l1i, 0] += -1e-9

# Setup and run a transient analysis with the modified x0 as start point
tran = ahkab.new_tran(tstart=0., tstop=20e-9, tstep=.01e-9, method='trap',
                      x0=x0)
res = ahkab.run(osc, tran)['tran']

# plot the results!
pylab.subplot(211)
pylab.hold(True)
pylab.plot(res.get_x(), res['vnd'], label='ND')
pylab.plot(res.get_x(), res['vns'], label='NS')
pylab.plot(res.get_x(), res['vbias'], label='BIAS')
pylab.legend()
pylab.subplot(212)
pylab.plot(res.get_x(), res['i(vtest)'], label='I(VTEST)')
pylab.legend()
pylab.show()

As we have increased in the above the W of M1 and therefore its \(g_m\), the oscillation will build up faster and to a higher top amplitude.

Running the simulation

To run the simulation, just save the above code to a file, for example colp.py and run:

python colp.py

If matplotlib is available and set up correctly, a graph should pop up in a little while.

Results

The OP is not shown here, it can be printed with res['op'].write_to_file('stdout'), but more interesting is manipulating the raw data with res['op'].asmatrix().

The following graph shows the gate, drain and source voltages of the MOS transistor, along with its drain current. M1 is on only for a fraction of each period, this happens if \(I_b\) is greater than approx. \(1.5I_{b,min}\).

../_images/colp-detail.png

It can be shown that an increase in \(I_b\) increases the oscillation amplitude. When the oscillation amplitude (at nd) approaches \(V_{dd}\), a damping will appear at the middle of the current peak, because \(V_{ds} = V_{nd}\) - \(V_{ns}\) will be near to zero. If the oscillation amplitude increases further \(V_{ds}\) crosses 0V and becomes negative for a small period of time. Accordingly, \(I_d\) crosses 0A and becomes negative for such period.

Of course, in any case, the average current through M1 has to be equal to \(I_b\). In fact:

>> print(res['i(vtest)'].mean())
0.00119411417458

Which is close enough counting that it is calculated over a fractional number of periods.

During a period, M1 is always on, switching from saturation region (\(Vgs > Vt\), \(Vgd < Vt\)) to ohmic operation (channel at both source and drain). The latter happens when \(I_d\) is maximum.