m-thesis-introduction/simulations/03_emitter_receiver_simulation.ipynb

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
}