{ "cells": [ { "cell_type": "raw", "id": "96aa12a7-69d2-4af8-8aca-e51bd02e7ccf", "metadata": {}, "source": [ "\\tableofcontents % LaTeX rendered pdf will have a TOC with links\n", "% These TeX commands run at the start to remove section numbering\n", "%\\renewcommand{\\thesection}{\\hspace*{-1.0em}}\n", "%\\renewcommand{\\thesubsection}{\\hspace*{-1.0em}}\n", "%\\renewcommand{\\thesubsubsection}{\\hspace*{-1.0em}}" ] }, { "cell_type": "code", "execution_count": null, "id": "519d6456-e844-4bb7-a9be-8f19ece1ea90", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from matplotlib import pyplot as plt\n", "from matplotlib import cm\n", "from matplotlib.ticker import LinearLocator\n", "from sk_dsp_comm import sigsys as ss\n", "from sk_dsp_comm import digitalcom as dc\n", "from sk_dsp_comm import synchronization as sync\n", "from scipy import signal\n", "\n", "%config InlineBackend.figure_formats=['svg'] # SVG inline viewing" ] }, { "cell_type": "markdown", "id": "0a33e77a-c4ee-4e59-b672-626aa5fabfde", "metadata": {}, "source": [ "# Phase Lock Loops\n", "\n", "The module `synchronization.py` has component classes for implementing NCO's (32-bit and 48-bit), DSP loop filters (two types), accumulator (used in the loop filters), $K_p$ and $K_i$ calculation functions, and several digital PLL analysis functions." ] }, { "cell_type": "code", "execution_count": null, "id": "2aa5972f-017c-44e3-ba28-3ab666eedfe0", "metadata": {}, "outputs": [], "source": [ "NCO1 = sync.NCO(3.25e6,120e6, n_bits=32)\n", "NCO2 = sync.NCO(3.0e6,120e6, n_bits=48)" ] }, { "cell_type": "code", "execution_count": null, "id": "c77f6dbc-16ba-40ae-806e-fe606171fe08", "metadata": {}, "outputs": [], "source": [ "Nclks = 100000\n", "n = np.arange(Nclks)\n", "x_32 = np.zeros(len(n))\n", "data_bit = 1\n", "for k in range(Nclks):\n", " NCO1.update(0.0)\n", " x_32[k] = NCO1.out_sin()\n", " # x[k] = data_bit\n", " # if NCO1.NCO32_pos_edge():\n", " # data_bit = 2*random.randint(0,2) - 1\n", "y_32 = dc.farrow_resample(x_32,3.5,3.25)" ] }, { "cell_type": "code", "execution_count": null, "id": "65ff2d1e-b797-4a25-b4a4-facb8d5ee928", "metadata": {}, "outputs": [], "source": [ "Nclks = 100000\n", "n = np.arange(Nclks)\n", "x_48 = np.zeros(len(n))\n", "data_bit = 1\n", "for k in range(Nclks):\n", " NCO2.update(0.0)\n", " x_48[k] = NCO2.out_sin()\n", " # x[k] = data_bit\n", " # if NCO2.NCO48_pos_edge():\n", " # data_bit = 2*random.randint(0,2) - 1\n", "y_48 = dc.farrow_resample(x_48,3.5,3.25)" ] }, { "cell_type": "code", "execution_count": null, "id": "28ff24b5-8d8e-4078-b513-01fbe3e4ad79", "metadata": {}, "outputs": [], "source": [ "plt.plot(y_32[1000:1300])\n", "plt.plot(y_48[1000:1300])\n", "\n", "plt.grid();" ] }, { "cell_type": "code", "execution_count": null, "id": "0cf28109-61e2-4d0b-a83d-2e8f19ddba65", "metadata": {}, "outputs": [], "source": [ "Py_32, fy_32 = ss.psd(y_32,2**16,120,scale_noise=False)\n", "Py_48, fy_48 = ss.psd(y_48,2**16,120,scale_noise=False)\n", "plt.plot(fy_32,10*np.log10(Py_32),120)\n", "plt.plot(fy_48,10*np.log10(Py_48),120)\n", "plt.ylim(-60,0)\n", "plt.xlim(0, 4)\n", "plt.title(r'Sinusoid Spectrum using the Sinusoid Scaling Option')\n", "plt.xlabel(r'Frequency (MHz)')\n", "plt.ylabel(r'PSD (dB)')\n", "plt.grid();" ] }, { "cell_type": "markdown", "id": "0b9d5045-53c1-4efe-9e7a-1b827bc2d539", "metadata": {}, "source": [ "## Complex Baseband PLL" ] }, { "cell_type": "code", "execution_count": null, "id": "e9f30f97-c4ff-4419-ac2e-4440d07b6fda", "metadata": {}, "outputs": [], "source": [ "fs = 100e3\n", "fc = 0\n", "n = np.arange(10000)\n", "x_in = np.exp(1j*2*np.pi*fc/fs*n + 1j*np.pi/8)" ] }, { "cell_type": "code", "execution_count": null, "id": "008ba0ec-e156-49ee-a589-4b68ab6850d0", "metadata": {}, "outputs": [], "source": [ "phi_pstep = sync.phi_phase_step(n,100,0.707,fs)\n", "phi_fstep = sync.phi_freq_step(n,100,0.707,fs)" ] }, { "cell_type": "code", "execution_count": null, "id": "ebcea9ae-d67a-474f-9975-fae69ec0fe9a", "metadata": {}, "outputs": [], "source": [ "y_d_pll, y_lf_pll, x_NCO_pll = sync.cbb_pll(x_in, 100, 1.0, fc_pll=0.0, f_clk_pll=fs, pll_open=False)\n", "t_pll = np.arange(0,len(y_d_pll))/fs\n", "plt.plot(t_pll*1e3,phi_pstep/2/np.pi * np.pi/8,label='Linear Theory')\n", "plt.plot(t_pll*1e3,y_d_pll,label='Measured')\n", "plt.title(r'Type 2 PLL Phase Step (Freq. Step) Response')\n", "plt.ylabel(r'Phase Error')\n", "plt.xlabel(r'Time (ms)')\n", "plt.legend()\n", "plt.grid();" ] } ], "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 }