{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Beacon Sync\n",
    "\n",
    "Synchronise two delta peaks, by using an intermediate beacon that was sent out together with it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import scipy.signal as signal\n",
    "\n",
    "import os\n",
    "import sys\n",
    "# Append parent directory to import path so lib can be found\n",
    "sys.path.append(os.path.dirname(os.path.abspath(os.getcwd())))\n",
    "from lib.util import *\n",
    "from lib.plotting import *\n",
    "from lib.timing import *\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Beacon period [ns]: 14.285714285714285\n",
      "Beacon initial [ns]: 4.4\n",
      "Beacon initial [phase]: 1.9352210746113125\n",
      "Beacon initial [idx]: 2.2\n",
      "Beacon difference [ns]: 8.571428571428571\n",
      "Beacon difference [phase]: 3.7699111843077517\n",
      "Impulse offsets [ns]: [ 64. 178.]\n",
      "Time difference Impulses [ns]: 113.99999999999999\n",
      "Time difference Impulses [T]: 7.9799999999999995\n"
     ]
    }
   ],
   "source": [
    "us = 1e3 # ns\n",
    "ns = 1/us # us\n",
    "\n",
    "\n",
    "band = (30, 80) # MHz\n",
    "samplerate = 500 # MHz\n",
    "timelength = 0.2 # us\n",
    "\n",
    "time = np.arange(0, timelength, 1/samplerate)\n",
    "\n",
    "# generate beacons\n",
    "if True: # in-band\n",
    "    f_beacon = 70 # MHz\n",
    "else: # under band\n",
    "    f_beacon = 20 # MHz\n",
    "\n",
    "beacon_amplitude = 0.1\n",
    "beacon_init_phase = time2phase(4.4*ns, f_beacon)\n",
    "beacon_phase_offset = 1.2*np.pi\n",
    "\n",
    "beacons = np.array([\n",
    "    beacon_amplitude * sin_delay(f_beacon, time, t_delay=0, phase=-beacon_init_phase),\n",
    "    beacon_amplitude * sin_delay(f_beacon, time, t_delay=0, phase=-beacon_init_phase-beacon_phase_offset)\n",
    "])\n",
    "\n",
    "\n",
    "# generate impulses\n",
    "impulses = []\n",
    "impulses_offsets = []\n",
    "impulses_def_offsets = [\n",
    "                        (0.3*len(time),0.4*len(time)),\n",
    "                        (0.5*len(time),0.9*len(time)),\n",
    "                       ]# random offsets in interval\n",
    "if True:\n",
    "    # freeze impulses\n",
    "    impulses_def_offsets = [\n",
    "        0.064*samplerate,\n",
    "        0.178*samplerate        \n",
    "    ]\n",
    "if not True:\n",
    "    # Equal offset to beacon and \n",
    "    impulses_def_offsets = [\n",
    "        64*ns*samplerate,\n",
    "        (64*ns + (beacon_phase_offset % (2*np.pi))/(2*np.pi*f_beacon) + 6/f_beacon)*samplerate\n",
    "    ]\n",
    "    if True:\n",
    "        impulses_def_offsets = [impulses_def_offsets[0]]\n",
    "        \n",
    "    \n",
    "for i in range(2):\n",
    "    offset = None\n",
    "    if impulses_def_offsets:\n",
    "        if len(impulses_def_offsets) == 1:\n",
    "            offset = impulses_def_offsets[0]\n",
    "        else:\n",
    "            offset = impulses_def_offsets[i]\n",
    "    orig_imp, imp_offset = deltapeak(timelength, samplerate, offset=offset, peaklength=1)\n",
    "\n",
    "    orig_imp[imp_offset] = 0.1\n",
    "    ## Bandpass it\n",
    "    imp, _ = fft_bandpass(orig_imp, band, samplerate)\n",
    "    imp /= np.max(imp)\n",
    "    \n",
    "    impulses.append(imp)\n",
    "    impulses_offsets.append(imp_offset/samplerate)\n",
    "\n",
    "impulses = np.array(impulses)\n",
    "impulses_offsets = np.array(impulses_offsets)\n",
    "print(\"Beacon period [ns]:\", 1/f_beacon/ns)\n",
    "print(\"Beacon initial [ns]:\", phase2time(beacon_init_phase, f_beacon) /ns)\n",
    "print(\"Beacon initial [phase]:\", beacon_init_phase)\n",
    "print(\"Beacon initial [idx]:\", phase2time(beacon_init_phase, f_beacon)*samplerate)\n",
    "print(\"Beacon difference [ns]:\", phase2time(beacon_phase_offset, f_beacon)/ns)\n",
    "print(\"Beacon difference [phase]:\", beacon_phase_offset)\n",
    "print(\"Impulse offsets [ns]:\", impulses_offsets[:,0]/ns)\n",
    "print(\"Time difference Impulses [ns]: {}\".format( (impulses_offsets[1,0]-impulses_offsets[0,0])/ns ))\n",
    "print(\"Time difference Impulses [T]: {}\".format( (impulses_offsets[1,0]-impulses_offsets[0,0])*f_beacon ))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "full_signals = impulses + beacons"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 47532 characters]\n",
      "text/plain": [
       "<Figure size 864x288 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Make a figure showing two signals with a beacon per signal\n",
    "colors = ['y','g']\n",
    "multiplier_name = ['m','n']\n",
    "\n",
    "\n",
    "fig, axes = plt.subplots(3,1, sharex=True, figsize=(12,4), gridspec_kw=dict(hspace=0))\n",
    "for i, ax in enumerate(axes):\n",
    "    #if i != 0:\n",
    "    #    ax.spines['top'].set_visible(False)\n",
    "    #ax.spines['right'].set_visible(False)\n",
    "    #if i != len(axes)-1:\n",
    "    #    ax.spines['bottom'].set_visible(False)\n",
    "    #ax.spines['left'].set_visible(False)\n",
    "    #ax.tick_params(left=False, bottom=False, labelleft=False, labelbottom=False)\n",
    "    pass\n",
    "\n",
    "axes[-1].set_xlabel(\"Time [ns]\")\n",
    "axes[-1].set_yticks([],[])\n",
    "for i in range(0, 2):\n",
    "    axes[i].set_yticks([],[])\n",
    "    axes[i].set_ylabel(\"Antenna {:d}\".format(i+1))\n",
    "    axes[i].plot(time/ns, impulses[i])\n",
    "    axes[i].plot(time/ns, beacons[i], marker='.')\n",
    "    if not True:\n",
    "        axes[i].plot(time/ns, full_signals[i])\n",
    "\n",
    "\n",
    "# indicate timing of pulses\n",
    "for i, impulse_offset in enumerate(impulses_offsets):\n",
    "    kwargs = dict(color=colors[i])\n",
    "    [ax.axvline(impulse_offset/ns, **kwargs) for ax in (axes[i], axes[-1])]\n",
    "\n",
    "\n",
    "# indicate timing of the beacons\n",
    "# and annotate ticks and impulse widths\n",
    "tmp_beacon_phases = beacon_init_phase + np.arange(0,2)*beacon_phase_offset\n",
    "if True: # mod phases\n",
    "    tmp_beacon_phases %= 2*np.pi\n",
    "tmp_beacon_offsets = phase2time(tmp_beacon_phases, f_beacon)\n",
    "\n",
    "\n",
    "A = np.empty(2)\n",
    "B = np.empty(2)\n",
    "for i in range(0,2):\n",
    "    kwargs = dict(color=colors[i], ls=(0, (3,2)))\n",
    "    tick_kwargs = dict(color='k', alpha=0.2)\n",
    "\n",
    "    # indicate every period of the beacon\n",
    "    beacon_ticks =  tmp_beacon_offsets[i] + [(n)*1/f_beacon for n in range(1+int((time[-1] - time[0]) * f_beacon))]\n",
    "\n",
    "    [axes[i].axvline(tick/ns, **{**kwargs, **tick_kwargs}) for tick in beacon_ticks]\n",
    "\n",
    "    # reference period in beacon\n",
    "    [ax.axvline(tmp_beacon_offsets[i]/ns, **kwargs) for ax in (axes[i], axes[-1])]\n",
    "\n",
    "    # annotate width between impulse and closest beacon tick\n",
    "    # and closest beacon tick and reference tick\n",
    "    closest_beacon_tick_id = np.argmin(np.abs(beacon_ticks-impulses_offsets[i]))\n",
    "    if closest_beacon_tick_id != 0 and beacon_ticks[closest_beacon_tick_id] > impulses_offsets[i]:\n",
    "        closest_beacon_tick_id -= 1\n",
    "    closest_beacon_tick = beacon_ticks[closest_beacon_tick_id]\n",
    "\n",
    "    annotate_width(axes[i], f\"$A_{i+1}$\", closest_beacon_tick/ns, impulses_offsets[i]/ns, 0.7)\n",
    "    annotate_width(axes[i], f\"$B_{i+1}={multiplier_name[i]}T$\", closest_beacon_tick/ns, tmp_beacon_offsets[i]/ns, 0.4)\n",
    "\n",
    "    A[i] = closest_beacon_tick - impulses_offsets[i]\n",
    "    B[i] = closest_beacon_tick - tmp_beacon_offsets[i]\n",
    "\n",
    "# annotate width between beacon reference periods\n",
    "annotate_width(axes[-1], \"$\\Delta t_\\\\varphi$\", tmp_beacon_offsets[0]/ns, tmp_beacon_offsets[-1]/ns, 0.4)\n",
    "\n",
    "# annotate width between pulses\n",
    "annotate_width(axes[-1], \"$\\Delta t$\", impulses_offsets[0]/ns, impulses_offsets[-1]/ns, 0.4)\n",
    "\n",
    "\n",
    "fig.show()\n",
    "if True:\n",
    "    fname = 'figures/08_beacon_sync_timing_outline'\n",
    "\n",
    "    # Dump figure\n",
    "    fig.savefig(fname +'.pdf')\n",
    "    \n",
    "    # Dump information into accompanying file\n",
    "    with open(fname + '.dat', 'w+') as fp:\n",
    "        fp.write(\"f_beacon = {}MHz\\n\".format(f_beacon))\n",
    "        fp.write(\"samplerate = {}\\n\".format(samplerate))\n",
    "        fp.write(\"band = {}MHz\\n\".format(band))\n",
    "        fp.write(\"timelength = {}us\\n\".format(timelength))\n",
    "        \n",
    "        fp.write(\"-\"*8 + \"\\n\")\n",
    "        fp.write(\"\\Delta t = {}ns\\n\".format( (impulses_offsets[1][0] - impulses_offsets[0][0])/ns ))\n",
    "        fp.write(\"t_phi = {}ns\\n\".format( (tmp_beacon_offsets[1]-tmp_beacon_offsets[0])/ns ))\n",
    "        fp.write(\"\\Delta A = {}ns\\n\".format( (A[1] - A[0])/ns ))\n",
    "        fp.write(\"kT = {}ns = {}T\\n\".format( (B[1]-B[0])/ns, (B[1]-B[0])*f_beacon ))\n",
    "        \n",
    "        fp.write(\"-\"*8 + \"\\n\")\n",
    "        fp.write(\"A_1 = {}ns\\n\".format( (A[0])/ns ))\n",
    "        fp.write(\"A_2 = {}ns\\n\".format( (A[1])/ns ))\n",
    "        fp.write(\"B_1 = {}ns = {}T\\n\".format( (B[0])/ns, (B[0]*f_beacon) ))\n",
    "        fp.write(\"B_2 = {}ns = {}T\\n\".format( (B[1])/ns, (B[1]*f_beacon) ))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\\Delta t = 113.99999999999999ns\n",
      "\\Delta A = -5.428571428571415ns\n",
      "t_phi = 8.571428571428573ns\n",
      "B_1 = 57.14285714285714ns = 4.0T\n",
      "B_2 = 157.14285714285714ns = 11.0T\n",
      "kT = 100.0ns = 7.0T\n"
     ]
    }
   ],
   "source": [
    "t_phi = (tmp_beacon_offsets[1]-tmp_beacon_offsets[0])\n",
    "Delta_A = (A[1] - A[0])\n",
    "\n",
    "print(\"\\Delta t = {}ns\".format( (impulses_offsets[1][0] - impulses_offsets[0][0])/ns ))\n",
    "print(\"\\Delta A = {}ns\".format( Delta_A/ns ))\n",
    "print(\"t_phi = {}ns\".format( t_phi/ns ))\n",
    "print(\"B_1 = {}ns = {}T\".format( (B[0])/ns, (B[0]*f_beacon) ))\n",
    "print(\"B_2 = {}ns = {}T\".format( (B[1])/ns, (B[1]*f_beacon) ))\n",
    "print(\"kT = {}ns = {}T\".format( (B[1]-B[0])/ns, (B[1]-B[0])*f_beacon ))\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$\n",
    "\\Delta t = (A_2 + B_2) - (A_1 + B_1) + t_\\phi\\\\\n",
    "\\quad         = (A_2 - A_1) + (B_2 - B_1) + t_\\phi\\\\\n",
    "\\quad         = (A_2 - A_1) + (nT - mT) + t_\\phi\\\\\n",
    "\\quad         = \\Delta A + t_\\phi + (kT) \n",
    "$\n",
    "\n",
    ", where $\\Delta A < T$ and $k \\in \\mathbb{Z}$ and $t_\\phi$ is minimisable by synchronising the beacons.\n",
    "\n",
    "Then $\\Delta t$ can be determined by iteratively summing the signals, changing $k$, and finding the $k$ belonging to the maximum of the sums."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Best k: 7\n",
      "Maximum: 2.0\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 108408 characters]\n",
      "text/plain": [
       "<Figure size 864x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Make figure showing the sums depending on k\n",
    "ref_impulse = impulses[0]\n",
    "my_impulse = impulses[1]\n",
    "\n",
    "# remove 'already determined' offsets\n",
    "if True:\n",
    "    # $t_\\phi$ offset\n",
    "    my_impulse = time_roll(my_impulse, samplerate, -t_phi)\n",
    "\n",
    "if True:\n",
    "    # $\\Delta A$ offset\n",
    "    my_impulse = time_roll(my_impulse, samplerate, +Delta_A)\n",
    "\n",
    "best_k, (ks, maxima) = beacon_integer_period(samplerate, f_beacon, ref_impulse, my_impulse)\n",
    "print(\"Best k: {:0g}\".format(best_k))\n",
    "print(\"Maximum: {}\".format(maxima[np.where(ks == best_k)][0]))\n",
    "\n",
    "\n",
    "# Make figure\n",
    "fig, axes = plt.subplots(1, 1, sharex=True,figsize=(12,4))\n",
    "if not hasattr(axes, 'ndim'):\n",
    "    axes = [axes]\n",
    "\n",
    "axes[0].set_title(\"Coherent sum of impulses with $kT$ offsets.\\nBest offset: ${:.0f}*T$\".format(best_k))\n",
    "axes[-1].set_xlabel(\"Time [ns]\")\n",
    "\n",
    "if not True:\n",
    "    i=0\n",
    "    axes[i].set_ylabel(\"Reference\")\n",
    "    axes[i].plot(time/ns, ref_impulse, label=\"reference\")\n",
    "    axes[i].plot(time/ns, my_impulse, label='impulse')\n",
    "    axes[i].legend()\n",
    "\n",
    "axes[-1].set_ylabel(\"Coherence Sum\")\n",
    "\n",
    "best_maximum = np.max(maxima)\n",
    "axes[-1].axhline(best_maximum, alpha=0.7)\n",
    "\n",
    "for i, k in enumerate(ks, 0):\n",
    "        sample_offset = int(k*1/f_beacon*samplerate)\n",
    "        augmented_impulses = np.roll(my_impulse, sample_offset)\n",
    "        \n",
    "        summed_impulse = ref_impulse + augmented_impulses\n",
    "        if True or k%2 == 1:\n",
    "            axes[-1].plot(time/ns, summed_impulse, label='k={:.0f}'.format(k),\n",
    "                         alpha=0.1 + 0.9*1/(1+2*abs(best_maximum-maxima[i]))\n",
    "                        )\n",
    "    \n",
    "axes[-1].legend()\n",
    "fig.show()\n",
    "\n",
    "if True:\n",
    "    fname = 'figures/08_beacon_sync_coherent_sum'\n",
    "\n",
    "    # Dump figure\n",
    "    fig.savefig(fname +'.pdf')\n",
    "\n",
    "del ref_impulse\n",
    "del my_impulse"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Solve it\n",
    "\n",
    " 1. Find $t_\\phi$\n",
    " 2. Find $\\Delta A$\n",
    " 3. Find $kT$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#####  1.1 Beacon Phase Delay ($t_\\phi$)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Beacon delays [ns] \\pm k*14.285714285714285ns: [0.         8.57142857]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_1809896/665080263.py:1: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.\n",
      "  abs_beacon_time_delays_tmp = np.array([\n"
     ]
    }
   ],
   "source": [
    "abs_beacon_time_delays_tmp = np.array([\n",
    "    beacon_time_delay(samplerate, beacons[0], beacon)\n",
    "        for beacon in beacons\n",
    "])\n",
    "\n",
    "\n",
    "abs_beacon_time_delays = abs_beacon_time_delays_tmp[:,0]\n",
    "t_phi = np.array(abs_beacon_time_delays % (1/f_beacon), dtype=np.float64)\n",
    "beacon_time_delays_err = abs_beacon_time_delays_tmp[:,1]\n",
    "\n",
    "print(\"Beacon delays [ns] \\pm k*{}ns: {}\".format(1/f_beacon/ns, t_phi/ns))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 33960 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Make a figure showing the corrected beacons\n",
    "fig, ax = plt.subplots(1,1, sharex=True)\n",
    "ax.set_xlabel(\"Time [ns]\")\n",
    "ax.set_ylabel(\"Amplitude [au]\")\n",
    "ax.set_title(\n",
    "    \"Beacon delays [ns] $\\pm$ $k*{}$\\n$t_{{\\phi}}$ = {}\"\n",
    "    .format(1/f_beacon/ns, t_phi/ns)\n",
    ")\n",
    "\n",
    "for i, _ in enumerate(beacons):\n",
    "    l = ax.plot(\n",
    "                time/ns, beacons[i],\n",
    "                label=\"ch {}\".format(i), \n",
    "                ls ='--', \n",
    "                alpha=0.5\n",
    "    )\n",
    "    \n",
    "    # indicate start of uncorrected beacons\n",
    "    ax.axvline(\n",
    "        t_phi[i]/ns,\n",
    "        color=l[0].get_color(),\n",
    "        ls = '--'\n",
    "    )\n",
    "    \n",
    "    ax.plot(\n",
    "            (time-t_phi[i])/ns,\n",
    "            beacons[i],\n",
    "            label='ch {} corrected'.format(i),\n",
    "            color=l[0].get_color(),\n",
    "            ls=(5*i+2, (20, 20))\n",
    "    )\n",
    "    \n",
    "ax.legend(ncol=2)\n",
    "ax.margins(y=0.3)\n",
    "if True:\n",
    "    ax.set_xlim(time[0]/ns - 10, time[2*samplerate//f_beacon]/ns)\n",
    "\n",
    "fig.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 1.1.2 Beacon Synced traces"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 45132 characters]\n",
      "text/plain": [
       "<Figure size 864x288 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, axes = beacon_sync_figure(\n",
    "    time, impulses, beacons,\n",
    "    delta_t = t_phi,\n",
    "    beacon_offsets = phase2time(beacon_init_phase, f_beacon) + t_phi,\n",
    "    impulse_offsets = impulses_offsets,\n",
    "    f_beacon = f_beacon,\n",
    "    show_annotations = True\n",
    ")\n",
    "axes[0].set_title(\"Beacons synchronised\")\n",
    "fig.show()\n",
    "\n",
    "if True:\n",
    "    fname = 'figures/08_beacon_sync_synchronised_outline'\n",
    "\n",
    "    # Dump figure\n",
    "    fig.savefig(fname +'.pdf')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 1.2 Impulse delays ($\\Delta A, kT$)\n",
    "\n",
    "###### 1.2.1 $\\Delta A$\n",
    "Find the delay within a single beacon period"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0. 7.]\n"
     ]
    }
   ],
   "source": [
    "impulse_max_time = np.argmax(impulses, axis=1) /samplerate\n",
    "impulse_time_in_periods = np.array((impulse_max_time - t_phi)*f_beacon)\n",
    "someB, A = np.divmod(impulse_time_in_periods, 1)\n",
    "\n",
    "# subtract the reference beacon's value to obtain time differences\n",
    "A -= A[0]\n",
    "someB -= someB[0]\n",
    "\n",
    "Delta_A = A[1:] - A[0]\n",
    "print(someB)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###### 1.2.2 $kT$\n",
    "Find integer number of periods"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Best k: 8\n",
      "Maximum: 2.0\n"
     ]
    }
   ],
   "source": [
    "ref_impulse = impulses[0]\n",
    "my_impulse = impulses[1]\n",
    "\n",
    "# remove 'already determined' offsets\n",
    "if True:\n",
    "    # $t_\\phi$ offset\n",
    "    my_impulse = time_roll(my_impulse, samplerate, -t_phi)\n",
    "\n",
    "if True:\n",
    "    # $\\Delta A$ offset\n",
    "    my_impulse = time_roll(my_impulse, samplerate, +Delta_A)\n",
    "\n",
    "best_k, (ks, maxima) = beacon_integer_period(samplerate, f_beacon, ref_impulse, my_impulse)\n",
    "print(\"Best k: {:0g}\".format(best_k))\n",
    "print(\"Maximum: {}\".format(maxima[np.where(ks == best_k)][0]))\n",
    "B = np.array([ 0, best_k])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 1.3 Total Time delay"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Δ𝐴 = [0.         5.42857143]\n",
      "B = kT = [0 8]T\n",
      "𝑡𝜙 = [0.         8.57142857]\n",
      "Δt = 0.12828571428571425\n",
      "Preset Δt = 0.11399999999999999\n"
     ]
    }
   ],
   "source": [
    "print(\"Δ𝐴 = {}\".format(A /f_beacon/ns))\n",
    "print(\"B = kT = {}T\".format(B))\n",
    "print(\"𝑡𝜙 = {}\".format(t_phi/ns))\n",
    "\n",
    "\n",
    "delta_t = A/f_beacon + B/f_beacon + t_phi\n",
    "\n",
    "print(\"Δt = {}\".format(delta_t[1]))\n",
    "\n",
    "print(\"Preset Δt = {}\".format(impulses_offsets[1,0]-impulses_offsets[0,0]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 1.3.2 Beacon Synced and Period Alignment"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 39808 characters]\n",
      "text/plain": [
       "<Figure size 864x288 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, axes = beacon_sync_figure(\n",
    "    time, impulses, beacons,\n",
    "    delta_t = (B + [0,-0])/f_beacon + t_phi,\n",
    "    beacon_offsets = phase2time(beacon_init_phase, f_beacon) + t_phi,\n",
    "    impulse_offsets = impulses_offsets,\n",
    "    f_beacon = f_beacon,\n",
    "    show_annotations = True\n",
    ")\n",
    "axes[0].set_title(\"Beacons synchronised, Period alignment\")\n",
    "fig.show()\n",
    "if True:\n",
    "    fname = 'figures/08_beacon_sync_synchronised_period_alignment'\n",
    "\n",
    "    # Dump figure\n",
    "    fig.savefig(fname +'.pdf')"
   ]
  }
 ],
 "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.9.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
