From 3f6e525108919c49a9224ef42b4a2791ae29a7f8 Mon Sep 17 00:00:00 2001 From: morgan Date: Tue, 5 Dec 2023 14:58:20 +0800 Subject: [PATCH] add notebook examples with 3 PLL modes --- src/both_PLL_example.ipynb | 156 ++++++++++++++++++++++++++++++++++ src/helper_PLL_example.ipynb | 149 ++++++++++++++++++++++++++++++++ src/main_PLL_example.ipynb | 159 +++++++++++++++++++++++++++++++++++ 3 files changed, 464 insertions(+) create mode 100644 src/both_PLL_example.ipynb create mode 100644 src/helper_PLL_example.ipynb create mode 100644 src/main_PLL_example.ipynb diff --git a/src/both_PLL_example.ipynb b/src/both_PLL_example.ipynb new file mode 100644 index 0000000..0ebb9fd --- /dev/null +++ b/src/both_PLL_example.ipynb @@ -0,0 +1,156 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Both PLL mode example\n", + "\n", + "Time domain simulation with helper and main PLL mode. \n", + "\n", + "- Period error (**Helper PLL**)\n", + " - $\\Delta{period} = N - (tag_{gtx}[n] - tag_{gtx}[n-1]) $\n", + " - where ideally $f_{helper} = \\dfrac{f_{in} * (N-1)}{N}$ \n", + "\n", + "- Phase error (**Main PLL**)\n", + " - $\\text{Let } \\Delta tag[n] = tag_{main}[n] - tag_{gtx}[n] \\text{ mod N}$\n", + "\n", + " - $\\Delta\\phi[n] = \\begin{cases}\n", + " \\Delta tag[n] - N, & \\text{if } \\Delta tag > N/2 \\\\\n", + " \\Delta tag[n], & otherwise\n", + " \\end{cases} \\quad$\n", + " \n", + "\n", + "- ADPLL PID (common for main and helper PLL)\n", + " - $P[n] = err[n] * K_P$\n", + " - $I[n] = I[n-1] + err[n] * K_I$\n", + " - $D[n] = (err[n] - err[n-1]) * K_D$\n", + " - $adpll[n] = \\text{base adpll} + P[i] + I[n] + D[n] $\n", + " - where $\\text{base adpll}$ is constant and obtain from frequency counter in HW" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from plotly_resampler import FigureResampler, FigureWidgetResampler\n", + "from plotly.subplots import make_subplots\n", + "import plotly.graph_objects as go\n", + "import numpy as np\n", + "from wave_gen import square_arr\n", + "from wrpll import WRPLL_simulator\n", + "\n", + "# settings\n", + "timestep = 4e-10 # even number is recommended to avoid strange glitches\n", + "total_steps = 300_000_000\n", + "sim_mode = \"both\"\n", + "adpll_period = int(100e-6/timestep) # in simulation steps, 100μs is minimum, smaller = more frequency adjustment and filter calulation per unit time\n", + "start_up_delay = int(100e-6/timestep) # in simulation steps, the frequency adjustment is DISABLE until steps > start_up_delay\n", + "\n", + "gtx_freq = 125_001_519\n", + "\n", + "helper_init_freq = gtx_freq * (4096-1)/4096\n", + "\n", + "helper_filter = {\n", + " \"KP\": 2,\n", + " \"KI\": 4,\n", + " \"KD\": 0,\n", + "}\n", + "\n", + "main_filter = { \n", + " \"KP\": 12,\n", + " \"KI\": 0,\n", + " \"KD\": 0,\n", + "}\n", + "\n", + "\n", + "t = np.linspace(0, timestep*total_steps, total_steps)\n", + "\n", + "# simulation will start with\n", + "# - random phase for main & helper\n", + "# - gussian based base_adpll error\n", + "# - gussian jitter for gtx, main and helper with the set standard deviation\n", + "\n", + "wrpll_sim = WRPLL_simulator(\n", + " time=t,\n", + " sim_mode=sim_mode,\n", + " helper_filter=helper_filter,\n", + " main_filter=main_filter,\n", + " gtx_freq=gtx_freq,\n", + " adpll_write_period=adpll_period,\n", + " start_up_delay=start_up_delay,\n", + " helper_init_freq=helper_init_freq,\n", + " # preset\n", + " gtx_jitter_SD=19e-12, # 0 = no jitter\n", + " dcxo_jitter_SD=9e-12,\n", + " dcxo_freq=125_000_000,\n", + " freq_acquisition_SD=100,\n", + " N=4096, # hardware used 4096\n", + " blind_period=300, # 300 is used to remove most glitches in simulation (for details see README 'Limitation')\n", + " cycle_slip_comp=True,\n", + ")\n", + "wrpll_sim.run()\n", + "\n", + "# faster than pyplot with resampling feature\n", + "# see https://github.com/predict-idlab/plotly-resampler\n", + "\n", + "fig = FigureWidgetResampler(make_subplots(rows=4, shared_xaxes=True))\n", + "fig.add_trace(go.Scattergl(name='phase error'), hf_x=t, hf_y=wrpll_sim.phase_err, row=1, col=1)\n", + "\n", + "fig.add_trace(go.Scattergl(name='freq error (ppm)'), hf_x=t, hf_y=(\n", + " wrpll_sim.mainfreq-gtx_freq) * (1e6/gtx_freq), row=2, col=1)\n", + "\n", + "fig.add_trace(go.Scattergl(name='period error'), hf_x=t, hf_y=wrpll_sim.period_err, row=3, col=1)\n", + "\n", + "fig.add_trace(go.Scattergl(name='gtx'), hf_x=t, hf_y=wrpll_sim.gtx+1, row=4, col=1)\n", + "fig.add_trace(go.Scattergl(name='main'), hf_x=t, hf_y=wrpll_sim.main, row=4, col=1)\n", + "fig.add_trace(go.Scattergl(name='helper'), hf_x=t, hf_y=wrpll_sim.helper-1, row=4, col=1)\n", + "\n", + "\n", + "fig.update_layout(\n", + " xaxis4=dict(title=\"time (sec)\"),\n", + " yaxis1=dict(title=\"phase error\"),\n", + " yaxis2=dict(title=\"freq error (ppm)\"),\n", + " yaxis3=dict(title=\"beating period error\"),\n", + " yaxis4=dict(title=\"Signal\"),\n", + "\n", + " height=1000,\n", + " showlegend=True,\n", + " title_text=\"PLL example\",\n", + " legend=dict(\n", + " orientation=\"h\",\n", + " yanchor=\"bottom\",\n", + " y=1.02,\n", + " xanchor=\"right\",\n", + " x=1,\n", + " ),\n", + ")\n", + "\n", + "fig" + ] + } + ], + "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.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/src/helper_PLL_example.ipynb b/src/helper_PLL_example.ipynb new file mode 100644 index 0000000..3821925 --- /dev/null +++ b/src/helper_PLL_example.ipynb @@ -0,0 +1,149 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Helper PLL mode example\n", + "\n", + "Time domain simulation with helper PLL mode\n", + "\n", + "- Period error (**Helper PLL**)\n", + " - $\\Delta{period} = N - (tag_{gtx}[n] - tag_{gtx}[n-1]) $\n", + " - where ideally $f_{helper} = \\dfrac{f_{in} * (N-1)}{N}$ \n", + "\n", + "- Phase error (**Main PLL**)\n", + " - $\\text{Let } \\Delta tag[n] = tag_{main}[n] - tag_{gtx}[n] \\text{ mod N}$\n", + "\n", + " - $\\Delta\\phi[n] = \\begin{cases}\n", + " \\Delta tag[n] - N, & \\text{if } \\Delta tag > N/2 \\\\\n", + " \\Delta tag[n], & otherwise\n", + " \\end{cases} \\quad$\n", + " \n", + "\n", + "- ADPLL PID (common for main and helper PLL)\n", + " - $P[n] = err[n] * K_P$\n", + " - $I[n] = I[n-1] + err[n] * K_I$\n", + " - $D[n] = (err[n] - err[n-1]) * K_D$\n", + " - $adpll[n] = \\text{base adpll} + P[i] + I[n] + D[n] $\n", + " - where $\\text{base adpll}$ is constant and obtain from frequency counter in HW" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from plotly_resampler import FigureResampler, FigureWidgetResampler\n", + "from plotly.subplots import make_subplots\n", + "import plotly.graph_objects as go\n", + "import numpy as np\n", + "from wave_gen import square_arr\n", + "from wrpll import WRPLL_simulator\n", + "\n", + "# settings\n", + "timestep = 4e-10 # even number is recommended to avoid strange glitches\n", + "total_steps = 200_000_000\n", + "sim_mode = \"helper_pll\"\n", + "adpll_period = int(100e-6/timestep) # in simulation steps, 100μs is minimum, smaller = more frequency adjustment and filter calulation per unit time\n", + "start_up_delay = int(100e-6/timestep) # in simulation steps, the frequency adjustment is DISABLE until steps > start_up_delay\n", + "\n", + "gtx_freq = 125_001_519\n", + "\n", + "helper_filter = {\n", + " \"KP\": 2,\n", + " \"KI\": 4,\n", + " \"KD\": 0,\n", + "}\n", + "\n", + "main_filter = { # unused\n", + " \"KP\": 12,\n", + " \"KI\": 0,\n", + " \"KD\": 0,\n", + "}\n", + "\n", + "\n", + "t = np.linspace(0, timestep*total_steps, total_steps)\n", + "\n", + "# simulation will start with\n", + "# - random phase for main & helper\n", + "# - gussian based base_adpll error\n", + "# - gussian jitter for gtx, main and helper with the set standard deviation\n", + "\n", + "wrpll_sim = WRPLL_simulator(\n", + " time=t,\n", + " sim_mode=sim_mode,\n", + " helper_filter=helper_filter,\n", + " main_filter=main_filter,\n", + " gtx_freq=gtx_freq,\n", + " adpll_write_period=adpll_period,\n", + " start_up_delay=start_up_delay,\n", + " # preset\n", + " gtx_jitter_SD=19e-12, # 0 = no jitter\n", + " dcxo_jitter_SD=9e-12,\n", + " dcxo_freq=125_000_000,\n", + " freq_acquisition_SD=500,\n", + " N=4096, # hardware used 4096\n", + " blind_period=300, # 300 is used to remove most glitches in simulation (for details see README 'Limitation')\n", + " cycle_slip_comp=True,\n", + ")\n", + "\n", + "wrpll_sim.run()\n", + "\n", + "# faster than pyplot with resampling feature\n", + "# see https://github.com/predict-idlab/plotly-resampler\n", + "\n", + "fig = FigureWidgetResampler(make_subplots(rows=3, shared_xaxes=True))\n", + "fig.add_trace(go.Scattergl(name='period error'), hf_x=t, hf_y=wrpll_sim.period_err, row=1, col=1)\n", + "\n", + "fig.add_trace(go.Scattergl(name='gtx'), hf_x=t, hf_y=wrpll_sim.gtx+1, row=2, col=1)\n", + "fig.add_trace(go.Scattergl(name='main'), hf_x=t, hf_y=wrpll_sim.main, row=2, col=1)\n", + "fig.add_trace(go.Scattergl(name='helper'), hf_x=t, hf_y=wrpll_sim.helper-1, row=2, col=1)\n", + "\n", + "fig.add_trace(go.Scattergl(name='helper'), hf_x=t, hf_y=wrpll_sim.helper_adpll, row=3, col=1)\n", + "\n", + "\n", + "fig.update_layout(\n", + " xaxis2=dict(title=\"time (sec)\"),\n", + "\n", + " yaxis1=dict(title=\"beating period error\"),\n", + " yaxis2=dict(title=\"Signal\"),\n", + " height=500,\n", + " showlegend=True,\n", + " title_text=\"PLL example\",\n", + " legend=dict(\n", + " orientation=\"h\",\n", + " yanchor=\"bottom\",\n", + " y=1.02,\n", + " xanchor=\"right\",\n", + " x=1,\n", + " ),\n", + ")\n", + "\n", + "fig" + ] + } + ], + "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.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/src/main_PLL_example.ipynb b/src/main_PLL_example.ipynb new file mode 100644 index 0000000..9daae33 --- /dev/null +++ b/src/main_PLL_example.ipynb @@ -0,0 +1,159 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Main PLL mode example\n", + "\n", + "Time domain simulation with main PLL mode, and helper PLL is assumed to be locked \n", + "\n", + "(`helper_init_freq` variable need to be set)\n", + "\n", + "\n", + "- Period error (**Helper PLL**)\n", + " - $\\Delta{period} = N - (tag_{gtx}[n] - tag_{gtx}[n-1]) $\n", + " - where ideally $f_{helper} = \\dfrac{f_{in} * (N-1)}{N}$ \n", + "\n", + "- Phase error (**Main PLL**)\n", + " - $\\text{Let } \\Delta tag[n] = tag_{main}[n] - tag_{gtx}[n] \\text{ mod N}$\n", + "\n", + " - $\\Delta\\phi[n] = \\begin{cases}\n", + " \\Delta tag[n] - N, & \\text{if } \\Delta tag > N/2 \\\\\n", + " \\Delta tag[n], & otherwise\n", + " \\end{cases} \\quad$\n", + " \n", + "\n", + "- ADPLL PID (common for main and helper PLL)\n", + " - $P[n] = err[n] * K_P$\n", + " - $I[n] = I[n-1] + err[n] * K_I$\n", + " - $D[n] = (err[n] - err[n-1]) * K_D$\n", + " - $adpll[n] = \\text{base adpll} + P[i] + I[n] + D[n] $\n", + " - where $\\text{base adpll}$ is constant and obtain from frequency counter in HW" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from plotly_resampler import FigureResampler, FigureWidgetResampler\n", + "from plotly.subplots import make_subplots\n", + "import plotly.graph_objects as go\n", + "import numpy as np\n", + "from wave_gen import square_arr\n", + "from wrpll import WRPLL_simulator\n", + "\n", + "# settings\n", + "timestep = 4e-10 # even number is recommended to avoid strange glitches\n", + "total_steps = 200_000_000\n", + "sim_mode = \"main_pll\"\n", + "adpll_period = int(100e-6/timestep) # in simulation steps, 100μs is minimum, smaller = more frequency adjustment and filter calulation per unit time\n", + "start_up_delay = int(100e-6/timestep) # in simulation steps, the frequency adjustment is DISABLE until steps > start_up_delay\n", + "\n", + "gtx_freq = 125_001_519\n", + "\n", + "helper_init_freq = gtx_freq * (4096-1)/4096\n", + "\n", + "helper_filter = { # unused\n", + " \"KP\": 2,\n", + " \"KI\": 4,\n", + " \"KD\": 0,\n", + "}\n", + "\n", + "main_filter = { \n", + " \"KP\": 12,\n", + " \"KI\": 0,\n", + " \"KD\": 0,\n", + "}\n", + "\n", + "\n", + "t = np.linspace(0, timestep*total_steps, total_steps)\n", + "\n", + "# simulation will start with\n", + "# - random phase for main & helper\n", + "# - gussian based base_adpll error\n", + "# - gussian jitter for gtx, main and helper with the set standard deviation\n", + "\n", + "wrpll_sim = WRPLL_simulator(\n", + " time=t,\n", + " sim_mode=sim_mode,\n", + " helper_filter=helper_filter,\n", + " main_filter=main_filter,\n", + " gtx_freq=gtx_freq,\n", + " adpll_write_period=adpll_period,\n", + " start_up_delay=start_up_delay,\n", + " helper_init_freq=helper_init_freq,\n", + " # preset\n", + " gtx_jitter_SD=19e-12, # 0 = no jitter\n", + " dcxo_jitter_SD=9e-12,\n", + " dcxo_freq=125_000_000,\n", + " freq_acquisition_SD=100,\n", + " N=4096, # hardware used 4096\n", + " blind_period=300, # 300 is used to remove most glitches in simulation (for details see README 'Limitation')\n", + " cycle_slip_comp=True,\n", + ")\n", + "wrpll_sim.run()\n", + "\n", + "# faster than pyplot with resampling feature\n", + "# see https://github.com/predict-idlab/plotly-resampler\n", + "\n", + "fig = FigureWidgetResampler(make_subplots(rows=4, shared_xaxes=True))\n", + "fig.add_trace(go.Scattergl(name='phase error'), hf_x=t, hf_y=wrpll_sim.phase_err, row=1, col=1)\n", + "\n", + "fig.add_trace(go.Scattergl(name='freq error (ppm)'), hf_x=t, hf_y=(\n", + " wrpll_sim.mainfreq-gtx_freq) * (1e6/gtx_freq), row=2, col=1)\n", + "\n", + "fig.add_trace(go.Scattergl(name='period error'), hf_x=t, hf_y=wrpll_sim.period_err, row=3, col=1)\n", + "\n", + "fig.add_trace(go.Scattergl(name='gtx'), hf_x=t, hf_y=wrpll_sim.gtx+1, row=4, col=1)\n", + "fig.add_trace(go.Scattergl(name='main'), hf_x=t, hf_y=wrpll_sim.main, row=4, col=1)\n", + "fig.add_trace(go.Scattergl(name='helper'), hf_x=t, hf_y=wrpll_sim.helper-1, row=4, col=1)\n", + "\n", + "\n", + "fig.update_layout(\n", + " xaxis4=dict(title=\"time (sec)\"),\n", + " yaxis1=dict(title=\"phase error\"),\n", + " yaxis2=dict(title=\"freq error (ppm)\"),\n", + " yaxis3=dict(title=\"beating period error\"),\n", + " yaxis4=dict(title=\"Signal\"),\n", + "\n", + " height=1000,\n", + " showlegend=True,\n", + " title_text=\"PLL example\",\n", + " legend=dict(\n", + " orientation=\"h\",\n", + " yanchor=\"bottom\",\n", + " y=1.02,\n", + " xanchor=\"right\",\n", + " x=1,\n", + " ),\n", + ")\n", + "\n", + "fig" + ] + } + ], + "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.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}