mirror of
https://gitlab.science.ru.nl/mthesis-edeboone/m-thesis-introduction.git
synced 2024-12-22 03:23:34 +01:00
288 lines
8.9 KiB
Text
288 lines
8.9 KiB
Text
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Emitter/Receiver Simulation with Signals"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"%matplotlib inline\n",
|
|
"\n",
|
|
"import numpy as np\n",
|
|
"import scipy.fft as ft\n",
|
|
"import matplotlib.pyplot as plt\n",
|
|
"import matplotlib.gridspec as gridspec\n",
|
|
"import matplotlib.ticker as tck\n",
|
|
"\n",
|
|
"rng = np.random.default_rng()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Signal"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# copied from 02_discrete_signal_translation.ipynb #ae7aba6\n",
|
|
"class TravelSignal:\n",
|
|
" \"\"\"\n",
|
|
" Model an arbitrary digitised signal that can be translated to another position and time.\n",
|
|
" \"\"\"\n",
|
|
"\n",
|
|
" def __init__(self, signal, sample_rate, t_0 = 0, x_0 = 0, periodic=True, interp1d_kw = None):\n",
|
|
" \"\"\"\n",
|
|
" Initialise by saving the raw signal\n",
|
|
" \n",
|
|
" Parameters\n",
|
|
" ----------\n",
|
|
" signal : arraylike\n",
|
|
" The raw signal to wrap.\n",
|
|
" sample_rate : float\n",
|
|
" Sample rate of the raw signal.\n",
|
|
" t_0 : float, optional\n",
|
|
" Time that this signal is sent out.\n",
|
|
" x_0 : float, optional\n",
|
|
" Location that this signal is sent out from.\n",
|
|
" periodic : bool, optional\n",
|
|
" Translated signal is 0 if it is not periodic\n",
|
|
" and the time/distance is outside the samples.\n",
|
|
" interp1d_kw : bool or dict, optional\n",
|
|
" Use scipy.interpolate's interp1d_kw for interpolation.\n",
|
|
" Set to True, or a dictionary to enable.\n",
|
|
" Dictionary will be entered in as **kwargs.\n",
|
|
" \"\"\"\n",
|
|
"\n",
|
|
" self.raw = signal\n",
|
|
" self.periodic = periodic\n",
|
|
"\n",
|
|
" self.sample_rate = sample_rate # Hz\n",
|
|
" self.sample_length = len(self.raw)\n",
|
|
" self.time_length = self.sample_length*sample_rate # s\n",
|
|
" \n",
|
|
" self.x_0 = x_0\n",
|
|
" self.t_0 = t_0\n",
|
|
"\n",
|
|
" # choose interpolation method\n",
|
|
" if not interp1d_kw:\n",
|
|
" self.interp_f = None\n",
|
|
"\n",
|
|
" else:\n",
|
|
" # offload interpolation to scipy.interpolate\n",
|
|
" import scipy.interpolate as interp\n",
|
|
"\n",
|
|
" interp1d_kw_defaults = {\n",
|
|
" \"copy\": False,\n",
|
|
" \"kind\": 'linear',\n",
|
|
" \"assume_sorted\": True,\n",
|
|
" \"bounds_error\": True\n",
|
|
" }\n",
|
|
"\n",
|
|
" if self.periodic:\n",
|
|
" interp1d_kw_defaults['bounds_error'] = False\n",
|
|
" interp1d_kw_defaults['fill_value'] = (self.raw[-1], self.raw[0])\n",
|
|
" \n",
|
|
" # merge kwargs\n",
|
|
" if interp1d_kw is not True:\n",
|
|
" interp1d_kw = { **interp1d_kw_defaults, **interp1d_kw }\n",
|
|
"\n",
|
|
" self.interp_f = interp.interp1d(\n",
|
|
" np.arange(0, self.sample_length),\n",
|
|
" self.raw,\n",
|
|
" **interp1d_kw\n",
|
|
" )\n",
|
|
" \n",
|
|
" def __len__(self):\n",
|
|
" return self.sample_length\n",
|
|
" \n",
|
|
" def __call__(self, t_f = None, x_f = None, **kwargs):\n",
|
|
" \"\"\"\n",
|
|
" Allow this class to be used as a function.\n",
|
|
" \"\"\"\n",
|
|
" return self._translate(t_f, x_f, **kwargs)[0]\n",
|
|
" \n",
|
|
" def _translate(self, t_f = None, x_f = None, t_0 = None, x_0 = None, velocity = None):\n",
|
|
" \"\"\"\n",
|
|
" Translate the signal from (t_0, x_0) to (t_f, x_f) with optional velocity.\n",
|
|
" \n",
|
|
" Returns the signal at (t_f, x_f)\n",
|
|
" \"\"\"\n",
|
|
" \n",
|
|
" if t_0 is None:\n",
|
|
" t_0 = self.t_0\n",
|
|
" \n",
|
|
" if velocity is None:\n",
|
|
" velocity = 1\n",
|
|
"\n",
|
|
"\n",
|
|
" ## spatial offset\n",
|
|
" if x_f is None:\n",
|
|
" spatial_time_offset = 0\n",
|
|
" else:\n",
|
|
" x_f = np.asarray(x_f)\n",
|
|
" if x_0 is None:\n",
|
|
" x_0 = self.x_0\n",
|
|
"\n",
|
|
" spatial_time_offset = np.sum(np.sqrt( (x_f - x_0)**2 )/velocity)\n",
|
|
"\n",
|
|
" ## temporal offset\n",
|
|
" if t_f is None:\n",
|
|
" temporal_time_offset = 0\n",
|
|
" else:\n",
|
|
" t_f = np.asarray(t_f)\n",
|
|
" \n",
|
|
" if t_0 is None:\n",
|
|
" t_0 = self.t_0\n",
|
|
" \n",
|
|
" temporal_time_offset = t_f - t_0\n",
|
|
"\n",
|
|
" # total offset\n",
|
|
" total_time_offset = spatial_time_offset + temporal_time_offset\n",
|
|
" n_offset = (total_time_offset * sample_rate )\n",
|
|
"\n",
|
|
" # periodic signal\n",
|
|
" if self.periodic:\n",
|
|
" n_offset = n_offset % self.sample_length\n",
|
|
"\n",
|
|
" # non-periodic and outside the bounds\n",
|
|
" else:\n",
|
|
" mask_idx = np.nonzero( (0 > n_offset) | (n_offset >= self.sample_length) )\n",
|
|
" n_offset[mask_idx] = 0\n",
|
|
"\n",
|
|
" # offload to scipy interpolation\n",
|
|
" if self.interp_f:\n",
|
|
" amplitude = self.interp_f(n_offset)\n",
|
|
" \n",
|
|
" # self written linear interpolation\n",
|
|
" else:\n",
|
|
" n_offset_eps, n_offset_int = np.modf(n_offset)\n",
|
|
" n_offset_int = n_offset.astype(int)\n",
|
|
"\n",
|
|
" if True:\n",
|
|
" amplitude = (1-n_offset_eps) * self.raw[n_offset_int] \\\n",
|
|
" + n_offset_eps * self.raw[(n_offset_int + 1) % self.sample_length]\n",
|
|
"\n",
|
|
" # use nearest value instead of interpolation\n",
|
|
" else:\n",
|
|
" amplitude = self.raw[n_offset_int]\n",
|
|
"\n",
|
|
" if not self.periodic:\n",
|
|
" amplitude[mask_idx] = 0\n",
|
|
" \n",
|
|
" return amplitude, total_time_offset"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## New code"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"### Location\n",
|
|
"class Location:\n",
|
|
" \"\"\"\n",
|
|
" A location is a point designated by a spatial coordinate x.\n",
|
|
" \"\"\"\n",
|
|
"\n",
|
|
" def __init__(self, x):\n",
|
|
" self.x = np.asarray(x) \n",
|
|
"\n",
|
|
" def __repr__(self):\n",
|
|
" return \"Location({})\".format(repr(self.x))\n",
|
|
"\n",
|
|
" def __getitem__(self, key):\n",
|
|
" return self.x[key]\n",
|
|
"\n",
|
|
" def __setitem__(self, key, val):\n",
|
|
" self.x[key] = val\n",
|
|
"\n",
|
|
" def __add__(self, other):\n",
|
|
" if isinstance(other, self.__class__):\n",
|
|
" other = other.x\n",
|
|
"\n",
|
|
" return self.__class__(self.x + other)\n",
|
|
"\n",
|
|
" def __sub__(self, other):\n",
|
|
" if isinstance(other, self.__class__):\n",
|
|
" other = other.x\n",
|
|
"\n",
|
|
" return self.__class__(self.x - other)\n",
|
|
" \n",
|
|
" def __eq__(self, other):\n",
|
|
" if isinstance(other, self.__class__):\n",
|
|
" other = other.x\n",
|
|
"\n",
|
|
" return np.all(self.x == other)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"### Receiver\n",
|
|
"class Receiver(Location):\n",
|
|
" \"\"\"\n",
|
|
" Receive a signal at position x and time t\n",
|
|
" \"\"\"\n",
|
|
" pass"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
" ### Emitter\n",
|
|
"class Emitter(TravelSignal):\n",
|
|
" \"\"\"\n",
|
|
" Emit a signal from position x_0 (and time t_0)\n",
|
|
" \"\"\"\n",
|
|
" pass"
|
|
]
|
|
}
|
|
],
|
|
"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
|
|
}
|