---
title: |
  Fundamentals of Analog VLSI Design \
  Exercise 5 - Problem
subtitle: The Cascode Gain Stage
author: Christian Enz (christian.enz@epfl.ch)
affiliation: EPFL
date: 10-15-2025
date-format: "DD.MM.YYYY"
execute:
  echo: false
  warning: false
toc: true
number-sections: true
number-depth: 3
highlight-style: pygments
bibliography: references.bib
csl: ieee.csl
format: 
  html:
    include-in-header: mathjax.html
    code-fold: true
    html-math-method: mathjax
    css: styles.css
  pdf:
    keep-tex: true
    pdf-engine: pdflatex
    documentclass: scrreprt
    papersize: a4
    geometry:
      - top=20mm
      - bottom=20mm
      - left=20mm
      - right=20mm
    include-in-header:
      text: |
        \usepackage{scrlayer-scrpage}
        \rohead[\thepage]{\thepage}
        \cohead[Exercise 5]{Exercise 5}
        \lofoot[$\copyright$ C. Enz]{$\copyright$ C. Enz}
        \cofoot[Fundamentals of Analog VLSI Design]{Fundamentals of Analog VLSI Design}
        \rofoot[15.09.2025]{15.10.2025}
---

```{python}
# Initialization

from ekv_functions import *

import pandas as pd
import matplotlib.pyplot as plt
import subprocess
import shutil
import os
import os.path as op
import sys
sys.path.append(".")
import re

from IPython.display import Markdown
from tabulate import tabulate

plt.rcParams['svg.fonttype'] = 'none'
plt.rcParams['pdf.fonttype'] = 42
plt.rcParams['font.family'] = 'Arial'
plt.rcParams['mathtext.fontset'] = 'custom'
plt.rcParams['mathtext.rm'] = 'Arial'
plt.rcParams['mathtext.it'] = 'Arial:italic'
plt.rcParams['mathtext.bf'] = 'Arial:bold'

inkscapePath = r"C:\\Program Files\\Inkscape\bin\\inkscape.exe"
savePlotPath = "./Plots/"
#savePlots=True
savePlots=False

if savePlots:
  lw=1
  curvelw=2
  msize=6
  textFontSize=12
  BodePlotParams = {'figure.figsize': (6,6)}
  pltStyle='plt_style_medium.mplstyle'
else:
  lw=1
  curvelw=1
  msize=5
  textFontSize=9
  BodePlotParams = {'figure.figsize': (5,5)}
  pltStyle='plt_style_small.mplstyle'

plt.style.use(pltStyle)

circuitName="cascode"
newSim=True
#newSim=False
refloat=r'.*?([+-]?\d+([.]\d*)?([eE][+-]?\d+)?|[.]\d+([eE][+-]?\d+)?)'

def saveFigures(savePath, plotName):
#  print("Patience, saving plot!")
  figFolder = savePath + r"\\{}.{}"
  pngFile = figFolder.format(plotName,"png")
  pdfFile = figFolder.format(plotName,"pdf")
  svgFile = figFolder.format(plotName,"svg")
  plt.savefig(pngFile, format="png", dpi=1200, bbox_inches="tight", transparent=True)
  plt.savefig(pdfFile, format="pdf", dpi=1200, bbox_inches="tight", transparent=True)
  plt.savefig(svgFile, format="svg", dpi=1200, bbox_inches="tight", transparent=True)
  cmd_emf = '"{}" "{}\\{}.svg" --export-filename="{}\\{}.emf" --export-overwrite'.format(inkscapePath, savePath, plotName, savePath, plotName)
#    cmd_emf = '"{}" "{}\{}.pdf" --export-filename="{}\{}.emf" --export-overwrite'.format(inkscapePath, savePath, plotName, savePath, plotName)
#    cmd_pdf = '"{}" "{}\{}.svg" --export-filename="{}\{}.pdf" --export-overwrite'.format(inkscapePath, savePath, plotName, savePath, plotName)
  subprocess.call(cmd_emf, shell=True)
#    subprocess.call(cmd_pdf, shell=True)
```

# Cascode stage{#sec-problem1}

![Schematic of the cascode gain stage.](Figures/cascode_schematic_with_cap.png){#fig-cascode_schematic}

@fig-cascode_schematic shows the schematic of the basic cascode gain stage, where both transistors M~1~ and M~2~ are biased in saturation. The cascode gain stage is used to increase the output resistance (reduce the output conductance) and therefore increase the DC gain without spending more current (current reuse). We will show that this increase of the output resistance and gain is done without significant increase of noise.

We will first carry a small-signal analyze to demonstrate the above features. Then we will show that the noise of the cascode transistor M~2~ can actually be neglected at low frequency.

## Analysis
### Small-signal analysis
* Draw the equivalent small-signal schematic of the cascode gain stage of @fig-cascode_schematic assuming that the transistors M~1~ and M~2~ are biased in saturation.
* Calculate the DC equivalent transconductance $G_{meq} \triangleq \left.\Delta I_{out}/\Delta V_{in}\right|_{\Delta V_{out}=0}$ assuming that $G_{ms2} \gg G_{ds1}, G_{ds2}$.
* Calculate the output conductance $G_{out} = \Delta I_{out}/\Delta V_{out}$ neglecting the parasitic capacitance $C_{p1}$. How does it compare to the output conductance $G_{ds1}$ of M~1~ alone?
* Calculate the output admittance $Y_{out} = \Delta I_{out}/\Delta V_{out}$ including the parasitic capacitance $C_{p1}$. What is the effect of the parasitic capacitance $C_{p1}$ on the output admittance $Y_{out}$?

### Noise analysis
* Calculate the output noise conductance $G_{nout}$ and input-referred noise resistance $R_{nin}$ neglecting the parasitic capacitance $C_{p1}$.
  Separate the input-referred noise resistance in its thermal and 1/f noise contributions $R_{nin}(f) = R_{nt} + R_{nf}(f)$.
* Calculate the cascode noise excess factor $\gamma_{cas} = G_{meq} \cdot R_{nt}$. How does it compare to the noise coming from M~1~ only?
* What is the effect of the parasitic capacitance $C_{p1}$ at node 1 on the input-referred noise?

## Design
Design the circuit of @fig-cascode_schematic to achieve the specifications given in @tbl-specs for a generic 180nm bulk CMOS process. Find the minimum current and size the transistor to achieve these specifications. The physical parameters are given in @tbl-physics_param, the global process parameters in @tbl-process_param and finally the MOSFET parameters for this 180nm bulk CMOS process are given in @tbl-mos_param. 

```{python}
#| label: tbl-specs
#| tbl-cap: Specifications for the cascode gain stage.

from specs import *

table = [["DC gain","$A_{{dc}}$",f'{AdcdBspec:.0f}',"$dB$"],
#         ["DC gain","$A_{{dc}}$",f'{Adcspec:.0f}',"-"],
         ["Gain-bandwidth product","$GBW$",f'{GBWspec/1e6:.0f}',"$MHz$"],
         ["Load capacitance","$C_L$",f'{CL/1e-12:.0f}',"$pF$"]
         ]

Markdown(tabulate(
  table,
  headers=["Specification","Symbol","Value","Unit"],
  numalign="center",
  stralign="center",
  colalign=("left","center","center","center")
))
```

```{python}
#| label: tbl-physics_param
#| tbl-cap: Physical parameters

from tsmc018_sekv_ekv2p6 import *

table = [["$T$",f'{T:.0f}',"$K$"],
         ["$U_T$",f'{UT/1e-3:.3f}',"$mV$"]
         ]

Markdown(tabulate(
  table,
  headers=["Parameter","Value","Unit"],
  numalign="center",
  stralign="center",
  colalign=("center", "center", "center")
))
```

```{python}
#| label: tbl-process_param
#| tbl-cap: Global process parameters

table = [["$V_{DD}$",f'{VDD:.1f}',"$V$"],
         ["$C_{ox}$",f'{Cox*1e3:.3f}',"$\\frac{fF}{\\mu m^2}$"],
         ["$W_{min}$",f'{Wmin/1e-9:.0f}',"$nm$"],
         ["$L_{min}$",f'{Lmin/1e-9:.0f}',"$nm$"]
         ]

Markdown(tabulate(
  table,
  headers=["Parameter","Value","Unit"],
  numalign="center",
  stralign="center",
  colalign=("center", "center", "center")
))
```

```{python}
#| label: tbl-mos_param
#| tbl-cap: Transistor process parameters

table = [["sEKV parameters"],
         ["$n$",f'{n0n:.2f}',f'{n0p:.2f}',"-"],
         ["$I_{{spec\\Box}}$",f'{Ispecsqn/1e-9:.0f}',f'{Ispecsqp/1e-9:.0f}',"$nA$"],
         ["$V_{{T0}}$",f'{VT0n:.3f}',f'{VT0p:.3f}',"$V$"],
         ["$L_{{sat}}$",f'{Lsatn/1e-9:.0f}',f'{Lsatp/1e-9:.0f}',"$nm$"],
         ["$\\lambda$",f'{lambdan*1e-6:.0f}',f'{lambdap*1e-6:.0f}',"$\\frac{{V}}{{\\mu m}}$"],
         ["Overlap capacitances parameters"],
         ["$C_{{GDo}}$",f'{CGDOn*1e9:.3f}',f'{CGDOp*1e9:.3f}','$\\frac{{fF}}{{\\mu m}}$'],
         ["$C_{{GSo}}$",f'{CGSOn*1e9:.3f}',f'{CGSOp*1e9:.3f}','$\\frac{{fF}}{{\\mu m}}$'],
         ["$C_{{GBo}}$",f'{CGBOn*1e9:.3f}',f'{CGBOp*1e9:.3f}','$\\frac{{fF}}{{\\mu m}}$'],
         ["Junction capacitances parameters"],
         ["$C_J$",f'{CJn*1e3:.3f}',f'{CJp*1e3:.3f}','$\\frac{{fF}}{{\\mu m^2}}$'],
         ["$C_{{JSW}}$",f'{CJSWn*1e9:.3f}',f'{CJSWp*1e9:.3f}','$\\frac{{fF}}{{\\mu m}}$'],
         ["Flicker noise parameters"],
         ["$K_F$",f'{KFn:.1e}',f'{KFp:.1e}',"$J$"],
         ["$AF$",f'{AFn:.1f}',f'{AFp:.1f}',"-"],
         ["$\\rho$",f'{rhon:.3e}',f'{rhop:.3e}','$\\frac{{V \\cdot m^2}}{{A \\cdot s}}$'],
         ["Matching parameters"],
         ["$A_{{VT}}$",f'{AVTn*1e9:.0f}',f'{AVTp*1e9:.0f}',"$mV \\cdot \\mu m$"],
         ["$A_{{\\beta}}$",f'{Abetan*1e8:.0f}',f'{Abetap*1e8:.0f}',"$\\% \\cdot \\mu m$"],
         ["Source and drain sheet resistance parameter"],
         ["$R_{{sh}}$",f'{RSHn:.0f}',f'{RSHp:.0f}',"$\\frac{{\\Omega}}{{\\mu m}}$"],
         ["Width and length parameters"],
         ["$\\Delta W$",f'{DWn/1e-9:.0f}',f'{DWp/1e-9:.0f}',"$\\,nm$"],
         ["$\\Delta L$",f'{DLn/1e-9:.0f}',f'{DLp/1e-9:.0f}',"$\\,nm$"]
         ]

Markdown(tabulate(
  table,
  headers=["Parameter","NMOS","PMOS","Unit"],
  numalign="center",
  stralign="center",
  colalign=("center", "center", "center")
))
```

## Simulation

![Schematic used for the simulation of the transfer function.](Figures/cascode_av_sim.png){#fig-cascode_av_sim}

You can check your design by simulating the transfer function $A_v = \Delta V_{out}/\Delta V_{in}$ using the schematic shown in @fig-cascode_av_sim. Note that transistors M~3~ and M~4~ have been added to correctly set the DC gate voltage of M~1~ such that its current is equal to the bias current $I_b$. Of course M~3~ is identical to M~1~ and M~4~ is identical to M~2~.

To save you some time and allow you to run the simulation using ngspice without writing the Jupyter or Quarto notebook, you can use the qucs-s schematic that is provided.

::: {.callout-note}
Note that the default design in the qucs-s schematic does not satisfy the specs. You need to update the parameters in the size_bias.par file with those obtained from your design.
:::

::: {.callout-warning}
You could also run a noise simulation using the same schematic. However, in qucs-s it is not possible to turn off the noise coming from the bias transistors M~3~ and M~4~. This means that you will get twice the noise of M~1~ and M~2~. In the Quarto notebook we read the raw file which gives all the individual noise contributions and from which we can extract only the noise coming from M~1~ and M~2~.
:::

# Regulated cascode

![Schematic of the regulated cascode.](Figures/reg_cascode_schematic.png){#fig-reg_cascode_schematic}

The schematic of @fig-reg_cascode_schematic corresponds to the regulated cascode, where an additional CS gain stage M~3~ is added to maintain the voltage at node 1 constant and therefore to further increase the output resistance and DC gain @bib:sackinger:jssc:25:1:1990.

## Small-signal analysis
* Draw the small-signal equivalent schematic of the circuit assuming that all the transistors are biased in saturation.
* Calculate the DC equivalent transconductance $G_{meq} \triangleq \left.\Delta I_{out}/\Delta V_{in}\right|_{\Delta V_{out}=0}$ assuming that all the transconductances are much larger than the output conductances.
* Calculate the output conductance $G_{out} = \Delta I_{out}/\Delta V_{out}$. How does it compare to the output conductance of the cascode of @sec-problem1 ?
* Calculate the voltage gain $A_v \triangleq \Delta V_{out}/\Delta V_{in}$. How does it compare to the cascode of @sec-problem1?

## Noise analysis
* Calculate the output noise conductance $G_{nout}$ and input-referred noise $R_{nin}$. Separate the input-referred noise resistance in its thermal and 1/f noise contributions $R_{nin}(f) = R_{nt} + R_{nf}(f)$.
* Calculate the cascode noise excess factor $\gamma_{cas} = G_{meq} \cdot R_{nt}$. How does it compare to the noise of the cascode of @sec-problem1?

# References
