Skip to content

Instantly share code, notes, and snippets.

@tspspi
Created June 15, 2022 14:01
Show Gist options
  • Save tspspi/2f42b00673ff6d6e077d5896bb92b5a4 to your computer and use it in GitHub Desktop.
Save tspspi/2f42b00673ff6d6e077d5896bb92b5a4 to your computer and use it in GitHub Desktop.
Thermal noise calculation for QUAK/ESR
Display the source blob
Display the rendered blob
Raw
{
"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