{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "ac90f2db-0f48-46ac-ad6b-db46f4252061",
   "metadata": {},
   "source": [
    "# Dual-stage Voltage Amplifier: design of dynamic response"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "6022eeab-021a-486d-af36-044a50a60497",
   "metadata": {
    "jupyter": {
     "source_hidden": true
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Compiling library: SLiCAP.lib.\n",
      "Compiling library: SLiCAPmodels.lib.\n"
     ]
    }
   ],
   "source": [
    "import SLiCAP as sl\n",
    "import sympy as sp\n",
    "sl.initProject(\"Dual stage\", notebook=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "ae020d03-8fbd-4bef-b261-e764d7e55230",
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Please select N or P type input CS stage:\n",
      ">>>  P\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Creating netlist of kicad/dual-stage_p/dual-stage_p.kicad_sch using KiCAD\n",
      "Creating drawing-size SVG and PDF images of kicad/dual-stage_p/dual-stage_p.kicad_sch\n",
      "Plotted to '/home/anton/DATA/www/SEDwebsite/_build/SEDwebsite/EE4109-2024-2025/designExample/HearingLoop/SLiCAPnotebooks/Vamp/img/dual-stage_p.svg'.\n",
      "Done\n",
      "Checking netlist: cir/dual-stage_p.cir\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<figure><img src=\"img/dual-stage_p.svg\" alt=\"\" style=\"width:500px\">\n",
       "</figure>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mosType = False\n",
    "while not mosType:\n",
    "    mosType = input(\"Please select N or P type input CS stage:\\n>>> \").upper()\n",
    "    if mosType != \"N\" and mosType != \"P\":\n",
    "        mosType = False\n",
    "if mosType == \"N\":\n",
    "    cir = sl.makeCircuit(\"kicad/dual-stage_n/dual-stage_n.kicad_sch\")\n",
    "    img = \"dual-stage_n.svg\"\n",
    "elif mosType == \"P\":\n",
    "    cir = sl.makeCircuit(\"kicad/dual-stage_p/dual-stage_p.kicad_sch\")\n",
    "    img = \"dual-stage_p.svg\"\n",
    "sl.img2html(img, 500)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "620d211c-74cb-46e6-92a6-37ab95cae9f9",
   "metadata": {
    "jupyter": {
     "source_hidden": true
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<h3>design specification</h3>\n",
       "<table><a id=\"table_design\"></a><caption>Table design specification </caption><tr><th class=\"left\">symbol</th><th class=\"left\">description</th><th class=\"left\">value</th><th class=\"left\">units</th></tr>\n",
       "<td class=\"left\">$C_{i}$</td><td class=\"left\">Required value of integrator capacitor</td><td class=\"left\">$1.798 \\cdot 10^{-9}$</td><td class=\"left\">$\\mathrm{F}$</td></tr>\n",
       "<td class=\"left\">$IC_{N}$</td><td class=\"left\">Inversion coefficient input stage NMOS</td><td class=\"left\">$0.001167$</td><td></td></tr>\n",
       "<td class=\"left\">$IC_{P}$</td><td class=\"left\">Inversion coefficient input stage PMOS</td><td class=\"left\">$1.197$</td><td></td></tr>\n",
       "<td class=\"left\">$ID_{N}$</td><td class=\"left\">Operating current input stage NMOS</td><td class=\"left\">$2.828 \\cdot 10^{-6}$</td><td class=\"left\">$\\mathrm{A}$</td></tr>\n",
       "<td class=\"left\">$ID_{P}$</td><td class=\"left\">Operating current input stage PMOS</td><td class=\"left\">$-4.36 \\cdot 10^{-6}$</td><td class=\"left\">$\\mathrm{A}$</td></tr>\n",
       "<td class=\"left\">$I_{fb}$</td><td class=\"left\">Maximum peak-peak current through feedback network</td><td class=\"left\">$4.542 \\cdot 10^{-5}$</td><td class=\"left\">$\\mathrm{A}$</td></tr>\n",
       "<td class=\"left\">$L_{N}$</td><td class=\"left\">Selected length input stage NMOS</td><td class=\"left\">$1.0 \\cdot 10^{-6}$</td><td class=\"left\">$\\mathrm{m}$</td></tr>\n",
       "<td class=\"left\">$L_{P}$</td><td class=\"left\">Selected length input stage PMOS</td><td class=\"left\">$4.0 \\cdot 10^{-7}$</td><td class=\"left\">$\\mathrm{m}$</td></tr>\n",
       "<td class=\"left\">$M_{N}$</td><td class=\"left\">Number of fingers input stage NMOS</td><td class=\"left\">$47$</td><td></td></tr>\n",
       "<td class=\"left\">$M_{P}$</td><td class=\"left\">Number of fingers input stage PMOS</td><td class=\"left\">$1$</td><td></td></tr>\n",
       "<td class=\"left\">$R_{i}$</td><td class=\"left\">Selected value of integrator resistor</td><td class=\"left\">$8900$</td><td class=\"left\">$\\mathrm{\\Omega}$</td></tr>\n",
       "<td class=\"left\">$Ri_{max}$</td><td class=\"left\">Max. value of integrator resistor</td><td class=\"left\">$8945.0$</td><td class=\"left\">$\\mathrm{\\Omega}$</td></tr>\n",
       "<td class=\"left\">$Ri_{min}$</td><td class=\"left\">Min. value of integrator resistor</td><td class=\"left\">$3380$</td><td class=\"left\">$\\mathrm{\\Omega}$</td></tr>\n",
       "<td class=\"left\">$SRCnoise$</td><td class=\"left\">DIN A weighted RMS output noise, source + termination</td><td class=\"left\">$1.571 \\cdot 10^{-6}$</td><td class=\"left\">$\\mathrm{V}$</td></tr>\n",
       "<td class=\"left\">$S_{Ri}$</td><td class=\"left\">Squared DIN A weighted RMS output noise due to source and feedback network</td><td class=\"left\">$2.491 \\cdot 10^{-11}$</td><td class=\"left\">$\\mathrm{\\frac{V^{2}}{Hz}}$</td></tr>\n",
       "<td class=\"left\">$W_{F N}$</td><td class=\"left\">Finger width input stage NMOS</td><td class=\"left\">$5.0 \\cdot 10^{-5}$</td><td class=\"left\">$\\mathrm{m}$</td></tr>\n",
       "<td class=\"left\">$W_{F P}$</td><td class=\"left\">Finger width input stage PMOS</td><td class=\"left\">$1.0 \\cdot 10^{-5}$</td><td class=\"left\">$\\mathrm{m}$</td></tr>\n",
       "<td class=\"left\">$W_{N}$</td><td class=\"left\">Selected width input stage NMOS</td><td class=\"left\">$0.00235$</td><td class=\"left\">$\\mathrm{m}$</td></tr>\n",
       "<td class=\"left\">$W_{P}$</td><td class=\"left\">Selected width input stage PMOS</td><td class=\"left\">$9.848 \\cdot 10^{-6}$</td><td class=\"left\">$\\mathrm{m}$</td></tr>\n",
       "<td class=\"left\">$c_{issN}$</td><td class=\"left\">Selected input capacitance NMOS</td><td class=\"left\">$6.912 \\cdot 10^{-12}$</td><td class=\"left\">$\\mathrm{F}$</td></tr>\n",
       "<td class=\"left\">$c_{issP}$</td><td class=\"left\">Selected input capacitance PMOS</td><td class=\"left\">$2.41 \\cdot 10^{-14}$</td><td class=\"left\">$\\mathrm{F}$</td></tr>\n",
       "<td class=\"left\">$c_{iss N o}$</td><td class=\"left\">Obtained input capacitance input stage NMOS</td><td class=\"left\">$6.888 \\cdot 10^{-12}$</td><td class=\"left\">$\\mathrm{F}$</td></tr>\n",
       "<td class=\"left\">$c_{iss P o}$</td><td class=\"left\">Obtained input capacitance input stage PMOS</td><td class=\"left\">$2.41 \\cdot 10^{-14}$</td><td class=\"left\">$\\mathrm{F}$</td></tr>\n",
       "<td class=\"left\">$c_{iss costs minN}$</td><td class=\"left\">Required c_iss NMOS for minimum costs</td><td class=\"left\">$6.912 \\cdot 10^{-12}$</td><td class=\"left\">$\\mathrm{F}$</td></tr>\n",
       "<td class=\"left\">$c_{iss costs minP}$</td><td class=\"left\">Required c_iss PMOS for minimum costs</td><td class=\"left\">$2.41 \\cdot 10^{-14}$</td><td class=\"left\">$\\mathrm{F}$</td></tr>\n",
       "<td class=\"left\">$c_{iss g m minN}$</td><td class=\"left\">Required c_issN at g_m_minN</td><td class=\"left\">$9.87 \\cdot 10^{-10}$</td><td class=\"left\">$\\mathrm{F}$</td></tr>\n",
       "<td class=\"left\">$c_{iss g m minP}$</td><td class=\"left\">Required c_issN at g_m_minP</td><td class=\"left\">$8.736 \\cdot 10^{-10}$</td><td class=\"left\">$\\mathrm{F}$</td></tr>\n",
       "<td class=\"left\">$g_{mN}$</td><td class=\"left\">Selected transconductance input stage NMOS</td><td class=\"left\">$7.854 \\cdot 10^{-5}$</td><td class=\"left\">$\\mathrm{\\mathtt{\\text{S}}}$</td></tr>\n",
       "<td class=\"left\">$g_{mP}$</td><td class=\"left\">Selected transconductance input stage PMOS</td><td class=\"left\">$7.537 \\cdot 10^{-5}$</td><td class=\"left\">$\\mathrm{\\mathtt{\\text{S}}}$</td></tr>\n",
       "<td class=\"left\">$g_{m N o}$</td><td class=\"left\">Obtained transconductance input stage NMOS</td><td class=\"left\">$7.854 \\cdot 10^{-5}$</td><td class=\"left\">$\\mathrm{\\mathtt{\\text{S}}}$</td></tr>\n",
       "<td class=\"left\">$g_{m P o}$</td><td class=\"left\">Obtained transconductance input stage PMOS</td><td class=\"left\">$7.535 \\cdot 10^{-5}$</td><td class=\"left\">$\\mathrm{\\mathtt{\\text{S}}}$</td></tr>\n",
       "<td class=\"left\">$g_{m costs minN}$</td><td class=\"left\">g_m NMOS for minimum costs</td><td class=\"left\">$7.854 \\cdot 10^{-5}$</td><td class=\"left\">$\\mathrm{\\mathtt{\\text{S}}}$</td></tr>\n",
       "<td class=\"left\">$g_{m costs minP}$</td><td class=\"left\">g_m PMOS for minimum costs</td><td class=\"left\">$7.537 \\cdot 10^{-5}$</td><td class=\"left\">$\\mathrm{\\mathtt{\\text{S}}}$</td></tr>\n",
       "<td class=\"left\">$g_{m minN}$</td><td class=\"left\">Minimum transconductance input stage NMOS</td><td class=\"left\">$3.926 \\cdot 10^{-5}$</td><td class=\"left\">$\\mathrm{\\mathtt{\\text{S}}}$</td></tr>\n",
       "<td class=\"left\">$g_{m minP}$</td><td class=\"left\">Minimum transconductance input stage PMOS</td><td class=\"left\">$3.827 \\cdot 10^{-5}$</td><td class=\"left\">$\\mathrm{\\mathtt{\\text{S}}}$</td></tr>\n",
       "<td class=\"left\">$n_{Ri obtained}$</td><td class=\"left\">Relative contribution of source and feedback network to squared DIN A weighted output noise</td><td class=\"left\">$0.199$</td><td></td></tr>\n",
       "</table>\n",
       "<h3>performance specification</h3>\n",
       "<table><a id=\"table_performance\"></a><caption>Table performance specification </caption><tr><th class=\"left\">symbol</th><th class=\"left\">description</th><th class=\"left\">value</th><th class=\"left\">units</th></tr>\n",
       "<td class=\"left\">$L_{s}$</td><td class=\"left\">Source inductance</td><td class=\"left\">$0.12$</td><td class=\"left\">$\\mathrm{H}$</td></tr>\n",
       "<td class=\"left\">$P_{max}$</td><td class=\"left\">Maximum power dissipation at maximum supply voltage</td><td class=\"left\">$0.001$</td><td class=\"left\">$\\mathrm{W}$</td></tr>\n",
       "<td class=\"left\">$R_{s}$</td><td class=\"left\">Source resistance</td><td class=\"left\">$875$</td><td class=\"left\">$\\mathrm{\\Omega}$</td></tr>\n",
       "<td class=\"left\">$R_{t}$</td><td class=\"left\">Termination resistance</td><td class=\"left\">$1.0 \\cdot 10^{4}$</td><td class=\"left\">$\\mathrm{\\Omega}$</td></tr>\n",
       "<td class=\"left\">$V_{DD}$</td><td class=\"left\">Maximum supply voltage</td><td class=\"left\">$1.3$</td><td class=\"left\">$\\mathrm{V}$</td></tr>\n",
       "<td class=\"left\">$V_{onoise}$</td><td class=\"left\">DIN A weighted output voltage noise</td><td class=\"left\">$1.062 \\cdot 10^{-5}$</td><td class=\"left\">$\\mathrm{V}$</td></tr>\n",
       "<td class=\"left\">$Vi_{ADC}$</td><td class=\"left\">Peak-peak input voltage ADC</td><td class=\"left\">$0.9$</td><td class=\"left\">$\\mathrm{V}$</td></tr>\n",
       "<td class=\"left\">$Vi_{pp}$</td><td class=\"left\">Maximum peak-peak input voltage</td><td class=\"left\">$0.2932$</td><td></td></tr>\n",
       "<td class=\"left\">$f_{fp}$</td><td class=\"left\">Maximum full-power frequency</td><td class=\"left\">$5000$</td><td class=\"left\">$\\mathrm{Hz}$</td></tr>\n",
       "<td class=\"left\">$f_{max}$</td><td class=\"left\">-3dB low-pass cut-off frequency</td><td class=\"left\">$6000$</td><td class=\"left\">$\\mathrm{Hz}$</td></tr>\n",
       "<td class=\"left\">$f_{min}$</td><td class=\"left\">-3dB high-pass cut-off frequency</td><td class=\"left\">$600$</td><td class=\"left\">$\\mathrm{Hz}$</td></tr>\n",
       "<td class=\"left\">$\\tau_{i}$</td><td class=\"left\">Integration time constant</td><td class=\"left\">$1.6 \\cdot 10^{-5}$</td><td class=\"left\">$\\mathrm{s}$</td></tr>\n",
       "</table>\n",
       "<h3>achievements specification</h3>\n",
       "<table><a id=\"table_achievements\"></a><caption>Table achievements specification </caption><tr><th class=\"left\">symbol</th><th class=\"left\">description</th><th class=\"left\">value</th><th class=\"left\">units</th></tr>\n",
       "<td class=\"left\">$V_{onoise WLI N}$</td><td class=\"left\">DIN A weighted RMS output noise with NMOS, W, L, and ID</td><td class=\"left\">$7.833 \\cdot 10^{-6}$</td><td class=\"left\">$\\mathrm{V}$</td></tr>\n",
       "<td class=\"left\">$V_{onoise WLI P}$</td><td class=\"left\">DIN A weighted RMS output noise with PMOS, W, L, and ID</td><td class=\"left\">$9.932 \\cdot 10^{-6}$</td><td class=\"left\">$\\mathrm{V}$</td></tr>\n",
       "<td class=\"left\">$V_{onoise gmCissN}$</td><td class=\"left\">DIN A weighted RMS output noise with NMOS and selected g_m and c_iss</td><td class=\"left\">$9.021 \\cdot 10^{-6}$</td><td class=\"left\">$\\mathrm{V}$</td></tr>\n",
       "<td class=\"left\">$V_{onoise gmCissP}$</td><td class=\"left\">DIN A weighted RMS output noise with PMOS and selected g_m and c_iss</td><td class=\"left\">$9.02 \\cdot 10^{-6}$</td><td class=\"left\">$\\mathrm{V}$</td></tr>\n",
       "</table>\n",
       "<h3>budgets specification</h3>\n",
       "<table><a id=\"table_budgets\"></a><caption>Table budgets specification </caption><tr><th class=\"left\">symbol</th><th class=\"left\">description</th><th class=\"left\">value</th><th class=\"left\">units</th></tr>\n",
       "<td class=\"left\">$n_{MN}$</td><td class=\"left\">Relative contribution controller NMOS input stagenoise to the squared DIN-A weighted RMS output noise</td><td class=\"left\">$0.5$</td><td></td></tr>\n",
       "<td class=\"left\">$n_{MP}$</td><td class=\"left\">Relative contribution controller PMOS input stagenoise to the squared DIN-A weighted RMS output noise</td><td class=\"left\">$0.5$</td><td></td></tr>\n",
       "<td class=\"left\">$n_{Ri}$</td><td class=\"left\">Relative contribution of R_i noise to the squared DIN-A weighted RMS output noise</td><td class=\"left\">$0.2$</td><td></td></tr>\n",
       "<td class=\"left\">$n_{SRC}$</td><td class=\"left\">Relative contribution of source noise to the squared DIN-A weighted RMS output noise</td><td class=\"left\">$0.02189$</td><td></td></tr>\n",
       "</table>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "specs = sl.csv2specs('A1specs.csv')\n",
    "sl.specs2html(specs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "a7e69560-f626-44ef-a2a9-f19f688b6773",
   "metadata": {},
   "outputs": [],
   "source": [
    "sl.specs2circuit(specs, cir)\n",
    "sl.elementData2html(cir)\n",
    "#cir.defPar(\"c_dg_X1\", 0) # If commented out, the loop gain reference is in a local loop \n",
    "                          # and the asymptotic gain does not equal the ideal gain\n",
    "cir.defPar(\"W_o\", 50e-6)  # A wider output stage required a lower VGS, which may be benificial for biasing, \n",
    "                          # this applies to NMOS output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "0bca87e5-d8e9-445a-bcfe-1ef495d3890f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 42676 characters]",
      "text/plain": [
       "<Figure size 400x300 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "gain        = sl.doLaplace(cir, pardefs=\"circuit\", numeric=True)\n",
    "asymptotic  = sl.doLaplace(cir, pardefs=\"circuit\", numeric=True, transfer=\"asymptotic\")\n",
    "loopgain    = sl.doLaplace(cir, pardefs=\"circuit\", numeric=True, transfer=\"loopgain\")\n",
    "servo       = sl.doLaplace(cir, pardefs=\"circuit\", numeric=True, transfer=\"servo\")\n",
    "direct      = sl.doLaplace(cir, pardefs=\"circuit\", numeric=True, transfer=\"direct\")\n",
    "\n",
    "fb_model    = [gain, asymptotic, loopgain, servo, direct]\n",
    "fbmodel_mag = sl.plotSweep(\"fb_mag\", \"Magnitude plots feedback model parameters\", \n",
    "                           fb_model, 10, 10e8, 200, show=True)\n",
    "# Plot in vector format (\".svg\"):\n",
    "#sl.fig2html(fbmodel_mag, 400)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "106d58cb-eaf1-4736-ba7a-d901819f1b15",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 39396 characters]",
      "text/plain": [
       "<Figure size 400x300 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fbmodel_phase = sl.plotSweep(\"fb_mag\", \"Magnitude plots feedback model parameters\", \n",
    "                             fb_model, 10, 10e8, 200, funcType=\"phase\", show=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "dd2c1a6c-a905-4ffe-97f3-5f6adbcce105",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<h2>PZ  analysis results</h2>\n",
       "<h3>Gain type: loopgain</h3>\n",
       "<p>DC value = $0$</p>\n",
       "<table><tr><th>pole</th><th>Re [Hz]</th><th>Im [Hz]</th><th>Mag [Hz]</th><th>Q</th></tr>\n",
       "<tr><td>p<sub>1</sub></td><td>-264.2</td><td>0</td><td>264.2</td><td></td></tr>\n",
       "<tr><td>p<sub>2</sub></td><td>-2.412e+5</td><td>0</td><td>2.412e+5</td><td></td></tr>\n",
       "<tr><td>p<sub>3</sub></td><td>-4.916e+6</td><td>0</td><td>4.916e+6</td><td></td></tr>\n",
       "<tr><td>p<sub>4</sub></td><td>-5.828e+8</td><td>0</td><td>5.828e+8</td><td></td></tr>\n",
       "</table>\n",
       "<table><tr><th>zero</th><th>Re [Hz]</th><th>Im [Hz]</th><th>Mag [Hz]</th><th>Q</th></tr>\n",
       "<tr><td>z<sub>1</sub></td><td>0</td><td>0</td><td>0</td><td></td></tr>\n",
       "<tr><td>z<sub>2</sub></td><td>-4.442e+6</td><td>1.583e+8</td><td>1.583e+8</td><td>17.82</td></tr>\n",
       "<tr><td>z<sub>3</sub></td><td>-4.442e+6</td><td>-1.583e+8</td><td>1.583e+8</td><td>17.82</td></tr>\n",
       "</table>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "PZ = sl.doPZ(cir, pardefs=\"circuit\", numeric=True, transfer=\"loopgain\")\n",
    "sl.pz2html(PZ)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b0091649-f7be-4834-a673-9874129cea2c",
   "metadata": {},
   "source": [
    "## Simplified equivalent circuit\n",
    "We will simplify the system, to a system with DC loop gain and a number of dominant poles. SLiCAP has the function \"findServoBandwidth(<loop gain expression>)\" for determination of the dominant poles and the midband loop gain:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "0dc4ecf8-f397-43cf-ba90-56dd7df6faac",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'mbv': 1648.7198560754714,\n",
       " 'mbf': 264.22487027692205,\n",
       " 'lpf': 44219768.73010752,\n",
       " 'lpo': -2.0,\n",
       " 'hpf': 0.1602606223872802,\n",
       " 'hpo': 1.0}"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "servoData = sl.findServoBandwidth(loopgain.laplace)\n",
    "servoData"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "f30f5590-1ceb-4813-b7fa-368b7a4fc94b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\\begin{equation}\n",
       "B_{f}=4.422 \\cdot 10^{7}\n",
       "\\end{equation}\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sl.eqn2html(\"B_f\", servoData['lpf']) # achievable MFM low-pass frequency"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "9c820b18-c20b-4c72-8f05-f4ceeaaa7e9b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\\begin{equation}\n",
       "L_{MB}=1649.0\n",
       "\\end{equation}\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sl.eqn2html(\"L_MB\", servoData['mbv']) # absolute value of the loop gain at midband frequencies"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "d4611026-8906-4365-8519-86aa43cdcc9b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\\begin{equation}\n",
       "f_{MB}=264.2\n",
       "\\end{equation}\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sl.eqn2html(\"f_MB\", servoData['mbf']) # lowest frequency at which the mid-band loop gain is achieved"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e4d91b52-0f54-496c-8868-8cfe1f2d29e4",
   "metadata": {},
   "source": [
    "### Determination of the dominant poles and estimated bandwidth"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "33073caa-6956-4e04-bb91-5871c712ba7a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\\begin{equation}\n",
       "B_{f est}=4.422 \\cdot 10^{7}\n",
       "\\end{equation}\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dominant_poles = []\n",
    "for pole in PZ.poles:\n",
    "    if sp.Abs(pole) > 1.01*servoData['mbf']*2*sp.pi and sp.Abs(pole) < servoData['lpf']*2*sp.pi:\n",
    "        dominant_poles.append(pole)\n",
    "dominant_zeros = []\n",
    "for zero in PZ.zeros:\n",
    "    if sp.Abs(zero) > 1.01*servoData['mbf']*2*sp.pi and sp.Abs(zero) < servoData['lpf']*2*sp.pi:\n",
    "        dominant_zeros.append(zero)\n",
    "LP_prod = servoData['mbv']\n",
    "for pole in dominant_poles:\n",
    "    LP_prod *= pole\n",
    "for zero in dominant_zeros:\n",
    "    LP_prod /= zero\n",
    "order = len(dominant_poles)-len(dominant_zeros)\n",
    "B_f_est = sp.N(sp.Abs(LP_prod)**(1/(order))/2/sp.pi)\n",
    "sl.eqn2html(\"B_f_est\", B_f_est)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a928036a-1641-47a8-a09a-4416592b12e2",
   "metadata": {},
   "source": [
    "### Redefine system with midband loop gain and dominant poles"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "2aa5b468-a042-4a3f-8db3-df19dbee7f94",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<h2>PZ  analysis results</h2>\n",
       "<h3>Gain type: loopgain</h3>\n",
       "<p>DC value = $-1649.0$</p>\n",
       "<table><tr><th>pole</th><th>Re [Hz]</th><th>Im [Hz]</th><th>Mag [Hz]</th><th>Q</th></tr>\n",
       "<tr><td>p<sub>1</sub></td><td>-2.412e+5</td><td>0</td><td>2.412e+5</td><td></td></tr>\n",
       "<tr><td>p<sub>2</sub></td><td>-4.916e+6</td><td>0</td><td>4.916e+6</td><td></td></tr>\n",
       "</table>\n",
       "<table><tr><th>zero</th><th>Re [Hz]</th><th>Im [Hz]</th><th>Mag [Hz]</th><th>Q</th></tr>\n",
       "</table>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "PZ.DCvalue = - servoData['mbv']\n",
    "PZ.poles   = dominant_poles\n",
    "PZ.zeros   = dominant_zeros\n",
    "sl.pz2html(PZ)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a58d53fd-4f0b-4b61-b10b-be9011dc2cd1",
   "metadata": {},
   "source": [
    "## Frequency compensation (only implemented for mosType == \"P\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "ad9d680b-57fe-4761-9d26-b66a88c1d1c0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2-nd order frequency MFM requires compensation with phantom zero at: -2.14e+8 Hz\n"
     ]
    }
   ],
   "source": [
    "z = False\n",
    "if order == 1:\n",
    "    print(\"1-st order response does not require frequency compensation\")\n",
    "elif order  == 2:\n",
    "    LP = sp.Abs(PZ.poles[0]*PZ.poles[1]*PZ.DCvalue)\n",
    "    if sp.Abs(PZ.poles[0] + PZ.poles[1]) > sp.sqrt(2*LP):\n",
    "        print(\"2-nd order MFM frequency compensation requires positive phantom zero: not impelmented\")\n",
    "    elif sp.Abs(PZ.poles[0] + PZ.poles[1]) == sp.sqrt(2*LP):\n",
    "        print(\"2-nd order frequency MFM requires no compensation.\")\n",
    "    else:\n",
    "        z = -LP/( sp.sqrt(2*LP) + PZ.poles[0] + PZ.poles[1] )\n",
    "        print(\"2-nd order frequency MFM requires compensation with phantom zero at: %s Hz\"%(str(sp.N(z,3))))\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "53f44ed1-f4a3-42c6-a990-2089680c999b",
   "metadata": {},
   "source": [
    "## Phantom zero at the load"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "a11f0d48-6b93-4258-9c66-fa9f3a2dbb6d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\\begin{equation}\n",
       "R_{phz}=467.0\n",
       "\\end{equation}\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "R_phz = -1/(z*cir.getParValue(\"C_ell\"))\n",
    "sl.eqn2html(\"R_phz\", R_phz)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "id": "64890426-7a50-46ed-8fe7-eb390cceccc9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Creating netlist of kicad/dual-stage_p_phz/dual-stage_p_phz.kicad_sch using KiCAD\n",
      "Creating drawing-size SVG and PDF images of kicad/dual-stage_p_phz/dual-stage_p_phz.kicad_sch\n",
      "Plotted to '/home/anton/DATA/www/SEDwebsite/_build/SEDwebsite/EE4109-2024-2025/designExample/HearingLoop/SLiCAPnotebooks/Vamp/img/dual-stage_p_phz.svg'.\n",
      "Done\n",
      "Checking netlist: cir/dual-stage_p_phz.cir\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<figure><img src=\"img/dual-stage_p_phz.svg\" alt=\"\" style=\"width:550px\">\n",
       "</figure>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "if mosType == \"N\":\n",
    "    print(\"Dual-stage NMOS input with phz compensation is not available\")\n",
    "elif mosType == \"P\":\n",
    "    cir_phz = sl.makeCircuit(\"kicad/dual-stage_p_phz/dual-stage_p_phz.kicad_sch\")\n",
    "    img = \"dual-stage_p_phz.svg\"\n",
    "sl.img2html(img, 550)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "id": "470b114e-7b4a-42b0-bd06-23b865d2e397",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 40804 characters]",
      "text/plain": [
       "<Figure size 400x300 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "sl.specs2circuit(specs, cir_phz)\n",
    "cir_phz.defPar(\"W_o\", 50e-6)\n",
    "cir_phz.defPar(\"R_phz\", R_phz)\n",
    "gain_phz        = sl.doLaplace(cir_phz, pardefs=\"circuit\", numeric=True)\n",
    "asymptotic_phz  = sl.doLaplace(cir_phz, pardefs=\"circuit\", numeric=True, transfer=\"asymptotic\")\n",
    "loopgain_phz    = sl.doLaplace(cir_phz, pardefs=\"circuit\", numeric=True, transfer=\"loopgain\")\n",
    "servo_phz       = sl.doLaplace(cir_phz, pardefs=\"circuit\", numeric=True, transfer=\"servo\")\n",
    "direct_phz      = sl.doLaplace(cir_phz, pardefs=\"circuit\", numeric=True, transfer=\"direct\")\n",
    "\n",
    "fb_model_phz = [gain_phz, asymptotic_phz, loopgain_phz, servo_phz, direct_phz]\n",
    "fbmodel_mag  = sl.plotSweep(\"fb_mag_phz\", \"Magnitude plots feedback model parameters\", \n",
    "                            fb_model_phz, 10, 10e8, 200, show=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "4d3a4581-02bf-49dd-9f39-5b29d71f0017",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 39324 characters]",
      "text/plain": [
       "<Figure size 400x300 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fbmodel_phase_phz = sl.plotSweep(\"fb_mag\", \"Magnitude plots feedback model parameters\", \n",
    "                             fb_model_phz, 10, 10e8, 200, funcType=\"phase\", show=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "22c8536b-741e-4f95-9a80-704a07a8fbfb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<h2>PZ  analysis results</h2>\n",
       "<h3>Gain type: gain</h3>\n",
       "<p>DC value = $5.708 \\cdot 10^{4}$</p>\n",
       "<table><tr><th>pole</th><th>Re [Hz]</th><th>Im [Hz]</th><th>Mag [Hz]</th><th>Q</th></tr>\n",
       "<tr><td>p<sub>1</sub></td><td>-0.1602</td><td>0</td><td>0.1602</td><td></td></tr>\n",
       "<tr><td>p<sub>2</sub></td><td>-1.442e+4</td><td>0</td><td>1.442e+4</td><td></td></tr>\n",
       "<tr><td>p<sub>3</sub></td><td>-2.643e+7</td><td>3.221e+7</td><td>4.167e+7</td><td>0.7883</td></tr>\n",
       "<tr><td>p<sub>4</sub></td><td>-2.643e+7</td><td>-3.221e+7</td><td>4.167e+7</td><td>0.7883</td></tr>\n",
       "<tr><td>p<sub>5</sub></td><td>-5.503e+8</td><td>0</td><td>5.503e+8</td><td></td></tr>\n",
       "<tr><td>p<sub>6</sub></td><td>-1.346e+10</td><td>0</td><td>1.346e+10</td><td></td></tr>\n",
       "</table>\n",
       "<table><tr><th>zero</th><th>Re [Hz]</th><th>Im [Hz]</th><th>Mag [Hz]</th><th>Q</th></tr>\n",
       "<tr><td>z<sub>1</sub></td><td>3.113e+8</td><td>8.723e+8</td><td>9.262e+8</td><td>1.487</td></tr>\n",
       "<tr><td>z<sub>2</sub></td><td>3.113e+8</td><td>-8.723e+8</td><td>9.262e+8</td><td>1.487</td></tr>\n",
       "<tr><td>z<sub>3</sub></td><td>-9947.</td><td>0</td><td>9947.</td><td></td></tr>\n",
       "</table>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "PZ_gain_phz = sl.doPZ(cir_phz, pardefs=\"circuit\", numeric=True)\n",
    "sl.pz2html(PZ_gain_phz)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
