m-thesis-introduction/simulations/08_beacon_sync.ipynb

610 lines
93 KiB
Text
Raw Normal View History

{
"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",
"import scipy.fft as ft"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Monkey patch correlation_lags\n",
"if not hasattr(signal, 'correlation_lags'):\n",
" def correlation_lags(in1_len, in2_len, mode='full'):\n",
" r\"\"\"\n",
" Calculates the lag / displacement indices array for 1D cross-correlation.\n",
" Parameters\n",
" ----------\n",
" in1_size : int\n",
" First input size.\n",
" in2_size : int\n",
" Second input size.\n",
" mode : str {'full', 'valid', 'same'}, optional\n",
" A string indicating the size of the output.\n",
" See the documentation `correlate` for more information.\n",
" See Also\n",
" --------\n",
" correlate : Compute the N-dimensional cross-correlation.\n",
" Returns\n",
" -------\n",
" lags : array\n",
" Returns an array containing cross-correlation lag/displacement indices.\n",
" Indices can be indexed with the np.argmax of the correlation to return\n",
" the lag/displacement.\n",
" Notes\n",
" -----\n",
" Cross-correlation for continuous functions :math:`f` and :math:`g` is\n",
" defined as:\n",
" .. math::\n",
" \\left ( f\\star g \\right )\\left ( \\tau \\right )\n",
" \\triangleq \\int_{t_0}^{t_0 +T}\n",
" \\overline{f\\left ( t \\right )}g\\left ( t+\\tau \\right )dt\n",
" Where :math:`\\tau` is defined as the displacement, also known as the lag.\n",
" Cross correlation for discrete functions :math:`f` and :math:`g` is\n",
" defined as:\n",
" .. math::\n",
" \\left ( f\\star g \\right )\\left [ n \\right ]\n",
" \\triangleq \\sum_{-\\infty}^{\\infty}\n",
" \\overline{f\\left [ m \\right ]}g\\left [ m+n \\right ]\n",
" Where :math:`n` is the lag.\n",
" Examples\n",
" --------\n",
" Cross-correlation of a signal with its time-delayed self.\n",
" >>> from scipy import signal\n",
" >>> from numpy.random import default_rng\n",
" >>> rng = default_rng()\n",
" >>> x = rng.standard_normal(1000)\n",
" >>> y = np.concatenate([rng.standard_normal(100), x])\n",
" >>> correlation = signal.correlate(x, y, mode=\"full\")\n",
" >>> lags = signal.correlation_lags(x.size, y.size, mode=\"full\")\n",
" >>> lag = lags[np.argmax(correlation)]\n",
" \"\"\"\n",
"\n",
" # calculate lag ranges in different modes of operation\n",
" if mode == \"full\":\n",
" # the output is the full discrete linear convolution\n",
" # of the inputs. (Default)\n",
" lags = np.arange(-in2_len + 1, in1_len)\n",
" elif mode == \"same\":\n",
" # the output is the same size as `in1`, centered\n",
" # with respect to the 'full' output.\n",
" # calculate the full output\n",
" lags = np.arange(-in2_len + 1, in1_len)\n",
" # determine the midpoint in the full output\n",
" mid = lags.size // 2\n",
" # determine lag_bound to be used with respect\n",
" # to the midpoint\n",
" lag_bound = in1_len // 2\n",
" # calculate lag ranges for even and odd scenarios\n",
" if in1_len % 2 == 0:\n",
" lags = lags[(mid-lag_bound):(mid+lag_bound)]\n",
" else:\n",
" lags = lags[(mid-lag_bound):(mid+lag_bound)+1]\n",
" elif mode == \"valid\":\n",
" # the output consists only of those elements that do not\n",
" # rely on the zero-padding. In 'valid' mode, either `in1` or `in2`\n",
" # must be at least as large as the other in every dimension.\n",
"\n",
" # the lag_bound will be either negative or positive\n",
" # this let's us infer how to present the lag range\n",
" lag_bound = in1_len - in2_len\n",
" if lag_bound >= 0:\n",
" lags = np.arange(lag_bound + 1)\n",
" else:\n",
" lags = np.arange(lag_bound, 1)\n",
" return lags\n",
"\n",
" signal.correlation_lags = correlation_lags"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"### signal generation\n",
"def fft_bandpass(signal, band, samplerate):\n",
" \"\"\"\n",
" Simple bandpassing function employing a FFT.\n",
"\n",
" Parameters\n",
" ----------\n",
" signal : arraylike\n",
" band : tuple(low, high)\n",
" Frequencies for bandpassing\n",
" samplerate : float\n",
" \"\"\"\n",
" signal = np.asarray(signal)\n",
"\n",
" fft = ft.rfft(signal)\n",
" freqs = ft.rfftfreq(signal.size, 1/samplerate)\n",
" fft[(freqs < band[0]) | (freqs > band[1])] = 0\n",
" \n",
" return ft.irfft(fft, signal.size), (fft, freqs)\n",
"\n",
"def deltapeak(timelength=1e3, samplerate=1, offset=None, peaklength=1):\n",
" N_samples = int(timelength * samplerate)\n",
" if offset is None:\n",
" offset = (np.random.random(1)*N_samples).astype(int) % N_samples\n",
" elif isinstance(offset, (tuple, list)):\n",
" offset_min = offset[0]\n",
" offset_max = offset[-1]\n",
" \n",
" offset = (np.random.random(1)*(offset_max - offset_min)+offset_min).astype(int) % N_samples\n",
" \n",
" position = (offset + np.arange(0, peaklength)).astype(int) % N_samples\n",
" \n",
" signal = np.zeros(N_samples)\n",
" signal[position] = 1\n",
" \n",
" return signal, position\n",
"\n",
"def sin_delay(f, t, t_delay=0, phase=0):\n",
" return np.cos(2*np.pi*f * (t - t_delay) + phase)"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Beacon initial [ns]: 897.9591836734695\n",
"Beacon initial [idx]: 4489.795918367347\n",
"Beacon difference [ns]: 35.71428571428571\n",
"Impulse offsets [ns]: [ 65.6 188.4]\n",
"Time difference peaks [ns]: 122.8\n"
]
}
],
"source": [
"us = 1e3 # ns\n",
"ns = 1/us # us\n",
"\n",
"\n",
"band = (30, 80) # MHz\n",
"samplerate = 5000 # MHz\n",
"timelength = 0.3 # 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_time_offset = 2.5/f_beacon # us\n",
"beacon_amplitude = 0.1\n",
"beacon_init_phase = 2*np.pi* 4.4/ns/f_beacon\n",
"\n",
"beacons = np.array([\n",
" beacon_amplitude * sin_delay(f_beacon, time, phase=beacon_init_phase, t_delay=0),\n",
" beacon_amplitude * sin_delay(f_beacon, time, phase=beacon_init_phase, t_delay=beacon_time_offset)\n",
"])\n",
"\n",
"# generate impulses\n",
"impulses = []\n",
"impulses_offsets = []\n",
"impulses_def_offsets = [(0.05*samplerate,0.2*samplerate)] # random offsets in interval\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",
" ## 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.asarray(impulses)\n",
"impulses_offsets = np.asarray(impulses_offsets)\n",
"print(\"Beacon initial [ns]:\", beacon_init_phase/(2*np.pi*f_beacon) /ns)\n",
"print(\"Beacon initial [idx]:\", beacon_init_phase/(2*np.pi*f_beacon)*samplerate)\n",
"print(\"Beacon difference [ns]:\", beacon_time_offset/ns)\n",
"print(\"Impulse offsets [ns]:\", impulses_offsets[:,0]/ns)\n",
"print(\"Time difference peaks [ns]: {}\".format( (impulses_offsets[1,0]-impulses_offsets[0,0])/ns ))"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
"full_signals = impulses + beacons"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"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",
"fig, axes = plt.subplots(3,1, sharex=True, figsize=(12,4))\n",
"axes[-1].set_xlabel(\"Time [ns]\")\n",
"for i in range(0, 2):\n",
" axes[i].set_ylabel(\"Antenna {:d}\".format(i))\n",
" axes[i].plot(time/ns, impulses[i])\n",
" axes[i].plot(time/ns, beacons[i], marker='.')\n",
" axes[i].plot(time/ns, full_signals[i])\n",
"\n",
"# indicate timing of pulses\n",
"for i, impulse_offset in enumerate(impulses_offsets):\n",
" kwargs = dict(color=['r','g'][i])\n",
" [ax.axvline(impulse_offset/ns, **kwargs) for ax in (axes[i], axes[-1])]\n",
"\n",
"# indicate timing of the beacons\n",
"for i in range(0,2):\n",
" kwargs = dict(color=['r','g'][i], ls=(0, (3,1)))\n",
" tick_kwargs = dict(color='k', alpha=0.2)\n",
"\n",
" tmp_beacon_offset = (beacon_init_phase / (2*np.pi*f_beacon) + i*beacon_time_offset) % (1/f_beacon)\n",
" # indicate every period of the beacon\n",
" beacon_ticks = [(n)*1/f_beacon + tmp_beacon_offset 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_offset/ns, **kwargs) for ax in (axes[i], axes[-1])]\n",
" \n",
"if not True:\n",
" axes[-1].set_xlim(0, 10)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. Solve it"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
"### correlation\n",
"def correlation_and_lag(sig1, sig2, mode=\"full\", normalise=False):\n",
" corr = signal.correlate(sig1, sig2, mode=mode)\n",
" if normalise:\n",
" corr /= np.max(corr)\n",
"\n",
" lags = signal.correlation_lags(sig1.size, sig2.size, mode=mode)\n",
" \n",
" return corr, lags\n",
"\n",
"def find_best_lag(sig1, sig2, fix_one_short=True, fix_positive=True, subtract_means=True, **corr_kwargs):\n",
" if subtract_means:\n",
" sig1 -= np.mean(sig1)\n",
" sig2 -= np.mean(sig2)\n",
" \n",
" corr, lags = correlation_and_lag(sig1, sig2, **corr_kwargs)\n",
" lag_id = corr.argmax()\n",
"\n",
" lag = lags[lag_id]\n",
" \n",
" if fix_one_short:\n",
" # for some reason it is always one short\n",
" if lag > 0:\n",
" lag += 1\n",
" elif lag < 0:\n",
" lag -= 1\n",
"\n",
" # turn negative lag into positive\n",
" if fix_positive and lag < 0:\n",
" lag += len(sig2)\n",
" \n",
" return lag, (corr, lags)\n",
"\n",
"def find_beacon_phase_delay(samplerate, f_beacon, reference_beacon, delayed_beacon, **lag_kwargs):\n",
" \"\"\"\n",
" Return phase delay of `beacon` with respect to `reference_beacon`.\n",
" Note that the returned value can be off by a multiple of $2\\pi$.\n",
" \n",
" Parameters\n",
" ==========\n",
" samplerate : float\n",
" Samplerate of both reference_beacon and delayed_beacon\n",
" f_beacon : float\n",
" Frequency of the beacons\n",
" reference_beacon : ndarray\n",
" The beacon to use as a reference\n",
" beacon : ndarray\n",
" The beacon to find the delay for\n",
" \"\"\"\n",
" \n",
" calc_lag, _ = find_best_lag(reference_beacon, delayed_beacon, **lag_kwargs)\n",
" \n",
" time = calc_lag / samplerate\n",
" \n",
" return 2*np.pi* f_beacon * time"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# single out one period of the beacon\n",
"beacon_samplerate = samplerate # MHz\n",
"beacon_time = np.arange(0, 1/f_beacon, 1/beacon_samplerate)\n",
"ref_beacon = sin_delay(f_beacon, beacon_time, phase=0, t_delay=0)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# show beacon period\n",
"fig, ax = plt.subplots()\n",
"ax.set_title(\"A single beacon period\")\n",
"ax.set_xlabel(\"Time [ns]\")\n",
"ax.set_ylabel(\"Amplitude\")\n",
"ax.plot(ref_beacon)\n",
"fig.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### 1.1 Beacon Phase Delays"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 0.0 0.0\n",
"37 0.0074 3.2546899891190257\n",
"Beacon delays [ns] \\pm k*14.285714285714285ns: [0. 7.4]\n"
]
}
],
"source": [
"beacon_phase_delays = np.array([\n",
" find_beacon_phase_delay(beacon_samplerate, f_beacon, beacons[0], beacon)\n",
" for beacon in beacons\n",
"])\n",
"\n",
"beacon_time_delays = (beacon_phase_delays) / (2*np.pi * f_beacon)\n",
"\n",
"print(\"Beacon delays [ns] \\pm k*{}ns: {}\".format(1/f_beacon/ns, beacon_time_delays/ns))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"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(\"Beacon delays [ns] $\\pm$ $k*{}$\\n{} == {}\".format(1/f_beacon/ns, beacon_time_delays/ns, None))\n",
"\n",
"for i, _ in enumerate(beacons):\n",
" l = ax.plot(time/ns, beacons[i], label=\"ch {}\".format(i), ls ='--', alpha=0.5)\n",
" \n",
" print(i, beacon_phase_delays[i], beacon_time_delays[i])\n",
"\n",
" if not True:\n",
" corrected_beacon = sin_delay(f_beacon, time, phase=+beacon_phase_delays[i], t_delay=0)\n",
" else:\n",
" corrected_beacon = sin_delay(f_beacon, time, t_delay=beacon_time_delays[i], phase=0)\n",
" \n",
" ax.plot(time/ns, 2*beacon_amplitude*corrected_beacon, label='ch {} corrected'.format(i), color=l[0].get_color())\n",
" \n",
" # indicate start of uncorrected beacons\n",
" ax.axvline(beacon_time_delays[i]/ns, color=l[0].get_color())\n",
"\n",
"print(\"sum:\", np.sum(beacon_time_delays)/ns)\n",
"print(\"diff:\", np.diff(beacon_time_delays)/ns)\n",
"\n",
"ax.legend(ncol=2)\n",
"ax.margins(y=0.3)\n",
"if True:\n",
" ax.set_xlim(time[0]/ns - 1, time[2*samplerate//f_beacon]/ns)\n",
"\n",
"fig.show()\n",
"\n",
"\n",
"# ax.plot((double_signal_time) * ns, signal_2(double_signal_time + calc_shift), 'r--', label='Recovered')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### 1.2 Impulse vs beacon delays\n",
"\n",
"Find the delay within a single beacon period"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"#def find_beacon_impulse_delay(samplerate, f_beacon, impulse, init_phase=0):\n",
"def find_beacon_impulse_phase_delay(samplerate, f_beacon, reference_beacon, impulse, **lag_kwargs):\n",
" \"\"\"\n",
" Return phase delay of `beacon` with respect to `reference_beacon`.\n",
" Note that the returned value can be off by a multiple of $2\\pi$.\n",
" \n",
" Parameters\n",
" ==========\n",
" samplerate : float\n",
" Samplerate of both reference_beacon and delayed_beacon\n",
" f_beacon : float\n",
" Frequency of the beacons\n",
" reference_beacon : ndarray\n",
" The beacon to use as a reference\n",
" beacon : ndarray\n",
" The beacon to find the delay for\n",
" \"\"\"\n",
" \n",
" calc_lag, _ = find_best_lag(reference_beacon, impulse, **lag_kwargs)\n",
" \n",
" return 2*np.pi* f_beacon * calc_lag / samplerate"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Beacon Impuls delays: $[ 867.07957239 1416.22996824]$ns\n"
]
}
],
"source": [
"impulse_beacon_phase_delays = np.empty( len(impulses) )\n",
"\n",
"for i, _ in enumerate(impulses):\n",
" impulse_beacon_phase_delays[i] = find_beacon_impulse_phase_delay(\n",
" beacon_samplerate, f_beacon, \n",
" ref_beacon, impulses[i]\n",
" )\n",
"\n",
"print(\"Beacon Impuls delays: ${}$ns\".format(impulse_beacon_phase_delays/f_beacon/ns))"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 432x288 with 2 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# Make a figure showing the corrected beacons\n",
"fig, axes = plt.subplots(len(impulses),1, sharex=True)\n",
"axes[-1].set_xlabel(\"Time [us]\")\n",
"ax.set_title(\"Beacon Impuls delays: ${}$ns\".format(impulse_beacon_phase_delays/f_beacon/ns))\n",
"\n",
"for i, beacon in enumerate(beacons):\n",
" ax.set_ylabel(\"Amplitude [au]\")\n",
" ax.plot(time, beacon, label=\"ch {}\".format(i))\n",
"\n",
"#ax.plot(beacon_time, corrected_beacon, label='phase corrected (overlaps ch 0)')\n",
"\n",
"ax.legend()\n",
"\n",
"fig.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}