Skip to content

Instantly share code, notes, and snippets.

@kumanna
Created January 30, 2026 10:29
Show Gist options
  • Select an option

  • Save kumanna/af9421db03e6e83855fdca0383788931 to your computer and use it in GitHub Desktop.

Select an option

Save kumanna/af9421db03e6e83855fdca0383788931 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "be9d289c",
"metadata": {},
"source": [
"# Quick introduction to OTFS\n",
"Follows the paper [\"Derivation of OTFS Modulation From First Principles\" by Prof. Saif Mohammed](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=9392379)."
]
},
{
"cell_type": "markdown",
"id": "85c32381",
"metadata": {},
"source": [
"We base our consideration on equation (19) in the paper, which discusses the construction of the signals $\\alpha_{(k,l)}(t)$."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "d93f5f8f",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"\n",
"T = 1\n",
"delta_f = 1 / T\n",
"M = 8\n",
"N = 8\n",
"OVERSAMPLING = 128\n",
"t = np.arange(-10 * N * M * T, 10 * N * T * M, 1 / OVERSAMPLING)\n",
"\n",
"def alpha_kl(k, l, t, M, N, T):\n",
" s = np.zeros_like(t, dtype='complex')\n",
" delta_f = 1 / T\n",
" for n in range(N):\n",
" EXPPARAM = (t - l * T / M - n * T)\n",
" s_ = np.exp(1j * 2 * np.pi * n * k / N) * \\\n",
" np.exp(1j * np.pi * delta_f * M * EXPPARAM) * \\\n",
" np.sinc(delta_f * M * EXPPARAM) * M * delta_f\n",
" s = s + s_\n",
" return np.sqrt(T / M / N) * s"
]
},
{
"cell_type": "markdown",
"id": "f97f5fc6",
"metadata": {},
"source": [
"We can initialize all of the $\\alpha_{(k,l)}$ signals into an array for convenience."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "1d32efb7",
"metadata": {},
"outputs": [],
"source": [
"sample_vector = alpha_kl(0, 0, t, M, N, T)\n",
"vector_len = len(sample_vector)\n",
"\n",
"# Initialize a 3D array of zeros\n",
"# Shape: (M rows, N columns, vector_len depth)\n",
"alpha_array = np.zeros((M, N, vector_len), dtype='complex')\n",
"\n",
"# Populate the array using nested loops\n",
"for k in range(M):\n",
" for l in range(N):\n",
" alpha_array[k, l, :] = alpha_kl(k, l, t, M, N, T)"
]
},
{
"cell_type": "markdown",
"id": "60d9fe9d",
"metadata": {},
"source": [
"Let us now suppose that w intend sending four symbols using some of these signals. One way to do it is this:"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "3f8771dc",
"metadata": {},
"outputs": [],
"source": [
"# Send symbols on these\n",
"symbols = np.array([1, 1j, 1+1j, -1j])\n",
"waveform = np.zeros_like(alpha_array[0][0], dtype='complex')\n",
"\n",
"waveform += symbols[0] * alpha_array[0][0]\n",
"waveform += symbols[1] * alpha_array[0][1]\n",
"waveform += symbols[2] * alpha_array[1][0]\n",
"waveform += symbols[3] * alpha_array[1][1]"
]
},
{
"cell_type": "markdown",
"id": "200511d1",
"metadata": {},
"source": [
"Using the orthogonality of the $\\alpha_{k,l}$ signals, we can recover our data:"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "e8b1a953",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[ 1.+0.j 0.+1.j 1.+1.j -0.-1.j]\n",
"[ 9.99841680e-01-1.58318873e-04j -1.58320298e-04+9.99841681e-01j\n",
" 1.00000000e+00+9.99999999e-01j 1.94412130e-09-1.00000000e+00j]\n"
]
}
],
"source": [
"# Recover the symbols\n",
"symbols_recovered = np.zeros_like(symbols, dtype='complex')\n",
"symbols_recovered[0] = np.trapezoid(waveform * np.conj(alpha_array[0][0]), t)\n",
"symbols_recovered[1] = np.trapezoid(waveform * np.conj(alpha_array[0][1]), t)\n",
"symbols_recovered[2] = np.trapezoid(waveform * np.conj(alpha_array[1][0]), t)\n",
"symbols_recovered[3] = np.trapezoid(waveform * np.conj(alpha_array[1][1]), t)\n",
"print(symbols)\n",
"print(symbols_recovered)"
]
},
{
"cell_type": "markdown",
"id": "be3b96f9",
"metadata": {},
"source": [
"Let's take a single symbol separately and add a delay and doppler offset to see what happens."
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "163271ec",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(0.9998416173283038-1.4934538260588343e-18j)\n",
"(0.9399505342307242+1.2242106723840473e-10j)\n"
]
}
],
"source": [
"waveform = symbols[0] * alpha_array[0][0]\n",
"waveform_delay = np.roll(waveform, OVERSAMPLING // M * 2) # Delay by 2 * T / M units of time\n",
"print(np.trapezoid(waveform_delay * np.conj(alpha_array[0][2]), t))\n",
"# In addition, add an extra 2 / N / T Doppler modulation\n",
"waveform_delay_doppler = np.roll(waveform * np.exp(1j * 2 * np.pi * 2 / T / N * t), OVERSAMPLING // M * 2)\n",
"print(np.trapezoid(waveform_delay_doppler * np.conj(alpha_array[2][2]), t))"
]
},
{
"cell_type": "markdown",
"id": "ddb265aa",
"metadata": {},
"source": [
"More realistic channels consist of multiple reflectors. Let's take them as triplets."
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "a42928a0",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"triplets = [\n",
" # (gain, normalized time delay, normalized doppler shift)\n",
" # normalized means between 0 and M - 1 and 0 and N - 1\n",
" (1.0+1j, 4, 4),\n",
" (0.5-0.5j, 3, 1),\n",
" ]\n",
"\n",
"actual_signal = np.zeros_like(t) * 0.0j\n",
"for i in triplets:\n",
" gain, time_delay, doppler = i\n",
" actual_signal += np.roll(waveform * np.exp(1j * 2 * np.pi * doppler / T / N * t), OVERSAMPLING // M * time_delay)\n",
"\n",
"dd_domain_rx = np.zeros((M, N), dtype='complex')\n",
"for k in range(M):\n",
" for l in range(N):\n",
" dd_domain_rx[k][l] = np.trapezoid(actual_signal * np.conj(alpha_array[k][l]), t)\n",
"plt.imshow(np.abs(dd_domain_rx))\n",
"plt.show()"
]
}
],
"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.13.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment