Back to Article
Sizing for Basic 5T-OTA
Download Notebook

Sizing for Basic 5T-OTA

Copyright 2024 Harald Pretl

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

In [1]:
# Read table data
from pygmid import Lookup as lk
import numpy as np
lv_nmos = lk('sg13_lv_nmos.mat')
lv_pmos = lk('sg13_lv_pmos.mat')
# List of parameters: VGS, VDS, VSB, L, W, NFING, ID, VT, GM, GMB, GDS, CGG, CGB, CGD, CGS, CDD, CSS, STH, SFL
# If not specified, minimum L, VDS=max(vgs)/2=0.9 and VSB=0 are used 
In [2]:
# Define the given parameters as taken from the specification table or inital guesses
c_load = 50e-15
gm_id_m12 = 10
gm_id_m34 = 5
gm_id_m56 = 5
l_12 = 5
l_34 = 5
l_56 = 5
f_bw = 10e6
i_total_limit = 10e-6
i_bias_in = 20e-6
output_voltage = 1.3
vin_min = 0.7
vin_max = 0.9
vdd_min = 1.45
vdd_max = 1.55
In [3]:
# We get the required gm of M1/2 from the bandwidth requirement
# We add a factor of 3 to allow for PVT variation plus additional MOSFET parasitic loading
gm_m12 = f_bw * 3 * 4*np.pi*c_load
print('gm12 =', gm_m12/1e-3, 'mS')
gm12 = 0.01884955592153876 mS
In [4]:
# Since we know gm12 and the gmid we can calculate the bias current
id_m12 = gm_m12 / gm_id_m12
i_total = 2*id_m12
print('i_total (exact) =', i_total/1e-6, 'µA')
# we round to 0.5µA bias currents
i_total = max(round(i_total / 1e-6 * 2) / 2 * 1e-6, 0.5e-6)
id_m12 = i_total/2

print('i_total (rounded) =', i_total/1e-6, 'µA')
if i_total < i_total_limit:
    print('[info] power consumption target is met!')
else:
    print('[info] power consumption target is NOT met!') 
i_total (exact) = 3.7699111843077517 µA
i_total (rounded) = 4.0 µA
[info] power consumption target is met!
In [5]:
# We calculate the dc gain
gm_gds_m12 = lv_nmos.lookup('GM_GDS', GM_ID=gm_id_m12, L=l_12, VDS=0.75, VSB=0)
gm_gds_m34 = lv_pmos.lookup('GM_GDS', GM_ID=gm_id_m34, L=l_34, VDS=0.75, VSB=0)

gds_m12 = gm_m12 / gm_gds_m12
gm_m34 = gm_id_m34 * i_total/2
gds_m34 = gm_m34 / gm_gds_m34

a0 = gm_m12 / (gds_m12 + gds_m34)
print('a0 =', 20*np.log10(a0), 'dB')
a0 = 34.78458740352468 dB
In [6]:
# We calculate the MOSFET capacitance which adds to Cload, to see the impact on the BW
gm_cgs_m12 = lv_nmos.lookup('GM_CGS', GM_ID=gm_id_m12, L=l_12, VDS=0.75, VSB=0)
gm_cdd_m12 = lv_nmos.lookup('GM_CDD', GM_ID=gm_id_m12, L=l_12, VDS=0.75, VSB=0)
gm_cdd_m34 = lv_pmos.lookup('GM_CDD', GM_ID=gm_id_m34, L=l_34, VDS=0.75, VSB=0)

c_load_parasitic = abs(gm_m12/gm_cgs_m12) + abs(gm_m12/gm_cdd_m12) + abs(gm_m34/gm_cdd_m34)
print('additional load capacitance =', c_load_parasitic/1e-15, 'fF')

f_bw = gm_m12 / (4*np.pi * (c_load + c_load_parasitic))
print('-3dB bandwidth incl. parasitics =', f_bw/1e6, 'MHz')
additional load capacitance = 54.92854674560976 fF
-3dB bandwidth incl. parasitics = 14.295442437000684 MHz
In [7]:
# We can now look up the VGS of the MOSFET
vgs_m12 = lv_nmos.look_upVGS(GM_ID=gm_id_m12, L=l_12, VDS=0.75, VSB=0.0)
vgs_m34 = lv_pmos.look_upVGS(GM_ID=gm_id_m34, L=l_34, VDS=0.75, VSB=0.0) 
vgs_m56 = lv_nmos.look_upVGS(GM_ID=gm_id_m56, L=l_56, VDS=0.75, VSB=0.0) 

print('vgs_12 =', vgs_m12, 'V')
print('vgs_34 =', vgs_m34, 'V')
print('vgs_56 =', vgs_m56, 'V')
vgs_12 = 0.36710119710062455 V
vgs_34 = 0.7287454603526495 V
vgs_56 = 0.5912200307058603 V
In [8]:
# Calculate settling time due to slewing with the calculated bias current
t_slew = (c_load + c_load_parasitic) * output_voltage / i_total
print('slewing time =', t_slew/1e-6, 'µs')
t_settle = 5/(2*np.pi*f_bw)
print('settling time =', t_settle/1e-6, 'µs')
slewing time = 0.034101777692323185 µs
settling time = 0.055666322953376014 µs
In [9]:
# Calculate voltage gain error
gain_error = a0 / (1 + a0)
print('voltage gain error =', (gain_error-1)*100, '%')
voltage gain error = -1.7902967715882068 %
In [10]:
# Calculate total rms output noise
sth_m12 = lv_nmos.lookup('STH_GM', VGS=vgs_m12, L=l_12, VDS=0.75, VSB=0) * gm_m12
gamma_m12 = sth_m12/(4*1.38e-23*300*gm_m12)

sth_m34 = lv_pmos.lookup('STH_GM', VGS=vgs_m34, L=l_34, VDS=0.75, VSB=0) * gm_m34
gamma_m34 = sth_m34/(4*1.38e-23*300*gm_m34)

output_noise_rms = 1.38e-23*300 / (c_load + c_load_parasitic) * (2*gamma_m12 + 2*gamma_m34 * gm_m34/gm_m12)
print('output noise (rms) =', output_noise_rms/1e-6, 'µV')
output noise (rms) = 0.12543377043178017 µV
In [11]:
# Calculate all widths
id_w_m12 = lv_nmos.lookup('ID_W', GM_ID=gm_id_m12, L=l_12, VDS=vgs_m12, VSB=0)
w_12 = id_m12 / id_w_m12
w_12_round = max(round(w_12*2)/2, 0.5)
print('M1/2 W =', w_12, 'um, rounded W =', w_12_round, 'um')

id_m34 = id_m12
id_w_m34 = lv_pmos.lookup('ID_W', GM_ID=gm_id_m34, L=l_34, VDS=vgs_m34, VSB=0)
w_34 = id_m34 / id_w_m34
w_34_round = max(round(w_34*2)/2, 0.5) 
print('M3/4 W =', w_34, 'um, rounded W =', w_34_round, 'um')

id_w_m5 = lv_nmos.lookup('ID_W', GM_ID=gm_id_m56, L=l_56, VDS=vgs_m56, VSB=0)
w_5 = i_total / id_w_m5
w_5_round = max(round(w_5*2)/2, 0.5)
print('M5 W =', w_5, 'um, rounded W =', w_5_round, 'um')
w_6 = w_5_round * i_bias_in / i_total
print('M6 W =', w_6, 'um')
M1/2 W = 1.7713641972645868 um, rounded W = 2.0 um
M3/4 W = 1.641014110777885 um, rounded W = 1.5 um
M5 W = 0.7351148286825442 um, rounded W = 0.5 um
M6 W = 2.5000000000000004 um
In [12]:
# Print out final design values
print('5T-OTA dimensioning:')
print('--------------------')
print('M1/2 W=', w_12_round, ', L=', l_12)
print('M3/4 W=', w_34_round, ', L=', l_34)
print('M5   W=', w_5_round, ', L=', l_56)
print('M6   W=', w_6, ', L=', l_56)
print()
print('5T-OTA performance summary:')
print('---------------------------')
print('supply current =', i_total/1e-6, 'µA')
print('output noise =', output_noise_rms/1e-6, 'µVrms')
print('voltage gain error =', (gain_error-1)*100, '%')
print('-3dB bandwidth incl. parasitics =', f_bw/1e6, 'MHz')
print('turn-on time (slewing+settling) =', (t_slew+t_settle)/1e-6, 'µs')
print()
print('5T-OTA bias point check:')
print('------------------------')
print('headroom M1 =', vdd_min-vgs_m34+vgs_m12-vin_max, 'V')
print('headroom M4 =', vdd_min-vin_max, 'V')
print('headroom M5 =', vin_min-vgs_m12, 'V')
5T-OTA dimensioning:
--------------------
M1/2 W= 2.0 , L= 5
M3/4 W= 1.5 , L= 5
M5   W= 0.5 , L= 5
M6   W= 2.5000000000000004 , L= 5

5T-OTA performance summary:
---------------------------
supply current = 4.0 µA
output noise = 0.12543377043178017 µVrms
voltage gain error = -1.7902967715882068 %
-3dB bandwidth incl. parasitics = 14.295442437000684 MHz
turn-on time (slewing+settling) = 0.08976810064569919 µs

5T-OTA bias point check:
------------------------
headroom M1 = 0.188355736747975 V
headroom M4 = 0.5499999999999999 V
headroom M5 = 0.3328988028993754 V