Created
June 15, 2022 14:01
-
-
Save tspspi/2f42b00673ff6d6e077d5896bb92b5a4 to your computer and use it in GitHub Desktop.
Thermal noise calculation for QUAK/ESR
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"id": "2a8d646e", | |
"metadata": {}, | |
"source": [ | |
"# Thermal noise\n", | |
"\n", | |
"## Thermal noise in a Ohmic resistor\n", | |
"\n", | |
"One sided power spectral density (mean square voltage variance per Hertz of bandwidth) for Ohmic resistor $R$:\n", | |
"\n", | |
"$\n", | |
"\\bar{v_n^2} = 4 k_B T R\n", | |
"$\n", | |
"\n", | |
"This means for a bandwidth of $f_{\\text{bw}}$:\n", | |
"\n", | |
"$\n", | |
"v_n = \\sqrt{\\bar{v_n^2}} * \\sqrt{f_{\\text{bw}}}\n", | |
"$" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"id": "37f73329", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import math\n", | |
"kb = 1.38e-23\n", | |
"\n", | |
"def oneSidedPowerSpectralDensity(R, *, T = 300):\n", | |
" return 4 * kb * T * R\n", | |
"\n", | |
"def thermalNoiseRMS(R, bandwidthHz, *, T = 300):\n", | |
" return math.sqrt(oneSidedPowerSpectralDensity(R, T=T)) * math.sqrt(bandwidthHz)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "0fa28502", | |
"metadata": {}, | |
"source": [ | |
"Example: A $50 \\Omega$ resistor at $300 K$ would have a one sided spectral power density of $0.9 \\frac{\\text{nV}}{\\sqrt{\\text{Hz}}}$:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"id": "0a191199", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"9.099450532861861e-10" | |
] | |
}, | |
"execution_count": 2, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"math.sqrt(oneSidedPowerSpectralDensity(50))" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"id": "e9e17a13", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def valueWithSiPrefix(value):\n", | |
" if value > 1e15:\n", | |
" return (value / 1.0e15, \"P\")\n", | |
" if value > 1e12:\n", | |
" return (value / 1.0e12, \"T\")\n", | |
" if value > 1e9:\n", | |
" return (value / 1.0e9, \"G\")\n", | |
" if value > 1e6:\n", | |
" return (value / 1.0e6, \"M\")\n", | |
" if value > 1e3:\n", | |
" return (value / 1.0e3, \"k\")\n", | |
" if value < 1e-15:\n", | |
" return (value * 1.0e18, \"a\")\n", | |
" if value < 1e-12:\n", | |
" return (value * 1.0e15, \"f\")\n", | |
" if value < 1e-9:\n", | |
" return (value * 1.0e12, \"p\")\n", | |
" if value < 1e-6:\n", | |
" return (value * 1.0e9, \"n\")\n", | |
" if value < 1e-3:\n", | |
" return (value * 1.0e6, \"u\")\n", | |
" if value < 1:\n", | |
" return (value * 1.0e3, \"m\")\n", | |
" return (value, \"\")\n", | |
"\n", | |
"def printValueWithSiPrefix(value, baseunit):\n", | |
" val, prefix = valueWithSiPrefix(value)\n", | |
" print(\"{} {}{}\".format(val, prefix, baseunit))" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"id": "91a63af0", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def f3dbBandwidth(timeConstant):\n", | |
" return 1.0 / (2.0 * math.pi * timeConstant)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "ebb9a40b", | |
"metadata": {}, | |
"source": [ | |
"## Time constant of filters\n", | |
"\n", | |
"### RC-Lowpass\n", | |
"\n", | |
"A simple filter with R in series, C as shunt. This has a time constant of $\\tau = R * C$" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 11, | |
"id": "36847c65", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def rcLowpassTimeConstant(R, C):\n", | |
" return R * C\n", | |
"def rcLowpassBandwidth(R, C):\n", | |
" return f3dbBandwidth(R * C)\n" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "f762009b", | |
"metadata": {}, | |
"source": [ | |
"## Our QUAK/ESR setup" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "d5eb6edb", | |
"metadata": {}, | |
"source": [ | |
"Our lock in amplifier at QUAK/ESR has a time constant of $100 ms = 0.1s$ and thus a bandwidth of $10 Hz$.\n", | |
"\n", | |
"We have to account for the factor of $2 \\pi$ since the bandwidth specification convention for a system is the point where the power drops about to half ($- 3 dB$):\n", | |
"\n", | |
"$\n", | |
"f_{3dB} = \\frac{1}{2 \\pi \\tau}\n", | |
"$" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"id": "316b675f", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Time constant of quak/esr lock in: 0.1\n", | |
"Bandwidth of quak/esr lock in: 1.5915494309189535\n", | |
"Expected thermal noise: 1.147955978598872 nV\n" | |
] | |
} | |
], | |
"source": [ | |
"quakEsrLockInTimeConstant = 100e-3\n", | |
"\n", | |
"quakEsrThermalNoise = thermalNoiseRMS(50, f3dbBandwidth(quakEsrLockInTimeConstant))\n", | |
"quakEsrThermalNoiseSI, quakEsrThermalNoiseUnit = valueWithSiPrefix(quakEsrThermalNoise)\n", | |
"print(\"Time constant of quak/esr lock in: {}\".format(quakEsrLockInTimeConstant))\n", | |
"print(\"Bandwidth of quak/esr lock in: {}\".format(f3dbBandwidth(quakEsrLockInTimeConstant)))\n", | |
"print(\"Expected thermal noise: {} {}V\".format(quakEsrThermalNoiseSI, quakEsrThermalNoiseUnit))" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "14847562", | |
"metadata": {}, | |
"source": [ | |
"We have two or three amplifiers.\n", | |
"\n", | |
"### Two amplifiers (2x ZFL-500LN+)\n", | |
"\n", | |
"In case we're using 2x ZFL-500LN+ each has $20 dB$ gain, thus a voltage factor of $10$ per amplifier, i.e. voltage gain of $100$:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"id": "beb941bd", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"229.5911957197744 nV\n" | |
] | |
} | |
], | |
"source": [ | |
"printValueWithSiPrefix(2 * 100 * quakEsrThermalNoise, \"V\")" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "db7bc874", | |
"metadata": {}, | |
"source": [ | |
"### Three amplifiers (2x ZFL-500LN+, 1x ZX60-P103LN+)\n", | |
"\n", | |
"When we're using three amplifiers we add a third ```ZX60-P103LN+``` to our setup (at the output stage) - this has a gain of $24 dB$ thus a voltage gain of around $16.85$:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"id": "e31e5f2f", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"3.8686116478781987 uV\n" | |
] | |
} | |
], | |
"source": [ | |
"printValueWithSiPrefix(2 * 100 * 16.85 * quakEsrThermalNoise, \"V\")" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"id": "b9c314bd", | |
"metadata": {}, | |
"source": [ | |
"### Three amplifiers plus 3dB attenuator (2x ZFL-500LN+, -3dB attenuator, 1x ZX60-P103LN+)\n", | |
"\n", | |
"Adding a 3 dB attenuator in front of the ```ZX60-P103LN+``` would induce a voltage gain factor of $0.70$:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"id": "c5bd1cfa", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"2.7080281535147392 uV\n" | |
] | |
} | |
], | |
"source": [ | |
"printValueWithSiPrefix(2 * 100 * 16.85 * 0.7 * quakEsrThermalNoise, \"V\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"id": "23aa8ef9", | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
} | |
], | |
"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.8.12" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 5 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment