IHP-AnalogAcademy/modules/module_1_bandgap_reference/scripting/OTA_low_gain.ipynb

852 lines
46 KiB
Plaintext

{
"cells": [
{
"cell_type": "code",
"execution_count": 429,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"#for windows\n",
"import sys\n",
"sys.path.append(r'C:\\Users\\pedersen\\gmid') # path to gmid repository\n",
"# ------\n",
"import matplotlib.pyplot as plt\n",
"from mosplot import load_lookup_table, LoadMosfet # make sure that mosplot can be found in the python path\n",
"import ipywidgets as widgets\n",
"from ipywidgets import interactive\n",
"from ipywidgets import interactive_output, HBox, VBox\n",
"import matplotlib.ticker as ticker "
]
},
{
"cell_type": "code",
"execution_count": 430,
"metadata": {},
"outputs": [],
"source": [
"pmos_lv_path = r'C:\\Users\\pedersen\\Desktop\\OpenDesingCourse\\no_touch_files\\gmoveridpypmos_gmid_final.npy'\n",
"nmos_lv_path =r'C:\\Users\\pedersen\\Desktop\\OpenDesingCourse\\no_touch_files\\gmoveridpynmos_final_gmid.npy'\n",
"\n",
"lookup_table_pmos = load_lookup_table(pmos_lv_path)\n",
"lookup_table_nmos = load_lookup_table(nmos_lv_path)"
]
},
{
"cell_type": "code",
"execution_count": 431,
"metadata": {},
"outputs": [],
"source": [
"nmos = LoadMosfet(lookup_table=lookup_table_nmos, mos=\"nmos\", vsb=0.0, vds=0.6)\n",
"pmos = LoadMosfet(lookup_table=lookup_table_pmos, mos=\"pmos\", vsb=0, vds=-0.6, vgs=(-1.2, -0.1))"
]
},
{
"cell_type": "code",
"execution_count": 432,
"metadata": {},
"outputs": [],
"source": [
"def plot_data_vs_data(x_values, y_values, z_values, length, x_axis_name, y_axis_name='y', y_multiplier=1, log=False):\n",
" x_values_flat = np.array(x_values).flatten()\n",
" y_values_flat = np.array(y_values, dtype=np.float64).flatten()\n",
" z_values_flat = np.array(z_values, dtype=np.float64).flatten()\n",
" length_flat = np.array(length).flatten()\n",
"\n",
" # Ensure all inputs have the same length\n",
" if not (len(x_values_flat) == len(y_values_flat) == len(z_values_flat) == len(length_flat)):\n",
" raise ValueError(\"All input arrays (x_values, y_values, z_values, length) must have the same number of elements.\")\n",
"\n",
" unique_lengths = np.unique(length_flat)\n",
" unique_lengths_in_micro = unique_lengths * 1e6\n",
"\n",
" def update_plot(selected_length, x_value=None, y_value=None):\n",
" plt.figure(figsize=(8, 6)) # Ensure the plot is drawn fresh for each update\n",
"\n",
" if selected_length == \"Show All\":\n",
" mask = np.ones_like(length_flat, dtype=bool)\n",
" else:\n",
" selected_length_in_micro = float(selected_length.replace(' μm', ''))\n",
" tolerance = 0.1\n",
" # Recalculate the mask with matching shapes\n",
" mask = np.abs(length_flat * 1e6 - selected_length_in_micro) < tolerance\n",
"\n",
" x_values_for_length = x_values_flat[mask]\n",
" y_values_for_length = y_values_flat[mask] * y_multiplier\n",
" z_values_for_length = z_values_flat[mask]\n",
" length_for_length = length_flat[mask] * 1e6\n",
"\n",
" if selected_length == \"Show All\":\n",
" for length_value in np.unique(length_for_length):\n",
" mask_all = (length_for_length == length_value)\n",
" plt.plot(x_values_for_length[mask_all], y_values_for_length[mask_all])\n",
"\n",
" min_length = np.min(unique_lengths_in_micro)\n",
" max_length = np.max(unique_lengths_in_micro)\n",
" plt.title(f'{y_axis_name} vs {x_axis_name} (Length from {min_length:.2f} μm to {max_length:.2f} μm)')\n",
"\n",
" else:\n",
" plt.plot(x_values_for_length, y_values_for_length)\n",
" plt.title(f'{y_axis_name} vs {x_axis_name} for {selected_length}')\n",
"\n",
" plt.xlabel(f'{x_axis_name}')\n",
" plt.ylabel(f'{y_axis_name}')\n",
"\n",
" if log:\n",
" plt.yscale('log')\n",
" plt.gca().yaxis.set_major_locator(ticker.LogLocator(base=10, subs=[], numticks=10))\n",
" plt.gca().yaxis.set_major_formatter(ticker.FuncFormatter(lambda x, _: f'$10^{int(np.log10(x))}$'))\n",
" plt.ylabel(f'{y_axis_name} (Log Base 10)')\n",
"\n",
" if y_value is not None and x_value_widget.disabled:\n",
" closest_index = np.abs(y_values_for_length - y_value).argmin()\n",
" closest_x = x_values_for_length[closest_index]\n",
" closest_y = y_values_for_length[closest_index]\n",
" corresponding_z = z_values_for_length[closest_index]\n",
"\n",
" plt.scatter(closest_x, closest_y, color='blue', label=f'Point ({closest_x:.2f}, {closest_y:.2f})')\n",
" z_value_widget.value = corresponding_z\n",
" print(f\"The corresponding {x_axis_name} value for {y_axis_name} = {closest_y:.2f} is: {closest_x:.2f}\")\n",
" elif x_value is not None and y_value_widget.disabled:\n",
" closest_index = np.abs(x_values_for_length - x_value).argmin()\n",
" closest_x = x_values_for_length[closest_index]\n",
" closest_y = y_values_for_length[closest_index]\n",
" corresponding_z = z_values_for_length[closest_index]\n",
"\n",
" plt.scatter(closest_x, closest_y, color='red', label=f'Point ({closest_x:.2f}, {closest_y:.2f})')\n",
" z_value_widget.value = corresponding_z\n",
" print(f\"The corresponding {y_axis_name} value for {x_axis_name} = {closest_x:.2f} is: {closest_y:.2f}\")\n",
"\n",
" plt.grid(True)\n",
" plt.legend()\n",
" plt.show()\n",
"\n",
" dropdown_options = [\"Show All\"] + [f'{length:.2f} μm' for length in unique_lengths_in_micro]\n",
" length_widget = widgets.Dropdown(\n",
" options=dropdown_options,\n",
" value=dropdown_options[0],\n",
" description='Select Length:',\n",
" )\n",
"\n",
" x_value_widget = widgets.FloatText(\n",
" value=np.mean(x_values_flat),\n",
" description=f\"Select {x_axis_name}:\",\n",
" disabled=False\n",
" )\n",
"\n",
" y_value_widget = widgets.FloatText(\n",
" value=None,\n",
" description=f\"Set {y_axis_name}:\",\n",
" disabled=True\n",
" )\n",
"\n",
" z_value_widget = widgets.FloatText(\n",
" value=None,\n",
" description=f\"Corresponding z value:\",\n",
" disabled=True\n",
" )\n",
"\n",
" select_x_or_y_widget = widgets.Checkbox(\n",
" value=True,\n",
" description=f\"Select {x_axis_name} (uncheck for {y_axis_name})\",\n",
" )\n",
"\n",
" def toggle_x_or_y(change):\n",
" if change['new']:\n",
" x_value_widget.disabled = False\n",
" y_value_widget.disabled = True\n",
" else:\n",
" x_value_widget.disabled = True\n",
" y_value_widget.disabled = False\n",
"\n",
" select_x_or_y_widget.observe(toggle_x_or_y, names='value')\n",
"\n",
" output = interactive_output(update_plot, {\n",
" 'selected_length': length_widget,\n",
" 'x_value': x_value_widget,\n",
" 'y_value': y_value_widget\n",
" })\n",
"\n",
" display(VBox([length_widget, select_x_or_y_widget, HBox([x_value_widget, y_value_widget]), z_value_widget, output]))\n",
"\n",
"\n",
"def display_resistance(ro_value):\n",
" \"\"\"Determine the resistance value and its unit.\"\"\"\n",
" if ro_value < 1e3:\n",
" return ro_value, \"Ω\"\n",
" elif ro_value < 1e6:\n",
" return ro_value / 1e3, \"kΩ\"\n",
" elif ro_value < 1e9:\n",
" return ro_value / 1e6, \"MΩ\"\n",
" else:\n",
" return ro_value / 1e9, \"GΩ\"\n",
"\n",
"def display_current(Id_value):\n",
" \"\"\"Determine the current value and its unit.\"\"\"\n",
" if Id_value < 1e-6:\n",
" return Id_value * 1e9, \"nA\" # Convert to nA\n",
" elif Id_value < 1e-3:\n",
" return Id_value * 1e6, \"μA\" # Convert to μA\n",
" else:\n",
" return Id_value * 1e3, \"mA\" # Convert to mA\n",
" \n",
"def dB_to_linear(av_db):\n",
" return 10 ** (av_db / 20)\n",
"\n",
"\n",
"def determine_inversion_region(gm_id_value, device_type):\n",
" \"\"\"Determine the inversion region based on gm/id value for NMOS or PMOS.\"\"\"\n",
" if device_type == 'nmos':\n",
" if gm_id_value > 20:\n",
" return \"Weak Inversion\"\n",
" elif 10 < gm_id_value <= 20:\n",
" return \"Moderate Inversion\"\n",
" else:\n",
" return \"Strong Inversion\"\n",
" elif device_type == 'pmos':\n",
" if gm_id_value > 20:\n",
" return \"Weak Inversion\"\n",
" elif 10 < gm_id_value <= 20:\n",
" return \"Moderate Inversion\"\n",
" else:\n",
" return \"Strong Inversion\"\n",
" else:\n",
" raise ValueError(\"Invalid device type. Use 'nmos' or 'pmos'.\")\n",
" \n"
]
},
{
"attachments": {
"image.png": {
"image/png": "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"
}
},
"cell_type": "markdown",
"metadata": {},
"source": [
"![image.png](attachment:image.png)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# As Starting point the input stage is sized."
]
},
{
"cell_type": "code",
"execution_count": 434,
"metadata": {},
"outputs": [],
"source": [
"vdd = 1.2 # supply voltage\n",
"Cl = 500e-15 # load capacitance\n",
"Av_wish = 80 # in db\n",
"phase_margin = 65 # At least :)\n",
"fdominant = 1000 # dominant pole frequency\n",
"CC = 0.3*Cl \n",
"GBW = fdominant * dB_to_linear(Av_wish) # Gain Bandwidth Product"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# First desigining the output stage looking at the output transistor"
]
},
{
"cell_type": "code",
"execution_count": 435,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "7885bed517d544a6a5186b585b73be1c",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(Dropdown(description='Select Length:', options=('Show All', '0.13 μm', '0.26 μm', '0.39 μm', '0…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"nmos_M6 = LoadMosfet(lookup_table=lookup_table_nmos, mos=\"nmos\", vsb=0, vds=0.6)\n",
"width_values_M6 = nmos_M6.extracted_table['width']\n",
"id_values_M6 = nmos_M6.extracted_table['id']\n",
"gm_values_M6 = nmos_M6.extracted_table['gm']\n",
"gds_values_M6 = nmos_M6.extracted_table['gds']\n",
"vgs_values_M6 = nmos_M6.extracted_table['vgs']\n",
"\n",
"plot_data_vs_data(gm_values_M6/id_values_M6, gm_values_M6/gds_values_M6, vgs_values_M6, nmos_M6.extracted_table['lengths'], 'gm/id', 'gds')"
]
},
{
"cell_type": "code",
"execution_count": 436,
"metadata": {},
"outputs": [],
"source": [
"# For max gmro and vgs of 0.6V we have gmid of 5\n",
"L_M6 = 9.75e-6\n",
"gmid_M6 = 5 # strong inversion, i.e saturation\n",
"gm_M6 = 2*np.pi*GBW*Cl # we have se\n",
"id_outputstage = gm_M6/gmid_M6\n",
"gmro_M6 = 55.68\n",
"ro_M6 = gmro_M6/gm_M6\n"
]
},
{
"cell_type": "code",
"execution_count": 437,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"gmro_M7 = 334.08\n"
]
}
],
"source": [
"# Now for the pmos output transistor we must have 3 time the output impedance to insure max output gain\n",
"ro_M7 = 3*ro_M6\n",
"\n",
"# we want to place this transistor in moderate inversion\n",
"gmid_M7 = 10\n",
"gm_M7 = gmid_M7 * id_outputstage\n",
"gmro_M7 = gm_M7 * ro_M7\n",
"print(f'gmro_M7 = {gmro_M7:.2f}')"
]
},
{
"cell_type": "code",
"execution_count": 438,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "36da585aea1b4f0bb5722f07a41fc809",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(Dropdown(description='Select Length:', options=('Show All', '0.13 μm', '0.26 μm', '0.39 μm', '0…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"pmos_M7 = LoadMosfet(lookup_table=lookup_table_pmos, mos=\"pmos\", vsb=0, vds=-0.6, vgs=(-1.2, -0.1))\n",
"width_values_M7 = pmos_M7.extracted_table['width']\n",
"id_values_M7 = pmos_M7.extracted_table['id']\n",
"gm_values_M7 = pmos_M7.extracted_table['gm']\n",
"gds_values_M7 = pmos_M7.extracted_table['gds']\n",
"vgs_values_M7 = pmos_M7.extracted_table['vgs']\n",
"\n",
"plot_data_vs_data(gm_values_M7/id_values_M7, gm_values_M7/gds_values_M7, vgs_values_M7, pmos_M7.extracted_table['lengths'], 'gm/id', 'gds')\n"
]
},
{
"cell_type": "code",
"execution_count": 439,
"metadata": {},
"outputs": [],
"source": [
"# For the criteria to be met we must have \n",
"L_M7 = 3.38e-6"
]
},
{
"cell_type": "code",
"execution_count": 440,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"L_M6 = 9.75e-06\n",
"gmid_M6 = 5.00\n",
"L_M7 = 3.38e-06\n",
"gmid_M7 = 10.00\n"
]
}
],
"source": [
"print(f'L_M6 = {L_M6:.2e}')\n",
"print(f'gmid_M6 = {gmid_M6:.2f}')\n",
"print(f'L_M7 = {L_M7:.2e}')\n",
"print(f'gmid_M7 = {gmid_M7:.2f}')\n"
]
},
{
"cell_type": "code",
"execution_count": 441,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "b0beb804bcf4452593b1eb60e6baed9d",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(Dropdown(description='Select Length:', options=('Show All', '0.13 μm', '0.26 μm', '0.39 μm', '0…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "0fc744fa24c34ef7a0d5b5590746f95c",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(Dropdown(description='Select Length:', options=('Show All', '0.13 μm', '0.26 μm', '0.39 μm', '0…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plot_data_vs_data(gm_values_M6/id_values_M6,id_values_M6/width_values_M6, vgs_values_M6, nmos_M6.extracted_table['lengths'], 'gm/id', 'M6 id/W', log=True)\n",
"plot_data_vs_data(gm_values_M7/id_values_M7, id_values_M7/width_values_M7,vgs_values_M7, pmos_M7.extracted_table['lengths'], 'gm/id', 'M7 id/W', log=True)"
]
},
{
"cell_type": "code",
"execution_count": 442,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Output Stage Amplification Summary\n",
"Width and Lengths for M6\n",
" W = 2.28 um\n",
" L = 9.75 um\n",
"Inversion Region for M6: Strong Inversion\n",
"\n",
"Width and Lengths for M7\n",
" W = 14.61 um\n",
" L = 3.38 um\n",
"Inversion Region for M7: Strong Inversion\n",
"\n",
"Output Stage Bias:\n",
" Output Current : 6.28 μA\n",
"\n",
"Output Stage Gain:\n",
" Av2 = 41.76 (32.42 dB)\n",
"\n"
]
}
],
"source": [
"id_over_W_M6 = 2.76\n",
"id_over_W_M7 = 0.43\n",
"\n",
"display_outcurrent, unit_outcurrent = display_current(id_outputstage)\n",
"Av2 = gm_M6 * (ro_M6 * ro_M7)/(ro_M6 + ro_M7)\n",
"Av2_db = 20 * np.log10(Av2)\n",
"\n",
"W_M6 = id_outputstage/id_over_W_M6\n",
"W_M7 = id_outputstage/id_over_W_M7\n",
"\n",
"output_stage_summary = f\"\"\"\n",
"Output Stage Amplification Summary\n",
"Width and Lengths for M6\n",
" W = {W_M6*1e6:.2f} um\n",
" L = {L_M6*1e6:.2f} um\n",
"Inversion Region for M6: {determine_inversion_region(gmid_M6, 'nmos')}\n",
"\n",
"Width and Lengths for M7\n",
" W = {W_M7*1e6:.2f} um\n",
" L = {L_M7*1e6:.2f} um\n",
"Inversion Region for M7: {determine_inversion_region(gmid_M7, 'pmos')}\n",
"\n",
"Output Stage Bias:\n",
" Output Current : {display_outcurrent:.2f} {unit_outcurrent}\n",
"\n",
"Output Stage Gain:\n",
" Av2 = {Av2:.2f} ({Av2_db:.2f} dB)\n",
"\"\"\"\n",
"\n",
"print(output_stage_summary)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# For sizing the output stage we must insure that we hit our target for the first pole, and get max gain"
]
},
{
"cell_type": "code",
"execution_count": 443,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1.392e-06"
]
},
"execution_count": 443,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Now we assume that the max gmro for our nmos in the input stage is 55.68\n",
"gmro_M34_assumption = 55.68\n",
"gmid_M34 = 5\n",
"Rout1 = 8e6\n",
"gm_M34 = gmro_M34_assumption/Rout1\n",
"id_outputstage = gm_M34/gmid_M34\n",
"id_outputstage"
]
},
{
"cell_type": "code",
"execution_count": 444,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"gmro_M12 = 718.39\n",
"gmid_M12 = 21.50\n"
]
}
],
"source": [
"gm_M12 = dB_to_linear(float(Av_wish-Av2_db))/Rout1\n",
"CC = 1/(2*np.pi*fdominant* Rout1 * (1 + Av2))\n",
"gmro_M12 = gm_M12 * Rout1*3\n",
"gmid_M12 = gm_M12/id_outputstage\n",
"print(f'gmro_M12 = {gmro_M12:.2f}')\n",
"print(f'gmid_M12 = {gmid_M12:.2f}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Finding the dimensions for the input stage transistors"
]
},
{
"cell_type": "code",
"execution_count": 445,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "1a84ed5efc7d45a490772af3f76341ee",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(Dropdown(description='Select Length:', options=('Show All', '0.13 μm', '0.26 μm', '0.39 μm', '0…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "1909ac8e35914a33aee50aedb2a86205",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(Dropdown(description='Select Length:', options=('Show All', '0.13 μm', '0.26 μm', '0.39 μm', '0…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"pmos_M12 = LoadMosfet(lookup_table=lookup_table_pmos, mos=\"pmos\", vsb=0, vds=-0.6, vgs=(-1.2, -0.1))\n",
"nmos_M34 = LoadMosfet(lookup_table=lookup_table_nmos, mos=\"nmos\", vsb=0, vds=0.6)\n",
"\n",
"id_values_M12 = pmos_M12.extracted_table['id']\n",
"gm_values_M12 = pmos_M12.extracted_table['gm']\n",
"gds_values_M12 = pmos_M12.extracted_table['gds']\n",
"vgs_values_M12 = pmos_M12.extracted_table['vgs']\n",
"\n",
"id_values_M34 = nmos_M34.extracted_table['id']\n",
"gm_values_M34 = nmos_M34.extracted_table['gm']\n",
"gds_values_M34 = nmos_M34.extracted_table['gds']\n",
"vgs_values_M34 = nmos_M34.extracted_table['vgs']\n",
"\n",
"plot_data_vs_data(gm_values_M12/id_values_M12, gm_values_M12/gds_values_M12, vgs_values_M12, pmos_M12.extracted_table['lengths'], 'gm/id', 'm12 gm/gds', log=True)\n",
"plot_data_vs_data(gm_values_M34/id_values_M34, gm_values_M34/gds_values_M34, vgs_values_M34, nmos_M34.extracted_table['lengths'], 'gm/id', 'm34 gm/gds', log=True)"
]
},
{
"cell_type": "code",
"execution_count": 446,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"L_M12 = 3.38e-06\n",
"gmid_M12 = 21.50\n",
"L_M34 = 9.75e-06\n",
"gmid_M34 = 5.00\n"
]
}
],
"source": [
"L_M12 = 3.38e-6\n",
"L_M34 = 9.75e-6\n",
"\n",
"print(f'L_M12 = {L_M12:.2e}')\n",
"print(f'gmid_M12 = {gmid_M12:.2f}')\n",
"print(f'L_M34 = {L_M34:.2e}')\n",
"print(f'gmid_M34 = {gmid_M34:.2f}')\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 447,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "6907db96f53d4e378c57942f9be804a3",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(Dropdown(description='Select Length:', options=('Show All', '0.13 μm', '0.26 μm', '0.39 μm', '0…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "b9ee6f9f9f54489796067b7b5209ab57",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(Dropdown(description='Select Length:', options=('Show All', '0.13 μm', '0.26 μm', '0.39 μm', '0…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"width_values_M12 = pmos_M12.extracted_table['width']\n",
"width_values_M34 = nmos_M34.extracted_table['width']\n",
"\n",
"plot_data_vs_data(gm_values_M12/id_values_M12,id_values_M12/width_values_M12, vgs_values_M12, pmos_M12.extracted_table['lengths'], 'gm/id', 'M12 id/W', log=True)\n",
"plot_data_vs_data(gm_values_M34/id_values_M34, id_values_M34/width_values_M34,vgs_values_M34, nmos_M34.extracted_table['lengths'], 'gm/id', 'M34 id/W', log=True)\n"
]
},
{
"cell_type": "code",
"execution_count": 448,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Input Stage Amplification Summary\n",
"Width and Lengths for M12\n",
" W = 34.80 um\n",
" L = 3.38 um\n",
"Inversion Region for M12: Weak Inversion\n",
"Width and Lengths for M34\n",
" W = 0.50 um\n",
" L = 9.75 um\n",
"Inversion Region for M34: Strong Inversion\n",
"Input Stage Bias:\n",
" Output Current : 1.39 μA\n",
" Output tail current: 2.78 μA\n",
"\n"
]
}
],
"source": [
"id_over_W_M12 = 0.04\n",
"id_over_W_M34 = 2.76\n",
"\n",
"display_outcurrent, unit_outcurrent = display_current(id_outputstage)\n",
"\n",
"W_M12 = id_outputstage/id_over_W_M12\n",
"W_M34 = id_outputstage/id_over_W_M34\n",
"\n",
"\n",
"input_stage_summary = f\"\"\"\n",
"Input Stage Amplification Summary\n",
"Width and Lengths for M12\n",
" W = {W_M12*1e6:.2f} um\n",
" L = {L_M12*1e6:.2f} um\n",
"Inversion Region for M12: {determine_inversion_region(gmid_M12, 'pmos')}\n",
"Width and Lengths for M34\n",
" W = {W_M34*1e6:.2f} um\n",
" L = {L_M34*1e6:.2f} um\n",
"Inversion Region for M34: {determine_inversion_region(gmid_M34, 'nmos')}\n",
"Input Stage Bias:\n",
" Output Current : {display_outcurrent:.2f} {unit_outcurrent}\n",
" Output tail current: {display_outcurrent*2:.2f} {unit_outcurrent}\n",
"\"\"\"\n",
"print(input_stage_summary)"
]
},
{
"cell_type": "code",
"execution_count": 451,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Amplifier is stable\n",
"\n",
"Summary\n",
"Output Stage:\n",
" \n",
"Output Stage Amplification Summary\n",
"Width and Lengths for M6\n",
" W = 2.28 um\n",
" L = 9.75 um\n",
"Inversion Region for M6: Strong Inversion\n",
"\n",
"Width and Lengths for M7\n",
" W = 14.61 um\n",
" L = 3.38 um\n",
"Inversion Region for M7: Strong Inversion\n",
"\n",
"Output Stage Bias:\n",
" Output Current : 6.28 μA\n",
"\n",
"Output Stage Gain:\n",
" Av2 = 41.76 (32.42 dB)\n",
"\n",
"Input Stage:\n",
" \n",
"Input Stage Amplification Summary\n",
"Width and Lengths for M12\n",
" W = 34.80 um\n",
" L = 3.38 um\n",
"Inversion Region for M12: Weak Inversion\n",
"Width and Lengths for M34\n",
" W = 0.50 um\n",
" L = 9.75 um\n",
"Inversion Region for M34: Strong Inversion\n",
"Input Stage Bias:\n",
" Output Current : 1.39 μA\n",
" Output tail current: 2.78 μA\n",
"\n",
"\n",
"Gain and frequency response:\n",
" Gain Bandwidth Product: 10000000.0 Hz\n",
" Dominant Pole Frequency: 1000 Hz\n",
" Output Stage Compensation Capacitance: 4.652564987485247e-13 F\n",
" Load Capacitance: 5e-13 F\n",
" dominant pole: 1000.0 Hz\n",
" non dominant pole: 10000000.000000002 Hz\n",
"\n",
"\n"
]
}
],
"source": [
"# summarizing everything\\\n",
"gmro_M12_actual = 800\n",
"ro_M12 = gmro_M12_actual/gm_M12\n",
"ro_M34 = gmro_M34_assumption/gm_M34\n",
"Av1 = gm_M12 * (ro_M12 * ro_M34)/(ro_M12 + ro_M34)\n",
"f_pole_1 = 1/(2*np.pi * Rout1 * CC * (1 + Av2))\n",
"f_pole_2 = gm_M6/(2*np.pi * Cl)\n",
"\n",
"decades = (20*np.log10(Av1) + Av2_db) / 20\n",
"\n",
"if f_pole_1 * 10**decades < f_pole_2:\n",
" print(\"Amplifier is stable\")\n",
"else:\n",
" print(\"Amplifier is not stable\")\n",
"\n",
"\n",
"\n",
"summary = f\"\"\"\n",
"Summary\n",
"Output Stage:\n",
" {output_stage_summary}\n",
"Input Stage:\n",
" {input_stage_summary}\n",
"\n",
"Gain and frequency response:\n",
" Gain Bandwidth Product: {GBW:} Hz\n",
" Dominant Pole Frequency: {fdominant} Hz\n",
" Output Stage Compensation Capacitance: {CC:} F\n",
" Load Capacitance: {Cl} F\n",
" dominant pole: {f_pole_1} Hz\n",
" non dominant pole: {f_pole_2} Hz\n",
"\n",
"\"\"\"\n",
"print(summary)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.5"
}
},
"nbformat": 4,
"nbformat_minor": 2
}