From 7c0fa48e6248cb8893460971509660c4511ceae9 Mon Sep 17 00:00:00 2001 From: SARA Date: Tue, 30 Nov 2021 20:32:54 +0100 Subject: Theory mit fractional delay erweitert --- doc/thesis/chapters/implementation.tex | 5 +- doc/thesis/chapters/theory.tex | 57 +++++++++++++- .../figures/screenshots/Fractional_delay_6.png | Bin 0 -> 15177 bytes .../figures/screenshots/Fractional_delay_637.png | Bin 0 -> 15835 bytes notebooks/FIR_mehrere_V2.ipynb | 87 ++++++++++----------- notebooks/Test_file.py | 17 ++-- 6 files changed, 110 insertions(+), 56 deletions(-) create mode 100644 doc/thesis/figures/screenshots/Fractional_delay_6.png create mode 100644 doc/thesis/figures/screenshots/Fractional_delay_637.png diff --git a/doc/thesis/chapters/implementation.tex b/doc/thesis/chapters/implementation.tex index b2e5d72..e366881 100644 --- a/doc/thesis/chapters/implementation.tex +++ b/doc/thesis/chapters/implementation.tex @@ -78,11 +78,10 @@ Here its possible to add some AWGN noise in the channel line. Different paramete \subsection{Fading} %TO DO: übersetzen -Für das veranschaulichen des Fading effekts wurde ein eigener Block kreaiert und in den Channel implementiert. Dieser Block basiert auf einem FIR Filter. Es kann mit direcktem Pfad oder ohne dargestellt werden ( Line of Side ). Mit Hilfe dieses Filters wird die Verspätung der nebenpfaden dargestellt. Es ist möglich beliebig viele dieser Pfade mit unterschiedlicher stärke zu simulieren. +Für die statische implementation und veranschaulichen des Fading effekts wurde ein eigener Block kreaiert und in den Channel implementiert. Dieser Block basiert auf einem FIR Filter. Es kann mit direcktem Pfad oder ohne dargestellt werden (Line of Side). Mit Hilfe dieses Filters wird die Verspätung der nebenpfaden dargestellt. Es ist möglich beliebig viele dieser Pfade mit unterschiedlicher stärke zu simulieren. Dieser Block wurde zusätzlich mit der methode in \ref{sec:fractional-delay} beschriben implementiert um nichtganzahlige delay werte zu erlauben. % Bild einfügen -\subsubsection{Fractional Delay} -Problem Werte nur auf dem Sample übermitelt und keine dazwischen. + diff --git a/doc/thesis/chapters/theory.tex b/doc/thesis/chapters/theory.tex index 64d412b..e3c0117 100644 --- a/doc/thesis/chapters/theory.tex +++ b/doc/thesis/chapters/theory.tex @@ -223,7 +223,7 @@ Equation \eqref{eqn:multipath-frequency-response} shows that the frequency respo } \end{figure} -\subsection{Discrete-time model} +\subsection{Discrete-time model}\label{sec:Discrete-time-model} Since in practice signal processing is done digitally, it is meaningful to discuss the properties of a discrete-time model. To keep the complexity of the model manageable some assumptions are necessary, thus the sent discrete signal \(s(n)\)\footnote{This is an abuse of notation. The argument \(n\) is used to mean the \(n\)-th digital sample of \(s\), whereas \(s(t)\) is used for the analog waveform.} is assumed to have a finite single sided bandwidth \(W\). This implies that in the time-domain signal is a series of sinc-shaped pulses each shifted from the previous by a time interval \(T = 1 / (2W)\) (Nyquist rate): \begin{equation} @@ -272,11 +272,62 @@ f = np.logspace(5, 8, num=320) multipath = tap(.8, 500e-9, f) + tap(.4, 300e-9, f) \end{lstlisting} -\subsection{Difficulties caused by discrete time} +\subsection{Fractional Delay}\label{sec:fractional-delay} +% TO Do quelle: http://users.spa.aalto.fi/vpv/publications/vesan_vaitos/ch3_pt1_fir.pdf + +\begin{figure} + \centering + \begin{subfigure}{.45\linewidth} + \includegraphics[width=\linewidth]{./figures/screenshots/Fractional_delay_6} + \caption{sinc function shifted by the delay = 6.0, with the sample points} + \end{subfigure} + \hskip 5mm + \begin{subfigure}{.45\linewidth} + \includegraphics[width=\linewidth]{./figures/screenshots/Fractional_delay_637} + \caption{sinc function shifted by the delay = 6.37, with the sample points} + \end{subfigure} + \label{fig:fractional-delay-sinc-plot} +\end{figure} + +As in \ref{sec:Discrete-time-model} mentioned a FIR filter can be used to cheat a discrete time model of multiparty fading. But with a FIR filter, the delays are set at the sample rate, so the delays are integer. When the delays are noninteger a approximation had to be done. + +In the example shown in \figref{fig:fractional-delay-sinc-plot}. For a integer delays in the sinc function all sample values are zero except the one by the delayed sample, which is the amplitude value, here one. When the delay is a fractional number all samples are non-zero. In theory this filter is notrealizable because its noncasual and the impulse respond is infinity long. This problem can't be solve by adding them because of the imaginary part. + +To desing a noninteger digital delay FIR Filter a least square integral error design approximation could be chosen. + +\begin{equation} \label{eqn:transfer-function-FIR} + H(z)=\sum_{n=0}^{N} h(n) z^{-n} +\end{equation} + +The transfare function is given in \eqref{eqn:transfer-function-FIR}, where \(N\) is the order of the filter given in integer coefficients. To be mention for the approximation is that the error decreases with a higher filter order. + +The error function between the ideal frequency respond an the approximation should be minimized, for the best possible approximation. + +\begin{equation} \label{eqn:error-function} + E\left(e^{j \omega}\right)=H\left(e^{j \omega}\right)-H_{\mathrm{id}}\left(e^{j \omega}\right) +\end{equation} + +The impulse respond of such least squared fractional delay filter in \eqref{eqn:impuls-respond}. Only positive values are used to make the sinc-function casual. + +\begin{equation} \label{eqn:impuls-respond} + h(n)= \begin{cases}\operatorname{sinc}(n-D), & 0 \leq n \leq N \\ 0, & \text { otherwise }\end{cases} +\end{equation} + +To simplify the calculation, the assumption was made that the filter order is an odd number. With this assumption the exact order for the filter can be found out with \eqref{eqn:filter-order} and the integer delay \(D_{\text {int }}\). +\begin{equation} \label{eqn:filter-order} + N = 2 D_{\text {int }} + 1 +\end{equation} + + +The first non-zero sample can be find out with the help of the index M in \eqref{eqn: M first non-zero sample}.With the help of this index it can also be said whether the FIR filter is causal or not. For \(M \geq 0\) casual and if \(M < 0\) noncasual, an so notrealizable. With the assumption that \(N\) is an odd number \(M \) should always be \( 0\) else something went wrong. + +\begin{equation}\label{eqn: M first non-zero sample} + M = \lfloor D\rfloor-\frac{N-1}{2} \quad \text { for odd } N +\end{equation} +%% TO DO : Mention windowing or not ? -\skelpar{Not sampling at peaks of sincs.} \skelpar{Discrete frequency response. Discuss bins, etc.} \subsection{Statistical model} diff --git a/doc/thesis/figures/screenshots/Fractional_delay_6.png b/doc/thesis/figures/screenshots/Fractional_delay_6.png new file mode 100644 index 0000000..016c696 Binary files /dev/null and b/doc/thesis/figures/screenshots/Fractional_delay_6.png differ diff --git a/doc/thesis/figures/screenshots/Fractional_delay_637.png b/doc/thesis/figures/screenshots/Fractional_delay_637.png new file mode 100644 index 0000000..c1e9162 Binary files /dev/null and b/doc/thesis/figures/screenshots/Fractional_delay_637.png differ diff --git a/notebooks/FIR_mehrere_V2.ipynb b/notebooks/FIR_mehrere_V2.ipynb index 1cfdd29..6fbcf3b 100644 --- a/notebooks/FIR_mehrere_V2.ipynb +++ b/notebooks/FIR_mehrere_V2.ipynb @@ -2,7 +2,6 @@ "cells": [ { "cell_type": "markdown", - "id": "d828ae1c", "metadata": {}, "source": [ "# FIR Filter Parameters" @@ -11,7 +10,6 @@ { "cell_type": "code", "execution_count": 1, - "id": "9aed9f51", "metadata": {}, "outputs": [], "source": [ @@ -23,7 +21,6 @@ { "cell_type": "code", "execution_count": 2, - "id": "9a16a6d2", "metadata": {}, "outputs": [], "source": [ @@ -34,7 +31,6 @@ }, { "cell_type": "markdown", - "id": "5ad0edf9", "metadata": {}, "source": [ "# Dealy Window\n" @@ -43,12 +39,11 @@ { "cell_type": "code", "execution_count": 3, - "id": "bf92d73a", "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -71,12 +66,11 @@ { "cell_type": "code", "execution_count": 4, - "id": "dd93e444", "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -102,7 +96,6 @@ }, { "cell_type": "markdown", - "id": "12b0c2d2", "metadata": {}, "source": [ "# FIR" @@ -111,7 +104,6 @@ { "cell_type": "code", "execution_count": 5, - "id": "efc93b69", "metadata": {}, "outputs": [], "source": [ @@ -127,7 +119,6 @@ { "cell_type": "code", "execution_count": 6, - "id": "43372541", "metadata": {}, "outputs": [], "source": [ @@ -138,7 +129,6 @@ { "cell_type": "code", "execution_count": 7, - "id": "a32cb580", "metadata": {}, "outputs": [ { @@ -153,7 +143,7 @@ }, { "data": { - "image/png": "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\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAW4AAAD4CAYAAADM6gxlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAAAsTAAALEwEAmpwYAAAVYElEQVR4nO3df2zcd33H8de7jguXksxAbwy77ZKiyBJpNowsWOcJsfLDUBD1qm20KBMLQokQ22Ca3MUTWpm0KtHMEPtjRWQtP6ZCaNe6B1paDFKALBOkOL2oLu28kbaEnkvjrrpCt4PYl/f+uDsvSf3j+73c93vfz93zIUXxffz9+PP+fD/2y+fvfe2PubsAAOG4pN0FAADiIbgBIDAENwAEhuAGgMAQ3AAQmA1JfNDLL7/ct2zZksSHBoCOdPz48efcPR/l2ESCe8uWLZqZmUniQwNARzKzH0c9lkslABAYghsAAkNwA0BgCG4ACAzBDQCBiXRXiZn9uaQPS3JJs5J2ufsvkixsPYViSZPTc5ovV9Tfl9P46KDGhgaC7ZOGNOrK6tyBTrJucJvZgKQ/k/R6d6+Y2T2SbpL0xYRrW1WhWNLE1Kwqi1VJUqlc0cTUrCStGhJZ7pOGNOrK6tyBThP1UskGSTkz2yBpo6T55Epa3+T03HI4NFQWq5qcnguyTxrSqCurcwc6zbrB7e4lSZ+SdErSM5JecPdvXnicme02sxkzm1lYWGh9peeYL1ditWe9TxrSqCurcwc6zbrBbWavlHSDpK2S+iVdZmY7LzzO3Q+4+7C7D+fzkX5rs2n9fblY7Vnvk4Y06srq3IFOE+VSydslPenuC+6+KGlK0m8nW9baxkcHlevtOa8t19uj8dHBIPukIY26sjp3oNNEuavklKTfMrONkiqS3iaprX+IpPFC1y33PqIz1bMaiHD3wsX0mbzviOaXNqm/b2MifdLQzPybHSNrcwc6jUXZc9LM/kbS+yUtSSpK+rC7/3K144eHhz2NPzL1/s99T5J0955rE+2jL7yn9v+uQ8n2SUFT848ro3MHsszMjrv7cJRjI93H7e63Srr1oqoCALQEvzkJAIEhuAEgMAQ3AASG4AaAwBDcABAYghsAAkNwA0BgCG4ACAzBDQCBIbgBIDAENwAEhuAGgMAQ3AAQGIIbAAJDcANAYAhuAAjMuhspmNmgpLvPabpa0l+7+2eSKipLCsWSJk/urG3Ftf9wIltxFYolTU7Pab5cUX/ELcWa6ZNGXQCSt25wu/ucpDdIkpn1SCpJuj/ZsrKhUCxpYmpWlaXNkqRSuaKJqVlJalmALY+xWI08RjN90qgLQDriXip5m6ST7v7jJIrJmsnpueXgaqgsVjU5PdfWMbJaF4B0xA3umyQdXOkdZrbbzGbMbGZhYeHiK8uA+XIlVntaY2S1LgDpiBzcZnappPdJ+peV3u/uB9x92N2H8/l8q+prq/6+XKz2tMbIal0A0hHnGfe7JT3s7s8mVUzWjI8OKtfbc15brrdH46ODbR0jq3UBSMe6L06e42atcpmkUzVehLvtnu/qOd+s/r6NLb+zovGxJu87UrtzJcIYjffdcu8jOlM9q4EE7vhopi4A6YgU3Ga2UdI7JO1JtpzsGRsa0LYHb5ckbd97NLExxk7cVXuw61DkPgcfOiVJunvPtZmpC0DyIgW3u/+vpFcnXAsAIAJ+cxIAAkNwA0BgCG4ACAzBDQCBIbgBIDAENwAEhuAGgMAQ3AAQGIIbAAJDcANAYAhuAAgMwQ0AgSG4ASAwBDcABIbgBoDAENwAEJioO+D0SbpD0jWSXNKH3P17CdaFQBWKJU2e3Fnb7mz/4US2OysUS5qcntN8uaL+iNu2NdMnjbrSkNb5itsnq+crBFH3nPwHSd9w99+v7/a+McGaEKhCsaSJqVlVljZLkkrliiamZiWpZV+Qy2MsViOP0UyfNOpKQ1rnK26frJ6vUKx7qcTMNkt6i6Q7Jcndz7h7OeG6EKDJ6bnlL8SGymJVk9NzbR0jq3WlIa3zFbdPVs9XKKJc475a0oKkL5hZ0czuMLPLLjzIzHab2YyZzSwsLLS8UGTffLkSqz2tMbJaVxrSOl9x+2T1fIUiSnBvkPRGSZ919yFJ/yNp74UHufsBdx929+F8Pt/iMhGC/r5crPa0xshqXWlI63zF7ZPV8xWKKMH9tKSn3f1Y/fG9qgU5cJ7x0UHlenvOa8v19mh8dLCtY2S1rjSkdb7i9snq+QrFui9OuvtPzewnZjbo7nOS3ibpseRLQ2gaLyrdds939ZxvVn/fxpbfKdD4WJP3HanduRJhjMb7brn3EZ2pntVAAncwNFNXGpqZ+8X0iTr/rJ6vUES9q+RPJX25fkfJE5J2JVcSQjY2NKBtD94uSdq+92hiY4yduKv2YNehyH0OPnRKknT3nmszU1campl7s33izD+r5ysEkYLb3U9IGk62FABAFPzmJAAEhuAGgMAQ3AAQGIIbAAJDcANAYAhuAAgMwQ0AgSG4ASAwBDcABIbgBoDAENwAEBiCGwACQ3ADQGAIbgAIDMENAIGJFNxm9pSZzZrZCTObSbqoblMoljRycqe2zn1EI/sPq1AsJTZO8VRZx558PtFxEF2hWNLI/sPauvdQ5DWJ26eZdedzJdui7oAjSb/r7s8lVkmXKhRLmpiaVWVpsySpVK5oYmpWklq6jVNjnDPVs4mOg+iW136xKinamsTt08y687mSfVwqabPJ6bnlL8KGymJVk9NzQY6D6JpZk7h90hgD6Ysa3C7pm2Z23Mx2r3SAme02sxkzm1lYWGhdhR1uvlyJ1Z71cRBdM2sSt08aYyB9UYN7xN3fKOndkj5qZm+58AB3P+Duw+4+nM/nW1pkJ+vvy8Vqz/o4iK6ZNYnbJ40xkL5Iwe3u8/X/T0u6X9Kbkiyqm4yPDirX23NeW663R+Ojg0GOg+iaWZO4fdIYA+lbN7jN7DIz29R4W9I7JT2adGHdYmxoQPtu3KG8vSCTa6Avp3037mj5i0BpjYPoGmtyaU/tyzDKmsTt08y687mSfVHuKnmNpPvNrHH8V9z9G4lW1WXGhga07cHbJUnb9x4NfhxENzY0oIMPnZIk3b3n2kT6NLPufK5k27rB7e5PSPrNFGoBAETA7YAAEBiCGwACQ3ADQGAIbgAIDMENAIEhuAEgMAQ3AASG4AaAwBDcABAYghsAAkNwA0BgCG4ACAzBDQCBIbgBIDAENwAEhuAGgMBE2QFHkmRmPZJmJJXc/b3JlYSsKBRLmjy5U/NLm9S//7DGRwcT2b6qUCxpcnpO8+WK+vtyiY0DdIrIwS3pY5Iel7Q5oVqQIYViSRNTs6os1Za7VK5oYmpWkloaqsvjLFYTHQfoJJEulZjZFZLeI+mOZMtBVkxOzy2HaUNlsarJ6bkgxwE6SdRr3J+RdIuks6sdYGa7zWzGzGYWFhZaURvaaL5cidWe9XGATrJucJvZeyWddvfjax3n7gfcfdjdh/P5fMsKRHv09+VitWd9HKCTRHnGPSLpfWb2lKSvSrrOzO5KtCq03fjooHK9Pee15Xp7ND46GOQ4QCdZN7jdfcLdr3D3LZJuknTY3XcmXhnaamxoQPtu3KG8vSCTa6Avp3037mj5C4aNcQY2/CzRcYBOEueuEnSZsaEBbXvwdknS9r1HEx1n7ET9h7hdhxIbB+gUsYLb3b8j6TuJVAIAiITfnASAwBDcABAYghsAAkNwA0BgCG4ACAzBDQCBIbgBIDAENwAEhuAGgMAQ3AAQGIIbAAJDcANAYAhuAAgMwQ0AgSG4ASAwBDcABGbdjRTM7OWSjkh6Wf34e9391lYXUiiWNDk9p/lyRf19OY2PDrZ8+6pCsaTiqbLOVM9qZP/hRMYAgKRF2QHnl5Kuc/cXzaxX0lEze9Ddv9+qIgrFkiamZlVZrEqSSuWKJqZmJallwdoY40z1bGJjAEAaomwW7O7+Yv1hb/2ft7KIyem55dBuqCxWNTk9F9QYAJCGSNe4zazHzE5IOi3pW+5+bIVjdpvZjJnNLCwsxCpivlyJ1d6MNMYAgDRECm53r7r7GyRdIelNZnbNCscccPdhdx/O5/Oxiujvy8Vqb0YaYwBAGmLdVeLuZdV2eX9XK4sYHx1UrrfnvLZcb4/GRweDGgMA0rBucJtZ3sz66m/nJL1d0n+0soixoQHtu3GHLu2plTPQl9O+G3e09EXDxhh5e0EmT2QMAEhDlLtKXivpS2bWo1rQ3+Pu/9rqQsaGBnTwoVOSpLv3XNvqD788xrYHb5ckbd97NJExACBp6wa3uz8iaSiFWgAAEfCbkwAQGIIbAAJDcANAYAhuAAgMwQ0AgSG4ASAwBDcABIbgBoDAENwAEBiCGwACQ3ADQGAIbgAIDMENAIEhuAEgMAQ3AAQmyg44V5rZt83scTP7oZl9LI3CAAAri7IDzpKkv3D3h81sk6TjZvYtd38s4doAACtY9xm3uz/j7g/X3/65pMclsVEjALRJrGvcZrZFtW3Mjq3wvt1mNmNmMwsLCy0qDwBwocjBbWavkHSfpI+7+88ufL+7H3D3YXcfzufzrawRAHCOSMFtZr2qhfaX3X0q2ZIAAGuJcleJSbpT0uPu/unkSwIArCXKM+4RSX8k6TozO1H/d33CdQEAVrHu7YDuflSSpVALACACfnMSAAJDcANAYAhuAAgMwQ0AgSG4ASAwBDcABIbgBoDAENwAEBiCGwACQ3ADQGAIbgAIDMENAIEhuAEgMAQ3AASG4AaAwBDcABCYKFuXfd7MTpvZo2kUhO5TKJY0cnKnts59RCP7D6tQLCUyRvFUWceefD6xMbpdWus4sv+wtu491NXrGOUZ9xclvSvhOtClCsWSJqZmVVraLJepVK5oYmq2pV+QjTHOVM9KUiJjdLs017FUrsjV3eu4bnC7+xFJz6dQC7rQ5PScKovV89oqi1VNTs8FNUa3Yx3T1bJr3Ga228xmzGxmYWGhVR8WHW6+XInVntUxuh3rmK6WBbe7H3D3YXcfzufzrfqw6HD9fblY7Vkdo9uxjunirhK01fjooHK9Pee15Xp7ND46GNQY3Y51TNeGdheA7jY2NCBJuu2e7+o536z+vo0aHx1cbg9ljG6X5jpO3ndE80ubunod1w1uMzso6a2SLjezpyXd6u53Jl0YusfY0IC2PXi7JGn73qPBjtHt0lrHsRN31R7sOpTIGCFYN7jd/eY0CgEARMM1bgAIDMENAIEhuAEgMAQ3AASG4AaAwBDcABAYghsAAkNwA0BgCG4ACAzBDQCBIbgBIDAENwAEhuAGgMAQ3AAQGIIbAAJDcANAYCIFt5m9y8zmzOxHZrY3iUIKxZKKp8o69uTzGtl/WIViqaXHp6lQLGnk5E5tnftIYrVlef5JS+P8StInCrN63cQD2rL3kF438YA+UZhteV3NrGM3r30zCsWSRvYf1ta9hyJnS5zjm+1zMaJsXdYj6R8lvUPS05J+YGZfd/fHWlVEoVjSxNSszlTPSpJK5YompmpfJCvtJxf3+DQ1aqssbZaUTG1Znn/S0ji/Ui207/r+qeXHVfflx387tqMldTWzjt289s1YXpfFqqTo2RL1+Gb7XCxz97UPMLtW0ifdfbT+eEKS3H3fan2Gh4d9ZmYmchEj+w+rVK5ozyNf09Uv/P93qkv9rF6/+N8vOf6x3lfrjL30h4XVjj9X9Rc/lyT1vHxT5Pri9HnxF0s6u8I5vcRMr3j56t8n44yR5vyTPl9x+zR7fuPW9eiGV2npkp6XtG84W9U1S8+3pK5m1rHZtU91HXtNl20fjtbhp/WfYn7tpd8MW9GneKqsXy5VX9L+sg09Grqq76KPv7DPE78yoM/9xg2SpIG+nP5973Xr1thgZsfdPdKJi7LL+4Ckn5zz+GlJb15h0N2SdkvSVVddFWXsZfPlyortK32CNtN+rjifhM30WemLd632ZsZIc/5Jn6+4fZo9v3HGkLRiaK/V3kxdzaxjs2uf5jpesnFj9A5xAruJPiuFcCvb13rfarnWClGC21Zoe8lno7sfkHRAqj3jjlNEf19OpXJl+TtVw2rfsT5Uf4Z+objf4ZIwkkJtWZ5/0tI4v5J0/cQDqq4Quj1mOrnv+pbU1cw6dvPaN+MDa5yv969wvuIev1af/r5cExVHE+XFyaclXXnO4yskzbeyiPHRQeV6z38mk+vt0fjoYEuOT1MatWV5/klLa+43v/nKWO3N1JVWn26WRra0Y02iPOP+gaRtZrZVUknSTZI+0MoiGhfwJ6fnNF+uqL8vp/HRwVUv7Mc9Pk1p1Jbl+Sctrbk3XoA8eOwnqrqrx0w3v/nKFV+YbLautPp0szSypR1rsu6Lk5JkZtdL+oykHkmfd/fb1jo+7ouTANDtWv3ipNz9AUkPXFRVAICW4DcnASAwBDcABIbgBoDAENwAEJhId5XE/qBmC5J+3GT3yyU918JyQtLNc5e6e/7MvXs15v/r7p6P0iGR4L4YZjYT9ZaYTtPNc5e6e/7MvTvnLjU3fy6VAEBgCG4ACEwWg/tAuwtoo26eu9Td82fu3Sv2/DN3jRsAsLYsPuMGAKyB4AaAwGQmuNPYkDjLzOwpM5s1sxNm1tF/WtHMPm9mp83s0XPaXmVm3zKz/6r//8p21pikVeb/STMr1df/RP0vcnYcM7vSzL5tZo+b2Q/N7GP19o5f/zXmHnvtM3GNu74h8X/qnA2JJd3cyg2Js87MnpI07O4d/4sIZvYWSS9K+md3v6be9neSnnf3/fVv3K90979sZ51JWWX+n5T0ort/qp21Jc3MXivpte7+sJltknRc0pikP1aHr/8ac/9DxVz7rDzjfpOkH7n7E+5+RtJXJd2wTh8Eyt2PSLpwx90bJH2p/vaXVPuE7kirzL8ruPsz7v5w/e2fS3pctX1tO37915h7bFkJ7pU2JO62LT1c0jfN7Hh94+Vu8xp3f0aqfYJL+tU219MOf2Jmj9QvpXTcpYILmdkWSUOSjqnL1v+CuUsx1z4rwR1pQ+ION+Lub5T0bkkfrf84je7xWUmvk/QGSc9I+vu2VpMwM3uFpPskfdzdf9buetK0wtxjr31WgjvxDYmzzt3n6/+flnS/apePusmz9WuAjWuBp9tcT6rc/Vl3r7r7WUn/pA5efzPrVS24vuzuU/Xmrlj/lebezNpnJbiXNyQ2s0tV25D4622uKTVmdln9xQqZ2WWS3inp0bV7dZyvS/pg/e0PSvpaG2tJXSO06n5PHbr+ZmaS7pT0uLt/+px3dfz6rzb3ZtY+E3eVSPE3JO4kZna1as+ypdo+oF/p5Pmb2UFJb1Xtz1k+K+lWSQVJ90i6StIpSX/g7h35At4q83+raj8qu6SnJO1pXPPtJGb2O5L+TdKspLP15r9S7VpvR6//GnO/WTHXPjPBDQCIJiuXSgAAERHcABAYghsAAkNwA0BgCG4ACAzBDQCBIbgBIDD/B2hsGfEWL3MdAAAAAElFTkSuQmCC\n", "text/plain": [ "
" ] @@ -176,13 +166,12 @@ { "cell_type": "code", "execution_count": 8, - "id": "39fb3489", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array([9, 8, 7, 6, 9, 7, 5, 7, 9, 0, 5, 5, 7, 5, 1, 0, 8, 6, 9, 0])" + "array([3, 8, 8, 7, 0, 5, 7, 8, 4, 6, 1, 0, 6, 0, 0, 5, 5, 6, 6, 1])" ] }, "execution_count": 8, @@ -197,7 +186,6 @@ { "cell_type": "code", "execution_count": 9, - "id": "7fd06347", "metadata": {}, "outputs": [ { @@ -218,14 +206,13 @@ { "cell_type": "code", "execution_count": 10, - "id": "a9612999", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array([0., 0., 9., 8., 7., 6., 9., 7., 5., 7., 9., 0., 5., 5., 7., 5., 1.,\n", - " 0., 8., 6., 9., 0., 0., 0., 0.])" + "array([0., 0., 3., 8., 8., 7., 0., 5., 7., 8., 4., 6., 1., 0., 6., 0., 0.,\n", + " 5., 5., 6., 6., 1., 0., 0., 0.])" ] }, "execution_count": 10, @@ -239,7 +226,6 @@ }, { "cell_type": "markdown", - "id": "706a51b1", "metadata": {}, "source": [ "# FIR mit Delay \n" @@ -247,23 +233,24 @@ }, { "cell_type": "code", - "execution_count": 11, - "id": "79e18131", + "execution_count": 58, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Tap with amplitude=1, delay=5.2\n", - "Creating filter of order N=11.0\n", - "[ 1. 0.04454711 -0.05846808 0.08504448 -0.15591488 0.93548928\n", - " 0.23387232 -0.10394325 0.06682066 -0.04923628 0.03897872 -0.03225825]\n" + "Tap with amplitude=1, delay=6\n", + "Creating filter of order N=13.0\n", + "[-3.89817183e-17 3.89817183e-17 -3.89817183e-17 3.89817183e-17\n", + " -3.89817183e-17 3.89817183e-17 1.00000000e+00 3.89817183e-17\n", + " -3.89817183e-17 3.89817183e-17 -3.89817183e-17 3.89817183e-17\n", + " -3.89817183e-17 3.89817183e-17]\n" ] }, { "data": { - "image/png": "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\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYoAAAEGCAYAAAB7DNKzAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAAAsTAAALEwEAmpwYAAA0+0lEQVR4nO3deXxU5bnA8d+ThX2JbBESdlmk4MLuHuEqLiiKWlELrkWtWmu1Va/XUlurWK91X6tWa12riBuKXCRiVZBNREAksiYgmwQIW0jy3D/eGRlDMplMzpwzA8/388lnMjPnvOfhMDnPnHcVVcUYY4ypTlrQARhjjEluliiMMcZEZYnCGGNMVJYojDHGRGWJwhhjTFQZQQeQCK1atdJOnTrFte/27dtp3LixtwH5JFVjT9W4wWIPisXuvTlz5mxU1dZVvbdfJopOnToxe/bsuPbNz88nLy/P24B8kqqxp2rcYLEHxWL3noisrO49q3oyxhgTlSUKY4wxUVmiMMYYE5UlCmOMMVFZojDGGBNVoIlCRJ4VkfUi8nU174uIPCQiBSLylYj09TtGY6oycV4Rx4z/iEs+2M4x4z9i4ryioEMyJmGCvqN4DjglyvunAt1CP2OBx32IyZioJs4r4tYJCygq3glAUfFObp2wwJKF2W8FmihUdTrwQ5RNRgD/VGcGkCUibf2Jzpiq3Tt5CTtKy9nxXRu2ftGZij1p7NxTzr2TlwQdmjEJkewD7nKA1RHPC0Ovra28oYiMxd11kJ2dTX5+flwHLCkpiXvfoKVq7KkWd1HxTrZ8fghbPulBZqutNB2w/MfXU+nfkWrnPZLF7q9kTxRSxWtVrrSkqk8BTwH0799f4x35mKyjJmORqrGnWtzN3/iClZ90p3GvIloMW4AIqELuQQ1T6t+Rauc9ksXur6DbKGpSCLSPeJ4LrAkoFmMAqDe/D+mN9tDipK9Jq1fOnh8asf6FYznj4D5Bh2ZMQiR7ongbGBPq/TQY2KKq+1Q7GeOXTZvg61kNGXnRLho0rgCgfa6Qsb0p8ydXOZ+aMSkv0KonEXkZyANaiUghMA7IBFDVJ4BJwGlAAbADuDSYSI1xWraEFSsgI6MZv3o9i+LiYibfnMdVa+CFF2D7dkjCiUGNqZNAE4WqXlDD+wpc41M4xsQkO3vf10aNgiefhHffhfPP9z8mYxIp2auejEkaq1fDkCEwZ86+7x13HLRuDe+8439cxiRasvd6MiZpTJ0K06ZBvXr7vpeeDjffDK1a+R+XMYlmicKYGH38sWuj+NnPqn7/xhv9jccYv1jVkzEx+vhjOP54SIvyV1NUBN99519MxvjBEoUxMVi9GpYvhxNOiL7d4MFw++3+xGSMXyxRGBOD4mI48USoaUDtoEEwc6YfERnjH0sUxsSgTx/46CM4/PDo2w0aBMuWwYYN/sRljB8sURgTgz17Yttu4ED3+MUXiYvFGL9ZojCmBhUVbpDdnXfWvG2/fq6x26qfzP7EuscaU4OlS2HzZmjXruZtmzSBt96qvgutManIEoUxNZg71z326xfb9sOHJy4WY4JgVU/G1GDuXKhfH3r1im37wkL4+99h27bExmWMXyxRGFODhQvh0EMhMzO27efPh7Fj3aMx+wOrejKmBiNHQnl57Nsfdph7XLAAjj02MTEZ4ydLFMbU4Iorard9bi40bw5ffZWYeIzxm1U9GRPFli1u+g6tcqX2qom4AXoLFiQuLmP8ZInCmCjeegs6dIAlS2q3X69esHhxYmIyxm+WKIyJYuFC14h9yCG12++OO9z4C2P2B9ZGYUwUixZBjx6QUcu/lIMPTkw8xgTB7iiMiWLRotjHT0Tavh3GjYP8fM9DMsZ3liiMqcauXW4Nip49a79v/fpw993wwQfex2WM36zqyZgo/vUv6N279vtlZEDXrrVvBDcmGVmiMKYaDRrAhRfGv3+PHvDtt97FY0xQrOrJmGosXgyffVa7MRSRevSAgoLajeo2JhkFmihE5BQRWSIiBSJySxXvNxeRd0RkvogsFJFLg4jTHJgefRROPz3+/cO9pdas8S4mY4IQWKIQkXTgUeBUoBdwgYhU7l9yDbBIVQ8H8oD7RKSer4GaA1ZBgRs/IRLf/qNHQ0kJtG/vbVzG+C3IO4qBQIGqLlPVUuAVYESlbRRoKiICNAF+AMr8DdMcqAoKXIN0vDIz408yxiSTIBuzc4DVEc8LgUGVtnkEeBtYAzQFzlfViqoKE5GxwFiA7Oxs8uPswF5SUhL3vkFL1diTMe6yMmH58uM56qhV5Ocvr3Kb4uKdlJeXR439/vu70bXrds48M/nqn5LxvMfKYvdXkImiqu9alZsNhwFfAkOArsAUEflEVbfus6PqU8BTAP3799e8vLy4gsrPzyfefYOWqrEnY9wFBW6t7KFDO5KX17HKbR5f8jnFxcVRY7/6atdOkZfXPUGRxi8Zz3usLHZ/BVn1VAhE1t7m4u4cIl0KTFCnAFgOxDH8yZjaycmB6dPhlFPqVk6XLrBsmTcxGROUIBPFLKCbiHQONVCPwlUzRVoFDAUQkWygB2B/dibhGjaE446r+5xN4UQRbxdbY5JBYIlCVcuAa4HJwGLgNVVdKCJXichVoc3+DBwtIguAqcDNqroxmIjNgWTKFJg4se7ldOkCW7fC5s11L8uYoAQ6MltVJwGTKr32RMTva4CT/Y7LmEcecXcCZ51Vt3K6d3c/mzZBixaehGaM72wKD2OqsHIldOpU93JOP71ug/aMSQY2hYcxVVixAjpW3dnJmAOOJQpjKikudmtle3FHAXD++fA//+NNWcYEwaqejKlk5Ur36FWiWLXKtVEYk6osURhTyc9+5hYs8qrxuXNnmDHDm7KMCYJVPRlTSUaGu5to1syb8jp2hMJCN9LbmFRkicKYSiZMgIce8q68Dh1gzx5Yt867Mo3xkyUKYyp58UV44omat4tVr14wdCjs3Oldmcb4ydoojKlk5Upvu8aecIL7MSZV2R2FMZWsWOFdjydj9geWKIyJUFLiurJ6PdhuwAD43e+8LdMYv1iiMCZCYaFblc7rO4pdu2DpUm/LNMYv1kZhTISePd1F3etpwTt2dAPvjElFdkdhTCX16kH9+t6W2aGDJQqTuixRGBPhhRfgxhu9L7dDB9f2sX2792Ubk2iWKIyJMHkyvPmm9+UOHAiXXOKqtYxJNdZGYUyE1ashN9f7cocMcT/GpCK7ozAmQmEhtG+fmLJVobQ0MWUbk0iWKIwJqahwiSIRdxTl5dC8Ofz5z96XbUyiWaIwJmTLFmjZ0jU8ey09HQ46yHo+mdRkbRTGhBx0EKxZk7jyrYusSVV2R2GMTyxRmFRlicKYkNdfh7POcvM9JUL79q5XlS1gZFJNoFVPInIK8CCQDjytquOr2CYPeADIBDaqqk3YbBJizhyYNAkaNUpM+SedBJmZbhEjr0d+G5NIgSUKEUkHHgVOAgqBWSLytqouitgmC3gMOEVVV4lIm0CCNQeE1ashJwfSEnSfPXSo+zEm1QRZ9TQQKFDVZapaCrwCjKi0zYXABFVdBaCq632O0RxAEjmGAtw4io0bYevWxB3DmEQIsuopB1gd8bwQGFRpm+5ApojkA02BB1X1n1UVJiJjgbEA2dnZ5OfnxxVUSUlJ3PsGLVVjT5a4ly4dRM+eW8nPXxzT9sXFOykvL4859k2b6nHuuUfzm998y4gRCexeFaNkOe/xsNj9FWSikCpeqzy5cwbQDxgKNAQ+F5EZqvrtPjuqPgU8BdC/f3/Ny8uLK6j8/Hzi3TdoqRp7ssTdtSsMHdqQvLzsmLZ/fMnnFBcXxxx7eTlkZECjRt3Jy+teh0i9kSznPR4Wu7+CTBSFQOSNfi5Q+WtWIa4BezuwXUSmA4cD+yQKY+pq+vTElp+eDm3buiouY1JJkG0Us4BuItJZROoBo4C3K23zFnCciGSISCNc1VRs9QLGJKHcXCgqCjoKY2onsEShqmXAtcBk3MX/NVVdKCJXichVoW0WAx8AXwFf4LrQfh1UzGb/NWUK9O8PBQWJPU5Ojt1RmNQT6DgKVZ0ETKr02hOVnt8L3OtnXObAs3SpG0fRpElij3PZZbDe+u6ZFGNzPRmD+5afkQFtEjxS59RTE1u+MYlgU3gYQ+IH24Xt3Anz5tlYCpNaLFEYQ+IH24XNmQN9+8Lnnyf+WMZ4xaqejAF694asrMQfJyfHPVrPJ5NKLFEYAzz8sD/HadfOPVrPJ5NKrOrJGB/Vrw+tW9sdhUktNSYKEWkkIreLyN9Dz7uJyPDEh2aMP7780vV2mjrVn+Pl5todhUktsVQ9/QOYAxwVel4I/Bt4N1FBGeOn1athwwZo2tSf4919NzRu7M+xjPFCLImiq6qeLyIXAKjqThGpakI/Y1JSuBooN9ef4w0b5s9xjPFKLG0UpSLSkNDMriLSFdid0KiM8VFRkZuwLzu2SWPrbO1aeOcdKC3153jG1FUsiWIcbr6l9iLyIjAV+H1CozLGR4WFcPDBLln4YfJkOPNMV+VlTCqosepJVaeIyFxgMG4NietVdWPCIzPGJwMH+nc3AXuruAoL3RoYxiS7ahOFiPSt9NLa0GMHEemgqnMTF5Yx/rn6an+PF04U1kXWpIpodxT3hR4bAP2B+bg7isOAmcCxiQ3NGH/s3u3GN/glPDrbusiaVFFtG4WqnqiqJwIrgb6q2l9V+wFHAgmetd8Yf5SUQIMG8MAD/h2zaVNo1swShUkdsXSP7amqC8JPVPVrETkicSEZ459w9U+rVv4e9513oEMHf49pTLxiSRSLReRp4F+4LrK/wJYjNfuJcKIIVwf55fjj/T2eMXURS/fYS4GFwPXAb4BFodeMSXlBJYp58+Af//D3mMbEq8ZEoaq7VPV+VT079HO/qu7yIzhjEi2oRDFhAlxxBZSV+XtcY+JRY9WTiCwnNCo7kqp2SUhExvhowAD4/e/9n3spNxcqKuD77/2bOsSYeMXSRtE/4vcGwHlAi8SEY4y/hg51P36LXMDIEoVJdrFUPW2K+ClS1QeAIYkPzZjEKyqCXQFUpEaOzjYm2cVS9RQ5QjsNd4fh04TMxiTWwIFuNtdnn/X3uLYkqkklsVQ93RfxexmwHPh5YsIxxj9lZa6NwO+GbHDjNhYsgE6d/D+2MbUVS/fYy8OjtFX1JFUdC3gyQbKInCIiS0SkQERuibLdABEpF5FzvTiuMQDr1rkG5SAShQj07g1Nmvh/bGNqK5ZE8XqMr9WKiKQDjwKnAr2AC0SkVzXb3QNMrusxjYkUVNfYsDffhCefDObYxtRGtNljewI/A5qLyMiIt5rhej/V1UCgQFWXhY73CjACN6Av0nXAG8AAD45pzI/CDclB9Tr6979h5ky48spgjm9MrKK1UfQAhgNZwBkRr28DfunBsXOAyKVbCoFBkRuISA5wNq6XVdREISJjgbEA2dnZ5OfnxxVUSUlJ3PsGLVVjDyru7dsbcvXVLSkqWsuWLeW13r+4eCfl5eVxx15R0YXVq3OZNm06QSwunKqfF7DYfaeqUX+Ao2raJp4f3HiMpyOejwYerrTNv4HBod+fA86Npex+/fppvKZNmxb3vkFL1dhTNe6fP/GZnjx+Utz7P/CAKqhu2OBhULWQqudd1WJPBGC2VnNNjVb19HtV/StwoYhcUEWC+XUdc1Qh0D7ieS6wptI2/YFXxH3dagWcJiJlqjqxjsc2hiVL3DoUQfU8ilzAyO/Za42pjWhVT+EZYmcn6NizgG4i0hkoAkYBF0ZuoKqdw7+LyHPAu5YkjFeuugpKS+HTT4M5fmSiOPzwYGIwJhbVJgpVfSf0+HwiDqyqZSJyLa43UzrwrKouFJGrQu8/kYjjGhNWVARHHhnc8fv2heJit4iRMcksWtXTO1QxGWCYqp5Z14Or6iRgUqXXqkwQqnpJXY9nTJiqSxTDhwcXQ2YmNG8e3PGNiVW0qqf/9S0KY3y2ZQvs2BHcGIqwe+6Bli3dlOPGJKtoVU8fh38XkXpAT9wdxhJV9WRktjFBCXqwXdiECZCVZYnCJLcaR2aLyOnAd8BDwCNAgYicmujAjEmkdu3g1Vfh2GODjSMnx2aQNckv1kkBT1TVAgAR6Qq8B7yfyMCMSaSDDoKfJ8HUlrm58NFHQUdhTHSxzPW0PpwkQpYB6xMUjzG+WLAAPv645u0SLTfXtZeUlAQdiTHVi+WOYqGITAJew7VRnAfMCs//pKoTEhifMQnx6KPwxhuwYUOwceTmuhlk16+3mWRN8orljqIBsA44AcgDNuCWQj0DNxeUMSmnqCj4hmyAUaNg2zboYivQmyRW4x2Fql7qRyDG+KmwMDkSRVosX9WMCVgsS6F2xk313Slyey8G3BkTlKIitwxq0CoqYMwYOPVUuOiioKMxpmqxtFFMBJ4B3gEqEhqNMT7Yvdu1TSTLHcUHH7hpPCxRmGQVS6LYpaoPJTwSY3ySnu4mAmzbNuhInNxcG0thklssieJBERkHfAjsDr+oqnMTFpUxCZSRAUcfHXQUe9mgO5PsYkkUfXCLCg1hb9WThp4bk3IWL4bZs2HkSGjcOOho3B3F7ERN5m+MB2JJFGcDXWx+J7O/eP99uPFGOP305EgU3bq5hYvKytzdjjHJJpbOefNx62Ybs18oKoKGDd00Hsngpptg4UJLEiZ5xfLRzAa+EZFZ7G2jUFUdkbiwjEmc8GA7t8KuMaYmsdxRjMNVP90F/A34AjgkkUEZk0jJMio7rKgITjgBJk2qeVtjglBjogitS7EFOB14DhgK2DKlJmWtWgXt2wcdxV5NmsD06a6R3ZhkFG0p1O7AKOACYBPwKiCqeqJPsRmTEJ9+6kZEJ4tmzVyjengxJWOSTbQ2im+AT4AzItaiuMGXqIxJoNzcoCP4KREbdGeSW7Sqp3OA74FpIvJ3ERkKWPOfSWnLlsFddyXft3cbdGeSWbWJQlXfVNXzcWtl5wM3ANki8riInOxTfMZ4as4cuO022LQp6Eh+avBgOMS6iJgkFcs049uBF4EXRaQFbuGiW3BTehiTUlavdo/J1JgN8Je/BB2BMdWr1Wz4qvqDqj6pqp5M3yEip4jIEhEpEJFbqnj/IhH5KvTzmYgc7sVxzYFr9WrXcJyVFXQkxqSOwJZNEZF04FHgVKAXcIGI9Kq02XLgBFU9DPgz8JS/UZr9zerV7m4i2Qbb/ec/bpW7uTbVpklCQa6vNRAoUNVloXmkXgF+MtpbVT9T1c2hpzOAJOuvYlJNYWHyVTuBm1Jk+XI3xsOYZBPk7DI5wOqI54XAoCjbXw68X92bIjIWGAuQnZ1Nfn5+XEGVlJTEvW/QUjV2P+P+y1+EHTvSyc8vq3NZxcU7KS8v9yT2H37IBI5h2rSlZGX50yUrVT8vYLH7LchEUdXNv1a5ociJuERxbHWFqepThKqm+vfvr3l5eXEFlZ+fT7z7Bi1VY0/VuB9f8jnFxcWexF5RAZmZ0KhRN/LyutU9uBik6nkHi91vQVY9FQKRlQC5wJrKG4nIYcDTwAhVTbJOjSaVfP89/OpXMH9+0JHsKy0N2rWzsRQmOQWZKGYB3USks4jUw00X8nbkBiLSAZgAjFbVbwOI0exHli6Fxx+HdeuCjqRq55wDh1u/PpOEAqt6UtUyEbkWmAykA8+q6kIRuSr0/hPAH4CWwGPiuqmUqWr/oGI2qS1Zx1CE3Xdf0BEYU7VAl0pR1UnApEqvPRHx+xXAFX7HZfZPyZ4owLVViCRf911zYAuy6skYX61e7QbaNWkSdCRVe+kl103W2ilMsrFEYQ4Y27dD585BR1G9Fi2gtBRWrgw6EmN+ylbpNQeMf/wjudahqKxjR/dog+5MsrE7CnNASUviT3yHDu7R7ihMskniPxtjvLNzJ5xxBnzwQdCRVK9xY2jVyhKFST6WKIynvvoKhg1z9e2HHgp/+xuU1X22jDpbtQrefRc2bAg6kuiuuw6OPz7oKH5q1y7o2hVuuQVKSoKOxgTBEoXxVEYGLFoE558P2dlw440wcqS72ARp+XL3mMyN2QB/+ANceGHQUcD06XDlle737duhd2/461+hf3/rlXUgskRhPLF0qXvs1ctdlB9/HPLz4bHHoHnz4BuRV6xwj8meKFTdVCNa5axn/vj2Wxg+HD75BHbsgJYt4a23YOpUWLsWhgyBLVuCi8/4zxKFqbOFC903zidCQyUzIvrSXX01vPACNGoUTGxhK1a4Sffatg02jpo89JCL8Ycfgjl+eTmMHu3+DydP/un/24knuuq7ZctsRb4DjSUKUyfl5XDZZdCsmZurqDrz57tvqUHVcderB4MGJXevJ9g7ajyoBu1//AO++AIeeaTqEezHHQfvvQd33OF/bCY4Sf5nY5LdY4+5C8vDD0Pr1tVvt327u8A89ph/sUX6059cVUqyC4+lCCJRlJe7O4WjjoILLqh+u2HD3AjyHTuscftAYYnCxG3bNncBHjLENV5Hc/TR7gJz7712cYkmyEF36emuHeKpp2qea2rHDujTB+65x5/YTLAsUZi4LVjgGl3Hj49tErtx42DjRnj++cTHFmnHDjd992uv+XvceLRs6doFgqp66tLFtTfVpFEjGDAA7r8/eadtN96xRGHidvTRbqK9AQNi2/6oo6BfP9cjys9ePStXuvEdyTCeoyYiLvEOH+7vcd99F047rXYX/T/9yXV7Hj8+cXGZ5GBzPSWpwkL44x/dqmfDh7uLcTJNPV1Q4LqaNmxYu/1uu831QCorc72Q/BDuGtupkz/Hq6vrrvP/mI884sa/tGwZ+z7du8MvfuGqqv7nf2q3rx8KCuDBB2HPHldNNmIE5OYGHVVqsjuKJPLxx+6bHbgP93vvwV13ud46Q4bAkiXBxhe2Zw/k5cGll9Z+37PPhhtu8C9JwN7BdqmSKLZuhdmz/Tve2rUwZQpcfPFPuzbH4qabXNXeyy8nJrbaqqjYO8ajtNRVc/7733Dtte6Lza9+5drWTO1YokgCqnDnna6f+iOPuNc6d3Z/wBs3ur718+e7u4qiomBjBXj9dRdHTQ3Y1dm2zY2t2L7d27iqs2IF1K8PBx/sz/Hq6umn3f+1X2MpXnrJXWBHj679vr17u15v11zjfVy1VVoKo0a5O4eKCjeFTHGx+xv69lsYO9b9WzdtCjrS1GOJImAVFXD99XD77W7qhtdf/+n7WVmuKmL+fJdMcnICCfNHqq4Bs3t3OPXU+MqYOxfGjIG33655Wy/k5MCZZyb/GIqwrl3d43ff+XO8F16AgQPd/2k8wtWiQY4m37MHzjrL3T2cdtreVQLT0txjt27w6KNusGD4znL9+uDijUV5ufsyFeR5DUuRP5391+23uzEIN9zg/mCrW32tfXv49a/d7wsXusQRhBkzYNYsl9zivfAed5y7eL/0krexVef661Ojx1OYn4mirAx+/nP47W/rVs4TT7hkE8RULarujub99+HJJ+H3v6++Pa9FC/f417+6u6Fvv/UvzljMnOn+vgG+/tpdD1q3dlW2Eye65BEESxQBqqhw1SK//CXcd19sjdXl5XDuue6Ds3lzwkPcx4svurucMWPiLyMtzQ3o+uCDYP4Nya5LF/foR6LIyID//u/4qxHDWrRw7SrhNjY/PfUU/P3vrqPE2LGx7TNihEsww4YlR1XUmjXurnfwYPdvATep5vjx7k5pxgz3N9+3795E4idLFAFKS3N3EY89FnuPpvR0N81CYaFLMH578EH49NO6rzt97rnu2+ykSd7EVZ2tW+Ggg/wfu1EXjRq59pRlyxJ/rI8/9mYA5MiRbuGlv/2t7mXV1nHHwW9+47rrxqpHD5fU1qxxVb5BfVMHF0efPm6w4113uSpmcJ+Bm292bVarV7sOA23a7F3gyk+WKALwww9w+unwzTcuWdS2p8ngwe6P4o03XJ2sX1RdourVq+5lDRjg/hBmzap7WdEsXeoaNJs2TexxvPbEE66HTiJt3ZrBkCGuGqauMjJcFd/HH8OcOXUvLxbhaq5evVy7WW2rQgcNcp1HPvzQTe8ehLfecnc3HTvCvHlw661VfwnLyHAN9VOmuM/yjh2uKtqvDg+WKHym6rqVTplSt256N93k1ga45hp/FuMpKYGePb1LTGlprg72gQe8Ka86BQXusVu3xB7HayNGuMGJiTR7dgsqKlzjrxcuv9xdxO6/35vyanL//XDRRa4hO16//KVLcD/7mXdx1cYJJ7gL/ief1K4zwRdfuPaYo47yZ7qXQBOFiJwiIktEpEBEbqnifRGRh0LvfyUifYOI00sPP+x6+9xzT+wjmquSkeGqoC65pO7VQLH45z9dw5+XA5b8GKAVXicj3ECcKtaudXeMu3cn7hgzZ7agZcu6fQ4jNW/uRt3fcIM35UWzaVM97rjDjZmo65icBx7Yu1iUXz2Mpk1zo9qzslzCa9y4dvvn5cH//Z8bSX/88T60Z6lqID9AOvAd0AWoB8wHelXa5jTgfUCAwcDMWMru16+f1tabcwv16Lunaseb39Wj756qb84trHUZNZXd9uLpKunl2v+4HVpR4VnxCY/9qL9M1YyDtmmT3GKdMMfbstsMKNJmg5Z6Hne4/NZ912h6kx0JKf/nT3ymJ4+f5GmZYb+5c5OCarvL8xP2f5rWaJe2OnxtQs770XdP1U4J/Ftq3Hu1Snq5PjZxrWdlX/fHH7RZlx+0403vJezzePTdU7XNeTNV0sr1rDFb61zmnDmqLVqotmhdpkf+9vM6nXNgtlZzTQ3yjmIgUKCqy1S1FHgFGFFpmxHAP0P/jhlAloh4vvTMxHlF3DphAUXFOwEoKt7JrRMWMHFe3Ue3RZa9ZcYhpDXazZYBn/HWl96MnJs4r4hf31fEl//sgWpiYi+Y15SyzU1ocOQy/vtNb8vetiWN7QtzKNzsXdyR5Ze32kiTwwo9PS+JNnFeEW8WuGH4e4obJeT/dPm3mVTsqI+2/97z837j09/x1atdKS9NT0jsyxbWZ/vXuTQdsIyHZn/pWdlvfLWSrcsO4oePe3r+efkx9sX12DCxLxmttrEwe0ady+/bF/7w+Dq2p21n3bZdKN5eA8JEAxrNISLnAqeo6hWh56OBQap6bcQ27wLjVfU/oedTgZtVNeoEB/3799fZtZgD4ZjxH1FUvJOzPv2CJQX9GNP5KdJEqZ+RzpEdsmr/j4swb1Uxu8tcl4rSikw27m5Du4ZFnpQdLn/q2uN4ZOnvGNv1QYZkfwjgaex3LvwLRTtzebjvZWSklXta9kfrTuap767nr4f/ig6NV3p6XsLnPZJX5QMsWruVsrIyDmvfwpPywuatKmbDzsaMnfUyYzo9yWnt3MhEL8+7Kqza0YnW9dfTKGOHp+d9weZu/GHBfVzS+XFOafuu57H/+eu7WLsrh78deSUN0nd5Wvazy67mw++Hc1PPP9O/xQxPz8vKbW34w4L/pUH6Lv7U5yay6m32LPadeypIE2VZ8xyePMx9387JasintwyJuRwRmaOq/at6L8hJAavqEFo5a8WyjdtQZCwwFiA7O5v8/PyYAwnfSXy3qScffH8miHJxp6fYXVZOcXFxzOVUZXdZOV9vOYwujQtolLGDdg2Lfny9rmWHyzmmVT5Tvj+NV1ZezMCWn9Eko8Sz2AHObf8i2/Y0IyOt/MfXvSr78CzXRWZ+cT86NF7p6Xkp1zRKK+rTMH3nT173onyAdg2hvFw9Ky9sd1k5TTO20iBtB+t3tf3J616ddxHo2HiFp2WHy+ne9Bu6NVnM+2tHcPLBk0iTCk9jv677vazfnU2D9F0/vu5V2aM7/Z2CbT14bOkNjD/817RpsM6T87JrTzkPL/0dinBLr9vJqrf5x+N6EXtaFVfKouKdtboORhPkHcVRwB9VdVjo+a0Aqnp3xDZPAvmq+nLo+RIgT1XXRis73jsKgB+mHsq22V3IyltMr2Fra5WRq3LkDTOY/8gAGvVcQ6vTv/rx9dpm++qEYy9d14y1zx9L074raPFfizwpP/K8RPK67DXPHE96491kj5rp6XlZ9k0m3z9/HK3PmUWjQ9Z7Fnuk/Px88vLyPCsP9p6btc8dS1qj3WT/3PUh9uq8r1pbxuZph9JswDLqtS7xrOzI2Ld/czAb3+pH67Nn06j7Ok/KP+rP+awp2b7PmCOvP497ihvy/XPHkXXCN/Q8cYNn52XFd2lUlGZQv+2WH19Ppr/TaHcUQbZRzAK6iUhnEakHjAIqz/7zNjAm1PtpMLClpiQRj98N60HDzHQADhqymEY911CcfyiDKo6oU7nFxbBhYj/S6pWRdcLeqV8bZqbzu2E96lR2WDj2etlbaXL4KrbN7UjalmaelH/pEYey5f96U7at/o+veRV75Dlvctgq6rUr9vy8pG11gycymrs/Ii/LT6TwuWl56le0HPY14O15L1+VzfYF7dE96Z6WHS6/YWY6jbqvI73ZDrbO6uxZ+S0X9WfDy0eh5XszRSI+j5lZO2k3Np82A4vqXPauXfDcc3DTyT1odvCunySJRMTuddlhgSUKVS0DrgUmA4uB11R1oYhcJSJXhTabBCwDCoC/AwkZgnTWkTncPbIPOVkNEYHDLvyWn/XbzaLpLeLuLldW5gbIrC/K5I4Ht9IxNw3BZfm7R/bhrCO9md0vMvas45fQ9ewl3Ht5F0/K//ajtmyd14HsJo08jz0y7mYDVtD7zFWen5e8tm4ujMys7Z6f90QKn5vOPfaQ2Xyn5+e9e2k3MhqXUq/tloR9HnNbNKD54O9o0WEHfz6j7uUvWAAf/LsJJwyuR27LBkDiPo8CdGiXzt0j+9B6Rw7vvBNfmWVlrtvtpZdCTtne8hMde0I+69V1h0rln3i6x4ZNmzZNVVWLi1V37XKvxdOVddw4VVB9+um4Q6m1cOyq8cUcaeNG1SZNVM8/v27lxGLatGlaWqr63Xfeljt6tGpOjrdlVhZ5zr22dq3q/ferLl/uXZnl5aqtWqn+4heJjd1LFRWqxx2n2rKl+1yq+hN7RYXqsceqNm2qOmtW7fbds0d1zBh3DXjwwZ++l6znnSTtHpvUmjd3axhs3eoGt9R2TqIrr3TzIl1+eULCi+qNN9yo3h074i/j3nvdFMe33+5dXNGcf37805ZXZ9Gi4EbcemHjRjd47bPPvCtz9mxXrtfnujqqbnBZXdZRefFFN3J5/Hh/V9ETcfMrtWoFJ50U+9Qku3bBeee5Qap33rl31udUZomiBqWlbvqKM85w8ytFmzxs61b3wSgrg7Ztg/uAtG7t5o2555749l+/3o0gHzXKvwvtCSe4kd/h1ei88KtfxT6baDLq1s1NdbJ4sXdlrl/vFsU6+WTvyoymqMhdZOP9LKq60d4DB8Jll3kbWyxyc12ia97cfUbfeKPmfebMgXfecQuO3XZb4mP0gyWKGrRq5SY6u/BCGDfOfWAnT/7pNqWlbhbYXr3cOtczZgQS6o+OP95d5O+5J76LTEWF23/cOO9jq84pp7jHyue2Li67DM45x7vy/Fa/vpt6xMtEMXy4m5W2VSvvyowmNxeuuMJd7L/5pvb7i7ipKl57LbiFpzp2hM8/dzO8Tp9e9Tbr18Obb7rfjznGfekJYu3zRLFEEYMmTdxt5Esvudv2yNk2hw51f3RjxrjH//wHjj02uFjD7r/fxT16dO0nTTv4YHjmGTcVs1+6d3d/kB984E1533/vLkxBTh/thUMPje8CW5U9e4JZWOhPf3JTp994Y+32W7jQVZ82bOg+G0Fq2xby8+Evf3HP33vP/X2cdJIbHZ2T476UhCehDK8psr+wRBEjEbfYzpIl7iIalpkJv/iFu8DNneumAE8GBx/sZpecM8d9qGNRVuZmo/3yy4SGViURd1fx0UfuDq2uXnjBXWS3bq17WUE69FA34ZsXCe/VV90Fb8WKupdVG23auGm8J02KfaXBTZvc5+GCCxIbW23Ur793Ak5VV4NQUuKqem++2SW2Qw4JNsZECXJkdkpq0GDvmrvg3TfgRDjnHNd4Get01Xfe6RZROvZYOOKIhIZWpeuuc1V86ek1b1uTRYvcRfGgg+peVpBuucVVAXpxTt5/3z0GsfDN9de7dR9iEV6edf16/zpT1Nbw4e7nQGGJYj8XThIzZriLTXVTSk+Y4KoIxowJ7luclw3nixZ5s8BS0LKyvCmnvNy1/5x+ejB1/RkZ7ktVeFS1atWrOlZUuB6DH33kBqr1r3KcsPGbVT0dAPbscQ27Q4ZUvabxa6+5b/KDB7tGxyDNmlX3FdcqKvafRKHqVj3717/qVs6sWa46x69usVUJJ4ZnnnFdztet23ebO++EZ591VVUXX+xreCYKSxQHgMxMt6Jely6um+/Ike7CEx5n8fzz7pvbu++6RscgTZ3q6nvXrIm/jOXLXd3xYYd5F1dQRGDiRHj99bqV8/777k7Cr26x0TRv7hJX795wxx2ut1C4XWzMGLjvPve6SR6WKA4QOTlu+cRx41x339Gj9zZqPvOMu0C38Ha27LiEv/HGWp9dlexstxZxuMttqjviCDcupi6GDXPdpZPh//jcc2HmTNdb6I9/dF9cwneRnTrBb38bZHSmKpYoDiD167s/zO+/d+tVh7scHnywey8ZHHaYi6cunQSaNIEzz/R22dYgHXmkWxf5hx/iL+Poo90668miTx/XZrJhg+st6Nc62yY+ligOQJmZruG4tuv0+iHcTfbDD13vl3i88Ybr7bW/OPJI9xhvt+W5c11nhoBWFIiqVSv378vODjoSE40lCpN0wlVG8UznoQpXXw2PPuptTEE64gg3x9GmTfHtf/fdqT1C3QTPuseapDNypKvHjmfswJo1rjqjb1/v4wpK69bu31RVd9KalJa6Kp5Ro+Lb3xiwRGGSUGZm/PvOnOke97f+9/Fe5KdPh23bXG83Y+JlVU8mKX3wAfTsWXVf+2g+/dQ1zO9PdxTgzkevXrU/H+++62YTGDo0MXGZA4MlCpOU2rVz82q99Vbt9vviCzf6PFl6cXmlaVM3i+znn9duv2nT3EDLoMfHmNRmicIkpT593BTbEybUbr8pU9xCN/ubfv2gXj13x1QbM2e6ySGNqQtLFCYpibhG7alTYfPm2Pdr0CCYSe8SrUED1+5S20TRoMH+M57EBMcShUla55zjxlJUNT9VVZ5+2q0olozjBbxwwglu6otYpk5XhbPOctOtG1NXlihM0howwI2J6No1tu2fecathra/dgMdMcLN7BtLovj6a9e+U1KS+LjM/s+6x5qklZbm1seIxebNriF7f1mjuCqDBrmfWLzyijt/NtDOeMHuKEzS+/bb6tcqDnv/fTe9+P4yEWB1VN3SqNGq18rK3FoOw4a51eWMqStLFCbpXXIJXHVV9Ivjq6+6GXKTZSnaRHn1Vbc86hdfVL/Ne++5EepXXulfXGb/FkiiEJEWIjJFRJaGHvdZsFJE2ovINBFZLCILReT6IGI1wbv8cjeGYOrUqt9XhWbNXEIJYvU2P512muvJFK2Ruk0buOgit5qdMV4I6s/qFmCqqnYDpoaeV1YG3KiqhwKDgWtEZD9Ys8zU1kUXufWv77676vdF3IXzzjv9jSsIzZq5Ru2XX9678FRlRx3lFqbKsBZI45GgEsUI4PnQ788DZ1XeQFXXqurc0O/bgMVAjl8BmuTRoIFbzOajj/ZtqygvhwULgokrKNdc49ameOaZfd97/HEoKvI/JrN/Ew2g07mIFKtqVsTzzaq6T/VTxPudgOlAb1WtsnOgiIwFxgJkZ2f3e+WVV+KKraSkhCZNmsS1b9BSNfZY4t65M40rrhjAuecWcvbZe6+EEye248EHu/PQQ/Po02dLokPdR1Dn/Ne/PoLycuGRR+b92B34k09a8Yc/9ObKK79j1KjVNZaRqp8XsNgT4cQTT5yjqlVPp6mqCfkB/g/4uoqfEUBxpW03RymnCTAHGBnrsfv166fxmjZtWtz7Bi1VY4817p079/5eVqY6Y4Zq48aqQ4eqVlQkJraaBHXOlyxRLS7e+3z2bNWsLNUjjlAtLY2tjFT9vKha7IkAzNZqrqkJq8VU1f+q7j0RWScibVV1rYi0BdZXs10m8AbwoqrWctYfs79p0MA9TpkC553nBp516ODaJ/bXQXbV6d7dPZaVwTHHuBHbubnw5pt1m6bdmKoE1UbxNnBx6PeLgX3mCBURAZ4BFqvq33yMzSS5+vVdorjtNrfMZ9u2QUcUnLVr3QSKt9/uzkWnTkFHZPZHQfWLGA+8JiKXA6uA8wBEpB3wtKqeBhwDjAYWiMiXof3+W1UnBRCvSSLHH+9+DLRv7+a4MiaRAkkUqroJ2GcpFVVdA5wW+v0/wAFWoWCMMclnPx+eZIwxpq4sURhjjInKEoUxxpioLFEYY4yJyhKFMcaYqCxRGGOMicoShTHGmKgCmRQw0URkA7Ayzt1bARs9DMdPqRp7qsYNFntQLHbvdVTV1lW9sV8miroQkdla3QyKSS5VY0/VuMFiD4rF7i+rejLGGBOVJQpjjDFRWaLY11NBB1AHqRp7qsYNFntQLHYfWRuFMcaYqOyOwhhjTFSWKIwxxkRliSJERE4RkSUiUiAitwQdT6xEpL2ITBORxSKyUESuDzqm2hKRdBGZJyLvBh1LbYhIloi8LiLfhM7/UUHHFCsRuSH0eflaRF4WkQZBx1QdEXlWRNaLyNcRr7UQkSkisjT0eFCQMValmrjvDX1evhKRN0UkK8AQY2aJAnehAh4FTgV6AReISK9go4pZGXCjqh4KDAauSaHYw64HFgcdRBweBD5Q1Z7A4aTIv0FEcoBfA/1VtTeQDowKNqqongNOqfTaLcBUVe0GTA09TzbPsW/cU4DeqnoY8C1wq99BxcMShTMQKFDVZapaCrwCjAg4ppio6lpVnRv6fRvuYpUTbFSxE5Fc4HQgpRb0FJFmwPG4dd1R1VJVLQ40qNrJABqKSAbQCFgTcDzVUtXpwA+VXh4BPB/6/XngLD9jikVVcavqh6paFno6A8j1PbA4WKJwcoDVEc8LSaGLbZiIdAKOBGYGHEptPAD8HqgIOI7a6gJsAP4RqjZ7WkQaBx1ULFS1CPhf3Hr1a4EtqvphsFHVWraqrgX3ZQloE3A88bgMeD/oIGJhicKpam3ulOo3LCJNgDeA36jq1qDjiYWIDAfWq+qcoGOJQwbQF3hcVY8EtpOc1R/7CNXnjwA6A+2AxiLyi2CjOrCIyG24auMXg44lFpYonEKgfcTzXJL4VrwyEcnEJYkXVXVC0PHUwjHAmSKyAlfdN0RE/hVsSDErBApVNXz39joucaSC/wKWq+oGVd0DTACODjim2lonIm0BQo/rA44nZiJyMTAcuEhTZCCbJQpnFtBNRDqLSD1cw97bAccUExERXD35YlX9W9Dx1Iaq3qqquaraCXfOP1LVlPhmq6rfA6tFpEfopaHAogBDqo1VwGARaRT6/AwlRRriI7wNXBz6/WLgrQBjiZmInALcDJypqjuCjidWliiAUOPStcBk3B/Ma6q6MNioYnYMMBr3bfzL0M9pQQd1gLgOeFFEvgKOAO4KNpzYhO6CXgfmAgtw14GknVZCRF4GPgd6iEihiFwOjAdOEpGlwEmh50mlmrgfAZoCU0J/q08EGmSMbAoPY4wxUdkdhTHGmKgsURhjjInKEoUxxpioLFEYY4yJyhKFMcaYqCxRGBMnESkPdXFcKCLzReS3IhL1b0pEOkXOJmpMKsgIOgBjUthOVT0CQETaAC8BzYFxQQZljNfsjsIYD6jqemAscK046aG1B2aF1h64svI+obuLT0Rkbujn6NDrL4jIiIjtXhSRM/371xjzU3ZHYYxHVHVZqOqpDW7SvS2qOkBE6gOfisiH/HSyyfXASaq6S0S6AS8D/XFTrt8AvCUizXHzMF2MMQGxRGGMt8IzEZ8MHCYi54aeNwe64RarCcsEHhGRI4ByoDuAqn4sIo+GqrNGAm9ErGFgjO8sURjjERHpgrvgr8cljOtUdXKlbTpFPL0BWIdbHS8N2BXx3gvARbjJEi9LXNTG1MzaKIzxgIi0Bp4AHglNHT0ZuDo0BTwi0r2KhY2aA2tVtQI3sWN6xHvPAb8BSKEJKs1+yu4ojIlfQxH5EleFVIa7CwhP9f400AmYG5rKewP7Ltf5GPCGiJwHTMMtfgSAqq4TkcXAxMSFb0xsbPZYY5KQiDTCTQHeV1W3BB2PObBZ1ZMxSUZE/gv4BnjYkoRJBnZHYYwxJiq7ozDGGBOVJQpjjDFRWaIwxhgTlSUKY4wxUVmiMMYYE9X/AzVr+CsoOnqrAAAAAElFTkSuQmCC\n", "text/plain": [ "
" ] @@ -272,11 +259,20 @@ "needs_background": "light" }, "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ "\n", - "delay = 5.2\n", + "delay = 6\n", "ampl = 1\n", "print(f\"Tap with amplitude={ampl}, delay={delay}\")\n", " \n", @@ -290,23 +286,27 @@ "\n", "h = ampl*(np.sinc(samples-delay)) #sinc\n", "\n", - "h[0] = 1\n", + "#h[0] = 1\n", "\n", "print(h)\n", - "\n", - "plt.stem(samples, h)\n", - "plt.show()\n" + "t1 =np.arange(0.0,order, 0.01)\n", + "plt.grid(True)\n", + "plt.stem(samples, h,linefmt='C0-')\n", + "plt.plot(t1,np.sinc(t1-delay),'b--')\n", + "plt.xlabel('Delay')\n", + "plt.ylabel('Amplitude')\n", + "plt.show()\n", + "plt.savefig(\"ganzzahliges_D.png\")\n" ] }, { "cell_type": "code", - "execution_count": 12, - "id": "c89c83ae", + "execution_count": 25, "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -319,16 +319,16 @@ { "data": { "text/plain": [ - "[]" + "[]" ] }, - "execution_count": 12, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXwAAAD7CAYAAABpJS8eAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAABNSUlEQVR4nO29e4yk13Uf+Dv17K6q7pl+DR9DzvTwYXllJZSUWUqyjEB27FgSlKUdxID0x8YIDHBtSIIXu/lDm+zGiwUWyP6RXSCR11puVrC8SaRVIFNiYkaybCdQgsCSSIqSSEqUhuQM2TPDmel316PrefePr25VdfVX9d3Hufer6b4/YDDd1dV96tzv3N8599x7zyEhBAICAgICTj4yaX+AgICAgAA/CIQfEBAQcEoQCD8gICDglCAQfkBAQMApQSD8gICAgFOCQPgBAQEBpwQshE9Enyei20T00oSff4iI9ojoxf6/f8QhNyAgICBAHTmmv/OHAD4L4I+mvOc/CiE+xiQvICAgIEATLIQvhPgWEa1z/K1RrK6uivV19j8bEBAQcGLx/PPPbwoh1uJ+xhXhq+ADRPR9ADcA/H0hxMtJv7C+vo7nnnvO/ScLCAgIOCEgomuTfuaL8F8AcFEIUSWijwL4KoBH495IRE8CeBIALly44OnjBQQEBJx8eDmlI4TYF0JU+18/CyBPRKsT3vuUEOKyEOLy2lrsqiQgICAgwABeCJ+I7iUi6n/9eF/ulg/ZAQEBAQERWFI6RPRFAB8CsEpEGwB+D0AeAIQQnwPwdwD8DhF1ADQAfFyEMp0BAQEBXsF1SucTCT//LKJjmwEBAQEBKSHctA0ICAg4JQiEHxAQEHBKEAjfM4QQePGtXXz5ubfgaxtDCIHvvbmDf+1Z5vPXdvCV5ze8yBvK3MYfv+BX5nNXt/HV7133KvM7b2zjay/6lfnt17e8y/zL17fwb75/w6vM//zaJv7tD/zJ9AmfF69mDq++fYA3Nqt4x72LuLRa9iLzHzz9Er74nTcBAI89cBbvuHfBuczPfOWH+P+eewsA8J4LS3jkXMW5zL//r3+Ar/SJ970Xl7yM73/35e/j6T7xXr64jAsrJecyf/dLL+KZPiFdXl/CA0vuZX7qX30Pf/LDmwCAxy8t474z885l/s6/eAFff/ltAMAHHlrBucU55zKf/H+fxzdfuQUA+PmHV7BSKTqX+VtfeA5/8ePbAIBfeGQVZ0sF5zJ94lRH+L/7pe/ht//FC/ilf/IfcH234UXmsz+8iZ/tk/xPbx84lyeEOCLziieZ/+6lET1vuZfZ6wnvY9vtCXz9pbdHxrbqXGan28M3XvYrs9Xp4U9f8SvzsN3Fn/3olleZjVYXf/Hj215l+sapJXwhBK5u1fDYA2cgBPDS9T3nMnfrLew12vjYX70PRH4MarvWwkGzg4/91fsA+JF556CJequLv/XY/ZHMO+5l3jo4RLPTG8r0oOfNvQZaXb8yr+820OkJrzI3duroCXh9nhs7dQjPMq9t1wDA69j6xqkl/O1aC4ftHn71XfeCKErvuMbVrToA4B33LuKBpXkvBiVl/tz9Z3D/mTmvMt91/gzuWSz6kbkZyXzsgbNYrfiRea2v53svLGGplMdrHkhJju3li0tYnMt51fN9l5ZRKfqRKZ/nBx5ewXw+61XmBx9ZRTGXCYR/krCxE6VwHj23gAvLJT+EvxlFEOsrJTyyVvFkxJHMiyslPHyu4iVSOqLnuQpe8+Jkhno+cq7sRc83pJ6rkZ4+n+el1bI3mUM9y5ENeXyeD62W8fC5sl+Za2U8tOZnrvjGqSf8B5bm8Y57FvDjt/edy7y6VQMR8OByRBBvbNbQ7bk9NXNtq4YMAQ8sSfKtoedY5tWtGnIZwvmz83hkrYLX7tScnw66ulVDIZvB/WfnB07GtcxrWzUUcxncszDnj/C3aigVslhbKEZ63qk5l3ltq4aFYg4r5UL/efrR88x8HmdLfZleVjI1rJQLWJzL98c2EP6JwcZOtHw7vzSPn713AVe36jhsd53KvLZVx/1n5jGXz+LhtQqanR6u77jdLL66VccDSyUUchk8cq6CRruLm/uHTmVe26rjweUSctlIZrXZwa39pluZm3U8uDyPbIbw8FoF+4cd3Km6lXl1q471lTIyfZk79Ta2HMu8tlXHxZUyiAiPnKtgs9rEXr3tVObVrTourpZARHj4XBm39pvYP3Qr89pWHev9k12PnKvgxt4has2OU5lXN+u42D/Z9chaBRs7Deec4BunmPAbODOfx+JcHu+4dxHdnnAeob2xWRsaVP9o5JU7blNJV7dqR4wYcL8ZNarnw+f8yLy6VcP6ypAgvMiMe54eZK6nYkP9se3bkOuI+40YPV1H3OM2JIR7mb5xigm/jgeWovPL8iy86zz+ta3akagFcEsQQoj+xPEr81os+bobW3nianxsXZJSrydwbbt+/Hk6JIhOt4e3dkZkrrk/Ptju9rCx08AljzbU7HRxY7cxdDIeZB62u7i5d+h1fqaBU0z4DZw/GxH++kqU8viJw/Pie/U2durtQdRytlTA2VJ+cALCBXbrbRwcdgZR6EqliIW5HN7ccpf33ay2UGt1B3quVYqoFHO4tu1Oz9sHTRy2ewOZ9y7OYS6fcTq2b+8fotXpDcb2/jPzKOQyeNOhzJt7h2h3xUDP80vzyGfJqZ7Xdxro9sRAzwvLJWQIeNPh89zYaaAnMNBTEr9LPaU+Us/11eh/l88zDZxKwhdC4PpuY3ArMpfN4N7FObztMLc9PEUyvHG6Wiliu9ZyJvONreGJDom1ShFbDmUO9OzLJCKsVApu9dw8OrZEhJWy27EdnJbpy8xkCCvlgtOxHdczmyEslRyP7dbwhA4QzZWlkls9r24elZnPZnC2lPdiQ3JlWsxlsTCXc6pnGjiVhL9Tb6Pe6g5SOgCwXHY7caQzkasKAFh2PHFu7UUyR6/eL7nWc++4nq5J6VZ/bO8/e/R5uhxb+Tzv86hnrA051lPa0OjYLpUL2K661/P+M0fnSho25FJmGjiVhC9P6Pgk/J3+314qD2tzuJa5XW8N5PiSudOXuTRSg2SlXMCWQ4KQ+vjUcyBzVM+KW/JN1YZKHm1ooGf+iMytmrsTUFKfpdJRmYHwTwBu7B6PfJfLhYGhuUDsxHGc6pD6nB0xYtdph+0YmT4Iggg4M39UT9eOLZshLMwN6w/6sKFCNoNyIXtEpuuxnctnMD8ic8U5+bZRLmRRzB3Vc6fm7ijoTq2FxbkcctkhJbqeK2ngVBK+PJ99bnFYfU8ujV1d1tmtt2Mnzm695ezy1U49mjhz+fGJ41bPxbkc8iMTZ7lSwHbdncydehtn5/PIZmgo0znht7FUyiPjUeZurY2lch799tAAfDi29pEgBejbkMOz/7v11pFVDOBh9VRvH1khAu4deBo4nYS/fwiiaLJILJcLaHZ6aDi6aLFdax1Jc0iZPQHsNdxMnp3a8YmzXC6g0xPYP3RziWU7TmapgFanh1rL0djWY8a2UkCj3UXDkcyduOdZKqDa7KDZ8afnUrmAvUYb7W7PicydWutYieCVcgE7DgOV7XrrGPkulSKZrm6J79SP6yn3u05S++1TSfi3D5pYKRePLN9kFOMq1xxLEH2j3na0PI4lwoFMR3pOk+lybMcjwv73rlIPsQ68Uuh/HocOPIZ8geHeCTfiyHe5XIAQUSTuAnFOZrlcQLcncOAwUBnXc6VcQKvbQ9XxDV+fOLWEf27haDMF10Q4aeIAjp3MBJmunMxOjJ4rFf/kK7936thGNhUB904mbmyXy5EdO9MzxoaWfMyV0tjYOrah3Xo7JlBxO7Zp4JQS/uGR/D0wYsSOopbdevvIRiYwJF9X0VmUfx0nJWnErqLQOD2L/c/jbmyXJhCEO8KPy/k6Jt8pNuRS5rGxdaxntFfhd2yjoCHegQfCv8txe/94hL/iOO0Qv2SMPoOrzaj46Czf/zzuou1jm3wO02VCiAmrJ3cEIYSYkKKTY8svs9cT2J2ySnQhs9PtYa8RF/m6k9nq9HDQ7Ey2IQcyD9tdNNpd7yuZNHDqCL/bE9iqtXBu4WhPziWH0fakiTMgXwdEKCfO8ZyvOyczaeIsO4y2660uWp3elNQVv8yDZgednvCaAtg/bKMn4JV8d/uHCSan6BzI7M+/sxNsyMWpmZ2Y+yrAaIouEP5di+1adLpgbSzCX5zLIZchJw93b8LEKeayWCi6ub692zh+SQcA5gtZzOezTpzMpIlTLmRRyGWckNJOzP0GwO3z3O2nw8bH9ux8HhlyQ75xl8uA4UUhF6snSb7HIl+H+yPyuOf483RJvsNLV34POKSBU0f4tw+iS1fjKR0iwpKjc7eSlMbzr0A0mVysKuRJkfGJA/TPizuQGXdbEZC1bdycF5d6jo+ty+c5vMF8VGamX9vGBSlNsqFcv86MCxuS+zzjz7OQy2ChmHPq2MY3xOfyWZQKWac2NK5nqZBFMZc5UWfxTyHhH790JeHqZp2cOOPRmXzN58RxKXO3LifOcT1d1ZmJKx8h4ep57kyICAG4Cxqm2ZAjJzMp8gXc3RKftEqUn8NnSoeInNcq8g0WwieizxPRbSJ6acLPiYj+KRFdIaIfENF7OeSa4E6/89J4Dh9wZ1DTJo6rOjNxNW0kXDuZWPJ1dFMyrr6MhHNnOmFsnZBv0vP0mKIbyPQ9V1zZ0ITUFXDy6ulwRfh/CODDU37+EQCP9v89CeAPmORqQ6Z0xnP4gLuoZVIuFHBnUNMmq2snM35pRn4Ol3r6dGzTCMJd6io9G5oYqLjctI1Jf7p2Mmfn42WGCH8MQohvAdie8pYnAPyRiPCXAM4S0X0csnVx+6CJxbnckfoyEsslR7ntCRuLwNDJcF/fjiucNpDpOZ/uVubxwmkSkWPjP34qC6ctjhROk3BHvu1jhdMkXK6exus/SUR68o/tdq2NSjF3pHDaUZluUpHjhdMkVhzpmRZ85fDPA3hr5PuN/mte0e0JvPr2Ac4tHk/nAJFB7dbb6DDXJZk2cZZK0fVt7ho+0ybOUjmqM8Nd82Wn3jpWOG0gs19nhrvmy3a9daxwmsTZUgH7hx32mi/bteiI7WgRM4mlUlQQz4UDHy+cJnG2VMBeg1/mdu144TSJSE/+y3txN5iPynQT4cethIFobF3omRZ8Ef5xKwVirZOIniSi54jouTt37rB9gF5P4NNffAHffmMbTzx2f+x7ZGTKXa9jJ+batoQsr8stc7feio20XcqMK5w2LrOawthy10LZrR+/lTkqsyei+wGciKuLNCqz3RVodnid6W5MQbFRmc1ODy1mmXG1mEZl1lpddgceVzhNYnEuh2qz46xom2/4IvwNAA+OfP8AgBtxbxRCPCWEuCyEuLy2tsb2AV65uY9nf/g2Pv1Lj+DTf+PR2PcszDki/JhiUMdl8kYRSQQRyeQmXxU9XYxtPPkuuhrbmFu2Eq70nO7Ao9f3XdjQhGjbld2qzBX+oGGaA89DCKDWOhkF1HwR/jMA/m7/tM77AewJIW56kg0AeKvfpPjD77p34nskEXJPnIPDTmy+FwAWilImr0EdHHawOD9JppvJOlVPl2Mbk78HgIojxzZ1bAcyXYztJMfmUM8JMitFlzJnx4ZcBUdpIX5kNUFEXwTwIQCrRLQB4PcA5AFACPE5AM8C+CiAKwDqAP4eh1wdbOw0AGDQuDwOi44ipWqzg/vOxO8buDKoWrODlXK8rq6IsDZNT0cEUWt2cGElXk9nY9vqoFyMnzqVOTcOvNrsDEj2mEyHYztJT1djO01PlzaU9DwD4Y9ACPGJhJ8LAJ/kkGWKjZ06FuZysac5JNIgCFdL46kTx1EUOp0gHOpZ8Ctzmp6LJ21sPcs8LXqmhVNz0/atncbU6B4Yzfne/ZHSdFKSKxmP0VkKeqYShTqzoa5XPYUQ/bE9fsprVCanDfV6ArWWXz073R4O2z2UJwYNJyvCPzWEv7FTxwNL81PfI/Oy+8wtByOCmD5x+COlFAii1U0kCE49JUH4HNs0CKLV6aHV7XnV87DdQ08gMWjglFnvH01O1LPJJ1O23Zxkt4uO9g3SwqkgfCEENnYaeDAhwneRC+32BA7bPZQmEES5kAMR78kDSRBxl3SAoZ6cMpudHro9MVHPwQkLxiOS8u5CKYmUGGVKUprs2BwQYf+ESNLYctqtPJWS5Ng4n2e96V9PObZJaaST0ubwVBD+Tr2NequbGOHnshmUClnWySonzqQUQCZDqBRzrEvjJCN2omdzup6FXAbFXIaXlJrT9SzmMshnyavMciGLDPGSUjVhbF0EKkl6utjMTNLTxeopSc+Q0rkLsbETHclMInwgigo5l29JBgVEpw98ThwgMmTeiSMj32ky86yObahnfLRNFDlTF45tkp5uZE4f22xGyvQ3tvlsBnP5jFc95/JZFLIZ1vlZbU5PI83ns8hmKGza3k1QOZIpwU+EkiDiDSqSmfc6cQYyGXOhSQQBRPlQJ3pOSAEAcmw5iXA6QbiRqWJDfp1MJDMtPR3Mzwk2RETsMtPEqSB8eenqvEKE7yry9Rpty5yvx4mTlGd2IbOWkLpyITMpzyxl+kzRSZlObMjj86wn7Bu4kKm0Ag+Ef3dhY6eBxYQz+BKL825SOokTh/PkgVJKx016JTki9JwuY458VdJli3N5VB08z8SVTCo2xD+2STZUdbDHNj3lymu3aeJUEP6t/UPcdyY5ugfcLVOTJo7PZWok000KwOdKRiWNxD62KUTb1TRWiQrplcUTsBquNqefupIyue+spIVTQfh3qs3YhidxYCfCVvLESYUgmDf5VAiCe2NRLc/snyAqKZAv/6atKvm6WLH5tCH/BxzSxOkg/AN1wl+cy2O/4TtqiZaMXPXM68pOxm+qgzulo5Lb5j51VVcmCP+pDtaxVUlFFt2snqanP/nTgkTRaRxfMtPEiSd8IYQW4S/M5dDq9nDI1JBkkMNPIAjOeuaqBHHY7rE1JFHdtOWsZy71LE2drFE9cy5nqk4QfDLrrQ6yGUIxN3m6cqdXqq0OCtkMClNkyrHlQq3ZGRyDnCaTe5UYXX6cLjNcvLpLcNDsoNnpYa2iGuHzXrSoKZISt8wkguBuSFJtdpUIInovn55z+UxsazqJSjHXr2fO48CrigTR6d+w5kBEStlEmZwNSabV0ZGozOVQb3XZOsRVp5QDkVicy6Ha4mtIoqKndDLcHcXSwIkn/DsHUT9K5ZTOPG+J5Gp/smYSohaA7zq+GkHwXlNXmTjc9Veqze7U1ArAX+pAjSC49ZxcrM2VzGm1mMZlcjrwaRvwUqYQ0QqEA9UplWxHZXZ7gr0NaRoIhD8GF9F2okEVeclXjSB4i0Ip6ZnG2DLLVCGIYcGtu1hPDRu6m59nLQU900Qg/DGwR0ot/wZVb3Wm7hm4kFltdqYeA41k8jq2eqszdc8gksm7eqor6ckrs9pUeZ4uxjZpxcYcNLR0bIgvUEnS8yTVxD89hK+cw++ndJhO6tSanak3XgEXKQCVXCivzPqU0sgSLohQJQUAcEbbKnpyk+/kEtBDmdxjq57S4Yu2dWyIT6b6ajhE+DOPO9Um8lma2AB6HG7y6WksU/1OnGoqy3G1TT5OmamlOhRtiDONNNspHcZVhWcbShMnn/APmlirFKduYI4ijVwody9dNYLgXxqns4HqWabiJh+nTB0bupvHVm9z2qeTCSmduwa3Nc7gA9ExPiLOVEeyQcllLNtpB4V9g0ETFMYTFsrRGaeeCY5N1m3nOn6qsqpIY2xdyPRtQ/Up7Q0l0gjIXDQMSgsnnvB1Ll0BUTnUciHHe247Ib2S69cWrzPJrDW7ifsGhVwGhWyGTc9aqzuxw5ZEMZdBNkOoN/3pKe8/sOnZ7CTqKX9e49KzlaynJEoOG5LtKpM2MyURcugZyVQY24Ge9uQ77EanJpPLhtJEIPwYlArZwYUpW6ikV4Co0BlXpKSSTwei8skceg4bXk+XSUQoFbIsekqCSIrOMhlie57yLHaSnrls1N2rxkBK7W50mSppJVPod/fiGFvZrjJJz7l8BhkCy9jWW12IKT10JaQDrzI4maRudBJDBx4i/JlGtyewXWsqn9CRqBR5yFeVIIDI0DkMSpUgAD4n0+z00FEgCCAaW58EAfCNrSpByPdwjK1KCWgJLj1V6iIBw9WwTz05HbiqzIEDD4Q/29ipt9ATwHK5oPV7aRAEm0wNguAiX5WKgxLlYo4l8tXV86STL8DnwGdez5Tmykmop3OiCX+vEW28ni3pEn6WJV9XVyjfK1EpZllyofJzJ+0byPdw5Hzl507KhUYyc7x6Ksm8i/WUMhWeZ6WYY9kfGbaO9De28m+ojG2lyLPHVtXSM8e2x5YmTgXhq3S6GkW5wBu1qJBvqeA/8i1zRb46KxnPy3EgGlvOyNerngoloCVKxSyPDWnI5LIhnQifK6VT17Ihnr2ntHE6CF/x0pUE+5JRIZ/OtWRUKY0sweXY0nAyOgTBnbpSTnUwOnCf+wbBho6Dy4bSBgvhE9GHiehVIrpCRJ+J+fmHiGiPiF7s//tHHHKTsFc3jPCLOZ5TAFpGzBv5qudCOZbGmvsGKaxkfOeZ2fcNFDfh07Ah306GzYFrrmROAuEna5oAIsoC+H0AvwJgA8B3iegZIcQrY2/9j0KIj9nK04FpSqfCRb6t5G5XEuw5X6VcKM8yddhqUC3n6zuHH+npN8/M5cBVWioOZfLYUF3ThjgceF1r74nLgevYUA4bO3VrmWmDI8J/HMAVIcTrQogWgC8BeILh71rDlPBLhRwabfvOTCo9OiVk5GvbZEEnOisVcywXWAaRUgpRqGragUNPvTwzzwaqShtHiTIT+eqemOHZKNZ5nlyHKvRy+GHTNsJ5AG+NfL/Rf20cHyCi7xPRvyOin5v0x4joSSJ6joieu3PnjtUH2623US5kkZ/SESkO0tBtSUJnmVoqRJ2ZbJss6CxTK0XZWtFSpiZBNDs96y5JWpu2/RMWtl2StI+8MjjwWT+uyJ7SUQkaGPUkUj91FTZtI8RVJRu38hcAXBRCPAbgnwH46qQ/JoR4SghxWQhxeW1tzeqD7TXa2tE9MHKV2jJy0SMInno6eue2eUoA6BIEh8whQailHQBYR7+6BNHjcODN5HaVElwOXKWfrUS5wOfAk/rZDmQyOXCVdpUSct/gbm9zyEH4GwAeHPn+AQA3Rt8ghNgXQlT7Xz8LIE9Eqwyyp2Kv0R60LNQBVzEzueyc1s92KJOHCOvNrjJBDGXaOpnkfrYSA8dmSb71Vjexn60EmwNv6RAEkw0ptKuU4HLgdYX6TwOZRaagQaFwmgSnA1fXM3LgXH2K0wIH4X8XwKNEdImICgA+DuCZ0TcQ0b3Ut1gierwvd4tB9lTsNVrKdfBHwZXSkYW2pvWzleAj36iDj2rUIn/HBipNXiQGxa8Y9FRZ/gMjRb4YnqdKdA+M6mm/klElQi4bivT0P7Y65AvYF4qrKnTYkuByMmnD+pSOEKJDRJ8C8A0AWQCfF0K8TES/3f/55wD8HQC/Q0QdAA0AHxce1kZ7jTYurZa1f08aOw8RKk7WAt9kVUnnABh8NmvHpjFxyoxjq0qEJaaxVSmlOy7TVk+V8toSZSby1dKT0cmY2NA9FjLrhja0qlmba5ZgTfjAIE3z7Nhrnxv5+rMAPsshSwemOXyusq86E6fMtUzVIIhh2sE+z6yuJ9/+iDoRcqVXdMaWL13mPcJvqUfbnHtP+jbEkC7TXFXc7Ru3J/6mrW4dHWA0L+lvmTpMr9g6mRQIwiDny0MQemNr72QMctsMqQ51PXkcuJYNFdIbW59OhrP2f5o4sYR/2O7isN2zi/Cto+3kfrYSXLntejO5icRAJlPaQSfPzLU/Um91lfPMXE0zdFJXfE5GPZ/Oa0N+00i1lnr6c2BD1hvFOmN7MnL4J5bw9/uXrkxO6XDmJXWXqT7Jl40gNIgwjXw65+a0cs6XMb2ibEMp7I9wpa5qzeR2lRIDG7JePflfDaeNE0v4g9LIJoTP1FVHb9OW63ibyb4Bx3Jcl3w5cvhqK5kSU8cinVRHhY189fPMPM5UcWzZ0p8mNuQvXRYIf8axa1hWAYi66nCUt602u8oGxdUWT4cgirksS1s8HYLgaounFZ0V+JyMOkHwOHC9FZu9A5f9bH068GG7St2xNbchnW50wKgDDzn8mYRppUwJjuvbOqkOgKfCos5yHLDXU7WfrQQRWV9TV+1nK8HRFk+XIDgcuE67SoDHgav2s5WYz2etHXijrd6uEuBx4Do9HAC+gxxp4+QSvkWED9h31en1BOoakRIgC1GZG1Sn20Oz09NyMrZt8XT62UpUinbFzCRBqG64AfI6vrnMQREzTQduQxDyd1XTgoC9DQ3LMatF27KvrY1jq2rqKR04h56qNsTZmD5NnHjCN7lpC/S7B9kY1KCImdrEAWRXHYuoRaOlokS5mLU67VDXKFMsEUXb5jKH9YLUZZZTGFt7G5LltXX0tOvlkIqeTX09bTvE6ZT0ljgJNfFPLOHLHP7CnGFKxzLyNZk4thFhtWVAhEXbiaNeOE3CNnVl5tgsx7ap78DtyVd/bG3r8OsU3xvKtKvDr9PkRcK2x4FOhVcJrl4OaeLEEv5+o42FuZxS9b04WJOv6cS5y8jXnCD86mm7b2BCEFw2pO3YbGxIo7y2xKmxIabeyGnixBJ+dMvWLLoHhiVYTZFmzlc3h59Gntlmf8QsIrTL4Usi9LlvYKonDxHqrWQ49ke0bYjDmXq0oVnAiSX83XrLeMMWiAyeI2rRX46nkX+1Oe1gkmf2vz9in3ZQb1c5lGlnQyZ5Ztv9EdN0mU16pWqQw4+6Xtk4GYOxtdRzFnBiCd+0cJqEfeRrMln955ltm4qbplfs9DQg34It+ZpFvhy5bd1UB4ueWisZ201bUxvi2PjX2zcIm7Yzir1GG2fn9QunSdh21THNp9u0xTMliDSWxjzk619Pr3lmw3w6xxHJWc+np2JDTP2Y08QJJvyOUR0dCdsCaroXO4DI+Gza4tUN8sy2bfFMydemLZ5ZFGrnwE3yzLYO3MSZ2pLvUE+9VSJH6kqlM5wEl5OZ15QZNm1nEEII7DXscvjS4E03bs2iFrvr+CapjpJlDR+TVMdApvHY6qfL5NjWDZ1p1YCUSsWsVVu8WrODDEXlKFRRLmTR7gq0OmYyq80u8llCMaeXurJy4K2OcrvKocyslQOv9ltHqnSjG8gsRjLv5r62J5LwG+0u2l1hRfi2BZqMCMKykqQRQVgWhaq19AnCtsJirdVBMadHEBxjq0sQtjYk6wWptKuUsH6emqU5Ipl2Dlyn8ulQZr/Sq8VqWF/PHLo9gaahM50FnEjCt71lCwyX0TYTp6QdQdg6mY42QVinrowIwm5sTQjCnnwN9GSwIVMitNJTI4U0KtOvk7n7bGgWcCIJf9eycBpgP3FMIgjbyLeuUVBMgmPi6BKE7cTR6UUqwbGS8U6+NjZksffk24ZqTfVGQRJ3owOfBZxIwrctnAbYd9WJSiObLY3N9w26g/y4Kmzb4unUpZcYdqAyH1tdPW3LFUe9DXTH1l5PnRpFwCj5WtiQtp62ezIWNmSjp+exnQUEwp+AQWMHq1SHGUHYpHR0nYzMbZtWHtSpSz+UadeT1CTVYbt6MlnJ2DYHMYtC7WQa5dNtU1cm+XRLGzLbN7j72xwGwp8ADvLVOR4J2LfFMyEI66WxQQqAY9NW38nY71XcFfsGHDZkmMO33XsykWmT/jSVGXL4M4ZB8xPLWjqA3w0327Z4aUycNDb57ppNWwbHdir0bKr3sz0m09CB67SrlODq35smTibhN9rIZggLmg90FPI4pWm+Trf5CWCfw6+3THK+9mfiTXPbpjLrFjl845xvS711pESlYKenTZ7ZeB/IQE9bG6rb2JDN3pPp2IYc/mxhr9HG4pze8cRx2LbF0+nzKjHoquMxOitkM8hlzNvimUTbtn1tbU5Y+DyuaJvDN9uTMc9t67arlLCJfHXbVUrYjK1uu0oJ232DWcCJJPxdy8JpEja1xU0IArC7pm5CELLHrOmmrUkuVLbFMyYlA4KwceAm7SoBIJ/NoGDowGU/W12ZxVzkwE1kynaVumM7n8+CDB14o91FT6OfrYSNA68blD0B7FNXswAWwieiDxPRq0R0hYg+E/NzIqJ/2v/5D4jovRxyJ8G2UqZERL76yzdJEDp1VyRM28UN+tkayDTVs9mJbjTrThzAvBaKKUEA5m3xTOoiSZg68PqgfISZAzcZ22GNIr2VqY0DNykjDgDZDGE+bzZXTEpAA0MHXj3Np3SIKAvg9wF8BMA7AXyCiN459raPAHi0/+9JAH9gK3ca9hptnCmZV8qUMC37Kq9766Z0ANlVR598ay0zI45+x3LiaBLEUKaBnga10yVM2+LVUxhbk3aVEqYOPA096xbP03QFblJGXMK2wcworu828L99/cc4OGyz/D0VmO9qDvE4gCtCiNcBgIi+BOAJAK+MvOcJAH8koqpDf0lEZ4noPiHETQb5x7DfaOPCcsn675jWpzcpnCZh2lXHNDoDLCLfpn4FSQnTyTqQaZAuM01d2RBEuWDW3ctGz1Iha2RDptG2/B0TPatWz9M0aNCvQipRKmTZNm0/+xdX8MXvvIlvv76FcwtzePXWAX7rFy7h/rNzODjs4Il3n2eRMwoOwj8P4K2R7zcAvE/hPecBOCH8qNuVvWqVYg63Dw61f8+kprhEuZjDbr2l/Xu2TsZmOW6kp6EztSUlEz1tCMI0vWJrQ1Z6GtqQTXDk04bSmCvjOGx38W9/cAM/e+8CfrCxh2LuAJfWyvgfv/oSAGBxLof/6rH7rQ6exIGD8OM+0Xj9UJX3RG8kehJR2gcXLlzQ/jBCCDywVGKJ8MvFHGqbfqOzcjGLjR3fBJHFnYOm9u8N+vYaktL13Yb279kRRBZ3qvp62jqZPQMHbprDB8zJd2hDJqtEw7SghQ2Zku+wLae/lek4vvnKLRwcdvA/feydOLdQxEqliKVSHt95Yxu5LOGh1Qo72QM8hL8B4MGR7x8AcMPgPQAAIcRTAJ4CgMuXL2sXniYi/JtP/4Lur8WiYtiT1KReu4RpWzy7/KtphG+XTzfK+Rr0IpUoF3O4ulXXl2nQZ0CiUsziuoUDN9PT1IHbOZnru/qrYZs9mXLRzIGb9HAYyswNbvLb4I9f2MD9Z+bwgYdWjlTUfd9DK9Z/exo4Tul8F8CjRHSJiAoAPg7gmbH3PAPg7/ZP67wfwJ6r/D0nygWznK9VFGq5EaV7UQcwb4tnnU/3nGc2TjsYdIGSKBdyRpegrNNINmPr8Xna78mY7xuY2VDW+AjzKH5yq4r3j5G9D1hH+EKIDhF9CsA3AGQBfF4I8TIR/Xb/558D8CyAjwK4AqAO4O/ZyvWBUn8jqtcTWg/Gdplaa0Zt8XSWdDZOxnRz+m7LM99V+XSbdFkKuW3bsTXV07cNmc6Vcewftq1asJqCI6UDIcSziEh99LXPjXwtAHySQ5ZPjLbF05nstgQh2+LNa0TrdhtRw7Z4hZz6oq9uOVkP21FbPJ3OVYOxNY58DRy4FRFmDR24ZZ7Z5vSK8VFQ30d7TVds+t3oJDg2bXs9gWqzg4U5FvrVwom8acsF05t1w2WqWV4S0L9BaNLPdijTUE+rfLpZ/ZVBw2uj9IpZX1uTdpUDmSMOXAcm7SolKsUsWv2bujow6WcrUSpkBw5cByb9bCUqxezAgWvJbOq3q5Qo92Xa9LWNGtsjEP6swbTy4DBqMYt8o7+hJ7PeMicI07Kv1WYHuQyhYDRZzfUs5DLIG8g0dWz1pn67SglTG5L1901Oahjr2dIv6S1hWhDPtAQJMFLMTNOBR81szGXa9rU9OIyey+Kc/5ROIPwpGDYHMTAo4wjCrOyrFUEY1oqXhbZMZMoJp7vRZ1IvSMLUyZjU35cY2JDh2JrA9HnajG3Z8Hna6DmwIQNnaqwnQ5vD/f7N2oVA+LMF0/SKDUGYln21IgjDyoN25GvWWtGkk5iEaYs6k3aVEhUrG/KrJ8/Y6qcizeeK4dimYEOjkBF+SOnMGEwjQpNepBKmZV+jVoNmMk2dTN1CpmmkVDVoeD2UefcQRM3CyRgHKhbkOxxbfSdjcgY/kmk4ti1zGzJ1MqOQtXPSOKUTCH8KTNMrdYto23jfwKBksIT5pq3NqsJMz3oaejLkmY1kppC68j22JuW1Jcz32Bj0tLhtGyL8GYVp5GvSalDCJhdqu+FmurFoI9NIT8+TlSVFZ5BPN32edjZku0r0Z0NWenp2bKPYb8gcfiD8mYI0fp+R0rCvrX6e2Xxj0TSNZJ7qKBnm8E06iUmY74+kMLYt+1SHfnrFIqVj6kxt0oIWR5h9p5FGsR9O6cwmTLvqWBGEcQ7fgiCMj9TZbLiZpjoscvhWm9N2TkaXfOtW5Ot/E75stQlvG21rjm3LZlVh17YSiFI6hX47U98IhD8Fpm3xqk39BskSpm3xbCaOaVs8m5XMfD5r1NfW6hifsQP3n8PnOCKpo6dpP9uBTINNeNN2lQOZBmNr2q5SwjT9OYqDwzYWLHtumyIQfgJMGjvYbNoCZsXMbPLMpm3xbPYNZFs8nehMEoRpCkC2xdPJ+dq0qwRGHLiGTNmu0nRspQPX0bPVjfrZGp8uK0R9bXXOxB+2e+gJs8JpgNl9g2GNIlM9zfYNRrF/mE5ZBSAQfiLKmhF+ryeiY18WhK/byafT7eGw3TOOQoFIT53l+LCfrdnEAfT790qCsBtbvfZ/Nu0qBzI1bcimvDYQOdNoZaqup2mf11GZuu05bervA5EDn8vrrYZt9SzkMihkM0YtJCWiCN9//h4IhJ8I3ciXhyD0CjTZ1LQZyNTU03biyN/VaQhtU5ROQrcOv03hNAndYmbDfrZ2q0QtG2LR0//Y6vbv5bAh0/69EgeHHSwydOQzQSD8BOiWt7Wp7z0q02Ti2BmxXhqJa7IaEYTF2OqWt+VxMno2ZFOFVELXhliIsGDmwH3qOejS5nF+juPgsI2FYojwZxK6+XQ28jUxYp/kyxCF6tZtt6kRL6FPvuaF8CRSIV9dPRnGVt9uzSu8DmQaOnCfNjSO/UbI4c8sdLvUc6Q6ZNlXVVQtc74ADHK+ciVjk0YyzTPbydTpQDXoJGY7thoyByWgLcdWT0/zuvRHZKZhQ1oBGc9cMeliJnGQUvMTIBB+InS9uU0vUgntyJch1aGvJ0N0lkIaKY10me7qiSXVYWpDHiNfrpWMSaBiv/FvFuF3+4c6QoQ/o0grn27mZPyR792aZ9bezEwl1eFfTzbynXUHzjS2pjn86qCOTojwZxKjbfFUMGh4bZXzHbbFUwEHQZSLeg2hU9nMZCBf3U1bm1aDEumcmNF0Mgwytce2xZD+1D3RlsLYjmJYCz9E+DMJebyyodhVh4MgZFs81a46gxZ8Fmkk3bZ4LPnXfl/brqIz5cgzV4pZ1NsaDpwpz1zXaIvHsSeje2Fw0OfVcmyN0itWY5sz2qswaVcpUTG4jCkhCT+NOjpAIPxElDSvjNs0gpbQvb7NkUbS1pMhOhv2tdUdWztnKoS6Ax+kyyyPguq0xZP9bOctSKlcyKLV6aGt2GNWtqu0qe9SLubQaHeVHXit2YluBRu0qxzKzPZ7xKrLNO1GJyHLrZj0tR22NwwR/kxCl3w5CEK3LgkHQZjoyUEQgJ6epv1sbWTaEoTJ2Jq2q5Qw0dO0XaWEbilom3pBEtKBq0b5NvWCRmV2DPva7jXSa34CBMJPhG5FPg6C0C37ykkQqhOnzkAQuqTEQxB6Y2tTo2goU09Pm6YgEiZOxnZsTVbDvse21jLvJCZhWukVAHZqLQDAUrlg9RlMEQg/AfoE0bXasI1k6jmZerNrlb+PZOo6GfM2jhK6fW3rra5VjhkYXT2p78nw6alKhBzP08CGbMdWs3RwjeF56o+teZMXCZu+ttv1iPCXS4HwZxJlzep4NnXpBzJ1l8YpRKEc0dmg8qDHKFQ37cCqp+LqiSXa1t0fYVxV6KyGuVYVOmNrPVcKemM7ip1aC/P5LOYtnY4pAuEnQLe2OAdB6C4ZOSaO9r5BCmmHNFIALARhoqflKlHXhrjy6ToyOeeKztj61nMU27U2llNK5wCB8BOhG7VwEoTWxGEiiFQmjsdoW5t8LRp0SGg7cMvy2oDZxr/NyTIgnX0D/f0RhrHV1HMUO/UWlsrpbNgCloRPRMtE9E0i+mn//6UJ77tKRD8koheJ6Dkbmb6hm5est+xzvvL3VXPbNq0GBzL7eqqfdjDvRTouU1nPlnkv0nGZOrltrrHVW7Fxka8/Gypppjoi8vWbw7dpVzmUaZ7D36q1sFwuWsm3gW2E/xkAfy6EeBTAn/e/n4RfFEK8Wwhx2VKmVwxOHqQQharmtm26QI3L1D0ZZCVTM4dv02FrIHNwGklHT98bxR3jDlsSpYED17AhtjSS+mrY9nnq5vA5bEjXsY1ip9bCcukujfABPAHgC/2vvwDg1yz/3sxBtsXzmQuVbfFUa4tzOJliLoOsRl9bjhy+bIvnNc+s2dc2rX0DrjTSrOope+j6TOnY9rOVsD2WmdaRTMCe8O8RQtwEgP7/5ya8TwD4UyJ6noietJTpHTpt8TgmDqBXoImDIKIWdeqOjUNPnbZ4wybbdtG2jgPnaFcJjLTFU3Dgsp+tbbSt48A52lUCeg6co10lMJr+TJY5LJzGdSxTj/BbnR4Omp3UjmQCQOJoE9GfAbg35kf/UEPOB4UQN4joHIBvEtGPhRDfmiDvSQBPAsCFCxc0RLiDalu8Xk+g3rYnCEC9Vny3J6z72Uqo1giJruzbEwQwLBSXhGaHhyAimWpOpsHQrnIoU01PjnaVwKgDT9Zz0OTFowPnIt9cNqPc17bOUA4EMO9ru1NP99IVoED4QohfnvQzIrpFRPcJIW4S0X0Abk/4Gzf6/98moqcBPA4glvCFEE8BeAoALl++rF+swgGiAk3JBtVodyGEXTGogUzFyoPD8r0cpKQos2lfEfSITIWx5ShZMZSZVXqe3HqqVCPlqBckobpK5BzbqDmI37FVDVTSsKFRbPdv2a7cxSmdZwD8Zv/r3wTwtfE3EFGZiBbk1wD+JoCXLOV6hWpTcc7JqkqEnDJLRTU9OUojSyg7Ns6xVZTJradvGyqp2hBD2WkJ1VLQHD0cJFTLMrOOrWZZZiD9sgqAPeH/YwC/QkQ/BfAr/e9BRPcT0bP999wD4D8R0fcBfAfAnwghvm4p1ytU0yusBKGYduCNCFXTDpyOTXds7VcyqqTE0a5SQrUVH6ee+jbkc5VoX0ZcVyZHNzoJkyYog7IKs5zSmQYhxBaAvxHz+g0AH+1//TqAx2zkpI1yMYdrW/XE93ESRKWYxY3dRuL7hq0GedJImwetxPdxEkSlmMON3UMFmbzku1lN1pOTIMrFHPYPNZwMS6pDzYFztKuUUHXgvDaU1XLgPvUcxSDCT3HTNty0VYByRCgjX4YcvuoyddCpiC0XmkJ05jntUFKMzjg6iUmoRoSsqyddG/KZumIc2yjCV9icZl2Z6qd0tgaEf/eewz8VKBXUuuqkuuHGQoSKKR3GDbfIsWmMLYdjK+htFHPpqXLBLI19IN7NTLUDDgMb4nJsvvUsqOk5ip1aC2fm81YNX2wRCF8BFcWuOpzkG+V8k9vi8ebT1ciXc69Ced+APc+s4mT4VjLqaQdOPf2nV1T3DQZpJKYTM7NqQ6PYrqdbOA0IhK8E1a463KkOlbZ4HP1PJSqFnFJfW+6Jo9IWjzPPrOrA2QlCwYHz5tNV0yu8e0+zSr5V5v0R3ZTOdq2ZajoHCISvBNWbdXXGM/GqV+PrjNG2ap0ZXoJQq1VUZ0yvKDvwFq9MFQdeb3VAlu0qJSqFnFJf21rTvl2lhKoDr7Xs+9lKyL2nJGdab9p3o5OQJ4N0+tpuHrSwWkmvcBoQCF8JQ1KaThDcOV8AiZd1ak1GglB0MrVmB1lGggCS9ay2Oij0awzZoqToZGrNDubzWWQZCEK1/gpHu0oJ1bGVXaBYZCo2DOIqQQIMHXhSY/pay75w2qjMTk+gpdgkHgA2q02sLgTCn3kMquMlTdbDaOLwEIRajZCDZgcVJoIYdElKIt9+7R4WmYq1UKqHHVTmeCZrRUdPJplDG0qQeWhfF0liUH46gXwPmh0szPGkGlTb/7HqqWhDB4cdLDA9z7Li85TodHvYrrewFiL82Ydq5MtqUIpRqAuZPvVUjXx5J6uazH0HeqZiQ15lpkC+ik4mjbGV2K61IARChH83QHniNNvskVLyxOGTqU6+/HqqyUyDfJn1TIy2+fTUs6G72IHPsA1J3Kk2ASBE+HcD0oh8VaNQFzKT8q+pRb5FHvItaRDEYiqrJ98OnE9mSXn1xB+o+LQh3Qj/zkGf8BfCscyZh2r7v30H+dekDbcDxty2asvB6mEHC0x6ytx20tjyppFkxyKFsfX8PDn3KlT3DZyk6FSeJ7sNJW+Ic88VlSqdAAalPNYqcyzyTREIXwE6S8ZF71FLCukVxrTDTOvJmALQ2TfgWlXopeiYiTCV9Mrs5vBlhL8aIvzZh2pbvGoKBlVtprWx6NvJpDC2DtIrqTi2KZGvEKJvQ/705Jap8jy7PWaZmq0yN6tNlAtZtmOhpgiErwDVtnicEYRqX1vOfLpKWzwhBKue8/nktni9wWTljbanTdZuv72hTyfT6kTtDblSHSrk2xx0L/OnZ73VRU/A69jKMfC9epK4c5D+GXwgEL4yZG2bSWh3e2i0u2wRBBCd9Z2W8212umh1emxpJCLqdyyaLFPeouTSM5MhlPLTxza6RclHENkMYS6fmapntV/KmEvPQi6DfJam6nlw2O7L5HPgGZq+b7Dfl8lFhPIC4HQ9ecdW5Uw899iWFPf1JDarzdRv2QKB8JWR1GRhSBB8S7YkmQcOZCaVgnYhU11PPmeapOc+M0EA/vUkosR6OtwyMxnZS3eaTN6xzWUzKOYyU1NX3HoWc1nks6R+LPOgmfqRTCAQvjKSaounQUrpkC8/Ec6mnrwpAEDHhnjH1rfMpLHdPyWByiiisgrpbtgCgfCVkVpEODVq6ctkOlssZU7XUxIhr0w1J8OZLvMvM5mUHOipakMnQc8UbEglwm93e9ipt1M/kgkEwldGUm1xFxFEqZCdetTMTUQ4PYfvJnXlf2zLCeVtXcmcSr5NN1GobxtKaqTjZPWUlHJ1MLaqTYq2+mfwQ4R/F6GkGClxRr6V4vQuSS6ilqTWii5SV0kdi7g3FgHZmWkKETZdRaHJ5Mu6eipkFW2IOXXlcdM2kjk9aHCRRiolBEcSb+9HPZvPLYQI/65BRZEIuY63AbOaC40IguvGIpDOpq3qZibr81RMI3GPrc9NW0Bl38CRDXlOf6r2uv7prQMAwMNrZTbZpgiEr4jk6OykbGaqLcfv9rSDqgM/Caeupq+e/AcqB4cdZGh4nJIDKnMl1z+OywXVJvE/vV1FIZfBxZVA+HcNktriuYlCp/e1HURK7JN1umMj4ulFKpHUFu/gsD24/MaFJD33D9soZDOYY5SZ1Bbv4LCNuXwGecYm18n7I21UijmWHg5DmUkOvM3WT2EoM9mGFua4Zaq1VvzJrQM8vFZhHWNTBMJXRCmhq061GbVs4+jINJBZmN4WTzZc4WgTJ1FO6Gu7fxg1XOFoEydRKkxviydv2bITxBQHzlkmQ6LU3zeYFjRwBgxAchTqQs9yITu1kBlnwxWJUiE39YKZk7FN2ISX+OmtKn7mngqrbFMEwldEUnnbfQcGlXR9m7PEgURSX1sXMispyExqi+dKz84UB+5Kz2anh86EVnyuZNZbXfQmOHBXY5u0Anehp0qtq+u7DfzMPQussk0RCF8RSW3xOGunSyR18uFsuCKR1Fqx6kBmop6HbdbNtlGZk/TkLGI2kJnQKtNF5JuODU0v2sZZVVaiXMyhN20F7sjJtLsCzc7klYXcsH30XIjw7yoklbd1E7VMJ1+XEf5k8nUhc7qenAXiJJIdeBpjyx80VBL62p4UG0qaK5wNVyRUavj89FYVAE5GhE9Ev0FELxNRj4guT3nfh4noVSK6QkSfsZGZFpIq8rmICEsJHahcpJEGjs0nQSTo6UJmUmcmp0SYgp6TzuJzNnmRGDYHSUNPf05GpXPaT24doJjL4MHlEqtsU9hG+C8B+NsAvjXpDUSUBfD7AD4C4J0APkFE77SU6x3SWOQxtnG4MCj59w4myuRrIqEnk9fJDMa24V9mGnpOlcmcuhrabXuyzFMyttxppMWEsT1sd/HM92/g8vrSTJzQASwJXwjxIyHEqwlvexzAFSHE60KIFoAvAXjCRm4aWCpF16J36q3Yn7uIlFRkctVOlzjbl7k7TU9mJ7NUVtCTW6aKnik8T/axlTJr8aTE2WFL4uwUPWU/BZ82JBuucD/P4VyJH9t/+e03cfugiU//0qOscm3gI4d/HsBbI99v9F+LBRE9SUTPEdFzd+7ccf7hVCENajJB8EctUuZ2bZpMXiNeTpTpl3yH3ZEc6Rkjs9cTqLb4iXBASjFj2+n2UGdsuCKxPIUIZT8FdpmlyXoetnvo9IQzG4rTs8bccEVi2ti2Oj38wX94DT//8Are/9AKq1wbJBI+Ef0ZEb0U8081So9by8SfnQIghHhKCHFZCHF5bW1NUYR7lAtZFLIZbMdESq1OD7VWF2dL/EvGbIZiDeqw3cVhuzeIMrhwZj4PovjJWm910Or2cHaeV6Yct7ixPWh20O0JZzLj9Nw/bEMI4Azz2EoijHMye41I97PzboKGOBva60em3HpOC1R2G9Fr3M9zWqAiAwnu+bk0xbHd3Gtgs9rEr71nYmybChJdnhDily1lbAB4cOT7BwDcsPyb3kFEWCrnYx+unEzS6FhllvKxRCgNm1tmNkM4O5+PJSVZ9W+FWWY+m8HiXC6WlLarbvQs5rIoF7KxY7tVc6PnfCGLuXwm1oYGz5O5Sca0QMWVntMClS1Hz3NaoDKcK7xjOy1QkWM7C01PRuEjpfNdAI8S0SUiKgD4OIBnPMhlx1Kp4JUIpcy4VIcrwpcyd2Lykk5llgux0dnWgAjdyJyVsXVFvkSEs6X4QMWVnjJQmWZDK8zPM5shnJmPl7nlSM98NoOFhEBlyYEN2cD2WOavE9EGgA8A+BMi+kb/9fuJ6FkAEEJ0AHwKwDcA/AjAl4UQL9t97HQwiXzlA3fxcCcRoWvynUYQTvQsFWInjvwcy8xpByAauzgH7pzwp42tIz1jSSkFPQdzxYWeEwIyV6tE+Tdjx7buLgi0gdUuhhDiaQBPx7x+A8BHR75/FsCzNrJmAcvlAn789v6x111FZwCwVMrjjc3asdddT9aNnfpEmS70XC4XcPvgcKJMF3qeTSBfVwQxzclwR77AZGfq2oZiV2wuV8MTAhVXKVdgsp4ux9YG4aatBs5OWqZWmwBcRhD+UgBA5GTijpptO0yvRGmHKXo6kLmckHZw42Smj62LyHepnJ+YLiPi3yiWMifpKdMv7DInPM+tWgv5LLGfuhrKjCf8Yi6DEmMJaA4EwtfAcj/nO14UaltOHBeTtR+FjheF2q41kc0Q+2USYBiFjsuUE4f77D8QLcfjJ04Tc/nM4CYlJyZFhFvVFsqFLGtpZInlKSm6hbkca7VViSgVGUe+TZyZz7NWW5WYtJLZqrWwVMqzVluVmJguq7awVCqwVlsdyCwX4gOVagvLZTcybRAIXwNLpQJ64vjNuu16ZFAubtMtlQro9MSg3+lAZq2NpVLBzcQpF9Dq9I61b9uuNZ0Z8VK5gHqri8P2uMw2VphPVwxklgo4aHaOlYLeqbecrGKkzL1G+1j1yq1ay1m+V+aZxwOVnVrbWcrh7IRAZafWciZzWqDiTOakvae6O5k2CISvgUlnfbf7UYsLDC58jUUREfm6kTm4OFOP09PdZI2X2cSSIz0HY9s4KnOr1nKySQwM9ZTn7iUiPd05mbhAZavWdOdk+oHKeDEzlzYkA5XxipkyUHElMy5QcelkbBAIXwODyzpjpLRVbTmLQiWpjy+Ptx0a1PBS0jgptZzk0gEMHGacM+U+Py0xvBEa50wdj+2x59l2Rr7SYcaPrTsiBI6P7Vat6d2GduruVjKTbvi6tCEbBMLXwPIEI3ZLvvG3+aIUgCsnE38j1CX5DssrjBOEu1THRCdTdehkBqtEf05mSEr+7HYwth4DlUl1g7aqDlcy5QnBUTVE+Hc9pEGNG7HLnO+k9IrLXOikukGu88xATHSWgp7bdZcrmePPUwjhdiUTU8On1xNuI9+YFF23J7DbaLvXc0Rmu9vD/mHHeaAyKvOw3UWt1Z25M/hAIHwtxBW/Gkwch3lJ4CgRyonjMuc7LrPV6eHgsOMs/xpXYVFOHJebfMBRB15vdXDY7jnNMwNHbeig2UG7K5ztycQFKvuHbXR7wkO6bChzt96CENFxWBeIs6HBxT3H+0Cjc2V47n+2yioAgfC1MKhLMmJQew05cdwQRFxdkp3+xHEVQcTVJRkYsaPI92xMesX15ZW4AmouLwYB8QXUhjdBHUWhMU5myzURxgQNruoFScStEod6+ovwh/WC3IytDQLha0AWUBs9MePyYtBA5lgBNddEGFdAzeUtW2BYQG00h+9az7gCaq5lxhVQc30NXwYqO7Fj64YIF2ICFZeXBYEJgYq3oMHf2NogEL4mxguouby2PSpz1yP5Av0LJR7JV/7tuIjQtZ5HxtbxSgaQZ7dHxtZhrRcgvtKr67HNZI4XUHNNvjJQGZXpOiCLq/TqgxNMEQhfE+cW5/D23rDmi1y+ucr5RjKLuDki02URs4HMheJRPT0Q/rmFo2PrS88jYyvJ1+HzXFuM19P12N7c9ytzbex5+rKh2LnidH7O4eZeY/C967SgDQLha2J9pYSrW7XBbT6XRa8kLq6UcW1rWEDN9dIYANbHZLqsFyRxsT+2Eqno6bBe0FBmvJ6uxzZWT6dje1RPH+Q7rufWQKa7fPr6SgnXtuqD77drLWQITuoF2SIQviYurpRxcNgZLBuvbdVQyGZwbmHOmcz1lRJ26u1Bh6JrmzUUcxmsOmyucHGljM1qCwf925lXt+ooFbJOI9/11TJuHzRRb0W3M69t1bBQzDmdOBdXyrixdzi4KXl1q4Yz83kn9YKOyNxtoNmJZF7bqmG5XEDZocz1lTI2dhpo90s6XN2sYbVSdFIvSOLiShlvbdfR7Zd0uLpVw72Lc07qBUmsr5Zxbbs+KCNxbauG82fnndQLkri4Uj4SBF7dquH80ryTsie2CISvifWVEgAMIpcrt6u4tFp22pX+4kr5qMw7VTy0VnFqUFJPGbm8dqeKh9bKTmVeHJN55XYVD52rOC1Atb4ayXxzeyjz4bWyW5krJfQE8NZ2lAZ47U4k0yUurpTQ7Qlc34lkXvEgc32lhHZX4MZuX8/bVTx8zr2erU5vkL6SdusS6yslHLZ7uH0QrYIjG6o4lWmKQPiaWF/tk+/mkHwfOef24V5aHSP82+5lro/JfO12FY84NuL1lbGxTUHmax6epxzbax6fp7ShN/qRqG8bEkLgtTs158/zUv95XtusodcTeO12zZueb2zW0O0JvL7pXk9TBMLXxANL88hQlOI4bHfx1nYdDzs2qAvL/VXFZh2NVhfXdxvODUpG21c3a6g1O7ixd+h84gxkbtWxf9jG7YOm+8k6snrarbewWW15k/nGZg1b1SZ26m3nEeHFESK8U23i4LDjb2w3a7i130S16V7mxRHHdmOvgUa7603Pa1s1XN9poNXpOZdpCndJwxOKYi6L+8/O49pWDVe3augJOH+4c/ks7jszh2tbNby+WYXwILNUyOHcQhFXt+p47U4VgHuZC3N5rFYKuLZVw2u3/cg8U8rjbCnvVc+lUh4Lczlc26rjiic9VysFlAtZXPUo89xCEXP5zBGZroOj+/p7BEfG1rEzve/MHPJZwtWtOtYWDiKZgfBPDi6tlo9OHA/Lt/X+xpCvyQr0N8B8y0xDz5UxPdcWnMojor4N1XDFk5MhosHz9OVMMxkaGVs/RJjJEC4ul3B1s4ZzC0UvMnPZDB5cjk4HydNAs0r4IaVjgIsrkUFduV0FEZxvCgHR5uLVrTpeu11FhoabjU5lrpTwxmYU+eYyNEgLuMTFlTKubtZx5U4VhWwGDy7NO5e5vlKKZN6uopjL4LwHmfJkx2u3a5jPZ3H/GR96DgOVSjGHexfdnSyTuLhSwhubkWNbnMthzeHJsqHM/tjeiQh4xYPM9ZUy3ujb0Gql4KT7HQcC4RtgfaWMvUYb//m1LTywNO/0aNuozO1aC3/5xjYuLJdQzHmQuVrGZrWJ717dwYWVEvIOj7ZJXFot4e39Q3zv2i7WV0tOj9NJrK+WcWOvgRff2nV+4kri0koJ13ca+MHGrvPTTxLrqyW8tV3HD6/vOT+JNJRZxlvbDbx0fR8POz5xJXFpNToX/8qNPW+nZeRK5pWb+zN7QgcIhG+Ey+vLIAK+88a2t934IzI9LRf/y/VlAH71HMi86k/Px9eXIQTw3as7/mReWkFPAM9d8yuz0xN44c1d57l0ifddWkar28OLb+16s6HHL62g2enh+xt7Hsd2GfVWFy9d35/ZdA4A0Hj/x1nC5cuXxXPPPZf2x4jFT28d4CsvXMdff3QVP//IqheZP7l1gK+8sIEP/cw5fODhFS8yX337AH/8wgZ+6WfP4X0P+ZH5o5v7+Or3ruOX33nPwAG4xis39vHVF6/jV3/uHvy1i35kvnxjD1/93nV8+F334a9dXPIi86Xre/jai9fx0b9yH95zwZ/Mr37vOv7WY/fjsQfPepH5g41dfO3FG/i1d5/HX3ngjBeZ339rF898/wZ+/T3n8a7zfmTGgYieF0Jcjv1ZIPyAgICAk4NphB9SOgEBAQGnBIHwAwICAk4JrAifiH6DiF4moh4RxS4h+u+7SkQ/JKIXiSjkaAICAgJSgO3Fq5cA/G0A/5fCe39RCLFpKS8gICAgwBBWhC+E+BEAL2drAwICAgLs4CuHLwD8KRE9T0RPepIZEBAQEDCCxAifiP4MwL0xP/qHQoivKcr5oBDiBhGdA/BNIvqxEOJbE+Q9CeBJALhw4YLinw8ICAgISEIi4QshftlWiBDiRv//20T0NIDHAcQSvhDiKQBPAdE5fFvZAQEBAQERnFfLJKIygIwQ4qD/9d8E8L+o/O7zzz+/SUTXDEWvAgibxJMRxicZYYymI4xPMtIYo4uTfmB105aIfh3APwOwBmAXwItCiF8lovsB/HMhxEeJ6CEAT/d/JQfgXwkh/ldjoeqf7blJt80CwvioIIzRdITxScasjZHtKZ2nMSTz0ddvAPho/+vXATxmIycgICAgwB7hpm1AQEDAKcFJJvyn0v4AM44wPskIYzQdYXySMVNjNNPVMgMCAgIC+HCSI/yAgICAgBGcOMInog8T0atEdIWIPpP255kVxBWwI6JlIvomEf20/7+fjhgzACL6PBHdJqKXRl6bOB5E9D/0bepVIvrVdD61X0wYo/+ZiK737ehFIvroyM9O1RgR0YNE9O+J6Ef9IpK/2399Zu3oRBE+EWUB/D6AjwB4J4BPENE70/1UM4VfFEK8e+SY2GcA/LkQ4lEAf97//rTgDwF8eOy12PHo29DHAfxc/3f+z76tnXT8IY6PEQD8H307ercQ4lng1I5RB8B/L4T4LwC8H8An++Mws3Z0oggf0Q3eK0KI14UQLQBfAvBEyp9plvEEgC/0v/4CgF9L76P4Rb+0x/bYy5PG4wkAXxJCNIUQbwC4gsjWTjQmjNEknLoxEkLcFEK80P/6AMCPAJzHDNvRSSP88wDeGvl+o/9aQHwBu3uEEDeByHgBnEvt080GJo1HsKuj+BQR/aCf8pHpilM9RkS0DuA9AL6NGbajk0b4cXWawzGkCB8UQrwXUbrrk0T019P+QHcRgl0N8QcAHgbwbgA3AfyT/uundoyIqALgKwD+WyHE/rS3xrzmdYxOGuFvAHhw5PsHANxI6bPMFEYL2CG6Hf04gFtEdB8A9P+/nd4nnAlMGo9gV30IIW4JIbpCiB6A/xvDlMSpHCMiyiMi+38phPjj/ssza0cnjfC/C+BRIrpERAVEGyTPpPyZUgcRlYloQX6NqIDdS4jG5jf7b/tNAKrlrk8qJo3HMwA+TkRFIroE4FEA30nh86UOSWR9/DoiOwJO4RhR1Pnp/wHwIyHE/z7yo5m1I+fVMn1CCNEhok8B+AaALIDPCyFeTvljzQLuAfB0vzOZLGD3dSL6LoAvE9FvAXgTwG+k+Bm9goi+COBDAFaJaAPA7wH4x4gZDyHEy0T0ZQCvIDqZ8UkhRDeVD+4RE8boQ0T0bkSpiKsA/hvg1I7RBwH81wB+SEQv9l/7B5hhOwo3bQMCAgJOCU5aSicgICAgYAIC4QcEBAScEgTCDwgICDglCIQfEBAQcEoQCD8gICDglCAQfkBAQMApQSD8gICAgFOCQPgBAQEBpwT/P/GZLuUrxJ6WAAAAAElFTkSuQmCC\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -355,8 +355,7 @@ }, { "cell_type": "code", - "execution_count": 13, - "id": "d51d8a62", + "execution_count": 26, "metadata": {}, "outputs": [ { @@ -379,7 +378,7 @@ }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -430,7 +429,6 @@ { "cell_type": "code", "execution_count": 14, - "id": "81b4ff57", "metadata": {}, "outputs": [ { @@ -452,7 +450,6 @@ { "cell_type": "code", "execution_count": null, - "id": "330915ff", "metadata": {}, "outputs": [], "source": [] @@ -460,7 +457,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -474,7 +471,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.2" + "version": "3.8.5" } }, "nbformat": 4, diff --git a/notebooks/Test_file.py b/notebooks/Test_file.py index 1a987aa..c67d857 100644 --- a/notebooks/Test_file.py +++ b/notebooks/Test_file.py @@ -8,7 +8,7 @@ Created on Sat Nov 27 16:05:59 2021 import numpy as np import matplotlib.pyplot as plt -delay = 5.33 +delay = 6.37 ampl = 1 print(f"Tap with amplitude={ampl}, delay={delay}") @@ -29,10 +29,17 @@ signal = np.sin(2 * np.pi * t * 0.05) signal_shifted = np.convolve(h, signal, mode='full') #Time PLot +# plt.xlabel('Delay') +# plt.ylabel('Amplitude') +# #plt.title('') +# plt.plot(t, signal) +# plt.grid(True) +# plt.show() +# plt.plot(signal_shifted) +t1 =np.arange(0.0,order, 0.01) +plt.grid(True) +plt.stem(samples, h,linefmt='C0-') +plt.plot(t1,np.sinc(t1-delay),'b--') plt.xlabel('Delay') plt.ylabel('Amplitude') -#plt.title('') -plt.plot(t, signal) -plt.grid(True) plt.show() -plt.plot(signal_shifted) \ No newline at end of file -- cgit v1.2.1 From 3ece31239358ec05ebe9e118bf40b77cba9909d6 Mon Sep 17 00:00:00 2001 From: sara Date: Wed, 1 Dec 2021 18:28:17 +0100 Subject: Fading Block erweitert --- notebooks/Fading Channel Taps.ipynb | 100 +++++++++++++++++++++ simulation/QAM_Fading/qam_fading.py | 4 +- .../QAM_Fading/qam_fading_V2_eigerner_block.grc | 2 +- simulation/QAM_Fading/qam_fading_block.py | 2 +- .../qam_fading_frequency_selectiv_copy.grc | 14 +-- 5 files changed, 111 insertions(+), 11 deletions(-) create mode 100644 notebooks/Fading Channel Taps.ipynb diff --git a/notebooks/Fading Channel Taps.ipynb b/notebooks/Fading Channel Taps.ipynb new file mode 100644 index 0000000..45a222e --- /dev/null +++ b/notebooks/Fading Channel Taps.ipynb @@ -0,0 +1,100 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "8460e242", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "9790f979", + "metadata": {}, + "outputs": [], + "source": [ + "db = -4" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "041264af", + "metadata": {}, + "outputs": [], + "source": [ + "lin = 10**(db/10)#dB Wert umrechnen " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "7b6019fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.3981071705534972" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lin" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50842115", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56081416", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38caef8e", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/simulation/QAM_Fading/qam_fading.py b/simulation/QAM_Fading/qam_fading.py index 42199d1..30f2262 100755 --- a/simulation/QAM_Fading/qam_fading.py +++ b/simulation/QAM_Fading/qam_fading.py @@ -88,7 +88,7 @@ class qam_fading(gr.top_block, Qt.QWidget): self.eq_ntaps = eq_ntaps = 15 self.eq_mod = eq_mod = 1 self.eq_gain = eq_gain = .01 - self.const = const = digital.constellation_16qam().base() + self.const = const = digital.constellation_qpsk().base() self.chn_taps = chn_taps = [1.0 + 0.0j, ] ################################################## @@ -456,7 +456,7 @@ class qam_fading(gr.top_block, Qt.QWidget): self.digital_constellation_decoder_cb_0 = digital.constellation_decoder_cb(const) self.digital_cma_equalizer_cc_0_0 = digital.cma_equalizer_cc(eq_ntaps, eq_mod, eq_gain, 2) self.digital_cma_equalizer_cc_0 = digital.cma_equalizer_cc(eq_ntaps, eq_mod, eq_gain, 2) - self.channels_selective_fading_model_0 = channels.selective_fading_model( 8, 0, False, 1.0, 0, (0,7), (1,0.2), 2 ) + self.channels_selective_fading_model_0 = channels.selective_fading_model( 8, 0, True, 4, 0, (0,0.3e-6), (1,0.39), 3 ) self.channels_channel_model_0 = channels.channel_model( noise_voltage=noise_volt, frequency_offset=freq_offset, diff --git a/simulation/QAM_Fading/qam_fading_V2_eigerner_block.grc b/simulation/QAM_Fading/qam_fading_V2_eigerner_block.grc index 641d78e..42a922b 100644 --- a/simulation/QAM_Fading/qam_fading_V2_eigerner_block.grc +++ b/simulation/QAM_Fading/qam_fading_V2_eigerner_block.grc @@ -811,7 +811,7 @@ blocks: amplitudes: '[amp_1]' comment: '' delays: '[fading_1]' - los: 'False' + los: 'True' maxoutbuf: '0' minoutbuf: '0' states: diff --git a/simulation/QAM_Fading/qam_fading_block.py b/simulation/QAM_Fading/qam_fading_block.py index 89c4a32..416799c 100755 --- a/simulation/QAM_Fading/qam_fading_block.py +++ b/simulation/QAM_Fading/qam_fading_block.py @@ -505,7 +505,7 @@ class qam_fading_block(gr.top_block, Qt.QWidget): self.plots_grid_layout_0.setRowStretch(r, 1) for c in range(0, 1): self.plots_grid_layout_0.setColumnStretch(c, 1) - self.fadingui_multipath_fading_0 = fadingui.multipath_fading(amplitudes=[amp_1], delays=[fading_1], los =False) + self.fadingui_multipath_fading_0 = fadingui.multipath_fading(amplitudes=[amp_1], delays=[fading_1], los =True) self.digital_pfb_clock_sync_xxx_0_0 = digital.pfb_clock_sync_ccf(sps , timing_loop_bw, rrc_taps, nfilts, nfilts/2, 1.5, 1) self.digital_pfb_clock_sync_xxx_0 = digital.pfb_clock_sync_ccf(sps, timing_loop_bw, rrc_taps, nfilts, nfilts/2, 1.5, 1) self.digital_map_bb_0_0 = digital.map_bb([0, 1, 3, 2]) diff --git a/simulation/QAM_Fading/qam_fading_frequency_selectiv_copy.grc b/simulation/QAM_Fading/qam_fading_frequency_selectiv_copy.grc index a960ec8..ce87db8 100644 --- a/simulation/QAM_Fading/qam_fading_frequency_selectiv_copy.grc +++ b/simulation/QAM_Fading/qam_fading_frequency_selectiv_copy.grc @@ -54,7 +54,7 @@ blocks: rot_sym: '4' soft_dec_lut: None sym_map: '[0, 1, 3, 2]' - type: 16qam + type: qpsk states: bus_sink: false bus_source: false @@ -453,24 +453,24 @@ blocks: - name: channels_selective_fading_model_0 id: channels_selective_fading_model parameters: - K: '1.0' - LOS: 'False' + K: '4' + LOS: 'True' N: '8' affinity: '' alias: '' comment: '' - delays: (0,7) + delays: (0,0.3e-6) fDTs: '0' - mags: (1,0.2) + mags: (1,0.39) maxoutbuf: '0' minoutbuf: '0' - ntaps: '2' + ntaps: '3' seed: '0' states: bus_sink: false bus_source: false bus_structure: null - coordinate: [960, 308.0] + coordinate: [976, 308.0] rotation: 0 state: true - name: digital_cma_equalizer_cc_0 -- cgit v1.2.1 From fcc71adefd8b021d56ad8847083ad8eaf33e3147 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Thu, 2 Dec 2021 12:49:41 +0100 Subject: Update .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 5bea3b5..5c1c951 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +doc/thesis/Fading.pdf +doc/projectplan/ProjectPlan.pdf + *.figlist # Created by https://www.toptal.com/developers/gitignore/api/windows,linux,latex,python # Edit at https://www.toptal.com/developers/gitignore?templates=windows,linux,latex,python -- cgit v1.2.1 From 8e6e1d62ef9beb978879bfd156b3ff51940c8725 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Thu, 2 Dec 2021 12:50:55 +0100 Subject: Implement phase correction in test file with embedded python block --- tests/correlator/correlator.grc | 424 +++++++++++----------------------------- tests/correlator/correlator.py | 274 +++++--------------------- tests/correlator/epy_block_0.py | 75 +++++++ 3 files changed, 234 insertions(+), 539 deletions(-) create mode 100644 tests/correlator/epy_block_0.py diff --git a/tests/correlator/correlator.grc b/tests/correlator/correlator.grc index 9deec54..aa21770 100644 --- a/tests/correlator/correlator.grc +++ b/tests/correlator/correlator.grc @@ -1,7 +1,6 @@ options: parameters: author: Naoki Pross - catch_exceptions: 'True' category: '[GRC Hier Blocks]' cmake_opt: '' comment: '' @@ -23,6 +22,7 @@ options: sizing_mode: fixed thread_safe_setters: '' title: Correlator Test + window_size: '' states: bus_sink: false bus_source: false @@ -72,7 +72,6 @@ blocks: comment: '' const_points: '[-1-1j, -1+1j, 1+1j, 1-1j]' dims: '1' - normalization: digital.constellation.AMPLITUDE_NORMALIZATION precision: '8' rot_sym: '4' soft_dec_lut: None @@ -184,42 +183,6 @@ blocks: coordinate: [224, 1068.0] rotation: 0 state: enabled -- name: blocks_burst_tagger_0 - id: blocks_burst_tagger - parameters: - affinity: '' - alias: '' - comment: '' - false_key: nothing - false_value: '0' - maxoutbuf: '0' - minoutbuf: '0' - true_key: peak - true_value: 'True' - type: float - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [944, 1580.0] - rotation: 0 - state: disabled -- name: blocks_char_to_short_0 - id: blocks_char_to_short - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [752, 1624.0] - rotation: 0 - state: disabled - name: blocks_complex_to_magphase_0 id: blocks_complex_to_magphase parameters: @@ -235,7 +198,7 @@ blocks: bus_structure: null coordinate: [1048, 696.0] rotation: 0 - state: enabled + state: disabled - name: blocks_complex_to_magphase_0_0 id: blocks_complex_to_magphase parameters: @@ -249,25 +212,9 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1048, 1104.0] + coordinate: [1048, 1128.0] rotation: 0 state: enabled -- name: blocks_complex_to_magphase_0_1 - id: blocks_complex_to_magphase - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [256, 1592.0] - rotation: 0 - state: disabled - name: blocks_multiply_const_vxx_0 id: blocks_multiply_const_vxx parameters: @@ -285,7 +232,7 @@ blocks: bus_structure: null coordinate: [1288, 724.0] rotation: 0 - state: enabled + state: disabled - name: blocks_multiply_const_vxx_0_0 id: blocks_multiply_const_vxx parameters: @@ -301,41 +248,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1336, 1180.0] - rotation: 0 - state: disabled -- name: blocks_null_sink_0 - id: blocks_null_sink - parameters: - affinity: '' - alias: '' - bus_structure_sink: '[[0,],]' - comment: '' - num_inputs: '1' - type: byte - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1504, 1696.0] - rotation: 0 - state: disabled -- name: blocks_null_sink_2 - id: blocks_null_sink - parameters: - affinity: '' - alias: '' - bus_structure_sink: '[[0,],]' - comment: '' - num_inputs: '1' - type: float - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [528, 1720.0] + coordinate: [1336, 1204.0] rotation: 0 state: disabled - name: blocks_null_sink_3 @@ -352,7 +265,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1336, 1232.0] + coordinate: [1336, 1256.0] rotation: 0 state: true - name: blocks_null_source_0 @@ -374,24 +287,6 @@ blocks: coordinate: [96, 344.0] rotation: 0 state: enabled -- name: blocks_peak_detector2_fb_0 - id: blocks_peak_detector2_fb - parameters: - affinity: '' - alias: '' - alpha: '0.001' - comment: '' - look_ahead: '1000' - maxoutbuf: '0' - minoutbuf: '0' - threshold_factor_rise: '7' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [528, 1620.0] - rotation: 0 - state: disabled - name: blocks_stream_mux_0 id: blocks_stream_mux parameters: @@ -449,6 +344,22 @@ blocks: coordinate: [1272, 404.0] rotation: 0 state: enabled +- name: blocks_vector_sink_x_0 + id: blocks_vector_sink_x + parameters: + affinity: '' + alias: '' + comment: '' + reserve_items: '1024' + type: byte + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [840, 1392.0] + rotation: 0 + state: true - name: blocks_vector_source_x_0 id: blocks_vector_source_x parameters: @@ -457,7 +368,7 @@ blocks: comment: '' maxoutbuf: '0' minoutbuf: '0' - repeat: 'False' + repeat: 'True' tags: '[]' type: byte vector: testvec * 1600 @@ -497,7 +408,7 @@ blocks: block_tags: 'False' comment: '' epsilon: '1.0' - freq_offset: '0.000001' + freq_offset: '0.00001' maxoutbuf: '0' minoutbuf: '0' noise_voltage: '0.2' @@ -542,9 +453,9 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1232, 1692.0] + coordinate: [248, 1388.0] rotation: 0 - state: disabled + state: enabled - name: digital_constellation_modulator_0 id: digital_constellation_modulator parameters: @@ -558,7 +469,6 @@ blocks: maxoutbuf: '0' minoutbuf: '0' samples_per_symbol: sps - truncate: 'False' verbose: 'False' states: bus_sink: false @@ -610,71 +520,87 @@ blocks: coordinate: [224, 836.0] rotation: 0 state: enabled -- name: fir_filter_xxx_1 - id: fir_filter_xxx +- name: epy_block_0 + id: epy_block parameters: + _source_code: "import pmt\n\nimport numpy as np\nfrom gnuradio import gr\n\n\n\ + class blk(gr.sync_block):\n def __init__(self):\n gr.sync_block.__init__(\n\ + \ self,\n name='Phase Lock',\n in_sig=[np.complex64],\n\ + \ out_sig=[np.complex64]\n )\n\n # keep track of how\ + \ many samples were processed,\n # because tags have an absolute offset\n\ + \ self.sampnr: np.complex64 = 0\n\n # because of block processing\ + \ a tagged block could\n # be split in half so we need to keep track\ + \ of the\n # \"previous\" values\n self.last_phase = 0\n\n \ + \ def work(self, input_items, output_items):\n # TODO: interpolate phase\ + \ values for frequency correction\n\n out = output_items[0]\n \ + \ inp = input_items[0]\n\n # create a phase correction vector\n \ + \ phase = np.zeros(len(inp), dtype=np.float64)\n\n # read tags\n \ + \ tags = self.get_tags_in_window(0, 0, len(inp))\n\n # get only\ + \ phase tags\n is_phase = lambda tag: pmt.to_python(tag.key) == \"phase_est\"\ + \n phase_tags = list(filter(is_phase, tags))\n\n print(f\"Processing\ + \ {len(inp)} samples, with {len(phase_tags)} tags\")\n\n # compute correction\ + \ from previous block\n first_tag = phase_tags[0]\n first_idx\ + \ = first_tag.offset - self.sampnr\n phase[:first_idx] = self.last_phase\n\ + \n # iterate phase tags \"in the middle\"\n for prev_tag, next_tag\ + \ in zip(phase_tags, phase_tags[1:]):\n # unpack pmt values\n \ + \ pval = pmt.to_python(prev_tag.value)\n\n # compute indexes\ + \ in phase vector\n pidx = prev_tag.offset - self.sampnr\n \ + \ idx = next_tag.offset - self.sampnr\n\n # compute phase correction\ + \ for block\n phase[pidx:idx] = pval\n print(f\"Correction\ + \ for block {pidx} to {idx} is {pval}\")\n\n # compute the remaining\ + \ part of the block\n last_tag = phase_tags[-1]\n last_val = pmt.to_python(last_tag.value)\n\ + \ last_idx = last_tag.offset - self.sampnr\n\n phase[last_idx:]\ + \ = last_val\n\n # save values for next call\n self.last_phase\ + \ = last_val\n\n # mark samples as processed and compute to output\n\ + \ self.sampnr += len(inp)\n out[:] = inp * np.exp(-1j * phase)\n\ + \n return len(out)\n" affinity: '' alias: '' comment: '' - decim: '1' maxoutbuf: '0' minoutbuf: '0' - samp_delay: '0' - taps: revconj_access_code_symbols - type: ccc states: + _io_cache: ('Phase Lock', 'blk', [], [('0', 'complex', 1)], [('0', 'complex', + 1)], '', []) bus_sink: false bus_source: false bus_structure: null - coordinate: [776, 828.0] + coordinate: [1088, 1040.0] rotation: 0 state: enabled -- name: high_pass_filter_0 - id: high_pass_filter +- name: fadingui_deframer_0 + id: fadingui_deframer parameters: affinity: '' alias: '' - beta: '6.76' comment: '' - cutoff_freq: 5e3 - decim: '1' - gain: '1' - interp: '1' + frame_obj: '' maxoutbuf: '0' minoutbuf: '0' - samp_rate: samp_rate - type: fir_filter_fff - width: '.7' - win: window.WIN_HAMMING states: bus_sink: false bus_source: false bus_structure: null - coordinate: [528, 1420.0] + coordinate: [552, 1388.0] rotation: 0 - state: disabled -- name: low_pass_filter_0 - id: low_pass_filter + state: true +- name: fir_filter_xxx_1 + id: fir_filter_xxx parameters: affinity: '' alias: '' - beta: '6.76' comment: '' - cutoff_freq: 7e3 decim: '1' - gain: '1' - interp: '1' maxoutbuf: '0' minoutbuf: '0' - samp_rate: samp_rate - type: fir_filter_fff - width: '.8' - win: window.WIN_HAMMING + samp_delay: '0' + taps: revconj_access_code_symbols + type: ccc states: bus_sink: false bus_source: false bus_structure: null - coordinate: [528, 1252.0] + coordinate: [776, 828.0] rotation: 0 state: disabled - name: qtgui_const_sink_x_0 @@ -769,12 +695,12 @@ blocks: coordinate: [776, 716.0] rotation: 0 state: enabled -- name: qtgui_const_sink_x_1 +- name: qtgui_const_sink_x_0_0 id: qtgui_const_sink_x parameters: affinity: '' alias: '' - alpha1: '.5' + alpha1: '1.0' alpha10: '1.0' alpha2: '1.0' alpha3: '1.0' @@ -784,7 +710,7 @@ blocks: alpha7: '1.0' alpha8: '1.0' alpha9: '1.0' - autoscale: 'True' + autoscale: 'False' axislabels: 'True' color1: '"blue"' color10: '"red"' @@ -797,7 +723,7 @@ blocks: color8: '"red"' color9: '"red"' comment: '' - grid: 'True' + grid: 'False' gui_hint: 2,1,2,1 label1: '' label10: '' @@ -810,7 +736,7 @@ blocks: label8: '' label9: '' legend: 'True' - marker1: '9' + marker1: '0' marker10: '0' marker2: '0' marker3: '0' @@ -820,10 +746,10 @@ blocks: marker7: '0' marker8: '0' marker9: '0' - name: '"Cross Correlation"' + name: '"Phase Locked Signal"' nconnections: '1' size: '1024' - style1: '2' + style1: '0' style10: '0' style2: '0' style3: '0' @@ -858,15 +784,15 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1048, 612.0] + coordinate: [1288, 940.0] rotation: 0 state: enabled -- name: qtgui_const_sink_x_2 +- name: qtgui_const_sink_x_1 id: qtgui_const_sink_x parameters: affinity: '' alias: '' - alpha1: '1.0' + alpha1: '.5' alpha10: '1.0' alpha2: '1.0' alpha3: '1.0' @@ -876,7 +802,7 @@ blocks: alpha7: '1.0' alpha8: '1.0' alpha9: '1.0' - autoscale: 'False' + autoscale: 'True' axislabels: 'True' color1: '"blue"' color10: '"red"' @@ -889,8 +815,8 @@ blocks: color8: '"red"' color9: '"red"' comment: '' - grid: 'False' - gui_hint: '2,1,2,1 ' + grid: 'True' + gui_hint: 2,1,2,1 label1: '' label10: '' label2: '' @@ -902,7 +828,7 @@ blocks: label8: '' label9: '' legend: 'True' - marker1: '0' + marker1: '9' marker10: '0' marker2: '0' marker3: '0' @@ -912,10 +838,10 @@ blocks: marker7: '0' marker8: '0' marker9: '0' - name: '"Phase Correction"' + name: '"Cross Correlation"' nconnections: '1' size: '1024' - style1: '0' + style1: '2' style10: '0' style2: '0' style3: '0' @@ -950,7 +876,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1248, 1588.0] + coordinate: [1048, 612.0] rotation: 0 state: disabled - name: qtgui_time_sink_x_0 @@ -1049,7 +975,7 @@ blocks: bus_structure: null coordinate: [1320, 604.0] rotation: 0 - state: enabled + state: disabled - name: qtgui_time_sink_x_0_0 id: qtgui_time_sink_x parameters: @@ -1144,7 +1070,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1336, 1084.0] + coordinate: [1336, 1108.0] rotation: 0 state: enabled - name: qtgui_time_sink_x_0_0_0 @@ -1233,7 +1159,7 @@ blocks: width7: '1' width8: '1' width9: '1' - ylabel: XC Magnitude + ylabel: Equalized ymax: '2' ymin: '-2' yunit: '""' @@ -1241,106 +1167,9 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1048, 1020.0] + coordinate: [1048, 940.0] rotation: 0 state: enabled -- name: qtgui_time_sink_x_1 - id: qtgui_time_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: blue - color10: dark blue - color2: red - color3: green - color4: black - color5: cyan - color6: magenta - color7: yellow - color8: dark red - color9: dark green - comment: '' - ctrlpanel: 'False' - entags: 'True' - grid: 'False' - gui_hint: '' - label1: Signal 1 - label10: Signal 10 - label2: Signal 2 - label3: Signal 3 - label4: Signal 4 - label5: Signal 5 - label6: Signal 6 - label7: Signal 7 - label8: Signal 8 - label9: Signal 9 - legend: 'True' - marker1: '-1' - marker10: '-1' - marker2: '-1' - marker3: '-1' - marker4: '-1' - marker5: '-1' - marker6: '-1' - marker7: '-1' - marker8: '-1' - marker9: '-1' - name: '""' - nconnections: '1' - size: '1024' - srate: samp_rate - stemplot: 'False' - style1: '1' - style10: '1' - style2: '1' - style3: '1' - style4: '1' - style5: '1' - style6: '1' - style7: '1' - style8: '1' - style9: '1' - tr_chan: '0' - tr_delay: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: float - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - ylabel: Amplitude - ymax: '20' - ymin: '-5' - yunit: '""' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [784, 1452.0] - rotation: 0 - state: disabled - name: qtgui_time_sink_x_1_0 id: qtgui_time_sink_x parameters: @@ -1534,7 +1363,7 @@ blocks: bus_structure: null coordinate: [776, 612.0] rotation: 0 - state: enabled + state: disabled - name: qtgui_time_sink_x_2 id: qtgui_time_sink_x parameters: @@ -1631,7 +1460,7 @@ blocks: bus_structure: null coordinate: [1480, 708.0] rotation: 0 - state: enabled + state: disabled - name: qtgui_time_sink_x_2_0 id: qtgui_time_sink_x parameters: @@ -1726,7 +1555,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1512, 1164.0] + coordinate: [1512, 1188.0] rotation: 0 state: disabled - name: root_raised_cosine_filter_0 @@ -1765,30 +1594,17 @@ blocks: coordinate: [1480, 404.0] rotation: 0 state: enabled -- name: virtual_sink_1 +- name: virtual_sink_3 id: virtual_sink parameters: alias: '' comment: '' - stream_id: symbols + stream_id: locked states: bus_sink: false bus_source: false bus_structure: null - coordinate: [776, 916.0] - rotation: 0 - state: true -- name: virtual_sink_2 - id: virtual_sink - parameters: - alias: '' - comment: '' - stream_id: xcorrelation - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1080, 836.0] + coordinate: [1336, 1036.0] rotation: 0 state: true - name: virtual_source_0 @@ -1804,49 +1620,29 @@ blocks: coordinate: [32, 884.0] rotation: 0 state: enabled -- name: virtual_source_2 - id: virtual_source - parameters: - alias: '' - comment: '' - stream_id: symbols - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [32, 1716.0] - rotation: 0 - state: disabled -- name: virtual_source_3 +- name: virtual_source_1 id: virtual_source parameters: alias: '' comment: '' - stream_id: xcorrelation + stream_id: locked states: bus_sink: false bus_source: false bus_structure: null - coordinate: [32, 1604.0] + coordinate: [24, 1388.0] rotation: 0 - state: disabled + state: true connections: -- [blocks_char_to_short_0, '0', blocks_burst_tagger_0, '1'] - [blocks_complex_to_magphase_0, '0', qtgui_time_sink_x_0, '0'] - [blocks_complex_to_magphase_0, '1', blocks_multiply_const_vxx_0, '0'] - [blocks_complex_to_magphase_0_0, '0', qtgui_time_sink_x_0_0, '0'] - [blocks_complex_to_magphase_0_0, '1', blocks_multiply_const_vxx_0_0, '0'] - [blocks_complex_to_magphase_0_0, '1', blocks_null_sink_3, '0'] -- [blocks_complex_to_magphase_0_1, '0', blocks_burst_tagger_0, '0'] -- [blocks_complex_to_magphase_0_1, '0', blocks_peak_detector2_fb_0, '0'] -- [blocks_complex_to_magphase_0_1, '0', high_pass_filter_0, '0'] -- [blocks_complex_to_magphase_0_1, '0', low_pass_filter_0, '0'] -- [blocks_complex_to_magphase_0_1, '1', blocks_null_sink_2, '0'] - [blocks_multiply_const_vxx_0, '0', qtgui_time_sink_x_2, '0'] - [blocks_multiply_const_vxx_0_0, '0', qtgui_time_sink_x_2_0, '0'] - [blocks_null_source_0, '0', blocks_stream_mux_0, '0'] -- [blocks_peak_detector2_fb_0, '0', blocks_char_to_short_0, '0'] - [blocks_stream_mux_0, '0', digital_constellation_modulator_0, '0'] - [blocks_stream_mux_1, '0', channels_channel_model_0, '0'] - [blocks_throttle_0, '0', virtual_sink_0, '0'] @@ -1857,22 +1653,22 @@ connections: - [digital_cma_equalizer_cc_0, '0', fir_filter_xxx_1, '0'] - [digital_cma_equalizer_cc_0, '0', qtgui_const_sink_x_0, '0'] - [digital_cma_equalizer_cc_0, '0', qtgui_time_sink_x_1_1, '0'] -- [digital_cma_equalizer_cc_0, '0', virtual_sink_1, '0'] -- [digital_constellation_decoder_cb_0, '0', blocks_null_sink_0, '0'] +- [digital_constellation_decoder_cb_0, '0', fadingui_deframer_0, '0'] - [digital_constellation_modulator_0, '0', blocks_stream_mux_1, '1'] - [digital_constellation_modulator_0, '0', channels_channel_model_0, '0'] - [digital_constellation_modulator_0, '0', qtgui_time_sink_x_1_0, '0'] +- [digital_corr_est_cc_0, '0', epy_block_0, '0'] - [digital_corr_est_cc_0, '0', qtgui_time_sink_x_0_0_0, '0'] - [digital_corr_est_cc_0, '1', blocks_complex_to_magphase_0_0, '0'] - [digital_pfb_clock_sync_xxx_0, '0', digital_cma_equalizer_cc_0, '0'] +- [epy_block_0, '0', qtgui_const_sink_x_0_0, '0'] +- [epy_block_0, '0', virtual_sink_3, '0'] +- [fadingui_deframer_0, '0', blocks_vector_sink_x_0, '0'] - [fir_filter_xxx_1, '0', blocks_complex_to_magphase_0, '0'] - [fir_filter_xxx_1, '0', qtgui_const_sink_x_1, '0'] -- [fir_filter_xxx_1, '0', virtual_sink_2, '0'] -- [high_pass_filter_0, '0', qtgui_time_sink_x_1, '0'] -- [low_pass_filter_0, '0', qtgui_time_sink_x_1, '0'] - [root_raised_cosine_filter_0, '0', blocks_stream_mux_1, '0'] - [virtual_source_0, '0', digital_pfb_clock_sync_xxx_0, '0'] -- [virtual_source_3, '0', blocks_complex_to_magphase_0_1, '0'] +- [virtual_source_1, '0', digital_constellation_decoder_cb_0, '0'] metadata: file_format: 1 diff --git a/tests/correlator/correlator.py b/tests/correlator/correlator.py index 376d061..a870cc0 100755 --- a/tests/correlator/correlator.py +++ b/tests/correlator/correlator.py @@ -7,7 +7,7 @@ # GNU Radio Python Flow Graph # Title: Correlator Test # Author: Naoki Pross -# GNU Radio version: 3.9.2.0 +# GNU Radio version: 3.8.2.0 from distutils.version import StrictVersion @@ -28,23 +28,20 @@ import sip from gnuradio import blocks from gnuradio import channels from gnuradio import digital -from gnuradio import filter from gnuradio import gr -from gnuradio.fft import window import sys import signal from argparse import ArgumentParser from gnuradio.eng_arg import eng_float, intx from gnuradio import eng_notation - - +import epy_block_0 from gnuradio import qtgui class correlator(gr.top_block, Qt.QWidget): def __init__(self): - gr.top_block.__init__(self, "Correlator Test", catch_exceptions=True) + gr.top_block.__init__(self, "Correlator Test") Qt.QWidget.__init__(self) self.setWindowTitle("Correlator Test") qtgui.util.check_set_qss() @@ -92,119 +89,11 @@ class correlator(gr.top_block, Qt.QWidget): ################################################## # Blocks ################################################## - self.qtgui_time_sink_x_2 = qtgui.time_sink_f( - 1024, #size - samp_rate, #samp_rate - "", #name - 1, #number of inputs - None # parent - ) - self.qtgui_time_sink_x_2.set_update_time(0.10) - self.qtgui_time_sink_x_2.set_y_axis(-1, 1) - - self.qtgui_time_sink_x_2.set_y_label('XC Phase', "") - - self.qtgui_time_sink_x_2.enable_tags(True) - self.qtgui_time_sink_x_2.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, 0, "") - self.qtgui_time_sink_x_2.enable_autoscale(True) - self.qtgui_time_sink_x_2.enable_grid(False) - self.qtgui_time_sink_x_2.enable_axis_labels(True) - self.qtgui_time_sink_x_2.enable_control_panel(False) - self.qtgui_time_sink_x_2.enable_stem_plot(False) - - - labels = ['Signal 1', 'Signal 2', 'Signal 3', 'Signal 4', 'Signal 5', - 'Signal 6', 'Signal 7', 'Signal 8', 'Signal 9', 'Signal 10'] - widths = [1, 1, 1, 1, 1, - 1, 1, 1, 1, 1] - colors = ['blue', 'red', 'green', 'black', 'cyan', - 'magenta', 'yellow', 'dark red', 'dark green', 'dark blue'] - alphas = [1.0, 1.0, 1.0, 1.0, 1.0, - 1.0, 1.0, 1.0, 1.0, 1.0] - styles = [1, 1, 1, 1, 1, - 1, 1, 1, 1, 1] - markers = [-1, -1, -1, -1, -1, - -1, -1, -1, -1, -1] - - - for i in range(1): - if len(labels[i]) == 0: - self.qtgui_time_sink_x_2.set_line_label(i, "Data {0}".format(i)) - else: - self.qtgui_time_sink_x_2.set_line_label(i, labels[i]) - self.qtgui_time_sink_x_2.set_line_width(i, widths[i]) - self.qtgui_time_sink_x_2.set_line_color(i, colors[i]) - self.qtgui_time_sink_x_2.set_line_style(i, styles[i]) - self.qtgui_time_sink_x_2.set_line_marker(i, markers[i]) - self.qtgui_time_sink_x_2.set_line_alpha(i, alphas[i]) - - self._qtgui_time_sink_x_2_win = sip.wrapinstance(self.qtgui_time_sink_x_2.pyqwidget(), Qt.QWidget) - self.top_grid_layout.addWidget(self._qtgui_time_sink_x_2_win, 3, 0, 1, 1) - for r in range(3, 4): - self.top_grid_layout.setRowStretch(r, 1) - for c in range(0, 1): - self.top_grid_layout.setColumnStretch(c, 1) - self.qtgui_time_sink_x_1_1 = qtgui.time_sink_c( - 1024, #size - samp_rate, #samp_rate - "", #name - 1, #number of inputs - None # parent - ) - self.qtgui_time_sink_x_1_1.set_update_time(0.10) - self.qtgui_time_sink_x_1_1.set_y_axis(-2, 2) - - self.qtgui_time_sink_x_1_1.set_y_label('Equalized', "") - - self.qtgui_time_sink_x_1_1.enable_tags(True) - self.qtgui_time_sink_x_1_1.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, 0, "") - self.qtgui_time_sink_x_1_1.enable_autoscale(True) - self.qtgui_time_sink_x_1_1.enable_grid(True) - self.qtgui_time_sink_x_1_1.enable_axis_labels(True) - self.qtgui_time_sink_x_1_1.enable_control_panel(False) - self.qtgui_time_sink_x_1_1.enable_stem_plot(False) - - - labels = ['Signal 1', 'Signal 2', 'Signal 3', 'Signal 4', 'Signal 5', - 'Signal 6', 'Signal 7', 'Signal 8', 'Signal 9', 'Signal 10'] - widths = [1, 1, 1, 1, 1, - 1, 1, 1, 1, 1] - colors = ['blue', 'red', 'green', 'black', 'cyan', - 'magenta', 'yellow', 'dark red', 'dark green', 'dark blue'] - alphas = [1.0, 1.0, 1.0, 1.0, 1.0, - 1.0, 1.0, 1.0, 1.0, 1.0] - styles = [1, 1, 1, 1, 1, - 1, 1, 1, 1, 1] - markers = [-1, -1, -1, -1, -1, - -1, -1, -1, -1, -1] - - - for i in range(2): - if len(labels[i]) == 0: - if (i % 2 == 0): - self.qtgui_time_sink_x_1_1.set_line_label(i, "Re{{Data {0}}}".format(i/2)) - else: - self.qtgui_time_sink_x_1_1.set_line_label(i, "Im{{Data {0}}}".format(i/2)) - else: - self.qtgui_time_sink_x_1_1.set_line_label(i, labels[i]) - self.qtgui_time_sink_x_1_1.set_line_width(i, widths[i]) - self.qtgui_time_sink_x_1_1.set_line_color(i, colors[i]) - self.qtgui_time_sink_x_1_1.set_line_style(i, styles[i]) - self.qtgui_time_sink_x_1_1.set_line_marker(i, markers[i]) - self.qtgui_time_sink_x_1_1.set_line_alpha(i, alphas[i]) - - self._qtgui_time_sink_x_1_1_win = sip.wrapinstance(self.qtgui_time_sink_x_1_1.pyqwidget(), Qt.QWidget) - self.top_grid_layout.addWidget(self._qtgui_time_sink_x_1_1_win, 1, 0, 1, 1) - for r in range(1, 2): - self.top_grid_layout.setRowStretch(r, 1) - for c in range(0, 1): - self.top_grid_layout.setColumnStretch(c, 1) self.qtgui_time_sink_x_1_0 = qtgui.time_sink_c( 1024, #size samp_rate, #samp_rate "", #name - 1, #number of inputs - None # parent + 1 #number of inputs ) self.qtgui_time_sink_x_1_0.set_update_time(0.10) self.qtgui_time_sink_x_1_0.set_y_axis(-2, 2) @@ -258,13 +147,12 @@ class correlator(gr.top_block, Qt.QWidget): 1024, #size samp_rate, #samp_rate "", #name - 1, #number of inputs - None # parent + 1 #number of inputs ) self.qtgui_time_sink_x_0_0_0.set_update_time(0.10) self.qtgui_time_sink_x_0_0_0.set_y_axis(-2, 2) - self.qtgui_time_sink_x_0_0_0.set_y_label('XC Magnitude', "") + self.qtgui_time_sink_x_0_0_0.set_y_label('Equalized', "") self.qtgui_time_sink_x_0_0_0.enable_tags(True) self.qtgui_time_sink_x_0_0_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, 0, "") @@ -304,13 +192,12 @@ class correlator(gr.top_block, Qt.QWidget): self.qtgui_time_sink_x_0_0_0.set_line_alpha(i, alphas[i]) self._qtgui_time_sink_x_0_0_0_win = sip.wrapinstance(self.qtgui_time_sink_x_0_0_0.pyqwidget(), Qt.QWidget) - self.top_layout.addWidget(self._qtgui_time_sink_x_0_0_0_win) + self.top_grid_layout.addWidget(self._qtgui_time_sink_x_0_0_0_win) self.qtgui_time_sink_x_0_0 = qtgui.time_sink_f( 1024, #size samp_rate, #samp_rate "", #name - 1, #number of inputs - None # parent + 1 #number of inputs ) self.qtgui_time_sink_x_0_0.set_update_time(0.10) self.qtgui_time_sink_x_0_0.set_y_axis(0, 20) @@ -352,72 +239,19 @@ class correlator(gr.top_block, Qt.QWidget): self.qtgui_time_sink_x_0_0.set_line_alpha(i, alphas[i]) self._qtgui_time_sink_x_0_0_win = sip.wrapinstance(self.qtgui_time_sink_x_0_0.pyqwidget(), Qt.QWidget) - self.top_layout.addWidget(self._qtgui_time_sink_x_0_0_win) - self.qtgui_time_sink_x_0 = qtgui.time_sink_f( + self.top_grid_layout.addWidget(self._qtgui_time_sink_x_0_0_win) + self.qtgui_const_sink_x_0_0 = qtgui.const_sink_c( 1024, #size - samp_rate, #samp_rate - "", #name - 1, #number of inputs - None # parent + "Phase Locked Signal", #name + 1 #number of inputs ) - self.qtgui_time_sink_x_0.set_update_time(0.10) - self.qtgui_time_sink_x_0.set_y_axis(0, 20) - - self.qtgui_time_sink_x_0.set_y_label('XC Magnitude', "") - - self.qtgui_time_sink_x_0.enable_tags(True) - self.qtgui_time_sink_x_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, 0, "") - self.qtgui_time_sink_x_0.enable_autoscale(True) - self.qtgui_time_sink_x_0.enable_grid(False) - self.qtgui_time_sink_x_0.enable_axis_labels(True) - self.qtgui_time_sink_x_0.enable_control_panel(False) - self.qtgui_time_sink_x_0.enable_stem_plot(False) - - - labels = ['Signal 1', 'Signal 2', 'Signal 3', 'Signal 4', 'Signal 5', - 'Signal 6', 'Signal 7', 'Signal 8', 'Signal 9', 'Signal 10'] - widths = [1, 1, 1, 1, 1, - 1, 1, 1, 1, 1] - colors = ['blue', 'red', 'green', 'black', 'cyan', - 'magenta', 'yellow', 'dark red', 'dark green', 'dark blue'] - alphas = [1.0, 1.0, 1.0, 1.0, 1.0, - 1.0, 1.0, 1.0, 1.0, 1.0] - styles = [1, 1, 1, 1, 1, - 1, 1, 1, 1, 1] - markers = [-1, -1, -1, -1, -1, - -1, -1, -1, -1, -1] - - - for i in range(1): - if len(labels[i]) == 0: - self.qtgui_time_sink_x_0.set_line_label(i, "Data {0}".format(i)) - else: - self.qtgui_time_sink_x_0.set_line_label(i, labels[i]) - self.qtgui_time_sink_x_0.set_line_width(i, widths[i]) - self.qtgui_time_sink_x_0.set_line_color(i, colors[i]) - self.qtgui_time_sink_x_0.set_line_style(i, styles[i]) - self.qtgui_time_sink_x_0.set_line_marker(i, markers[i]) - self.qtgui_time_sink_x_0.set_line_alpha(i, alphas[i]) - - self._qtgui_time_sink_x_0_win = sip.wrapinstance(self.qtgui_time_sink_x_0.pyqwidget(), Qt.QWidget) - self.top_grid_layout.addWidget(self._qtgui_time_sink_x_0_win, 2, 0, 1, 1) - for r in range(2, 3): - self.top_grid_layout.setRowStretch(r, 1) - for c in range(0, 1): - self.top_grid_layout.setColumnStretch(c, 1) - self.qtgui_const_sink_x_1 = qtgui.const_sink_c( - 1024, #size - "Cross Correlation", #name - 1, #number of inputs - None # parent - ) - self.qtgui_const_sink_x_1.set_update_time(0.10) - self.qtgui_const_sink_x_1.set_y_axis(-2, 2) - self.qtgui_const_sink_x_1.set_x_axis(-2, 2) - self.qtgui_const_sink_x_1.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, "") - self.qtgui_const_sink_x_1.enable_autoscale(True) - self.qtgui_const_sink_x_1.enable_grid(True) - self.qtgui_const_sink_x_1.enable_axis_labels(True) + self.qtgui_const_sink_x_0_0.set_update_time(0.10) + self.qtgui_const_sink_x_0_0.set_y_axis(-2, 2) + self.qtgui_const_sink_x_0_0.set_x_axis(-2, 2) + self.qtgui_const_sink_x_0_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, "") + self.qtgui_const_sink_x_0_0.enable_autoscale(False) + self.qtgui_const_sink_x_0_0.enable_grid(False) + self.qtgui_const_sink_x_0_0.enable_axis_labels(True) labels = ['', '', '', '', '', @@ -426,26 +260,26 @@ class correlator(gr.top_block, Qt.QWidget): 1, 1, 1, 1, 1] colors = ["blue", "red", "red", "red", "red", "red", "red", "red", "red", "red"] - styles = [2, 0, 0, 0, 0, + styles = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - markers = [9, 0, 0, 0, 0, + markers = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - alphas = [.5, 1.0, 1.0, 1.0, 1.0, + alphas = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] for i in range(1): if len(labels[i]) == 0: - self.qtgui_const_sink_x_1.set_line_label(i, "Data {0}".format(i)) + self.qtgui_const_sink_x_0_0.set_line_label(i, "Data {0}".format(i)) else: - self.qtgui_const_sink_x_1.set_line_label(i, labels[i]) - self.qtgui_const_sink_x_1.set_line_width(i, widths[i]) - self.qtgui_const_sink_x_1.set_line_color(i, colors[i]) - self.qtgui_const_sink_x_1.set_line_style(i, styles[i]) - self.qtgui_const_sink_x_1.set_line_marker(i, markers[i]) - self.qtgui_const_sink_x_1.set_line_alpha(i, alphas[i]) - - self._qtgui_const_sink_x_1_win = sip.wrapinstance(self.qtgui_const_sink_x_1.pyqwidget(), Qt.QWidget) - self.top_grid_layout.addWidget(self._qtgui_const_sink_x_1_win, 2, 1, 2, 1) + self.qtgui_const_sink_x_0_0.set_line_label(i, labels[i]) + self.qtgui_const_sink_x_0_0.set_line_width(i, widths[i]) + self.qtgui_const_sink_x_0_0.set_line_color(i, colors[i]) + self.qtgui_const_sink_x_0_0.set_line_style(i, styles[i]) + self.qtgui_const_sink_x_0_0.set_line_marker(i, markers[i]) + self.qtgui_const_sink_x_0_0.set_line_alpha(i, alphas[i]) + + self._qtgui_const_sink_x_0_0_win = sip.wrapinstance(self.qtgui_const_sink_x_0_0.pyqwidget(), Qt.QWidget) + self.top_grid_layout.addWidget(self._qtgui_const_sink_x_0_0_win, 2, 1, 2, 1) for r in range(2, 4): self.top_grid_layout.setRowStretch(r, 1) for c in range(1, 2): @@ -453,8 +287,7 @@ class correlator(gr.top_block, Qt.QWidget): self.qtgui_const_sink_x_0 = qtgui.const_sink_c( 1024, #size "Equalized Signal", #name - 1, #number of inputs - None # parent + 1 #number of inputs ) self.qtgui_const_sink_x_0.set_update_time(0.10) self.qtgui_const_sink_x_0.set_y_axis(-2, 2) @@ -495,8 +328,7 @@ class correlator(gr.top_block, Qt.QWidget): self.top_grid_layout.setRowStretch(r, 1) for c in range(1, 2): self.top_grid_layout.setColumnStretch(c, 1) - self.fir_filter_xxx_1 = filter.fir_filter_ccc(1, revconj_access_code_symbols) - self.fir_filter_xxx_1.declare_sample_delay(0) + self.epy_block_0 = epy_block_0.blk() self.digital_pfb_clock_sync_xxx_0 = digital.pfb_clock_sync_ccf(sps, timing_loop_bw, rrc_taps, nfilts, 16, 1.5, 1) self.digital_corr_est_cc_0 = digital.corr_est_cc(access_code_symbols, 1, 0, .8, digital.THRESHOLD_DYNAMIC) self.digital_constellation_modulator_0 = digital.generic_mod( @@ -506,59 +338,52 @@ class correlator(gr.top_block, Qt.QWidget): pre_diff_code=True, excess_bw=excess_bw, verbose=False, - log=False, - truncate=False) + log=False) + self.digital_constellation_decoder_cb_0 = digital.constellation_decoder_cb(const) self.digital_cma_equalizer_cc_0 = digital.cma_equalizer_cc(15, 1, .002, 1) self.channels_channel_model_0 = channels.channel_model( noise_voltage=0.2, - frequency_offset=0.000001, + frequency_offset=0.00001, epsilon=1.0, taps=[-1.4 + .4j], noise_seed=243, block_tags=False) - self.blocks_vector_source_x_0 = blocks.vector_source_b(testvec * 1600, False, 1, []) + self.blocks_vector_source_x_0 = blocks.vector_source_b(testvec * 1600, True, 1, []) + self.blocks_vector_sink_x_0 = blocks.vector_sink_b(1, 1024) self.blocks_throttle_0 = blocks.throttle(gr.sizeof_gr_complex*1, samp_rate,True) self.blocks_stream_mux_0 = blocks.stream_mux(gr.sizeof_char*1, [10, len(testvec)]) self.blocks_null_source_0 = blocks.null_source(gr.sizeof_char*1) self.blocks_null_sink_3 = blocks.null_sink(gr.sizeof_float*1) - self.blocks_multiply_const_vxx_0 = blocks.multiply_const_ff(180 / 3.141592653589793) self.blocks_complex_to_magphase_0_0 = blocks.complex_to_magphase(1) - self.blocks_complex_to_magphase_0 = blocks.complex_to_magphase(1) ################################################## # Connections ################################################## - self.connect((self.blocks_complex_to_magphase_0, 1), (self.blocks_multiply_const_vxx_0, 0)) - self.connect((self.blocks_complex_to_magphase_0, 0), (self.qtgui_time_sink_x_0, 0)) self.connect((self.blocks_complex_to_magphase_0_0, 1), (self.blocks_null_sink_3, 0)) self.connect((self.blocks_complex_to_magphase_0_0, 0), (self.qtgui_time_sink_x_0_0, 0)) - self.connect((self.blocks_multiply_const_vxx_0, 0), (self.qtgui_time_sink_x_2, 0)) self.connect((self.blocks_null_source_0, 0), (self.blocks_stream_mux_0, 0)) self.connect((self.blocks_stream_mux_0, 0), (self.digital_constellation_modulator_0, 0)) self.connect((self.blocks_throttle_0, 0), (self.digital_pfb_clock_sync_xxx_0, 0)) self.connect((self.blocks_vector_source_x_0, 0), (self.blocks_stream_mux_0, 1)) self.connect((self.channels_channel_model_0, 0), (self.blocks_throttle_0, 0)) self.connect((self.digital_cma_equalizer_cc_0, 0), (self.digital_corr_est_cc_0, 0)) - self.connect((self.digital_cma_equalizer_cc_0, 0), (self.fir_filter_xxx_1, 0)) self.connect((self.digital_cma_equalizer_cc_0, 0), (self.qtgui_const_sink_x_0, 0)) - self.connect((self.digital_cma_equalizer_cc_0, 0), (self.qtgui_time_sink_x_1_1, 0)) + self.connect((self.digital_constellation_decoder_cb_0, 0), (self.blocks_vector_sink_x_0, 0)) self.connect((self.digital_constellation_modulator_0, 0), (self.channels_channel_model_0, 0)) self.connect((self.digital_constellation_modulator_0, 0), (self.qtgui_time_sink_x_1_0, 0)) self.connect((self.digital_corr_est_cc_0, 1), (self.blocks_complex_to_magphase_0_0, 0)) + self.connect((self.digital_corr_est_cc_0, 0), (self.epy_block_0, 0)) self.connect((self.digital_corr_est_cc_0, 0), (self.qtgui_time_sink_x_0_0_0, 0)) self.connect((self.digital_pfb_clock_sync_xxx_0, 0), (self.digital_cma_equalizer_cc_0, 0)) - self.connect((self.fir_filter_xxx_1, 0), (self.blocks_complex_to_magphase_0, 0)) - self.connect((self.fir_filter_xxx_1, 0), (self.qtgui_const_sink_x_1, 0)) + self.connect((self.epy_block_0, 0), (self.digital_constellation_decoder_cb_0, 0)) + self.connect((self.epy_block_0, 0), (self.qtgui_const_sink_x_0_0, 0)) def closeEvent(self, event): self.settings = Qt.QSettings("GNU Radio", "correlator") self.settings.setValue("geometry", self.saveGeometry()) - self.stop() - self.wait() - event.accept() def get_sps(self): @@ -602,12 +427,9 @@ class correlator(gr.top_block, Qt.QWidget): def set_samp_rate(self, samp_rate): self.samp_rate = samp_rate self.blocks_throttle_0.set_sample_rate(self.samp_rate) - self.qtgui_time_sink_x_0.set_samp_rate(self.samp_rate) self.qtgui_time_sink_x_0_0.set_samp_rate(self.samp_rate) self.qtgui_time_sink_x_0_0_0.set_samp_rate(self.samp_rate) self.qtgui_time_sink_x_1_0.set_samp_rate(self.samp_rate) - self.qtgui_time_sink_x_1_1.set_samp_rate(self.samp_rate) - self.qtgui_time_sink_x_2.set_samp_rate(self.samp_rate) def get_rrc_taps(self): return self.rrc_taps @@ -621,7 +443,6 @@ class correlator(gr.top_block, Qt.QWidget): def set_revconj_access_code_symbols(self, revconj_access_code_symbols): self.revconj_access_code_symbols = revconj_access_code_symbols - self.fir_filter_xxx_1.set_taps(self.revconj_access_code_symbols) def get_const(self): return self.const @@ -644,6 +465,7 @@ class correlator(gr.top_block, Qt.QWidget): + def main(top_block_cls=correlator, options=None): if StrictVersion("4.5.0") <= StrictVersion(Qt.qVersion()) < StrictVersion("5.0.0"): @@ -658,9 +480,6 @@ def main(top_block_cls=correlator, options=None): tb.show() def sig_handler(sig=None, frame=None): - tb.stop() - tb.wait() - Qt.QApplication.quit() signal.signal(signal.SIGINT, sig_handler) @@ -670,6 +489,11 @@ def main(top_block_cls=correlator, options=None): timer.start(500) timer.timeout.connect(lambda: None) + def quitting(): + tb.stop() + tb.wait() + + qapp.aboutToQuit.connect(quitting) qapp.exec_() if __name__ == '__main__': diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py new file mode 100644 index 0000000..1fa4794 --- /dev/null +++ b/tests/correlator/epy_block_0.py @@ -0,0 +1,75 @@ +import pmt + +import numpy as np +from gnuradio import gr + + +class blk(gr.sync_block): + def __init__(self): + gr.sync_block.__init__( + self, + name='Phase Lock', + in_sig=[np.complex64], + out_sig=[np.complex64] + ) + + # keep track of how many samples were processed, + # because tags have an absolute offset + self.sampnr: np.complex64 = 0 + + # because of block processing a tagged block could + # be split in half so we need to keep track of the + # "previous" values + self.last_phase = 0 + + def work(self, input_items, output_items): + # TODO: interpolate phase values for frequency correction + + out = output_items[0] + inp = input_items[0] + + # create a phase correction vector + phase = np.zeros(len(inp), dtype=np.float64) + + # read tags + tags = self.get_tags_in_window(0, 0, len(inp)) + + # get only phase tags + is_phase = lambda tag: pmt.to_python(tag.key) == "phase_est" + phase_tags = list(filter(is_phase, tags)) + + print(f"Processing {len(inp)} samples, with {len(phase_tags)} tags") + + # compute correction from previous block + first_tag = phase_tags[0] + first_idx = first_tag.offset - self.sampnr + phase[:first_idx] = self.last_phase + + # iterate phase tags "in the middle" + for prev_tag, next_tag in zip(phase_tags, phase_tags[1:]): + # unpack pmt values + pval = pmt.to_python(prev_tag.value) + + # compute indexes in phase vector + pidx = prev_tag.offset - self.sampnr + idx = next_tag.offset - self.sampnr + + # compute phase correction for block + phase[pidx:idx] = pval + print(f"Correction for block {pidx} to {idx} is {pval}") + + # compute the remaining part of the block + last_tag = phase_tags[-1] + last_val = pmt.to_python(last_tag.value) + last_idx = last_tag.offset - self.sampnr + + phase[last_idx:] = last_val + + # save values for next call + self.last_phase = last_val + + # mark samples as processed and compute to output + self.sampnr += len(inp) + out[:] = inp * np.exp(-1j * phase) + + return len(out) -- cgit v1.2.1 From a396c568457bc4e36eac820c209d133e9a7b0b2d Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Thu, 2 Dec 2021 12:52:34 +0100 Subject: Delete ZMQ tests --- tests/zmq/lena512color.tiff | Bin 786572 -> 0 bytes tests/zmq/server.py | 4 -- tests/zmq/zmqtest.grc | 112 -------------------------------------------- tests/zmq/zmqtest.py | 85 --------------------------------- 4 files changed, 201 deletions(-) delete mode 100644 tests/zmq/lena512color.tiff delete mode 100644 tests/zmq/server.py delete mode 100644 tests/zmq/zmqtest.grc delete mode 100755 tests/zmq/zmqtest.py diff --git a/tests/zmq/lena512color.tiff b/tests/zmq/lena512color.tiff deleted file mode 100644 index ffe5c83..0000000 Binary files a/tests/zmq/lena512color.tiff and /dev/null differ diff --git a/tests/zmq/server.py b/tests/zmq/server.py deleted file mode 100644 index be4bede..0000000 --- a/tests/zmq/server.py +++ /dev/null @@ -1,4 +0,0 @@ -import zmq -import pmt - -import numpy as np diff --git a/tests/zmq/zmqtest.grc b/tests/zmq/zmqtest.grc deleted file mode 100644 index ad1729d..0000000 --- a/tests/zmq/zmqtest.grc +++ /dev/null @@ -1,112 +0,0 @@ -options: - parameters: - author: Naoki Pross - category: '[GRC Hier Blocks]' - cmake_opt: '' - comment: '' - copyright: '' - description: '' - gen_cmake: 'On' - gen_linking: dynamic - generate_options: no_gui - hier_block_src_path: '.:' - id: zmqtest - max_nouts: '0' - output_language: python - placement: (0,0) - qt_qss_theme: '' - realtime_scheduling: '1' - run: 'True' - run_command: '{python} -u {filename}' - run_options: prompt - sizing_mode: fixed - thread_safe_setters: '' - title: ZMQ test - window_size: '' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [8, 8] - rotation: 0 - state: enabled - -blocks: -- name: samp_rate - id: variable - parameters: - comment: '' - value: '32000' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [184, 12] - rotation: 0 - state: enabled -- name: blocks_throttle_0 - id: blocks_throttle - parameters: - affinity: '' - alias: '' - comment: '' - ignoretag: 'True' - maxoutbuf: '0' - minoutbuf: '0' - samples_per_second: samp_rate - type: complex - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [440, 324.0] - rotation: 0 - state: true -- name: zeromq_rep_sink_0 - id: zeromq_rep_sink - parameters: - address: '' - affinity: '' - alias: '' - comment: '' - hwm: '-1' - pass_tags: 'False' - timeout: '100' - type: complex - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [664, 308.0] - rotation: 0 - state: true -- name: zeromq_req_source_0 - id: zeromq_req_source - parameters: - address: '' - affinity: '' - alias: '' - comment: '' - hwm: '-1' - maxoutbuf: '0' - minoutbuf: '0' - pass_tags: 'False' - timeout: '100' - type: complex - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [216, 308.0] - rotation: 0 - state: true - -connections: -- [blocks_throttle_0, '0', zeromq_rep_sink_0, '0'] -- [zeromq_req_source_0, '0', blocks_throttle_0, '0'] - -metadata: - file_format: 1 diff --git a/tests/zmq/zmqtest.py b/tests/zmq/zmqtest.py deleted file mode 100755 index a046c13..0000000 --- a/tests/zmq/zmqtest.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# -# SPDX-License-Identifier: GPL-3.0 -# -# GNU Radio Python Flow Graph -# Title: ZMQ test -# Author: Naoki Pross -# GNU Radio version: 3.8.2.0 - -from gnuradio import blocks -from gnuradio import gr -from gnuradio.filter import firdes -import sys -import signal -from argparse import ArgumentParser -from gnuradio.eng_arg import eng_float, intx -from gnuradio import eng_notation -from gnuradio import zeromq - - -class zmqtest(gr.top_block): - - def __init__(self): - gr.top_block.__init__(self, "ZMQ test") - - ################################################## - # Variables - ################################################## - self.samp_rate = samp_rate = 32000 - - ################################################## - # Blocks - ################################################## - self.zeromq_req_source_0 = zeromq.req_source(gr.sizeof_gr_complex, 1, '', 100, False, -1) - self.zeromq_rep_sink_0 = zeromq.rep_sink(gr.sizeof_gr_complex, 1, '', 100, False, -1) - self.blocks_throttle_0 = blocks.throttle(gr.sizeof_gr_complex*1, samp_rate,True) - - - - ################################################## - # Connections - ################################################## - self.connect((self.blocks_throttle_0, 0), (self.zeromq_rep_sink_0, 0)) - self.connect((self.zeromq_req_source_0, 0), (self.blocks_throttle_0, 0)) - - - def get_samp_rate(self): - return self.samp_rate - - def set_samp_rate(self, samp_rate): - self.samp_rate = samp_rate - self.blocks_throttle_0.set_sample_rate(self.samp_rate) - - - - - -def main(top_block_cls=zmqtest, options=None): - if gr.enable_realtime_scheduling() != gr.RT_OK: - print("Error: failed to enable real-time scheduling.") - tb = top_block_cls() - - def sig_handler(sig=None, frame=None): - tb.stop() - tb.wait() - - sys.exit(0) - - signal.signal(signal.SIGINT, sig_handler) - signal.signal(signal.SIGTERM, sig_handler) - - tb.start() - - try: - input('Press Enter to quit: ') - except EOFError: - pass - tb.stop() - tb.wait() - - -if __name__ == '__main__': - main() -- cgit v1.2.1 From f7b154f2485b2d897db449890684928e12b1734e Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Thu, 2 Dec 2021 12:54:32 +0100 Subject: Delete XOR Correlator (replaced with by phase correction) --- src/gr-fadingui/grc/CMakeLists.txt | 1 - .../grc/fadingui_xor_frame_sync.block.yml | 42 ------ src/gr-fadingui/python/CMakeLists.txt | 2 - src/gr-fadingui/python/__init__.py | 2 +- src/gr-fadingui/python/qa_xor_frame_sync.py | 57 -------- src/gr-fadingui/python/xor_frame_sync.py | 152 --------------------- 6 files changed, 1 insertion(+), 255 deletions(-) delete mode 100644 src/gr-fadingui/grc/fadingui_xor_frame_sync.block.yml delete mode 100644 src/gr-fadingui/python/qa_xor_frame_sync.py delete mode 100644 src/gr-fadingui/python/xor_frame_sync.py diff --git a/src/gr-fadingui/grc/CMakeLists.txt b/src/gr-fadingui/grc/CMakeLists.txt index 2394de4..d5f23a6 100644 --- a/src/gr-fadingui/grc/CMakeLists.txt +++ b/src/gr-fadingui/grc/CMakeLists.txt @@ -20,7 +20,6 @@ install(FILES fadingui_datasource.block.yml fadingui_dearpygui_sink.block.yml - fadingui_xor_frame_sync.block.yml fadingui_deframer.block.yml fadingui_frame_obj.block.yml fadingui_multipath_fading.block.yml DESTINATION share/gnuradio/grc/blocks diff --git a/src/gr-fadingui/grc/fadingui_xor_frame_sync.block.yml b/src/gr-fadingui/grc/fadingui_xor_frame_sync.block.yml deleted file mode 100644 index 1a8640d..0000000 --- a/src/gr-fadingui/grc/fadingui_xor_frame_sync.block.yml +++ /dev/null @@ -1,42 +0,0 @@ -id: fadingui_xor_frame_sync -label: XOR Correlation Synchronizer -category: '[fadingui]' -flags: [ python ] - -templates: - imports: import fadingui - make: fadingui.xor_frame_sync(sync_pattern=${pattern}, buffer_size=${buffer_size}) - -# Make one 'parameters' list entry for every parameter you want settable from the GUI. -# Keys include: -# * id (makes the value accessible as \$keyname, e.g. in the make entry) -# * label (label shown in the GUI) -# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...) -parameters: -- id: pattern - label: Bit pattern - dtype: raw -- id: buffer_size - label: Delay buffer size - dtype: raw - -# Make one 'inputs' list entry per input and one 'outputs' list entry per output. -# Keys include: -# * label (an identifier for the GUI) -# * domain (optional - stream or message. Default is stream) -# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...) -# * vlen (optional - data stream vector length. Default is 1) -# * optional (optional - set to 1 for optional inputs. Default is 0) -inputs: -- label: in - domain: stream - dtype: byte - -outputs: -- label: out - domain: stream - dtype: byte - -# 'file_format' specifies the version of the GRC yml format used in the file -# and should usually not be changed. -file_format: 1 diff --git a/src/gr-fadingui/python/CMakeLists.txt b/src/gr-fadingui/python/CMakeLists.txt index 95bb852..eb0e7cc 100644 --- a/src/gr-fadingui/python/CMakeLists.txt +++ b/src/gr-fadingui/python/CMakeLists.txt @@ -35,7 +35,6 @@ GR_PYTHON_INSTALL( logger.py datasource.py dearpygui_sink.py - xor_frame_sync.py deframer.py frame_obj.py multipath_fading.py DESTINATION ${GR_PYTHON_DIR}/fadingui @@ -48,5 +47,4 @@ include(GrTest) set(GR_TEST_TARGET_DEPS gnuradio-fadingui) set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig) -GR_ADD_TEST(qa_xor_frame_sync ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_xor_frame_sync.py) GR_ADD_TEST(qa_multipath_fading ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_multipath_fading.py) diff --git a/src/gr-fadingui/python/__init__.py b/src/gr-fadingui/python/__init__.py index 5a7b546..dba999e 100644 --- a/src/gr-fadingui/python/__init__.py +++ b/src/gr-fadingui/python/__init__.py @@ -34,7 +34,7 @@ except ImportError: # import any pure python here from .datasource import datasource from .dearpygui_sink import dearpygui_sink -from .xor_frame_sync import xor_frame_sync + from .deframer import deframer from .frame_obj import frame_obj from .multipath_fading import multipath_fading diff --git a/src/gr-fadingui/python/qa_xor_frame_sync.py b/src/gr-fadingui/python/qa_xor_frame_sync.py deleted file mode 100644 index 9c480a0..0000000 --- a/src/gr-fadingui/python/qa_xor_frame_sync.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python - -from gnuradio import gr, gr_unittest, blocks - -from xor_frame_sync import xor_frame_sync -import numpy as np - - -class test_xor_frame_sync(gr_unittest.TestCase): - - def setUp(self): - self.tb = gr.top_block() - - def tearDown(self): - self.tb = None - - def test_001(self): - """Test a byte aligned delay""" - pattern = np.array([0xc0, 0xff, 0xee], dtype=np.uint8) - testdata = np.packbits(np.concatenate([ - np.unpackbits(np.arange(0, 5, dtype=np.uint8)), - np.random.randint(0, 2, size = 8 * 5), - np.unpackbits(pattern), - np.random.randint(0, 2, size = 64) - ])) - - src = blocks.vector_source_b(testdata) - op = xor_frame_sync(pattern, 2048) - dst = blocks.vector_sink_b() - - self.tb.connect(src, op, dst) - self.tb.run() - - self.assertEqual(op.synchronized, True) - - # FIXME: implement feature - # def test_002(self): - # """Test a byte unaligned delay""" - # pattern = np.array([0xbe, 0xef], dtype=np.uint8) - # testdata = np.packbits(np.concatenate([ - # np.unpackbits(np.arange(0, 10, dtype=np.uint8)), - # np.random.randint(0, 2, size = (2 + 8 * 5)), np.unpackbits(pattern), - # np.random.randint(0, 2, size = 64) - # ])) - - # src = blocks.vector_source_b(testdata) - # op = xor_frame_sync(pattern, 2048) - # dst = blocks.vector_sink_b() - - # self.tb.connect(src, op, dst) - # self.tb.run() - - # self.assertEqual(op.synchronized, True) - - -if __name__ == "__main__": - gr_unittest.run(test_xor_frame_sync) diff --git a/src/gr-fadingui/python/xor_frame_sync.py b/src/gr-fadingui/python/xor_frame_sync.py deleted file mode 100644 index bb5cfb1..0000000 --- a/src/gr-fadingui/python/xor_frame_sync.py +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# Copyright 2021 Naoki Pross. - - -import numpy as np -from numpy_ringbuffer import RingBuffer - -from gnuradio import gr - -from fadingui.logger import get_logger -log = get_logger("xor_frame_sync") - - -class xor_frame_sync(gr.sync_block): - """ - Performs a frame synchronization by XOR matching a preamble bit sequence - """ - def __init__(self, sync_pattern, buffer_size): - # TODO: buffer size should be in packets - gr.sync_block.__init__(self, - name="xor_frame_sync", - in_sig=[np.byte], - out_sig=[np.byte]) - - # binary pattern to match - self.pattern = sync_pattern - self.nbytes = len(self.pattern) - - self.pattern_bits = np.unpackbits(np.array(self.pattern, dtype=np.uint8))[::-1] - self.nbits = len(self.pattern_bits) - - log.debug(f"Loaded pattern {self.pattern_bits} length={self.nbits}") - assert(self.nbits % 8 == 0) - - # packed buffer to delay the data - self.delaybuf = RingBuffer(buffer_size, dtype=np.uint8) - self.delay = 0 - - log.debug(f"Created delay ring buffer of size {self.delaybuf.maxlen}") - - # unpacked buffer to compute correlation values, initially filled with zeros - self.corrbuf = RingBuffer(self.nbits, dtype=np.uint8) - self.corrbuf.extend(np.zeros(self.corrbuf.maxlen)) - - # synchronization state - self.synchronized = False - - def xcorrelation(self, v): - """ - Compute the binary correlations between the stored pattern and - correlation buffer, while shifting v into the buffer. - - Binary correlation between two bit vectors is just size of the - vector(s) minus the number of bits that differ. - - @return: Number of bits of v that were shifted into the buffer - when the correlation matched. If no match is found - the return value is None. - """ - # this could be much faster with shifts, bitwise or and xor - # but this should do alright for the moment - v_bits = np.unpackbits(np.array(v, dtype=np.uint8)) - for bitnr, b in enumerate(v_bits): - self.corrbuf.appendleft(b) - if (np.bitwise_xor(self.corrbuf, self.pattern_bits) == 0).all(): - return bitnr - - # no cross correlation found - return None - - def work(self, input_items, output_items): - """ - Process the inputs, that means: - - - Check that the buffer is synchronized, i.e. there is the sync - pattern appears every k bits, where k is the size of the packet. - - - If the buffer is not synchronized, compute a binary cross - correlation to find how much the stream should be delayed. - """ - # array of samples, growing index = forward in time - inp = input_items[0] - inp_len = len(inp) - - if not self.synchronized: - if inp_len > self.delaybuf.maxlen: - log.error("Input is bigger than delay buffer") - - # FIXME: Makes the QA hang for some reason - raise NotImplemented - - # create space for new samples in the delay buffer - self.delaybuf.extendleft(np.zeros(inp_len)) - - # Add values and while processing - for bytenr, value in enumerate(inp): - # save value in the buffer - # FIXME: this is wrong, it should be in reverse order - self.delaybuf.appendleft(value) - - # compute the cross correlation - bitnr = self.xcorrelation(value) - if bitnr is not None: - # correlation was found - delay_bits = (bitnr - 7) - delay_bytes = 8 * (bytenr -1) - - log.debug(f"Synchronized with delay_bytes={delay_bytes} delay_bits={delay_bits}") - - # FIXME: add bit delay - self.delay = delay_bytes - self.synchronized = True - - # Not aligned to bytes - if delay_bits != 0: - log.error("Not implemented: byte unaligned delay") - self.synchronized = False - self.delay = 0 - - # FIXME: Makes the QA hang for some reason - # raise NotImplemented - - # stop processing inputs - break - - if not self.synchronized: - log.warning(f"Processed {inp_len} samples but could not synchronize") - else: - self.delaybuf.extendleft(inp) - - # return data with delay - out = output_items[0] - # FIXME: this is also wrong - # out[:] = self.delaybuf[:len(out)] - out[:] = inp[:] - - - inptmp = np.array(inp[:12], dtype=np.uint8) - inphex = np.array(list(map(hex, inptmp))) - inpbits = np.array(list(map("{:08b}".format, inptmp))) - - log.debug(f"inp={inptmp}") - log.debug(f"inp={inphex}") - log.debug(f"inp={inpbits}") - - # outtmp = np.array(out[:12], dtype=np.uint8) - # log.debug(f"out={outtmp}") - - return inp_len - -- cgit v1.2.1 From 834febb9aa0dac463f43914cb028be931f85de73 Mon Sep 17 00:00:00 2001 From: sara Date: Thu, 2 Dec 2021 20:02:16 +0100 Subject: =?UTF-8?q?BER=20Block=20erstellt,=20l=C3=A4uft=20noch=20nichtwie?= =?UTF-8?q?=20gew=C3=BCnscht?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- notebooks/BER .ipynb | 171 +++++++++++++++++++++++++++++ notebooks/FIR_mehrere_V2.ipynb | 23 +++- notebooks/FrameSynchronization.ipynb | 4 +- src/gr-fadingui/grc/CMakeLists.txt | 3 +- src/gr-fadingui/grc/fadingui_ber.block.yml | 37 +++++++ src/gr-fadingui/python/CMakeLists.txt | 4 +- src/gr-fadingui/python/__init__.py | 1 + src/gr-fadingui/python/ber.py | 55 ++++++++++ src/gr-fadingui/python/qa_ber.py | 41 +++++++ tests/BER/Bit_error.grc | 98 +++++++++++++++++ tests/BER/Test_Bit_Errorrate.py | 143 ++++++++++++++++++++++++ tests/correlator/correlator.py | 5 +- 12 files changed, 578 insertions(+), 7 deletions(-) create mode 100644 notebooks/BER .ipynb create mode 100644 src/gr-fadingui/grc/fadingui_ber.block.yml create mode 100644 src/gr-fadingui/python/ber.py create mode 100755 src/gr-fadingui/python/qa_ber.py create mode 100644 tests/BER/Bit_error.grc create mode 100755 tests/BER/Test_Bit_Errorrate.py diff --git a/notebooks/BER .ipynb b/notebooks/BER .ipynb new file mode 100644 index 0000000..8e0a6f4 --- /dev/null +++ b/notebooks/BER .ipynb @@ -0,0 +1,171 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "ec5412d2", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np \n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "be1f0d01", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0, 1])" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "byte1= np.array([0x12, 0xe3, 0x9b])\n", + "byte2 = np.array([0x12, 0xe3, 0x9c])\n", + "b1 = np.array([0,0])\n", + "b2 = np.array([0,1])\n", + "b1\n", + "b2" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "c256a3d0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0 0 7]\n" + ] + }, + { + "data": { + "text/plain": [ + "array([0, 1], dtype=uint8)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v = byte1^byte2\n", + "v1 = np.array (v,dtype = np.uint8)\n", + "print(v1)\n", + "v2 = b1^b2\n", + "v2 = np.array (v2,dtype = np.uint8)\n", + "v2" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "227f0142", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1]\n" + ] + }, + { + "data": { + "text/plain": [ + "array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], dtype=uint8)" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "z = np.unpackbits(v1)\n", + "print(z)\n", + "z1 = np.unpackbits(v2)\n", + "z1" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "092d8dae", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a = sum(z)\n", + "a" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ac2e304", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "034142b6", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f203fbce", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/FIR_mehrere_V2.ipynb b/notebooks/FIR_mehrere_V2.ipynb index 6fbcf3b..9fdea2e 100644 --- a/notebooks/FIR_mehrere_V2.ipynb +++ b/notebooks/FIR_mehrere_V2.ipynb @@ -2,6 +2,7 @@ "cells": [ { "cell_type": "markdown", + "id": "c377e559", "metadata": {}, "source": [ "# FIR Filter Parameters" @@ -10,6 +11,7 @@ { "cell_type": "code", "execution_count": 1, + "id": "f14e4383", "metadata": {}, "outputs": [], "source": [ @@ -21,6 +23,7 @@ { "cell_type": "code", "execution_count": 2, + "id": "e8e2130b", "metadata": {}, "outputs": [], "source": [ @@ -31,6 +34,7 @@ }, { "cell_type": "markdown", + "id": "d39d7698", "metadata": {}, "source": [ "# Dealy Window\n" @@ -39,6 +43,7 @@ { "cell_type": "code", "execution_count": 3, + "id": "bd005466", "metadata": {}, "outputs": [ { @@ -66,6 +71,7 @@ { "cell_type": "code", "execution_count": 4, + "id": "e48a4dbd", "metadata": {}, "outputs": [ { @@ -96,6 +102,7 @@ }, { "cell_type": "markdown", + "id": "0ddadf5d", "metadata": {}, "source": [ "# FIR" @@ -104,6 +111,7 @@ { "cell_type": "code", "execution_count": 5, + "id": "bd6d61b3", "metadata": {}, "outputs": [], "source": [ @@ -119,6 +127,7 @@ { "cell_type": "code", "execution_count": 6, + "id": "ef41b7d8", "metadata": {}, "outputs": [], "source": [ @@ -129,6 +138,7 @@ { "cell_type": "code", "execution_count": 7, + "id": "fea2ae61", "metadata": {}, "outputs": [ { @@ -166,6 +176,7 @@ { "cell_type": "code", "execution_count": 8, + "id": "a65b4b37", "metadata": {}, "outputs": [ { @@ -186,6 +197,7 @@ { "cell_type": "code", "execution_count": 9, + "id": "ce9b4835", "metadata": {}, "outputs": [ { @@ -206,6 +218,7 @@ { "cell_type": "code", "execution_count": 10, + "id": "fc67f0a5", "metadata": {}, "outputs": [ { @@ -226,6 +239,7 @@ }, { "cell_type": "markdown", + "id": "35e1aaef", "metadata": {}, "source": [ "# FIR mit Delay \n" @@ -234,6 +248,7 @@ { "cell_type": "code", "execution_count": 58, + "id": "d8986bc9", "metadata": {}, "outputs": [ { @@ -302,6 +317,7 @@ { "cell_type": "code", "execution_count": 25, + "id": "d39528be", "metadata": {}, "outputs": [ { @@ -356,6 +372,7 @@ { "cell_type": "code", "execution_count": 26, + "id": "b6f61760", "metadata": {}, "outputs": [ { @@ -429,6 +446,7 @@ { "cell_type": "code", "execution_count": 14, + "id": "52c30c0f", "metadata": {}, "outputs": [ { @@ -450,6 +468,7 @@ { "cell_type": "code", "execution_count": null, + "id": "356ce18c", "metadata": {}, "outputs": [], "source": [] @@ -457,7 +476,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -471,7 +490,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.9.2" } }, "nbformat": 4, diff --git a/notebooks/FrameSynchronization.ipynb b/notebooks/FrameSynchronization.ipynb index 911ddd6..27e615c 100644 --- a/notebooks/FrameSynchronization.ipynb +++ b/notebooks/FrameSynchronization.ipynb @@ -216,7 +216,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -230,7 +230,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.11" + "version": "3.9.2" } }, "nbformat": 4, diff --git a/src/gr-fadingui/grc/CMakeLists.txt b/src/gr-fadingui/grc/CMakeLists.txt index d5f23a6..297ae8d 100644 --- a/src/gr-fadingui/grc/CMakeLists.txt +++ b/src/gr-fadingui/grc/CMakeLists.txt @@ -22,5 +22,6 @@ install(FILES fadingui_dearpygui_sink.block.yml fadingui_deframer.block.yml fadingui_frame_obj.block.yml - fadingui_multipath_fading.block.yml DESTINATION share/gnuradio/grc/blocks + fadingui_multipath_fading.block.yml + fadingui_ber.block.yml DESTINATION share/gnuradio/grc/blocks ) diff --git a/src/gr-fadingui/grc/fadingui_ber.block.yml b/src/gr-fadingui/grc/fadingui_ber.block.yml new file mode 100644 index 0000000..3383df5 --- /dev/null +++ b/src/gr-fadingui/grc/fadingui_ber.block.yml @@ -0,0 +1,37 @@ +id: fadingui_ber +label: BER +category: '[fadingui]' + +templates: + imports: import fadingui + make: fadingui.ber(vgl=${vgl}) + +# Make one 'parameters' list entry for every parameter you want settable from the GUI. +# Keys include: +# * id (makes the value accessible as \$keyname, e.g. in the make entry) +# * label (label shown in the GUI) +# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...) +parameters: + - id: vgl + label: Vergleichsparameter + dtype: raw +# - id: ... +# label: ... +# dtype: ... + +# Make one 'inputs' list entry per input and one 'outputs' list entry per output. +# Keys include: +# * label (an identifier for the GUI) +# * domain (optional - stream or message. Default is stream) +# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...) +# * vlen (optional - data stream vector length. Default is 1) +# * optional (optional - set to 1 for optional inputs. Default is 0) +inputs: +- label: in + domain: stream + dtype: byte + + +# 'file_format' specifies the version of the GRC yml format used in the file +# and should usually not be changed. +file_format: 1 diff --git a/src/gr-fadingui/python/CMakeLists.txt b/src/gr-fadingui/python/CMakeLists.txt index eb0e7cc..e04eb5b 100644 --- a/src/gr-fadingui/python/CMakeLists.txt +++ b/src/gr-fadingui/python/CMakeLists.txt @@ -37,7 +37,8 @@ GR_PYTHON_INSTALL( dearpygui_sink.py deframer.py frame_obj.py - multipath_fading.py DESTINATION ${GR_PYTHON_DIR}/fadingui + multipath_fading.py + ber.py DESTINATION ${GR_PYTHON_DIR}/fadingui ) ######################################################################## @@ -48,3 +49,4 @@ include(GrTest) set(GR_TEST_TARGET_DEPS gnuradio-fadingui) set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig) GR_ADD_TEST(qa_multipath_fading ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_multipath_fading.py) +GR_ADD_TEST(qa_ber ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_ber.py) diff --git a/src/gr-fadingui/python/__init__.py b/src/gr-fadingui/python/__init__.py index dba999e..9fe45d5 100644 --- a/src/gr-fadingui/python/__init__.py +++ b/src/gr-fadingui/python/__init__.py @@ -38,5 +38,6 @@ from .dearpygui_sink import dearpygui_sink from .deframer import deframer from .frame_obj import frame_obj from .multipath_fading import multipath_fading +from .ber import ber # diff --git a/src/gr-fadingui/python/ber.py b/src/gr-fadingui/python/ber.py new file mode 100644 index 0000000..387b75f --- /dev/null +++ b/src/gr-fadingui/python/ber.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2021 Sara Cinzia Halter. +# +# This is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# This software is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this software; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + + +import numpy as np +from gnuradio import gr + +from fadingui.logger import get_logger +log = get_logger("ber") + +class ber(gr.sync_block): + """ + docstring for block ber + """ + def __init__(self, vgl): + gr.sync_block.__init__(self, + name="ber", + in_sig=[np.byte, ], + out_sig=None) + self.vgl=vgl + + + + def work(self, input_items, output_items): + inp = input_items[0] + # <+signal processing here+> + + v = self.vgl^inp + v_array= np.array(v,dtype = np.uint8) + + ber = sum(np.unpackbits(v_array)) + + + log.debug(ber) + + return len(input_items[0]) + diff --git a/src/gr-fadingui/python/qa_ber.py b/src/gr-fadingui/python/qa_ber.py new file mode 100755 index 0000000..8b6d56e --- /dev/null +++ b/src/gr-fadingui/python/qa_ber.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2021 Sara Cinzia Halter. +# +# This is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# This software is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this software; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio import gr, gr_unittest +from gnuradio import blocks +from ber import ber + +class qa_ber(gr_unittest.TestCase): + + def setUp(self): + self.tb = gr.top_block() + + def tearDown(self): + self.tb = None + + def test_001_t(self): + # set up fg + self.tb.run() + # check data + + +if __name__ == '__main__': + gr_unittest.run(qa_ber) diff --git a/tests/BER/Bit_error.grc b/tests/BER/Bit_error.grc new file mode 100644 index 0000000..04c624b --- /dev/null +++ b/tests/BER/Bit_error.grc @@ -0,0 +1,98 @@ +options: + parameters: + author: 'Sara Halter ' + category: '[GRC Hier Blocks]' + cmake_opt: '' + comment: '' + copyright: '' + description: '' + gen_cmake: 'On' + gen_linking: dynamic + generate_options: qt_gui + hier_block_src_path: '.:' + id: Test_Bit_Errorrate + max_nouts: '0' + output_language: python + placement: (0,0) + qt_qss_theme: '' + realtime_scheduling: '' + run: 'True' + run_command: '{python} -u {filename}' + run_options: prompt + sizing_mode: fixed + thread_safe_setters: '' + title: 'Bit Error Rate test ' + window_size: '' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [8, 8] + rotation: 0 + state: enabled + +blocks: +- name: samp_rate + id: variable + parameters: + comment: '' + value: '32000' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [184, 12] + rotation: 0 + state: enabled +- name: testvec + id: variable + parameters: + comment: '' + value: '[31, 53] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3]' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [216, 396.0] + rotation: 0 + state: enabled +- name: blocks_vector_source_x_0 + id: blocks_vector_source_x + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + repeat: 'True' + tags: '[]' + type: byte + vector: testvec * 1600 + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [216, 276.0] + rotation: 0 + state: enabled +- name: fadingui_ber_0 + id: fadingui_ber + parameters: + affinity: '' + alias: '' + comment: '' + vgl: testvec + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [704, 296.0] + rotation: 0 + state: true + +connections: +- [blocks_vector_source_x_0, '0', fadingui_ber_0, '0'] + +metadata: + file_format: 1 diff --git a/tests/BER/Test_Bit_Errorrate.py b/tests/BER/Test_Bit_Errorrate.py new file mode 100755 index 0000000..4022997 --- /dev/null +++ b/tests/BER/Test_Bit_Errorrate.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# SPDX-License-Identifier: GPL-3.0 +# +# GNU Radio Python Flow Graph +# Title: Bit Error Rate test +# Author: Sara Halter +# GNU Radio version: 3.8.2.0 + +from distutils.version import StrictVersion + +if __name__ == '__main__': + import ctypes + import sys + if sys.platform.startswith('linux'): + try: + x11 = ctypes.cdll.LoadLibrary('libX11.so') + x11.XInitThreads() + except: + print("Warning: failed to XInitThreads()") + +from gnuradio import blocks +from gnuradio import gr +from gnuradio.filter import firdes +import sys +import signal +from PyQt5 import Qt +from argparse import ArgumentParser +from gnuradio.eng_arg import eng_float, intx +from gnuradio import eng_notation +import fadingui + +from gnuradio import qtgui + +class Test_Bit_Errorrate(gr.top_block, Qt.QWidget): + + def __init__(self): + gr.top_block.__init__(self, "Bit Error Rate test ") + Qt.QWidget.__init__(self) + self.setWindowTitle("Bit Error Rate test ") + qtgui.util.check_set_qss() + try: + self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc')) + except: + pass + self.top_scroll_layout = Qt.QVBoxLayout() + self.setLayout(self.top_scroll_layout) + self.top_scroll = Qt.QScrollArea() + self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame) + self.top_scroll_layout.addWidget(self.top_scroll) + self.top_scroll.setWidgetResizable(True) + self.top_widget = Qt.QWidget() + self.top_scroll.setWidget(self.top_widget) + self.top_layout = Qt.QVBoxLayout(self.top_widget) + self.top_grid_layout = Qt.QGridLayout() + self.top_layout.addLayout(self.top_grid_layout) + + self.settings = Qt.QSettings("GNU Radio", "Test_Bit_Errorrate") + + try: + if StrictVersion(Qt.qVersion()) < StrictVersion("5.0.0"): + self.restoreGeometry(self.settings.value("geometry").toByteArray()) + else: + self.restoreGeometry(self.settings.value("geometry")) + except: + pass + + ################################################## + # Variables + ################################################## + self.testvec = testvec = [31, 53] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3] + self.samp_rate = samp_rate = 32000 + + ################################################## + # Blocks + ################################################## + self.fadingui_ber_0 = fadingui.ber(vgl=testvec) + self.blocks_vector_source_x_0 = blocks.vector_source_b(testvec * 1600, True, 1, []) + + + + ################################################## + # Connections + ################################################## + self.connect((self.blocks_vector_source_x_0, 0), (self.fadingui_ber_0, 0)) + + + def closeEvent(self, event): + self.settings = Qt.QSettings("GNU Radio", "Test_Bit_Errorrate") + self.settings.setValue("geometry", self.saveGeometry()) + event.accept() + + def get_testvec(self): + return self.testvec + + def set_testvec(self, testvec): + self.testvec = testvec + self.blocks_vector_source_x_0.set_data(self.testvec * 1600, []) + + def get_samp_rate(self): + return self.samp_rate + + def set_samp_rate(self, samp_rate): + self.samp_rate = samp_rate + + + + + +def main(top_block_cls=Test_Bit_Errorrate, options=None): + + if StrictVersion("4.5.0") <= StrictVersion(Qt.qVersion()) < StrictVersion("5.0.0"): + style = gr.prefs().get_string('qtgui', 'style', 'raster') + Qt.QApplication.setGraphicsSystem(style) + qapp = Qt.QApplication(sys.argv) + + tb = top_block_cls() + + tb.start() + + tb.show() + + def sig_handler(sig=None, frame=None): + Qt.QApplication.quit() + + signal.signal(signal.SIGINT, sig_handler) + signal.signal(signal.SIGTERM, sig_handler) + + timer = Qt.QTimer() + timer.start(500) + timer.timeout.connect(lambda: None) + + def quitting(): + tb.stop() + tb.wait() + + qapp.aboutToQuit.connect(quitting) + qapp.exec_() + +if __name__ == '__main__': + main() diff --git a/tests/correlator/correlator.py b/tests/correlator/correlator.py index a870cc0..67def9f 100755 --- a/tests/correlator/correlator.py +++ b/tests/correlator/correlator.py @@ -35,6 +35,7 @@ from argparse import ArgumentParser from gnuradio.eng_arg import eng_float, intx from gnuradio import eng_notation import epy_block_0 +import fadingui from gnuradio import qtgui @@ -328,6 +329,7 @@ class correlator(gr.top_block, Qt.QWidget): self.top_grid_layout.setRowStretch(r, 1) for c in range(1, 2): self.top_grid_layout.setColumnStretch(c, 1) + self.fadingui_deframer_0 = fadingui.deframer(frame_obj=) self.epy_block_0 = epy_block_0.blk() self.digital_pfb_clock_sync_xxx_0 = digital.pfb_clock_sync_ccf(sps, timing_loop_bw, rrc_taps, nfilts, 16, 1.5, 1) self.digital_corr_est_cc_0 = digital.corr_est_cc(access_code_symbols, 1, 0, .8, digital.THRESHOLD_DYNAMIC) @@ -370,7 +372,7 @@ class correlator(gr.top_block, Qt.QWidget): self.connect((self.channels_channel_model_0, 0), (self.blocks_throttle_0, 0)) self.connect((self.digital_cma_equalizer_cc_0, 0), (self.digital_corr_est_cc_0, 0)) self.connect((self.digital_cma_equalizer_cc_0, 0), (self.qtgui_const_sink_x_0, 0)) - self.connect((self.digital_constellation_decoder_cb_0, 0), (self.blocks_vector_sink_x_0, 0)) + self.connect((self.digital_constellation_decoder_cb_0, 0), (self.fadingui_deframer_0, 0)) self.connect((self.digital_constellation_modulator_0, 0), (self.channels_channel_model_0, 0)) self.connect((self.digital_constellation_modulator_0, 0), (self.qtgui_time_sink_x_1_0, 0)) self.connect((self.digital_corr_est_cc_0, 1), (self.blocks_complex_to_magphase_0_0, 0)) @@ -379,6 +381,7 @@ class correlator(gr.top_block, Qt.QWidget): self.connect((self.digital_pfb_clock_sync_xxx_0, 0), (self.digital_cma_equalizer_cc_0, 0)) self.connect((self.epy_block_0, 0), (self.digital_constellation_decoder_cb_0, 0)) self.connect((self.epy_block_0, 0), (self.qtgui_const_sink_x_0_0, 0)) + self.connect((self.fadingui_deframer_0, 0), (self.blocks_vector_sink_x_0, 0)) def closeEvent(self, event): -- cgit v1.2.1 From de7b4dac4af5ff592258f48eee72d191201826d7 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Thu, 2 Dec 2021 21:24:33 +0100 Subject: Begin frequency correction (incomplete) --- tests/correlator/correlator.grc | 65 +++++++++++++++++++++-------------- tests/correlator/correlator.py | 3 +- tests/correlator/epy_block_0.py | 75 +++++++++++++++++++++++++++-------------- 3 files changed, 92 insertions(+), 51 deletions(-) diff --git a/tests/correlator/correlator.grc b/tests/correlator/correlator.grc index aa21770..58cf3b4 100644 --- a/tests/correlator/correlator.grc +++ b/tests/correlator/correlator.grc @@ -408,7 +408,7 @@ blocks: block_tags: 'False' comment: '' epsilon: '1.0' - freq_offset: '0.00001' + freq_offset: '0.0001' maxoutbuf: '0' minoutbuf: '0' noise_voltage: '0.2' @@ -530,30 +530,45 @@ blocks: \ many samples were processed,\n # because tags have an absolute offset\n\ \ self.sampnr: np.complex64 = 0\n\n # because of block processing\ \ a tagged block could\n # be split in half so we need to keep track\ - \ of the\n # \"previous\" values\n self.last_phase = 0\n\n \ - \ def work(self, input_items, output_items):\n # TODO: interpolate phase\ - \ values for frequency correction\n\n out = output_items[0]\n \ - \ inp = input_items[0]\n\n # create a phase correction vector\n \ - \ phase = np.zeros(len(inp), dtype=np.float64)\n\n # read tags\n \ - \ tags = self.get_tags_in_window(0, 0, len(inp))\n\n # get only\ - \ phase tags\n is_phase = lambda tag: pmt.to_python(tag.key) == \"phase_est\"\ - \n phase_tags = list(filter(is_phase, tags))\n\n print(f\"Processing\ - \ {len(inp)} samples, with {len(phase_tags)} tags\")\n\n # compute correction\ - \ from previous block\n first_tag = phase_tags[0]\n first_idx\ - \ = first_tag.offset - self.sampnr\n phase[:first_idx] = self.last_phase\n\ - \n # iterate phase tags \"in the middle\"\n for prev_tag, next_tag\ - \ in zip(phase_tags, phase_tags[1:]):\n # unpack pmt values\n \ - \ pval = pmt.to_python(prev_tag.value)\n\n # compute indexes\ + \ of the\n # \"previous\" values\n self.last_tag = None\n\n \ + \ def work(self, input_items, output_items):\n # nicer aliases\n \ + \ out = output_items[0]\n inp = input_items[0]\n\n def print_phase_correction(start,\ + \ end, phase, freq):\n print(f\"Correction for block {start:3d} to\ + \ {end:3d} is phase = {phase: 2.4f} rad, freq = {freq * 1e3: 2.4f} milli rad/samp\"\ + )\n\n # read only phase tags\n tags = self.get_tags_in_window(0,\ + \ 0, len(inp))\n\n is_phase = lambda tag: pmt.to_python(tag.key) == \"\ + phase_est\"\n phase_tags = list(filter(is_phase, tags))\n\n #\ + \ FIXME: what if there are no tags? check that!\n\n print(f\"Processing\ + \ {len(inp)} samples, with {len(phase_tags)} tags\")\n\n # create a phase\ + \ correction vector\n phase = np.zeros(len(inp), dtype=np.float64)\n\n\ + \ # compute correction from previous block (if present)\n if self.last_tag:\n\ + \ # variables for first and last phase values\n lval =\ + \ pmt.to_python(self.last_tag.value)\n fval = pmt.to_python(phase_tags[0].value)\n\ + \n # compute index for phase vector\n fidx = phase_tags[0].offset\ + \ - self.sampnr\n\n # compute frequency offset\n nsamples\ + \ = phase_tags[0].offset - self.last_tag.offset\n freq = (fval -\ + \ lval) / nsamples\n\n # total phase correction is: phase + freq\ + \ * time\n phase[:fidx] = lval * np.ones(fidx) + freq * np.arange(0,\ + \ fidx)\n\n # compute correction\n print_phase_correction(0,\ + \ fidx, lval, freq)\n\n # iterate phase tags \"in the middle\"\n \ + \ # FIXME: what if there are less than 2 tags?\n # the code\ + \ below will probably crash\n for prev_tag, next_tag in zip(phase_tags,\ + \ phase_tags[1:]):\n # unpack pmt values\n pval = pmt.to_python(prev_tag.value)\n\ + \ nval = pmt.to_python(next_tag.value)\n\n # compute indexes\ \ in phase vector\n pidx = prev_tag.offset - self.sampnr\n \ - \ idx = next_tag.offset - self.sampnr\n\n # compute phase correction\ - \ for block\n phase[pidx:idx] = pval\n print(f\"Correction\ - \ for block {pidx} to {idx} is {pval}\")\n\n # compute the remaining\ - \ part of the block\n last_tag = phase_tags[-1]\n last_val = pmt.to_python(last_tag.value)\n\ - \ last_idx = last_tag.offset - self.sampnr\n\n phase[last_idx:]\ - \ = last_val\n\n # save values for next call\n self.last_phase\ - \ = last_val\n\n # mark samples as processed and compute to output\n\ - \ self.sampnr += len(inp)\n out[:] = inp * np.exp(-1j * phase)\n\ - \n return len(out)\n" + \ nidx = next_tag.offset - self.sampnr\n\n # compute frquency\ + \ correction for block by linearly interpolating\n # frame values\n\ + \ nsamples = nidx - pidx\n freq = (nval - pval) / nsamples\n\ + \n # total correction is: phase + freq * time\n phase[pidx:nidx]\ + \ = pval * np.ones(nsamples) + freq * np.arange(0, nsamples)\n print_phase_correction(pidx,\ + \ nidx, pval, freq)\n\n # for the last block because the next tag is\ + \ unknown (in the future) we\n # cannot predict the frequency offset.\ + \ Thus we save the last tag for\n # the next call.\n self.last_tag\ + \ = phase_tags[-1]\n val = pmt.to_python(self.last_tag.value)\n \ + \ idx = self.last_tag.offset - self.sampnr\n\n phase[idx:] = val\n\n\ + \ # compute correction\n out[:] = inp * np.exp(-1j * phase)\n\n\ + \ # increment processed samples counter\n self.sampnr += len(inp)\n\ + \ return len(phase)\n" affinity: '' alias: '' comment: '' @@ -583,7 +598,7 @@ blocks: bus_structure: null coordinate: [552, 1388.0] rotation: 0 - state: true + state: bypassed - name: fir_filter_xxx_1 id: fir_filter_xxx parameters: diff --git a/tests/correlator/correlator.py b/tests/correlator/correlator.py index a870cc0..e8eaaa8 100755 --- a/tests/correlator/correlator.py +++ b/tests/correlator/correlator.py @@ -35,6 +35,7 @@ from argparse import ArgumentParser from gnuradio.eng_arg import eng_float, intx from gnuradio import eng_notation import epy_block_0 +import fadingui from gnuradio import qtgui @@ -343,7 +344,7 @@ class correlator(gr.top_block, Qt.QWidget): self.digital_cma_equalizer_cc_0 = digital.cma_equalizer_cc(15, 1, .002, 1) self.channels_channel_model_0 = channels.channel_model( noise_voltage=0.2, - frequency_offset=0.00001, + frequency_offset=0.0001, epsilon=1.0, taps=[-1.4 + .4j], noise_seed=243, diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py index 1fa4794..90ad75e 100644 --- a/tests/correlator/epy_block_0.py +++ b/tests/correlator/epy_block_0.py @@ -20,56 +20,81 @@ class blk(gr.sync_block): # because of block processing a tagged block could # be split in half so we need to keep track of the # "previous" values - self.last_phase = 0 + self.last_tag = None def work(self, input_items, output_items): - # TODO: interpolate phase values for frequency correction - + # nicer aliases out = output_items[0] inp = input_items[0] - # create a phase correction vector - phase = np.zeros(len(inp), dtype=np.float64) + def print_phase_correction(start, end, phase, freq): + print(f"Correction for block {start:3d} to {end:3d} is phase = {phase: 2.4f} rad, freq = {freq * 1e3: 2.4f} milli rad/samp") - # read tags + # read only phase tags tags = self.get_tags_in_window(0, 0, len(inp)) - # get only phase tags is_phase = lambda tag: pmt.to_python(tag.key) == "phase_est" phase_tags = list(filter(is_phase, tags)) + # FIXME: what if there are no tags? check that! + print(f"Processing {len(inp)} samples, with {len(phase_tags)} tags") - # compute correction from previous block - first_tag = phase_tags[0] - first_idx = first_tag.offset - self.sampnr - phase[:first_idx] = self.last_phase + # create a phase correction vector + phase = np.zeros(len(inp), dtype=np.float64) + + # compute correction from previous block (if present) + if self.last_tag: + # variables for first and last phase values + lval = pmt.to_python(self.last_tag.value) + fval = pmt.to_python(phase_tags[0].value) + + # compute index for phase vector + fidx = phase_tags[0].offset - self.sampnr + + # compute frequency offset + nsamples = phase_tags[0].offset - self.last_tag.offset + freq = (fval - lval) / nsamples + + # total phase correction is: phase + freq * time + phase[:fidx] = lval * np.ones(fidx) + freq * np.arange(0, fidx) + + # compute correction + print_phase_correction(0, fidx, lval, freq) # iterate phase tags "in the middle" + # FIXME: what if there are less than 2 tags? + # the code below will probably crash for prev_tag, next_tag in zip(phase_tags, phase_tags[1:]): # unpack pmt values pval = pmt.to_python(prev_tag.value) + nval = pmt.to_python(next_tag.value) # compute indexes in phase vector pidx = prev_tag.offset - self.sampnr - idx = next_tag.offset - self.sampnr + nidx = next_tag.offset - self.sampnr - # compute phase correction for block - phase[pidx:idx] = pval - print(f"Correction for block {pidx} to {idx} is {pval}") + # compute frquency correction for block by linearly interpolating + # frame values + nsamples = nidx - pidx + freq = (nval - pval) / nsamples - # compute the remaining part of the block - last_tag = phase_tags[-1] - last_val = pmt.to_python(last_tag.value) - last_idx = last_tag.offset - self.sampnr + # total correction is: phase + freq * time + phase[pidx:nidx] = pval * np.ones(nsamples) + freq * np.arange(0, nsamples) + print_phase_correction(pidx, nidx, pval, freq) - phase[last_idx:] = last_val + # for the last block because the next tag is unknown (in the future) we + # cannot predict the frequency offset. Thus we save the last tag for + # the next call. + self.last_tag = phase_tags[-1] + val = pmt.to_python(self.last_tag.value) + idx = self.last_tag.offset - self.sampnr - # save values for next call - self.last_phase = last_val + phase[idx:] = val - # mark samples as processed and compute to output - self.sampnr += len(inp) + # compute correction out[:] = inp * np.exp(-1j * phase) - return len(out) + # increment processed samples counter + self.sampnr += len(inp) + return len(phase) -- cgit v1.2.1 From 6d56e1b35b061ffe4f677d0d6e7867f366068e82 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Thu, 2 Dec 2021 21:27:17 +0100 Subject: Remove custom blocks from correlator test --- tests/correlator/correlator.grc | 21 ++------------------- tests/correlator/correlator.py | 5 +---- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/tests/correlator/correlator.grc b/tests/correlator/correlator.grc index 58cf3b4..f54430c 100644 --- a/tests/correlator/correlator.grc +++ b/tests/correlator/correlator.grc @@ -357,7 +357,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [840, 1392.0] + coordinate: [536, 1392.0] rotation: 0 state: true - name: blocks_vector_source_x_0 @@ -583,22 +583,6 @@ blocks: coordinate: [1088, 1040.0] rotation: 0 state: enabled -- name: fadingui_deframer_0 - id: fadingui_deframer - parameters: - affinity: '' - alias: '' - comment: '' - frame_obj: '' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [552, 1388.0] - rotation: 0 - state: bypassed - name: fir_filter_xxx_1 id: fir_filter_xxx parameters: @@ -1668,7 +1652,7 @@ connections: - [digital_cma_equalizer_cc_0, '0', fir_filter_xxx_1, '0'] - [digital_cma_equalizer_cc_0, '0', qtgui_const_sink_x_0, '0'] - [digital_cma_equalizer_cc_0, '0', qtgui_time_sink_x_1_1, '0'] -- [digital_constellation_decoder_cb_0, '0', fadingui_deframer_0, '0'] +- [digital_constellation_decoder_cb_0, '0', blocks_vector_sink_x_0, '0'] - [digital_constellation_modulator_0, '0', blocks_stream_mux_1, '1'] - [digital_constellation_modulator_0, '0', channels_channel_model_0, '0'] - [digital_constellation_modulator_0, '0', qtgui_time_sink_x_1_0, '0'] @@ -1678,7 +1662,6 @@ connections: - [digital_pfb_clock_sync_xxx_0, '0', digital_cma_equalizer_cc_0, '0'] - [epy_block_0, '0', qtgui_const_sink_x_0_0, '0'] - [epy_block_0, '0', virtual_sink_3, '0'] -- [fadingui_deframer_0, '0', blocks_vector_sink_x_0, '0'] - [fir_filter_xxx_1, '0', blocks_complex_to_magphase_0, '0'] - [fir_filter_xxx_1, '0', qtgui_const_sink_x_1, '0'] - [root_raised_cosine_filter_0, '0', blocks_stream_mux_1, '0'] diff --git a/tests/correlator/correlator.py b/tests/correlator/correlator.py index 93ee8bb..e080dbc 100755 --- a/tests/correlator/correlator.py +++ b/tests/correlator/correlator.py @@ -35,7 +35,6 @@ from argparse import ArgumentParser from gnuradio.eng_arg import eng_float, intx from gnuradio import eng_notation import epy_block_0 -import fadingui from gnuradio import qtgui @@ -329,7 +328,6 @@ class correlator(gr.top_block, Qt.QWidget): self.top_grid_layout.setRowStretch(r, 1) for c in range(1, 2): self.top_grid_layout.setColumnStretch(c, 1) - self.fadingui_deframer_0 = fadingui.deframer(frame_obj=) self.epy_block_0 = epy_block_0.blk() self.digital_pfb_clock_sync_xxx_0 = digital.pfb_clock_sync_ccf(sps, timing_loop_bw, rrc_taps, nfilts, 16, 1.5, 1) self.digital_corr_est_cc_0 = digital.corr_est_cc(access_code_symbols, 1, 0, .8, digital.THRESHOLD_DYNAMIC) @@ -372,7 +370,7 @@ class correlator(gr.top_block, Qt.QWidget): self.connect((self.channels_channel_model_0, 0), (self.blocks_throttle_0, 0)) self.connect((self.digital_cma_equalizer_cc_0, 0), (self.digital_corr_est_cc_0, 0)) self.connect((self.digital_cma_equalizer_cc_0, 0), (self.qtgui_const_sink_x_0, 0)) - self.connect((self.digital_constellation_decoder_cb_0, 0), (self.fadingui_deframer_0, 0)) + self.connect((self.digital_constellation_decoder_cb_0, 0), (self.blocks_vector_sink_x_0, 0)) self.connect((self.digital_constellation_modulator_0, 0), (self.channels_channel_model_0, 0)) self.connect((self.digital_constellation_modulator_0, 0), (self.qtgui_time_sink_x_1_0, 0)) self.connect((self.digital_corr_est_cc_0, 1), (self.blocks_complex_to_magphase_0_0, 0)) @@ -381,7 +379,6 @@ class correlator(gr.top_block, Qt.QWidget): self.connect((self.digital_pfb_clock_sync_xxx_0, 0), (self.digital_cma_equalizer_cc_0, 0)) self.connect((self.epy_block_0, 0), (self.digital_constellation_decoder_cb_0, 0)) self.connect((self.epy_block_0, 0), (self.qtgui_const_sink_x_0_0, 0)) - self.connect((self.fadingui_deframer_0, 0), (self.blocks_vector_sink_x_0, 0)) def closeEvent(self, event): -- cgit v1.2.1 From 3718e92fe6418e33a7e8d53192383d021d20c524 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 3 Dec 2021 00:18:55 +0100 Subject: Refractor frequency correction --- tests/correlator/correlator.grc | 82 +++++++++++++------------- tests/correlator/epy_block_0.py | 124 ++++++++++++++++++---------------------- 2 files changed, 95 insertions(+), 111 deletions(-) diff --git a/tests/correlator/correlator.grc b/tests/correlator/correlator.grc index f54430c..57c1762 100644 --- a/tests/correlator/correlator.grc +++ b/tests/correlator/correlator.grc @@ -526,49 +526,45 @@ blocks: _source_code: "import pmt\n\nimport numpy as np\nfrom gnuradio import gr\n\n\n\ class blk(gr.sync_block):\n def __init__(self):\n gr.sync_block.__init__(\n\ \ self,\n name='Phase Lock',\n in_sig=[np.complex64],\n\ - \ out_sig=[np.complex64]\n )\n\n # keep track of how\ - \ many samples were processed,\n # because tags have an absolute offset\n\ - \ self.sampnr: np.complex64 = 0\n\n # because of block processing\ - \ a tagged block could\n # be split in half so we need to keep track\ - \ of the\n # \"previous\" values\n self.last_tag = None\n\n \ - \ def work(self, input_items, output_items):\n # nicer aliases\n \ - \ out = output_items[0]\n inp = input_items[0]\n\n def print_phase_correction(start,\ - \ end, phase, freq):\n print(f\"Correction for block {start:3d} to\ - \ {end:3d} is phase = {phase: 2.4f} rad, freq = {freq * 1e3: 2.4f} milli rad/samp\"\ - )\n\n # read only phase tags\n tags = self.get_tags_in_window(0,\ - \ 0, len(inp))\n\n is_phase = lambda tag: pmt.to_python(tag.key) == \"\ - phase_est\"\n phase_tags = list(filter(is_phase, tags))\n\n #\ - \ FIXME: what if there are no tags? check that!\n\n print(f\"Processing\ - \ {len(inp)} samples, with {len(phase_tags)} tags\")\n\n # create a phase\ - \ correction vector\n phase = np.zeros(len(inp), dtype=np.float64)\n\n\ - \ # compute correction from previous block (if present)\n if self.last_tag:\n\ - \ # variables for first and last phase values\n lval =\ - \ pmt.to_python(self.last_tag.value)\n fval = pmt.to_python(phase_tags[0].value)\n\ - \n # compute index for phase vector\n fidx = phase_tags[0].offset\ - \ - self.sampnr\n\n # compute frequency offset\n nsamples\ - \ = phase_tags[0].offset - self.last_tag.offset\n freq = (fval -\ - \ lval) / nsamples\n\n # total phase correction is: phase + freq\ - \ * time\n phase[:fidx] = lval * np.ones(fidx) + freq * np.arange(0,\ - \ fidx)\n\n # compute correction\n print_phase_correction(0,\ - \ fidx, lval, freq)\n\n # iterate phase tags \"in the middle\"\n \ - \ # FIXME: what if there are less than 2 tags?\n # the code\ - \ below will probably crash\n for prev_tag, next_tag in zip(phase_tags,\ - \ phase_tags[1:]):\n # unpack pmt values\n pval = pmt.to_python(prev_tag.value)\n\ - \ nval = pmt.to_python(next_tag.value)\n\n # compute indexes\ - \ in phase vector\n pidx = prev_tag.offset - self.sampnr\n \ - \ nidx = next_tag.offset - self.sampnr\n\n # compute frquency\ - \ correction for block by linearly interpolating\n # frame values\n\ - \ nsamples = nidx - pidx\n freq = (nval - pval) / nsamples\n\ - \n # total correction is: phase + freq * time\n phase[pidx:nidx]\ - \ = pval * np.ones(nsamples) + freq * np.arange(0, nsamples)\n print_phase_correction(pidx,\ - \ nidx, pval, freq)\n\n # for the last block because the next tag is\ - \ unknown (in the future) we\n # cannot predict the frequency offset.\ - \ Thus we save the last tag for\n # the next call.\n self.last_tag\ - \ = phase_tags[-1]\n val = pmt.to_python(self.last_tag.value)\n \ - \ idx = self.last_tag.offset - self.sampnr\n\n phase[idx:] = val\n\n\ - \ # compute correction\n out[:] = inp * np.exp(-1j * phase)\n\n\ - \ # increment processed samples counter\n self.sampnr += len(inp)\n\ - \ return len(phase)\n" + \ out_sig=[np.complex64]\n )\n\n # we need to keep\ + \ track of the aboslute number of samples that have\n # been processed,\ + \ because tags have an absolute offset\n self.counter: np.uint64 = 0\n\ + \n # because we do block processing, we need to keep track of the last\ + \ tag\n # of the previous block to correct the first values of the next\ + \ block\n self.last = None\n\n def block_phase(self, start, end):\n\ + \ # compute number of samples in block\n nsamples = end.offset\ + \ - start.offset\n\n # unpack pmt values into start and end phase\n \ + \ sphase = pmt.to_python(start.value)\n ephase = pmt.to_python(end.value)\n\ + \n # compute frequency offset between start and end\n freq = (sphase\ + \ - ephase) / nsamples\n\n # debugging\n print(f\"Correction for\ + \ block of {nsamples:2d} samples is \" \\\n f\"phase={sphase: .4f}\ + \ rad and freq={freq*1e3: .4f} milli rad / sample\")\n\n # compute block\ + \ values\n return sphase * np.ones(nsamples) + freq * np.arange(0, nsamples)\n\ + \n def work(self, input_items, output_items):\n # FIXME: replace class\ + \ counter with local variable\n # self.counter = self.nitems_written(0)\n\ + \n # nicer aliases\n inp = input_items[0]\n out = output_items[0]\n\ + \n # read phase tags\n is_phase = lambda tag: pmt.to_python(tag.key)\ + \ == \"phase_est\"\n tags = list(filter(is_phase, self.get_tags_in_window(0,\ + \ 0, len(inp))))\n\n # debugging\n print(f\"Processing {len(tags)}\ + \ tags = {tags[-1].offset - tags[0].offset} \" \\\n f\"samples\ + \ out of {len(inp)} input samples\")\n\n # compute \"the middle\"\n \ + \ enough_samples = lambda pair: ((pair[1].offset - pair[0].offset) > 0)\n\ + \ pairs = list(filter(enough_samples, zip(tags, tags[1:])))\n \ + \ blocks = [ self.block_phase(start, end) for (start, end) in pairs ]\n \ + \ middle = np.concatenate(blocks) if blocks else []\n\n # compute\ + \ the remainder from the previous call\n nfront = tags[0].offset - self.counter\n\ + \ print(f\"Processing {nfront} samples at the front of the buffer\")\n\ + \ start = self.block_phase(self.last, tags[0])[-nfront:] \\\n \ + \ if self.last else np.zeros(nfront)\n\n # compute values at\ + \ the end\n nback = len(inp) - (tags[-1].offset - self.counter)\n \ + \ print(f\"Processing {nback} samples at the back of the buffer\")\n \ + \ end = np.ones(nback) * pmt.to_python(tags[-1].value)\n\n # compute\ + \ correction\n correction = np.exp(-1j * np.concatenate([start, middle,\ + \ end]))\n length = len(correction)\n\n # write outputs\n \ + \ out[:length] = inp[:length] * correction\n self.counter += len(inp)\n\ + \n # save last tag for next call\n self.last = tags[-1]\n\n \ + \ # FIXME: should return `length' but then the last sample is not\n \ + \ # included and self.last does something weird\n return len(out)\n" affinity: '' alias: '' comment: '' diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py index 90ad75e..9cb25bb 100644 --- a/tests/correlator/epy_block_0.py +++ b/tests/correlator/epy_block_0.py @@ -13,88 +13,76 @@ class blk(gr.sync_block): out_sig=[np.complex64] ) - # keep track of how many samples were processed, - # because tags have an absolute offset - self.sampnr: np.complex64 = 0 + # we need to keep track of the aboslute number of samples that have + # been processed, because tags have an absolute offset + self.counter: np.uint64 = 0 - # because of block processing a tagged block could - # be split in half so we need to keep track of the - # "previous" values - self.last_tag = None + # because we do block processing, we need to keep track of the last tag + # of the previous block to correct the first values of the next block + self.last = None - def work(self, input_items, output_items): - # nicer aliases - out = output_items[0] - inp = input_items[0] - - def print_phase_correction(start, end, phase, freq): - print(f"Correction for block {start:3d} to {end:3d} is phase = {phase: 2.4f} rad, freq = {freq * 1e3: 2.4f} milli rad/samp") - - # read only phase tags - tags = self.get_tags_in_window(0, 0, len(inp)) - - is_phase = lambda tag: pmt.to_python(tag.key) == "phase_est" - phase_tags = list(filter(is_phase, tags)) + def block_phase(self, start, end): + # compute number of samples in block + nsamples = end.offset - start.offset - # FIXME: what if there are no tags? check that! + # unpack pmt values into start and end phase + sphase = pmt.to_python(start.value) + ephase = pmt.to_python(end.value) - print(f"Processing {len(inp)} samples, with {len(phase_tags)} tags") + # compute frequency offset between start and end + freq = (sphase - ephase) / nsamples - # create a phase correction vector - phase = np.zeros(len(inp), dtype=np.float64) + # debugging + print(f"Correction for block of {nsamples:2d} samples is " \ + f"phase={sphase: .4f} rad and freq={freq*1e3: .4f} milli rad / sample") - # compute correction from previous block (if present) - if self.last_tag: - # variables for first and last phase values - lval = pmt.to_python(self.last_tag.value) - fval = pmt.to_python(phase_tags[0].value) + # compute block values + return sphase * np.ones(nsamples) + freq * np.arange(0, nsamples) - # compute index for phase vector - fidx = phase_tags[0].offset - self.sampnr - - # compute frequency offset - nsamples = phase_tags[0].offset - self.last_tag.offset - freq = (fval - lval) / nsamples + def work(self, input_items, output_items): + # FIXME: replace class counter with local variable + # self.counter = self.nitems_written(0) - # total phase correction is: phase + freq * time - phase[:fidx] = lval * np.ones(fidx) + freq * np.arange(0, fidx) + # nicer aliases + inp = input_items[0] + out = output_items[0] - # compute correction - print_phase_correction(0, fidx, lval, freq) + # read phase tags + is_phase = lambda tag: pmt.to_python(tag.key) == "phase_est" + tags = list(filter(is_phase, self.get_tags_in_window(0, 0, len(inp)))) - # iterate phase tags "in the middle" - # FIXME: what if there are less than 2 tags? - # the code below will probably crash - for prev_tag, next_tag in zip(phase_tags, phase_tags[1:]): - # unpack pmt values - pval = pmt.to_python(prev_tag.value) - nval = pmt.to_python(next_tag.value) + # debugging + print(f"Processing {len(tags)} tags = {tags[-1].offset - tags[0].offset} " \ + f"samples out of {len(inp)} input samples") - # compute indexes in phase vector - pidx = prev_tag.offset - self.sampnr - nidx = next_tag.offset - self.sampnr + # compute "the middle" + enough_samples = lambda pair: ((pair[1].offset - pair[0].offset) > 0) + pairs = list(filter(enough_samples, zip(tags, tags[1:]))) + blocks = [ self.block_phase(start, end) for (start, end) in pairs ] + middle = np.concatenate(blocks) if blocks else [] - # compute frquency correction for block by linearly interpolating - # frame values - nsamples = nidx - pidx - freq = (nval - pval) / nsamples + # compute the remainder from the previous call + nfront = tags[0].offset - self.counter + print(f"Processing {nfront} samples at the front of the buffer") + start = self.block_phase(self.last, tags[0])[-nfront:] \ + if self.last else np.zeros(nfront) - # total correction is: phase + freq * time - phase[pidx:nidx] = pval * np.ones(nsamples) + freq * np.arange(0, nsamples) - print_phase_correction(pidx, nidx, pval, freq) + # compute values at the end + nback = len(inp) - (tags[-1].offset - self.counter) + print(f"Processing {nback} samples at the back of the buffer") + end = np.ones(nback) * pmt.to_python(tags[-1].value) - # for the last block because the next tag is unknown (in the future) we - # cannot predict the frequency offset. Thus we save the last tag for - # the next call. - self.last_tag = phase_tags[-1] - val = pmt.to_python(self.last_tag.value) - idx = self.last_tag.offset - self.sampnr + # compute correction + correction = np.exp(-1j * np.concatenate([start, middle, end])) + length = len(correction) - phase[idx:] = val + # write outputs + out[:length] = inp[:length] * correction + self.counter += len(inp) - # compute correction - out[:] = inp * np.exp(-1j * phase) + # save last tag for next call + self.last = tags[-1] - # increment processed samples counter - self.sampnr += len(inp) - return len(phase) + # FIXME: should return `length' but then the last sample is not + # included and self.last does something weird + return len(out) -- cgit v1.2.1 From 5d2f01fe71b736f2f5bb8a57bb2f4cd383290e9f Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 3 Dec 2021 00:29:03 +0100 Subject: Fix bug when tag is aligned with inp block --- tests/correlator/correlator.grc | 12 ++++++------ tests/correlator/correlator.py | 2 +- tests/correlator/epy_block_0.py | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/correlator/correlator.grc b/tests/correlator/correlator.grc index 57c1762..5a73092 100644 --- a/tests/correlator/correlator.grc +++ b/tests/correlator/correlator.grc @@ -408,7 +408,7 @@ blocks: block_tags: 'False' comment: '' epsilon: '1.0' - freq_offset: '0.0001' + freq_offset: '0.0002' maxoutbuf: '0' minoutbuf: '0' noise_voltage: '0.2' @@ -541,7 +541,7 @@ blocks: \ rad and freq={freq*1e3: .4f} milli rad / sample\")\n\n # compute block\ \ values\n return sphase * np.ones(nsamples) + freq * np.arange(0, nsamples)\n\ \n def work(self, input_items, output_items):\n # FIXME: replace class\ - \ counter with local variable\n # self.counter = self.nitems_written(0)\n\ + \ counter with local variable\n self.counter = self.nitems_written(0)\n\ \n # nicer aliases\n inp = input_items[0]\n out = output_items[0]\n\ \n # read phase tags\n is_phase = lambda tag: pmt.to_python(tag.key)\ \ == \"phase_est\"\n tags = list(filter(is_phase, self.get_tags_in_window(0,\ @@ -555,10 +555,10 @@ blocks: \ the remainder from the previous call\n nfront = tags[0].offset - self.counter\n\ \ print(f\"Processing {nfront} samples at the front of the buffer\")\n\ \ start = self.block_phase(self.last, tags[0])[-nfront:] \\\n \ - \ if self.last else np.zeros(nfront)\n\n # compute values at\ - \ the end\n nback = len(inp) - (tags[-1].offset - self.counter)\n \ - \ print(f\"Processing {nback} samples at the back of the buffer\")\n \ - \ end = np.ones(nback) * pmt.to_python(tags[-1].value)\n\n # compute\ + \ if self.last and nfront else np.zeros(nfront)\n\n # compute\ + \ values at the end\n nback = len(inp) - (tags[-1].offset - self.counter)\n\ + \ print(f\"Processing {nback} samples at the back of the buffer\")\n\ + \ end = np.ones(nback) * pmt.to_python(tags[-1].value)\n\n # compute\ \ correction\n correction = np.exp(-1j * np.concatenate([start, middle,\ \ end]))\n length = len(correction)\n\n # write outputs\n \ \ out[:length] = inp[:length] * correction\n self.counter += len(inp)\n\ diff --git a/tests/correlator/correlator.py b/tests/correlator/correlator.py index e080dbc..536ac00 100755 --- a/tests/correlator/correlator.py +++ b/tests/correlator/correlator.py @@ -343,7 +343,7 @@ class correlator(gr.top_block, Qt.QWidget): self.digital_cma_equalizer_cc_0 = digital.cma_equalizer_cc(15, 1, .002, 1) self.channels_channel_model_0 = channels.channel_model( noise_voltage=0.2, - frequency_offset=0.0001, + frequency_offset=0.0002, epsilon=1.0, taps=[-1.4 + .4j], noise_seed=243, diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py index 9cb25bb..abf4486 100644 --- a/tests/correlator/epy_block_0.py +++ b/tests/correlator/epy_block_0.py @@ -41,7 +41,7 @@ class blk(gr.sync_block): def work(self, input_items, output_items): # FIXME: replace class counter with local variable - # self.counter = self.nitems_written(0) + self.counter = self.nitems_written(0) # nicer aliases inp = input_items[0] @@ -65,7 +65,7 @@ class blk(gr.sync_block): nfront = tags[0].offset - self.counter print(f"Processing {nfront} samples at the front of the buffer") start = self.block_phase(self.last, tags[0])[-nfront:] \ - if self.last else np.zeros(nfront) + if self.last and nfront else np.zeros(nfront) # compute values at the end nback = len(inp) - (tags[-1].offset - self.counter) -- cgit v1.2.1 From edf08d1815772fc985a89c976a190b3fcd6fb087 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 3 Dec 2021 00:45:23 +0100 Subject: Add a LPF on the frequency --- tests/correlator/correlator.grc | 52 ++++++++++++++++++++++++----------------- tests/correlator/correlator.py | 2 +- tests/correlator/epy_block_0.py | 26 ++++++++++++++++----- 3 files changed, 51 insertions(+), 29 deletions(-) diff --git a/tests/correlator/correlator.grc b/tests/correlator/correlator.grc index 5a73092..bf44544 100644 --- a/tests/correlator/correlator.grc +++ b/tests/correlator/correlator.grc @@ -163,7 +163,7 @@ blocks: id: variable parameters: comment: '' - value: '[31, 53] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3]' + value: '[31, 53] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3] * 2' states: bus_sink: false bus_source: false @@ -531,17 +531,23 @@ blocks: \ because tags have an absolute offset\n self.counter: np.uint64 = 0\n\ \n # because we do block processing, we need to keep track of the last\ \ tag\n # of the previous block to correct the first values of the next\ - \ block\n self.last = None\n\n def block_phase(self, start, end):\n\ - \ # compute number of samples in block\n nsamples = end.offset\ - \ - start.offset\n\n # unpack pmt values into start and end phase\n \ - \ sphase = pmt.to_python(start.value)\n ephase = pmt.to_python(end.value)\n\ - \n # compute frequency offset between start and end\n freq = (sphase\ - \ - ephase) / nsamples\n\n # debugging\n print(f\"Correction for\ - \ block of {nsamples:2d} samples is \" \\\n f\"phase={sphase: .4f}\ - \ rad and freq={freq*1e3: .4f} milli rad / sample\")\n\n # compute block\ - \ values\n return sphase * np.ones(nsamples) + freq * np.arange(0, nsamples)\n\ - \n def work(self, input_items, output_items):\n # FIXME: replace class\ - \ counter with local variable\n self.counter = self.nitems_written(0)\n\ + \ block\n self.last = None\n\n # to compute the values that are\ + \ at the end we need to know the frequency\n # of the last block\n \ + \ self.freq = 1\n\n def block_phase(self, start, end):\n # compute\ + \ number of samples in block\n nsamples = end.offset - start.offset\n\ + \n # unpack pmt values into start and end phase\n sphase = pmt.to_python(start.value)\n\ + \ ephase = pmt.to_python(end.value)\n\n # compute frequency offset\ + \ between start and end\n freq = (sphase - ephase) / nsamples\n\n \ + \ # save this frequency values to compute the end block, unless frequency\n\ + \ # has changed too fast, in that case replace the current values with\n\ + \ # the previous one . This is effectively like a low pass filter.\n\ + \ if abs(freq / self.freq) > 4:\n freq = self.freq\n \ + \ else:\n self.freq = freq\n\n\n # debugging\n print(f\"\ + Correction for block of {nsamples:2d} samples is \" \\\n f\"phase={sphase:\ + \ .4f} rad and freq={freq*1e3: .4f} milli rad / sample\")\n\n # compute\ + \ block values\n return sphase * np.ones(nsamples) + freq * np.arange(0,\ + \ nsamples)\n\n def work(self, input_items, output_items):\n # FIXME:\ + \ replace class counter with local variable\n self.counter = self.nitems_written(0)\n\ \n # nicer aliases\n inp = input_items[0]\n out = output_items[0]\n\ \n # read phase tags\n is_phase = lambda tag: pmt.to_python(tag.key)\ \ == \"phase_est\"\n tags = list(filter(is_phase, self.get_tags_in_window(0,\ @@ -552,16 +558,18 @@ blocks: \ pairs = list(filter(enough_samples, zip(tags, tags[1:])))\n \ \ blocks = [ self.block_phase(start, end) for (start, end) in pairs ]\n \ \ middle = np.concatenate(blocks) if blocks else []\n\n # compute\ - \ the remainder from the previous call\n nfront = tags[0].offset - self.counter\n\ - \ print(f\"Processing {nfront} samples at the front of the buffer\")\n\ - \ start = self.block_phase(self.last, tags[0])[-nfront:] \\\n \ - \ if self.last and nfront else np.zeros(nfront)\n\n # compute\ - \ values at the end\n nback = len(inp) - (tags[-1].offset - self.counter)\n\ - \ print(f\"Processing {nback} samples at the back of the buffer\")\n\ - \ end = np.ones(nback) * pmt.to_python(tags[-1].value)\n\n # compute\ - \ correction\n correction = np.exp(-1j * np.concatenate([start, middle,\ - \ end]))\n length = len(correction)\n\n # write outputs\n \ - \ out[:length] = inp[:length] * correction\n self.counter += len(inp)\n\ + \ values at the end, we do not have informations about the future\n #\ + \ but we can use the frequency of the last block to approximate\n nback\ + \ = len(inp) - (tags[-1].offset - self.counter)\n print(f\"Processing\ + \ {nback} samples at the back of the buffer\")\n end = np.ones(nback)\ + \ * pmt.to_python(tags[-1].value) + self.freq * np.arange(0, nback)\n\n \ + \ # compute the \"start\", using the last tag from the previous call\n \ + \ nfront = tags[0].offset - self.counter\n print(f\"Processing {nfront}\ + \ samples at the front of the buffer\")\n start = self.block_phase(self.last,\ + \ tags[0])[-nfront:] \\\n if self.last and nfront else np.zeros(nfront)\n\ + \n # compute correction\n correction = np.exp(-1j * np.concatenate([start,\ + \ middle, end]))\n length = len(correction)\n\n # write outputs\n\ + \ out[:length] = inp[:length] * correction\n self.counter += len(inp)\n\ \n # save last tag for next call\n self.last = tags[-1]\n\n \ \ # FIXME: should return `length' but then the last sample is not\n \ \ # included and self.last does something weird\n return len(out)\n" diff --git a/tests/correlator/correlator.py b/tests/correlator/correlator.py index 536ac00..5edc8ee 100755 --- a/tests/correlator/correlator.py +++ b/tests/correlator/correlator.py @@ -78,7 +78,7 @@ class correlator(gr.top_block, Qt.QWidget): self.nfilts = nfilts = 32 self.excess_bw = excess_bw = .35 self.timing_loop_bw = timing_loop_bw = 2 * 3.141592653589793 / 100 - self.testvec = testvec = [31, 53] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3] + self.testvec = testvec = [31, 53] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3] * 2 self.samp_rate = samp_rate = 32000 self.rrc_taps = rrc_taps = firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), excess_bw, 45*nfilts) self.revconj_access_code_symbols = revconj_access_code_symbols = [(1.4142135623730951+1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (-1.4142135623730951+1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (-1.4142135623730951+1.4142135623730951j)] diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py index abf4486..6b47e80 100644 --- a/tests/correlator/epy_block_0.py +++ b/tests/correlator/epy_block_0.py @@ -21,6 +21,10 @@ class blk(gr.sync_block): # of the previous block to correct the first values of the next block self.last = None + # to compute the values that are at the end we need to know the frequency + # of the last block + self.freq = 1 + def block_phase(self, start, end): # compute number of samples in block nsamples = end.offset - start.offset @@ -32,6 +36,15 @@ class blk(gr.sync_block): # compute frequency offset between start and end freq = (sphase - ephase) / nsamples + # save this frequency values to compute the end block, unless frequency + # has changed too fast, in that case replace the current values with + # the previous one . This is effectively like a low pass filter. + if abs(freq / self.freq) > 4: + freq = self.freq + else: + self.freq = freq + + # debugging print(f"Correction for block of {nsamples:2d} samples is " \ f"phase={sphase: .4f} rad and freq={freq*1e3: .4f} milli rad / sample") @@ -61,17 +74,18 @@ class blk(gr.sync_block): blocks = [ self.block_phase(start, end) for (start, end) in pairs ] middle = np.concatenate(blocks) if blocks else [] - # compute the remainder from the previous call + # compute values at the end, we do not have informations about the future + # but we can use the frequency of the last block to approximate + nback = len(inp) - (tags[-1].offset - self.counter) + print(f"Processing {nback} samples at the back of the buffer") + end = np.ones(nback) * pmt.to_python(tags[-1].value) + self.freq * np.arange(0, nback) + + # compute the "start", using the last tag from the previous call nfront = tags[0].offset - self.counter print(f"Processing {nfront} samples at the front of the buffer") start = self.block_phase(self.last, tags[0])[-nfront:] \ if self.last and nfront else np.zeros(nfront) - # compute values at the end - nback = len(inp) - (tags[-1].offset - self.counter) - print(f"Processing {nback} samples at the back of the buffer") - end = np.ones(nback) * pmt.to_python(tags[-1].value) - # compute correction correction = np.exp(-1j * np.concatenate([start, middle, end])) length = len(correction) -- cgit v1.2.1 From b389c8d00064d224a534d3c4a37bd4ee700a5022 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 3 Dec 2021 13:01:42 +0100 Subject: Improve frequency LPF --- tests/correlator/correlator.grc | 100 +++++++++++++++++++++++++--------------- tests/correlator/correlator.py | 13 ++++-- tests/correlator/epy_block_0.py | 36 +++++++++------ 3 files changed, 93 insertions(+), 56 deletions(-) diff --git a/tests/correlator/correlator.grc b/tests/correlator/correlator.grc index bf44544..220eaed 100644 --- a/tests/correlator/correlator.grc +++ b/tests/correlator/correlator.grc @@ -163,7 +163,7 @@ blocks: id: variable parameters: comment: '' - value: '[31, 53] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3] * 2' + value: '[31, 53] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3] ' states: bus_sink: false bus_source: false @@ -212,7 +212,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1048, 1128.0] + coordinate: [1088, 1304.0] rotation: 0 state: enabled - name: blocks_multiply_const_vxx_0 @@ -248,7 +248,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1336, 1204.0] + coordinate: [1376, 1380.0] rotation: 0 state: disabled - name: blocks_null_sink_3 @@ -265,7 +265,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1336, 1256.0] + coordinate: [1376, 1432.0] rotation: 0 state: true - name: blocks_null_source_0 @@ -408,7 +408,7 @@ blocks: block_tags: 'False' comment: '' epsilon: '1.0' - freq_offset: '0.0002' + freq_offset: '0.0001' maxoutbuf: '0' minoutbuf: '0' noise_voltage: '0.2' @@ -497,6 +497,24 @@ blocks: coordinate: [776, 1020.0] rotation: 0 state: enabled +- name: digital_costas_loop_cc_0 + id: digital_costas_loop_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + order: '4' + use_snr: 'False' + w: 2 * 3.141592653589793 / 100 + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1088, 1128.0] + rotation: 0 + state: true - name: digital_pfb_clock_sync_xxx_0 id: digital_pfb_clock_sync_xxx parameters: @@ -531,18 +549,20 @@ blocks: \ because tags have an absolute offset\n self.counter: np.uint64 = 0\n\ \n # because we do block processing, we need to keep track of the last\ \ tag\n # of the previous block to correct the first values of the next\ - \ block\n self.last = None\n\n # to compute the values that are\ - \ at the end we need to know the frequency\n # of the last block\n \ - \ self.freq = 1\n\n def block_phase(self, start, end):\n # compute\ - \ number of samples in block\n nsamples = end.offset - start.offset\n\ - \n # unpack pmt values into start and end phase\n sphase = pmt.to_python(start.value)\n\ - \ ephase = pmt.to_python(end.value)\n\n # compute frequency offset\ - \ between start and end\n freq = (sphase - ephase) / nsamples\n\n \ - \ # save this frequency values to compute the end block, unless frequency\n\ - \ # has changed too fast, in that case replace the current values with\n\ - \ # the previous one . This is effectively like a low pass filter.\n\ - \ if abs(freq / self.freq) > 4:\n freq = self.freq\n \ - \ else:\n self.freq = freq\n\n\n # debugging\n print(f\"\ + \ block\n self.last = None\n\n # both the phase and frequency\ + \ corrections should go through a low pass\n # filter to avoid werid\ + \ jumps in the correction. to do that, there are\n # two buffers with\ + \ an index\n self.index = 0\n self.length = 7\n self.freq\ + \ = np.zeros(self.length)\n\n def lpf_freq(self, new_sample):\n #\ + \ save new sample\n self.freq[self.index] = new_sample\n # increment\ + \ index\n self.index = (self.index + 1) % self.length\n\n return\ + \ np.sum(self.freq) / self.length\n\n def block_phase(self, start, end):\n\ + \ # compute number of samples in block\n nsamples = end.offset\ + \ - start.offset\n\n # unpack pmt values into start and end phase\n \ + \ sphase = pmt.to_python(start.value)\n ephase = pmt.to_python(end.value)\n\ + \n # compute frequency offset between start and end\n # and run\ + \ it through a low pass filter (mean)\n freq = (sphase - ephase) / nsamples\n\ + \ freq = self.lpf_freq(freq)\n\n # debugging\n print(f\"\ Correction for block of {nsamples:2d} samples is \" \\\n f\"phase={sphase:\ \ .4f} rad and freq={freq*1e3: .4f} milli rad / sample\")\n\n # compute\ \ block values\n return sphase * np.ones(nsamples) + freq * np.arange(0,\ @@ -551,20 +571,22 @@ blocks: \n # nicer aliases\n inp = input_items[0]\n out = output_items[0]\n\ \n # read phase tags\n is_phase = lambda tag: pmt.to_python(tag.key)\ \ == \"phase_est\"\n tags = list(filter(is_phase, self.get_tags_in_window(0,\ - \ 0, len(inp))))\n\n # debugging\n print(f\"Processing {len(tags)}\ - \ tags = {tags[-1].offset - tags[0].offset} \" \\\n f\"samples\ - \ out of {len(inp)} input samples\")\n\n # compute \"the middle\"\n \ - \ enough_samples = lambda pair: ((pair[1].offset - pair[0].offset) > 0)\n\ - \ pairs = list(filter(enough_samples, zip(tags, tags[1:])))\n \ - \ blocks = [ self.block_phase(start, end) for (start, end) in pairs ]\n \ - \ middle = np.concatenate(blocks) if blocks else []\n\n # compute\ - \ values at the end, we do not have informations about the future\n #\ - \ but we can use the frequency of the last block to approximate\n nback\ - \ = len(inp) - (tags[-1].offset - self.counter)\n print(f\"Processing\ - \ {nback} samples at the back of the buffer\")\n end = np.ones(nback)\ - \ * pmt.to_python(tags[-1].value) + self.freq * np.arange(0, nback)\n\n \ - \ # compute the \"start\", using the last tag from the previous call\n \ - \ nfront = tags[0].offset - self.counter\n print(f\"Processing {nfront}\ + \ 0, len(inp))))\n\n if not tags:\n print(f\"There were no\ + \ tags in {len(inp)} samples!\")\n out[:] = inp\n return\ + \ len(out)\n\n # debugging\n print(f\"Processing {len(tags)} tags\ + \ = {tags[-1].offset - tags[0].offset} \" \\\n f\"samples out of\ + \ {len(inp)} input samples\")\n\n # compute \"the middle\"\n enough_samples\ + \ = lambda pair: ((pair[1].offset - pair[0].offset) > 0)\n pairs = list(filter(enough_samples,\ + \ zip(tags, tags[1:])))\n blocks = [ self.block_phase(start, end) for\ + \ (start, end) in pairs ]\n middle = np.concatenate(blocks) if blocks\ + \ else []\n\n # compute values at the end, we do not have informations\ + \ about the future\n # but we can use the frequency of the last block\ + \ to approximate\n nback = len(inp) - (tags[-1].offset - self.counter)\n\ + \ print(f\"Processing {nback} samples at the back of the buffer\")\n\ + \ endfreq = self.lpf_freq(self.freq[-1])\n end = np.ones(nback)\ + \ * pmt.to_python(tags[-1].value) + endfreq * np.arange(0, nback)\n\n \ + \ # compute the \"start\", using the last tag from the previous call\n \ + \ nfront = tags[0].offset - self.counter\n print(f\"Processing {nfront}\ \ samples at the front of the buffer\")\n start = self.block_phase(self.last,\ \ tags[0])[-nfront:] \\\n if self.last and nfront else np.zeros(nfront)\n\ \n # compute correction\n correction = np.exp(-1j * np.concatenate([start,\ @@ -728,9 +750,9 @@ blocks: comment: '' grid: 'False' gui_hint: 2,1,2,1 - label1: '' + label1: Custom Block label10: '' - label2: '' + label2: Costas Loop label3: '' label4: '' label5: '' @@ -750,7 +772,7 @@ blocks: marker8: '0' marker9: '0' name: '"Phase Locked Signal"' - nconnections: '1' + nconnections: '2' size: '1024' style1: '0' style10: '0' @@ -787,7 +809,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1288, 940.0] + coordinate: [1368, 1092.0] rotation: 0 state: enabled - name: qtgui_const_sink_x_1 @@ -1073,7 +1095,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1336, 1108.0] + coordinate: [1376, 1284.0] rotation: 0 state: enabled - name: qtgui_time_sink_x_0_0_0 @@ -1558,7 +1580,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1512, 1188.0] + coordinate: [1552, 1364.0] rotation: 0 state: disabled - name: root_raised_cosine_filter_0 @@ -1607,7 +1629,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1336, 1036.0] + coordinate: [1368, 1036.0] rotation: 0 state: true - name: virtual_source_0 @@ -1660,9 +1682,11 @@ connections: - [digital_constellation_modulator_0, '0', blocks_stream_mux_1, '1'] - [digital_constellation_modulator_0, '0', channels_channel_model_0, '0'] - [digital_constellation_modulator_0, '0', qtgui_time_sink_x_1_0, '0'] +- [digital_corr_est_cc_0, '0', digital_costas_loop_cc_0, '0'] - [digital_corr_est_cc_0, '0', epy_block_0, '0'] - [digital_corr_est_cc_0, '0', qtgui_time_sink_x_0_0_0, '0'] - [digital_corr_est_cc_0, '1', blocks_complex_to_magphase_0_0, '0'] +- [digital_costas_loop_cc_0, '0', qtgui_const_sink_x_0_0, '1'] - [digital_pfb_clock_sync_xxx_0, '0', digital_cma_equalizer_cc_0, '0'] - [epy_block_0, '0', qtgui_const_sink_x_0_0, '0'] - [epy_block_0, '0', virtual_sink_3, '0'] diff --git a/tests/correlator/correlator.py b/tests/correlator/correlator.py index 5edc8ee..50283c0 100755 --- a/tests/correlator/correlator.py +++ b/tests/correlator/correlator.py @@ -78,7 +78,7 @@ class correlator(gr.top_block, Qt.QWidget): self.nfilts = nfilts = 32 self.excess_bw = excess_bw = .35 self.timing_loop_bw = timing_loop_bw = 2 * 3.141592653589793 / 100 - self.testvec = testvec = [31, 53] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3] * 2 + self.testvec = testvec = [31, 53] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3] self.samp_rate = samp_rate = 32000 self.rrc_taps = rrc_taps = firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), excess_bw, 45*nfilts) self.revconj_access_code_symbols = revconj_access_code_symbols = [(1.4142135623730951+1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (-1.4142135623730951+1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (-1.4142135623730951+1.4142135623730951j)] @@ -243,7 +243,7 @@ class correlator(gr.top_block, Qt.QWidget): self.qtgui_const_sink_x_0_0 = qtgui.const_sink_c( 1024, #size "Phase Locked Signal", #name - 1 #number of inputs + 2 #number of inputs ) self.qtgui_const_sink_x_0_0.set_update_time(0.10) self.qtgui_const_sink_x_0_0.set_y_axis(-2, 2) @@ -254,7 +254,7 @@ class correlator(gr.top_block, Qt.QWidget): self.qtgui_const_sink_x_0_0.enable_axis_labels(True) - labels = ['', '', '', '', '', + labels = ['Custom Block', 'Costas Loop', '', '', '', '', '', '', '', ''] widths = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] @@ -267,7 +267,7 @@ class correlator(gr.top_block, Qt.QWidget): alphas = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] - for i in range(1): + for i in range(2): if len(labels[i]) == 0: self.qtgui_const_sink_x_0_0.set_line_label(i, "Data {0}".format(i)) else: @@ -330,6 +330,7 @@ class correlator(gr.top_block, Qt.QWidget): self.top_grid_layout.setColumnStretch(c, 1) self.epy_block_0 = epy_block_0.blk() self.digital_pfb_clock_sync_xxx_0 = digital.pfb_clock_sync_ccf(sps, timing_loop_bw, rrc_taps, nfilts, 16, 1.5, 1) + self.digital_costas_loop_cc_0 = digital.costas_loop_cc(2 * 3.141592653589793 / 100, 4, False) self.digital_corr_est_cc_0 = digital.corr_est_cc(access_code_symbols, 1, 0, .8, digital.THRESHOLD_DYNAMIC) self.digital_constellation_modulator_0 = digital.generic_mod( constellation=const, @@ -343,7 +344,7 @@ class correlator(gr.top_block, Qt.QWidget): self.digital_cma_equalizer_cc_0 = digital.cma_equalizer_cc(15, 1, .002, 1) self.channels_channel_model_0 = channels.channel_model( noise_voltage=0.2, - frequency_offset=0.0002, + frequency_offset=0.0001, epsilon=1.0, taps=[-1.4 + .4j], noise_seed=243, @@ -374,8 +375,10 @@ class correlator(gr.top_block, Qt.QWidget): self.connect((self.digital_constellation_modulator_0, 0), (self.channels_channel_model_0, 0)) self.connect((self.digital_constellation_modulator_0, 0), (self.qtgui_time_sink_x_1_0, 0)) self.connect((self.digital_corr_est_cc_0, 1), (self.blocks_complex_to_magphase_0_0, 0)) + self.connect((self.digital_corr_est_cc_0, 0), (self.digital_costas_loop_cc_0, 0)) self.connect((self.digital_corr_est_cc_0, 0), (self.epy_block_0, 0)) self.connect((self.digital_corr_est_cc_0, 0), (self.qtgui_time_sink_x_0_0_0, 0)) + self.connect((self.digital_costas_loop_cc_0, 0), (self.qtgui_const_sink_x_0_0, 1)) self.connect((self.digital_pfb_clock_sync_xxx_0, 0), (self.digital_cma_equalizer_cc_0, 0)) self.connect((self.epy_block_0, 0), (self.digital_constellation_decoder_cb_0, 0)) self.connect((self.epy_block_0, 0), (self.qtgui_const_sink_x_0_0, 0)) diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py index 6b47e80..e7599c9 100644 --- a/tests/correlator/epy_block_0.py +++ b/tests/correlator/epy_block_0.py @@ -21,9 +21,20 @@ class blk(gr.sync_block): # of the previous block to correct the first values of the next block self.last = None - # to compute the values that are at the end we need to know the frequency - # of the last block - self.freq = 1 + # both the phase and frequency corrections should go through a low pass + # filter to avoid werid jumps in the correction. to do that, there are + # two buffers with an index + self.index = 0 + self.length = 7 + self.freq = np.zeros(self.length) + + def lpf_freq(self, new_sample): + # save new sample + self.freq[self.index] = new_sample + # increment index + self.index = (self.index + 1) % self.length + + return np.sum(self.freq) / self.length def block_phase(self, start, end): # compute number of samples in block @@ -34,16 +45,9 @@ class blk(gr.sync_block): ephase = pmt.to_python(end.value) # compute frequency offset between start and end + # and run it through a low pass filter (mean) freq = (sphase - ephase) / nsamples - - # save this frequency values to compute the end block, unless frequency - # has changed too fast, in that case replace the current values with - # the previous one . This is effectively like a low pass filter. - if abs(freq / self.freq) > 4: - freq = self.freq - else: - self.freq = freq - + freq = self.lpf_freq(freq) # debugging print(f"Correction for block of {nsamples:2d} samples is " \ @@ -64,6 +68,11 @@ class blk(gr.sync_block): is_phase = lambda tag: pmt.to_python(tag.key) == "phase_est" tags = list(filter(is_phase, self.get_tags_in_window(0, 0, len(inp)))) + if not tags: + print(f"There were no tags in {len(inp)} samples!") + out[:] = inp + return len(out) + # debugging print(f"Processing {len(tags)} tags = {tags[-1].offset - tags[0].offset} " \ f"samples out of {len(inp)} input samples") @@ -78,7 +87,8 @@ class blk(gr.sync_block): # but we can use the frequency of the last block to approximate nback = len(inp) - (tags[-1].offset - self.counter) print(f"Processing {nback} samples at the back of the buffer") - end = np.ones(nback) * pmt.to_python(tags[-1].value) + self.freq * np.arange(0, nback) + endfreq = self.lpf_freq(self.freq[-1]) + end = np.ones(nback) * pmt.to_python(tags[-1].value) + endfreq * np.arange(0, nback) # compute the "start", using the last tag from the previous call nfront = tags[0].offset - self.counter -- cgit v1.2.1 From 0cb8ac7bd0e88d6d26c1fda3abcf0977c2e8150b Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 3 Dec 2021 17:54:07 +0100 Subject: Fix bug that makes jump estimated frequency to unreasonably high values --- tests/correlator/correlator.grc | 285 +++++++++++++++++++--------------------- tests/correlator/correlator.py | 41 +++--- tests/correlator/epy_block_0.py | 16 ++- tests/correlator/epy_block_1.py | 27 ++++ 4 files changed, 191 insertions(+), 178 deletions(-) create mode 100644 tests/correlator/epy_block_1.py diff --git a/tests/correlator/correlator.grc b/tests/correlator/correlator.grc index 220eaed..0f82f27 100644 --- a/tests/correlator/correlator.grc +++ b/tests/correlator/correlator.grc @@ -44,26 +44,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [776, 1140.0] - rotation: 0 - state: enabled -- name: access_code_symbols_sps - id: variable - parameters: - comment: '' - value: '[(1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), - (1.4142197+1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), - (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), - (1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197-1.4142197j), - (-1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), - (1.4142197-1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), - (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), - (1.4142197+1.4142197j)]' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [224, 132.0] + coordinate: [768, 1016.0] rotation: 0 state: enabled - name: const @@ -81,7 +62,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [592, 484.0] + coordinate: [592, 360.0] rotation: 0 state: enabled - name: excess_bw @@ -93,7 +74,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [496, 484.0] + coordinate: [496, 360.0] rotation: 0 state: enabled - name: nfilts @@ -105,7 +86,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [224, 988.0] + coordinate: [224, 856.0] rotation: 0 state: enabled - name: revconj_access_code_symbols @@ -120,7 +101,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [48, 564.0] + coordinate: [48, 440.0] rotation: 0 state: enabled - name: rrc_taps @@ -132,14 +113,14 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [304, 988.0] + coordinate: [304, 856.0] rotation: 0 state: enabled - name: samp_rate id: variable parameters: comment: '' - value: '32000' + value: int(1.5e6) states: bus_sink: false bus_source: false @@ -163,24 +144,24 @@ blocks: id: variable parameters: comment: '' - value: '[31, 53] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3] ' + value: '[0x1f, 0x35] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3] ' states: bus_sink: false bus_source: false bus_structure: null - coordinate: [48, 492.0] + coordinate: [48, 360.0] rotation: 0 state: enabled - name: timing_loop_bw id: variable parameters: comment: '' - value: 2 * 3.141592653589793 / 100 + value: 2 * np.pi / 100 states: bus_sink: false bus_source: false bus_structure: null - coordinate: [224, 1068.0] + coordinate: [224, 936.0] rotation: 0 state: enabled - name: blocks_complex_to_magphase_0 @@ -196,7 +177,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1048, 696.0] + coordinate: [1040, 568.0] rotation: 0 state: disabled - name: blocks_complex_to_magphase_0_0 @@ -212,7 +193,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1088, 1304.0] + coordinate: [1032, 1176.0] rotation: 0 state: enabled - name: blocks_multiply_const_vxx_0 @@ -230,7 +211,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1288, 724.0] + coordinate: [1288, 596.0] rotation: 0 state: disabled - name: blocks_multiply_const_vxx_0_0 @@ -248,7 +229,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1376, 1380.0] + coordinate: [1376, 1248.0] rotation: 0 state: disabled - name: blocks_null_sink_3 @@ -265,7 +246,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1376, 1432.0] + coordinate: [1376, 1304.0] rotation: 0 state: true - name: blocks_null_source_0 @@ -284,47 +265,48 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [96, 344.0] + coordinate: [96, 200.0] rotation: 0 state: enabled -- name: blocks_stream_mux_0 - id: blocks_stream_mux +- name: blocks_repack_bits_bb_0 + id: blocks_repack_bits_bb parameters: affinity: '' alias: '' + align_output: 'False' comment: '' - lengths: '[10, len(testvec)]' + endianness: gr.GR_MSB_FIRST + k: '2' + l: '8' + len_tag_key: '""' maxoutbuf: '0' minoutbuf: '0' - num_inputs: '2' - type: byte - vlen: '1' states: bus_sink: false bus_source: false bus_structure: null - coordinate: [288, 392.0] + coordinate: [672, 1252.0] rotation: 0 - state: enabled -- name: blocks_stream_mux_1 + state: true +- name: blocks_stream_mux_0 id: blocks_stream_mux parameters: affinity: '' alias: '' comment: '' - lengths: '[len(access_code_symbols_sps), sps * (len(testvec) + 15)]' + lengths: '[5, len(testvec)]' maxoutbuf: '0' minoutbuf: '0' num_inputs: '2' - type: complex + type: byte vlen: '1' states: bus_sink: false bus_source: false bus_structure: null - coordinate: [776, 280.0] + coordinate: [288, 256.0] rotation: 0 - state: disabled + state: enabled - name: blocks_throttle_0 id: blocks_throttle parameters: @@ -341,25 +323,9 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1272, 404.0] + coordinate: [1272, 268.0] rotation: 0 state: enabled -- name: blocks_vector_sink_x_0 - id: blocks_vector_sink_x - parameters: - affinity: '' - alias: '' - comment: '' - reserve_items: '1024' - type: byte - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [536, 1392.0] - rotation: 0 - state: true - name: blocks_vector_source_x_0 id: blocks_vector_source_x parameters: @@ -371,35 +337,15 @@ blocks: repeat: 'True' tags: '[]' type: byte - vector: testvec * 1600 + vector: testvec * 500 vlen: '1' states: bus_sink: false bus_source: false bus_structure: null - coordinate: [48, 404.0] + coordinate: [48, 268.0] rotation: 0 state: enabled -- name: blocks_vector_source_x_1 - id: blocks_vector_source_x - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - repeat: 'True' - tags: '[]' - type: complex - vector: access_code_symbols_sps - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [224, 204.0] - rotation: 0 - state: disabled - name: channels_channel_model_0 id: channels_channel_model parameters: @@ -411,14 +357,14 @@ blocks: freq_offset: '0.0001' maxoutbuf: '0' minoutbuf: '0' - noise_voltage: '0.2' + noise_voltage: '0.01' seed: '243' - taps: -1.4 + .4j + taps: np.exp(1j * 30 / 180 * np.pi) states: bus_sink: false bus_source: false bus_structure: null - coordinate: [992, 364.0] + coordinate: [1000, 228.0] rotation: 0 state: enabled - name: digital_cma_equalizer_cc_0 @@ -437,7 +383,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [528, 812.0] + coordinate: [520, 676.0] rotation: 0 state: enabled - name: digital_constellation_decoder_cb_0 @@ -453,7 +399,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [248, 1388.0] + coordinate: [224, 1260.0] rotation: 0 state: enabled - name: digital_constellation_modulator_0 @@ -474,7 +420,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [496, 380.0] + coordinate: [504, 244.0] rotation: 0 state: enabled - name: digital_corr_est_cc_0 @@ -494,7 +440,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [776, 1020.0] + coordinate: [768, 892.0] rotation: 0 state: enabled - name: digital_costas_loop_cc_0 @@ -512,9 +458,25 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1088, 1128.0] + coordinate: [1080, 1000.0] rotation: 0 state: true +- name: digital_map_bb_0 + id: digital_map_bb + parameters: + affinity: '' + alias: '' + comment: '' + map: '[0, 1, 3, 2]' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [496, 1260.0] + rotation: 0 + state: bypassed - name: digital_pfb_clock_sync_xxx_0 id: digital_pfb_clock_sync_xxx parameters: @@ -535,7 +497,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [224, 836.0] + coordinate: [224, 700.0] rotation: 0 state: enabled - name: epy_block_0 @@ -552,7 +514,7 @@ blocks: \ block\n self.last = None\n\n # both the phase and frequency\ \ corrections should go through a low pass\n # filter to avoid werid\ \ jumps in the correction. to do that, there are\n # two buffers with\ - \ an index\n self.index = 0\n self.length = 7\n self.freq\ + \ an index\n self.index = 0\n self.length = 5\n self.freq\ \ = np.zeros(self.length)\n\n def lpf_freq(self, new_sample):\n #\ \ save new sample\n self.freq[self.index] = new_sample\n # increment\ \ index\n self.index = (self.index + 1) % self.length\n\n return\ @@ -561,15 +523,18 @@ blocks: \ - start.offset\n\n # unpack pmt values into start and end phase\n \ \ sphase = pmt.to_python(start.value)\n ephase = pmt.to_python(end.value)\n\ \n # compute frequency offset between start and end\n # and run\ - \ it through a low pass filter (mean)\n freq = (sphase - ephase) / nsamples\n\ - \ freq = self.lpf_freq(freq)\n\n # debugging\n print(f\"\ - Correction for block of {nsamples:2d} samples is \" \\\n f\"phase={sphase:\ - \ .4f} rad and freq={freq*1e3: .4f} milli rad / sample\")\n\n # compute\ - \ block values\n return sphase * np.ones(nsamples) + freq * np.arange(0,\ - \ nsamples)\n\n def work(self, input_items, output_items):\n # FIXME:\ - \ replace class counter with local variable\n self.counter = self.nitems_written(0)\n\ - \n # nicer aliases\n inp = input_items[0]\n out = output_items[0]\n\ - \n # read phase tags\n is_phase = lambda tag: pmt.to_python(tag.key)\ + \ it through a low pass filter (mean)\n phasediff = ephase - sphase\n\ + \n if phasediff > np.pi:\n phasediff -= 2*np.pi\n\n \ + \ elif phasediff < -np.pi:\n phasediff += 2*np.pi\n\n freq\ + \ = phasediff / nsamples\n # freq = self.lpf_freq(freq)\n\n #\ + \ debugging\n print(f\"Correction for block of {nsamples:2d} samples\ + \ is \" \\\n f\"sphase={sphase: .4f} rad and freq={freq*1e3: .4f}\ + \ milli rad / sample\")\n\n # compute block values\n return sphase\ + \ * np.ones(nsamples) + freq * np.arange(0, nsamples)\n\n def work(self,\ + \ input_items, output_items):\n # FIXME: replace class counter with local\ + \ variable\n self.counter = self.nitems_written(0)\n\n # nicer\ + \ aliases\n inp = input_items[0]\n out = output_items[0]\n\n \ + \ # read phase tags\n is_phase = lambda tag: pmt.to_python(tag.key)\ \ == \"phase_est\"\n tags = list(filter(is_phase, self.get_tags_in_window(0,\ \ 0, len(inp))))\n\n if not tags:\n print(f\"There were no\ \ tags in {len(inp)} samples!\")\n out[:] = inp\n return\ @@ -606,9 +571,35 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1088, 1040.0] + coordinate: [1208, 912.0] rotation: 0 state: enabled +- name: epy_block_1 + id: epy_block + parameters: + _source_code: "\"\"\"\nEmbedded Python Blocks:\n\nEach time this file is saved,\ + \ GRC will instantiate the first class it finds\nto get ports and parameters\ + \ of your block. The arguments to __init__ will\nbe the parameters. All of\ + \ them are required to have default values!\n\"\"\"\n\nimport numpy as np\n\ + from gnuradio import gr\n\nnp.set_printoptions(formatter={'int':hex})\n\nclass\ + \ blk(gr.sync_block):\n def __init__(self):\n gr.sync_block.__init__(\n\ + \ self,\n name='Printer',\n in_sig=[np.byte],\n\ + \ out_sig=[]\n )\n\n def work(self, input_items, output_items):\n\ + \ inp = np.array(input_items[0], dtype=np.uint8)\n print(f\"Decoded\ + \ {len(inp)} samples:\\n{inp}\")\n\n return len(inp)\n" + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + states: + _io_cache: ('Printer', 'blk', [], [('0', 'byte', 1)], [], '', []) + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [920, 1264.0] + rotation: 0 + state: true - name: fir_filter_xxx_1 id: fir_filter_xxx parameters: @@ -625,9 +616,22 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [776, 828.0] + coordinate: [776, 692.0] rotation: 0 state: disabled +- name: import_0 + id: import + parameters: + alias: '' + comment: '' + imports: import numpy as np + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [184, 12.0] + rotation: 0 + state: true - name: qtgui_const_sink_x_0 id: qtgui_const_sink_x parameters: @@ -717,7 +721,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [776, 716.0] + coordinate: [768, 592.0] rotation: 0 state: enabled - name: qtgui_const_sink_x_0_0 @@ -809,7 +813,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1368, 1092.0] + coordinate: [1408, 964.0] rotation: 0 state: enabled - name: qtgui_const_sink_x_1 @@ -901,7 +905,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1048, 612.0] + coordinate: [1040, 480.0] rotation: 0 state: disabled - name: qtgui_time_sink_x_0 @@ -998,7 +1002,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1320, 604.0] + coordinate: [1312, 480.0] rotation: 0 state: disabled - name: qtgui_time_sink_x_0_0 @@ -1057,7 +1061,7 @@ blocks: name: '""' nconnections: '1' size: '1024' - srate: samp_rate + srate: samp_rate / sps stemplot: 'False' style1: '1' style10: '1' @@ -1095,7 +1099,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1376, 1284.0] + coordinate: [1376, 1152.0] rotation: 0 state: enabled - name: qtgui_time_sink_x_0_0_0 @@ -1154,7 +1158,7 @@ blocks: name: '""' nconnections: '1' size: '1024' - srate: samp_rate + srate: samp_rate / sps stemplot: 'False' style1: '1' style10: '1' @@ -1192,7 +1196,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1048, 940.0] + coordinate: [1072, 788.0] rotation: 0 state: enabled - name: qtgui_time_sink_x_1_0 @@ -1289,7 +1293,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [808, 452.0] + coordinate: [800, 320.0] rotation: 0 state: enabled - name: qtgui_time_sink_x_1_1 @@ -1386,7 +1390,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [776, 612.0] + coordinate: [768, 480.0] rotation: 0 state: disabled - name: qtgui_time_sink_x_2 @@ -1483,7 +1487,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1480, 708.0] + coordinate: [1488, 580.0] rotation: 0 state: disabled - name: qtgui_time_sink_x_2_0 @@ -1580,30 +1584,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1552, 1364.0] - rotation: 0 - state: disabled -- name: root_raised_cosine_filter_0 - id: root_raised_cosine_filter - parameters: - affinity: '' - alias: '' - alpha: excess_bw - comment: '' - decim: '1' - gain: '2' - interp: '1' - maxoutbuf: '0' - minoutbuf: '0' - ntaps: 11*samp_rate - samp_rate: samp_rate - sym_rate: sps * samp_rate - type: fir_filter_ccf - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [496, 180.0] + coordinate: [1552, 1232.0] rotation: 0 state: disabled - name: virtual_sink_0 @@ -1616,7 +1597,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1480, 404.0] + coordinate: [1488, 268.0] rotation: 0 state: enabled - name: virtual_sink_3 @@ -1629,7 +1610,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1368, 1036.0] + coordinate: [1400, 828.0] rotation: 0 state: true - name: virtual_source_0 @@ -1642,7 +1623,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [32, 884.0] + coordinate: [16, 748.0] rotation: 0 state: enabled - name: virtual_source_1 @@ -1655,7 +1636,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [24, 1388.0] + coordinate: [16, 1260.0] rotation: 0 state: true @@ -1668,18 +1649,16 @@ connections: - [blocks_multiply_const_vxx_0, '0', qtgui_time_sink_x_2, '0'] - [blocks_multiply_const_vxx_0_0, '0', qtgui_time_sink_x_2_0, '0'] - [blocks_null_source_0, '0', blocks_stream_mux_0, '0'] +- [blocks_repack_bits_bb_0, '0', epy_block_1, '0'] - [blocks_stream_mux_0, '0', digital_constellation_modulator_0, '0'] -- [blocks_stream_mux_1, '0', channels_channel_model_0, '0'] - [blocks_throttle_0, '0', virtual_sink_0, '0'] - [blocks_vector_source_x_0, '0', blocks_stream_mux_0, '1'] -- [blocks_vector_source_x_1, '0', root_raised_cosine_filter_0, '0'] - [channels_channel_model_0, '0', blocks_throttle_0, '0'] - [digital_cma_equalizer_cc_0, '0', digital_corr_est_cc_0, '0'] - [digital_cma_equalizer_cc_0, '0', fir_filter_xxx_1, '0'] - [digital_cma_equalizer_cc_0, '0', qtgui_const_sink_x_0, '0'] - [digital_cma_equalizer_cc_0, '0', qtgui_time_sink_x_1_1, '0'] -- [digital_constellation_decoder_cb_0, '0', blocks_vector_sink_x_0, '0'] -- [digital_constellation_modulator_0, '0', blocks_stream_mux_1, '1'] +- [digital_constellation_decoder_cb_0, '0', digital_map_bb_0, '0'] - [digital_constellation_modulator_0, '0', channels_channel_model_0, '0'] - [digital_constellation_modulator_0, '0', qtgui_time_sink_x_1_0, '0'] - [digital_corr_est_cc_0, '0', digital_costas_loop_cc_0, '0'] @@ -1687,12 +1666,12 @@ connections: - [digital_corr_est_cc_0, '0', qtgui_time_sink_x_0_0_0, '0'] - [digital_corr_est_cc_0, '1', blocks_complex_to_magphase_0_0, '0'] - [digital_costas_loop_cc_0, '0', qtgui_const_sink_x_0_0, '1'] +- [digital_map_bb_0, '0', blocks_repack_bits_bb_0, '0'] - [digital_pfb_clock_sync_xxx_0, '0', digital_cma_equalizer_cc_0, '0'] - [epy_block_0, '0', qtgui_const_sink_x_0_0, '0'] - [epy_block_0, '0', virtual_sink_3, '0'] - [fir_filter_xxx_1, '0', blocks_complex_to_magphase_0, '0'] - [fir_filter_xxx_1, '0', qtgui_const_sink_x_1, '0'] -- [root_raised_cosine_filter_0, '0', blocks_stream_mux_1, '0'] - [virtual_source_0, '0', digital_pfb_clock_sync_xxx_0, '0'] - [virtual_source_1, '0', digital_constellation_decoder_cb_0, '0'] diff --git a/tests/correlator/correlator.py b/tests/correlator/correlator.py index 50283c0..255010a 100755 --- a/tests/correlator/correlator.py +++ b/tests/correlator/correlator.py @@ -35,6 +35,8 @@ from argparse import ArgumentParser from gnuradio.eng_arg import eng_float, intx from gnuradio import eng_notation import epy_block_0 +import epy_block_1 +import numpy as np from gnuradio import qtgui @@ -77,13 +79,12 @@ class correlator(gr.top_block, Qt.QWidget): self.sps = sps = 4 self.nfilts = nfilts = 32 self.excess_bw = excess_bw = .35 - self.timing_loop_bw = timing_loop_bw = 2 * 3.141592653589793 / 100 - self.testvec = testvec = [31, 53] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3] - self.samp_rate = samp_rate = 32000 + self.timing_loop_bw = timing_loop_bw = 2 * np.pi / 100 + self.testvec = testvec = [0x1f, 0x35] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3] + self.samp_rate = samp_rate = int(1.5e6) self.rrc_taps = rrc_taps = firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), excess_bw, 45*nfilts) self.revconj_access_code_symbols = revconj_access_code_symbols = [(1.4142135623730951+1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (-1.4142135623730951+1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (-1.4142135623730951+1.4142135623730951j)] self.const = const = digital.constellation_qpsk().base() - self.access_code_symbols_sps = access_code_symbols_sps = [(1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j)] self.access_code_symbols = access_code_symbols = [(-1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (-1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j)] ################################################## @@ -145,7 +146,7 @@ class correlator(gr.top_block, Qt.QWidget): self.top_grid_layout.setColumnStretch(c, 1) self.qtgui_time_sink_x_0_0_0 = qtgui.time_sink_c( 1024, #size - samp_rate, #samp_rate + samp_rate / sps, #samp_rate "", #name 1 #number of inputs ) @@ -195,7 +196,7 @@ class correlator(gr.top_block, Qt.QWidget): self.top_grid_layout.addWidget(self._qtgui_time_sink_x_0_0_0_win) self.qtgui_time_sink_x_0_0 = qtgui.time_sink_f( 1024, #size - samp_rate, #samp_rate + samp_rate / sps, #samp_rate "", #name 1 #number of inputs ) @@ -328,6 +329,7 @@ class correlator(gr.top_block, Qt.QWidget): self.top_grid_layout.setRowStretch(r, 1) for c in range(1, 2): self.top_grid_layout.setColumnStretch(c, 1) + self.epy_block_1 = epy_block_1.blk() self.epy_block_0 = epy_block_0.blk() self.digital_pfb_clock_sync_xxx_0 = digital.pfb_clock_sync_ccf(sps, timing_loop_bw, rrc_taps, nfilts, 16, 1.5, 1) self.digital_costas_loop_cc_0 = digital.costas_loop_cc(2 * 3.141592653589793 / 100, 4, False) @@ -343,16 +345,16 @@ class correlator(gr.top_block, Qt.QWidget): self.digital_constellation_decoder_cb_0 = digital.constellation_decoder_cb(const) self.digital_cma_equalizer_cc_0 = digital.cma_equalizer_cc(15, 1, .002, 1) self.channels_channel_model_0 = channels.channel_model( - noise_voltage=0.2, + noise_voltage=0.01, frequency_offset=0.0001, epsilon=1.0, - taps=[-1.4 + .4j], + taps=[np.exp(1j * 30 / 180 * np.pi)], noise_seed=243, block_tags=False) - self.blocks_vector_source_x_0 = blocks.vector_source_b(testvec * 1600, True, 1, []) - self.blocks_vector_sink_x_0 = blocks.vector_sink_b(1, 1024) + self.blocks_vector_source_x_0 = blocks.vector_source_b(testvec * 500, True, 1, []) self.blocks_throttle_0 = blocks.throttle(gr.sizeof_gr_complex*1, samp_rate,True) - self.blocks_stream_mux_0 = blocks.stream_mux(gr.sizeof_char*1, [10, len(testvec)]) + self.blocks_stream_mux_0 = blocks.stream_mux(gr.sizeof_char*1, [5, len(testvec)]) + self.blocks_repack_bits_bb_0 = blocks.repack_bits_bb(2, 8, "", False, gr.GR_MSB_FIRST) self.blocks_null_source_0 = blocks.null_source(gr.sizeof_char*1) self.blocks_null_sink_3 = blocks.null_sink(gr.sizeof_float*1) self.blocks_complex_to_magphase_0_0 = blocks.complex_to_magphase(1) @@ -365,13 +367,14 @@ class correlator(gr.top_block, Qt.QWidget): self.connect((self.blocks_complex_to_magphase_0_0, 1), (self.blocks_null_sink_3, 0)) self.connect((self.blocks_complex_to_magphase_0_0, 0), (self.qtgui_time_sink_x_0_0, 0)) self.connect((self.blocks_null_source_0, 0), (self.blocks_stream_mux_0, 0)) + self.connect((self.blocks_repack_bits_bb_0, 0), (self.epy_block_1, 0)) self.connect((self.blocks_stream_mux_0, 0), (self.digital_constellation_modulator_0, 0)) self.connect((self.blocks_throttle_0, 0), (self.digital_pfb_clock_sync_xxx_0, 0)) self.connect((self.blocks_vector_source_x_0, 0), (self.blocks_stream_mux_0, 1)) self.connect((self.channels_channel_model_0, 0), (self.blocks_throttle_0, 0)) self.connect((self.digital_cma_equalizer_cc_0, 0), (self.digital_corr_est_cc_0, 0)) self.connect((self.digital_cma_equalizer_cc_0, 0), (self.qtgui_const_sink_x_0, 0)) - self.connect((self.digital_constellation_decoder_cb_0, 0), (self.blocks_vector_sink_x_0, 0)) + self.connect((self.digital_constellation_decoder_cb_0, 0), (self.blocks_repack_bits_bb_0, 0)) self.connect((self.digital_constellation_modulator_0, 0), (self.channels_channel_model_0, 0)) self.connect((self.digital_constellation_modulator_0, 0), (self.qtgui_time_sink_x_1_0, 0)) self.connect((self.digital_corr_est_cc_0, 1), (self.blocks_complex_to_magphase_0_0, 0)) @@ -395,6 +398,8 @@ class correlator(gr.top_block, Qt.QWidget): def set_sps(self, sps): self.sps = sps self.set_rrc_taps(firdes.root_raised_cosine(self.nfilts, self.nfilts, 1.0/float(self.sps), self.excess_bw, 45*self.nfilts)) + self.qtgui_time_sink_x_0_0.set_samp_rate(self.samp_rate / self.sps) + self.qtgui_time_sink_x_0_0_0.set_samp_rate(self.samp_rate / self.sps) def get_nfilts(self): return self.nfilts @@ -422,7 +427,7 @@ class correlator(gr.top_block, Qt.QWidget): def set_testvec(self, testvec): self.testvec = testvec - self.blocks_vector_source_x_0.set_data(self.testvec * 1600, []) + self.blocks_vector_source_x_0.set_data(self.testvec * 500, []) def get_samp_rate(self): return self.samp_rate @@ -430,8 +435,8 @@ class correlator(gr.top_block, Qt.QWidget): def set_samp_rate(self, samp_rate): self.samp_rate = samp_rate self.blocks_throttle_0.set_sample_rate(self.samp_rate) - self.qtgui_time_sink_x_0_0.set_samp_rate(self.samp_rate) - self.qtgui_time_sink_x_0_0_0.set_samp_rate(self.samp_rate) + self.qtgui_time_sink_x_0_0.set_samp_rate(self.samp_rate / self.sps) + self.qtgui_time_sink_x_0_0_0.set_samp_rate(self.samp_rate / self.sps) self.qtgui_time_sink_x_1_0.set_samp_rate(self.samp_rate) def get_rrc_taps(self): @@ -453,12 +458,6 @@ class correlator(gr.top_block, Qt.QWidget): def set_const(self, const): self.const = const - def get_access_code_symbols_sps(self): - return self.access_code_symbols_sps - - def set_access_code_symbols_sps(self, access_code_symbols_sps): - self.access_code_symbols_sps = access_code_symbols_sps - def get_access_code_symbols(self): return self.access_code_symbols diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py index e7599c9..a581a3a 100644 --- a/tests/correlator/epy_block_0.py +++ b/tests/correlator/epy_block_0.py @@ -25,7 +25,7 @@ class blk(gr.sync_block): # filter to avoid werid jumps in the correction. to do that, there are # two buffers with an index self.index = 0 - self.length = 7 + self.length = 5 self.freq = np.zeros(self.length) def lpf_freq(self, new_sample): @@ -46,12 +46,20 @@ class blk(gr.sync_block): # compute frequency offset between start and end # and run it through a low pass filter (mean) - freq = (sphase - ephase) / nsamples - freq = self.lpf_freq(freq) + phasediff = ephase - sphase + + if phasediff > np.pi: + phasediff -= 2*np.pi + + elif phasediff < -np.pi: + phasediff += 2*np.pi + + freq = phasediff / nsamples + # freq = self.lpf_freq(freq) # debugging print(f"Correction for block of {nsamples:2d} samples is " \ - f"phase={sphase: .4f} rad and freq={freq*1e3: .4f} milli rad / sample") + f"sphase={sphase: .4f} rad and freq={freq*1e3: .4f} milli rad / sample") # compute block values return sphase * np.ones(nsamples) + freq * np.arange(0, nsamples) diff --git a/tests/correlator/epy_block_1.py b/tests/correlator/epy_block_1.py new file mode 100644 index 0000000..d30c2eb --- /dev/null +++ b/tests/correlator/epy_block_1.py @@ -0,0 +1,27 @@ +""" +Embedded Python Blocks: + +Each time this file is saved, GRC will instantiate the first class it finds +to get ports and parameters of your block. The arguments to __init__ will +be the parameters. All of them are required to have default values! +""" + +import numpy as np +from gnuradio import gr + +np.set_printoptions(formatter={'int':hex}) + +class blk(gr.sync_block): + def __init__(self): + gr.sync_block.__init__( + self, + name='Printer', + in_sig=[np.byte], + out_sig=[] + ) + + def work(self, input_items, output_items): + inp = np.array(input_items[0], dtype=np.uint8) + print(f"Decoded {len(inp)} samples:\n{inp}") + + return len(inp) -- cgit v1.2.1 From cafce753722ec8d396cadfdf991b5c6f5a18dc12 Mon Sep 17 00:00:00 2001 From: sara Date: Fri, 3 Dec 2021 20:46:20 +0100 Subject: BER Block Fertig gestellt --- notebooks/BER .ipynb | 172 ++- .../Alte_versionen/qam_fading_FIR_Filter_v1.grc | 1445 +++++++++++++++++ .../QAM_Fading/Alte_versionen/qam_fading_V2.grc | 1539 +++++++++++++++++++ .../Alte_versionen/qam_fading_V2_mehrere.grc | 1623 ++++++++++++++++++++ .../qam_fading_frequency_selectiv.grc | 1448 +++++++++++++++++ simulation/QAM_Fading/epy_block_0.py | 74 - simulation/QAM_Fading/qam_fading_FIR_Filter_v1.grc | 1445 ----------------- simulation/QAM_Fading/qam_fading_V2.grc | 1539 ------------------- simulation/QAM_Fading/qam_fading_V2_mehrere.grc | 1623 -------------------- .../QAM_Fading/qam_fading_frequency_selectiv.grc | 20 +- .../qam_fading_frequency_selectiv_copy.grc | 1448 ----------------- src/gr-fadingui/grc/fadingui_ber.block.yml | 16 +- src/gr-fadingui/python/ber.py | 29 +- src/gr-fadingui/python/qa_ber.py | 13 +- tests/BER/Bit_error.grc | 66 +- tests/BER/Test_Bit_Errorrate.py | 26 +- 16 files changed, 6302 insertions(+), 6224 deletions(-) create mode 100644 simulation/QAM_Fading/Alte_versionen/qam_fading_FIR_Filter_v1.grc create mode 100644 simulation/QAM_Fading/Alte_versionen/qam_fading_V2.grc create mode 100644 simulation/QAM_Fading/Alte_versionen/qam_fading_V2_mehrere.grc create mode 100644 simulation/QAM_Fading/Alte_versionen/qam_fading_frequency_selectiv.grc delete mode 100644 simulation/QAM_Fading/epy_block_0.py delete mode 100644 simulation/QAM_Fading/qam_fading_FIR_Filter_v1.grc delete mode 100644 simulation/QAM_Fading/qam_fading_V2.grc delete mode 100644 simulation/QAM_Fading/qam_fading_V2_mehrere.grc delete mode 100644 simulation/QAM_Fading/qam_fading_frequency_selectiv_copy.grc diff --git a/notebooks/BER .ipynb b/notebooks/BER .ipynb index 8e0a6f4..57675f1 100644 --- a/notebooks/BER .ipynb +++ b/notebooks/BER .ipynb @@ -15,47 +15,25 @@ "execution_count": 2, "id": "be1f0d01", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([0, 1])" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "byte1= np.array([0x12, 0xe3, 0x9b])\n", - "byte2 = np.array([0x12, 0xe3, 0x9c])\n", - "b1 = np.array([0,0])\n", - "b2 = np.array([0,1])\n", - "b1\n", - "b2" + "byte2 = np.array([0x12, 0xe3, 0x9c])\n" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 3, "id": "c256a3d0", "metadata": {}, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0 0 7]\n" - ] - }, { "data": { "text/plain": [ - "array([0, 1], dtype=uint8)" + "array([0, 0, 7], dtype=uint8)" ] }, - "execution_count": 6, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -63,41 +41,32 @@ "source": [ "v = byte1^byte2\n", "v1 = np.array (v,dtype = np.uint8)\n", - "print(v1)\n", - "v2 = b1^b2\n", - "v2 = np.array (v2,dtype = np.uint8)\n", - "v2" + "v1" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 4, "id": "227f0142", - "metadata": {}, + "metadata": { + "scrolled": true + }, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1]\n" - ] - }, { "data": { "text/plain": [ - "array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], dtype=uint8)" + "array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,\n", + " 1, 1], dtype=uint8)" ] }, - "execution_count": 7, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z = np.unpackbits(v1)\n", - "print(z)\n", - "z1 = np.unpackbits(v2)\n", - "z1" + "z" ] }, { @@ -123,26 +92,123 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "0ac2e304", + "cell_type": "markdown", + "id": "1551b295", "metadata": {}, - "outputs": [], - "source": [] + "source": [ + "# TEST Längenanpassung" + ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "034142b6", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "test_byte=np.array([31, 53] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3])\n", + "test_byte\n", + "vlen= 10 " + ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "f203fbce", "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(test_byte)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "fc4fef77", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "20" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "inp= ([31, 53,0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3]+[30, 53,0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3])\n", + "len(inp)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "74ae964c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v = test_byte^inp[:vlen]\n", + "v" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "5a1d95f1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0 0 0 0 0 0 0 0 0 0]\n", + "[0 0 0 0 0 0 0 0 0 0]\n", + "[0 0 0 0 0 0 0 0 0 0]\n", + "[0 0 0 0 0 0 0 0 0 0]\n", + "[0 0 0 0 0 0 0 0 0 0]\n", + "[0 0 0 0 0 0 0 0 0 0]\n", + "[0 0 0 0 0 0 0 0 0 0]\n", + "[0 0 0 0 0 0 0 0 0 0]\n", + "[0 0 0 0 0 0 0 0 0 0]\n" + ] + } + ], + "source": [ + "for i in range(1,10):\n", + " v = test_byte^inp[:vlen]\n", + " print(v)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "038ceffa", + "metadata": {}, "outputs": [], "source": [] } diff --git a/simulation/QAM_Fading/Alte_versionen/qam_fading_FIR_Filter_v1.grc b/simulation/QAM_Fading/Alte_versionen/qam_fading_FIR_Filter_v1.grc new file mode 100644 index 0000000..ffc47f6 --- /dev/null +++ b/simulation/QAM_Fading/Alte_versionen/qam_fading_FIR_Filter_v1.grc @@ -0,0 +1,1445 @@ +options: + parameters: + author: Pross Naoki, Halter Sara Cinzia + category: '[GRC Hier Blocks]' + cmake_opt: '' + comment: '' + copyright: '' + description: '' + gen_cmake: 'On' + gen_linking: dynamic + generate_options: qt_gui + hier_block_src_path: '.:' + id: qam_fading + max_nouts: '0' + output_language: python + placement: (0,0) + qt_qss_theme: '' + realtime_scheduling: '1' + run: 'True' + run_command: '{python} -u {filename}' + run_options: prompt + sizing_mode: fixed + thread_safe_setters: '' + title: QAM mit Fading + window_size: '' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [8, 8] + rotation: 0 + state: enabled + +blocks: +- name: chn_taps + id: variable + parameters: + comment: '' + value: '[1.0 + 0.0j, ]' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [672, 236.0] + rotation: 0 + state: true +- name: const + id: variable_constellation + parameters: + comment: '' + const_points: '[-1-1j, -1+1j, 1+1j, 1-1j]' + dims: '1' + precision: '8' + rot_sym: '4' + soft_dec_lut: None + sym_map: '[0, 1, 3, 2]' + type: qpsk + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [224, 428.0] + rotation: 0 + state: true +- name: eq_gain + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@1: 0,0,1,1' + label: Equalizer Rate + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: '.001' + stop: '.1' + value: '.01' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1648, 476.0] + rotation: 0 + state: true +- name: eq_mod + id: variable + parameters: + comment: '' + value: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1648, 400.0] + rotation: 0 + state: true +- name: eq_ntaps + id: variable + parameters: + comment: '' + value: '15' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1728, 400.0] + rotation: 0 + state: true +- name: excess_bw + id: variable + parameters: + comment: '' + value: 350e-3 + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [320, 268.0] + rotation: 0 + state: true +- name: freq_offset + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@0: 1,0,1,1' + label: Frequency Offset + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: -100e-3 + step: 1e-3 + stop: 100e-3 + value: '0' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [712, 476.0] + rotation: 0 + state: true +- name: nfilts + id: variable + parameters: + comment: '' + value: '32' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1312, 132.0] + rotation: 0 + state: true +- name: noise_volt + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@0: 0,0,1,1' + label: Noise Voltage + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: '0.01' + stop: '1' + value: '0.0001' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [576, 476.0] + rotation: 0 + state: true +- name: phase_bw + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@1: 1,0,1,1' + label: Phase Bandwidth + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: '.01' + stop: '1' + value: 2 * 3.141592653589793 / 100 + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1952, 444.0] + rotation: 0 + state: true +- name: rrc_taps + id: variable + parameters: + comment: '' + value: firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), excess_bw, 45*nfilts) + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1376, 132.0] + rotation: 0 + state: true +- name: samp_rate + id: variable + parameters: + comment: '' + value: '32000' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [192, 12.0] + rotation: 0 + state: enabled +- name: sps + id: variable + parameters: + comment: '' + value: '4' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [224, 268.0] + rotation: 0 + state: true +- name: time_offset + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@0: 0,1,1,1' + label: Timing Offset + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0.999' + step: '0.0001' + stop: '1.001' + value: '1.0' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [576, 620.0] + rotation: 0 + state: true +- name: timing_loop_bw + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@0: 1,1,1,1' + label: Time Bandwidth + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: 10e-3 + stop: 200e-3 + value: 2 * 3.141592653589793 / 100 + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1312, 196.0] + rotation: 0 + state: true +- name: analog_random_source_x_0 + id: analog_random_source_x + parameters: + affinity: '' + alias: '' + comment: '' + max: '256' + maxoutbuf: '0' + min: '0' + minoutbuf: '0' + num_samps: '1000' + repeat: 'True' + type: byte + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [32, 332.0] + rotation: 0 + state: enabled +- name: blocks_char_to_float_0 + id: blocks_char_to_float + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + scale: '1' + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2592, 296.0] + rotation: 0 + state: true +- name: blocks_char_to_float_0_0 + id: blocks_char_to_float + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + scale: '1' + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [424, 1336.0] + rotation: 0 + state: true +- name: blocks_char_to_float_0_1 + id: blocks_char_to_float + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + scale: '1' + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2544, 692.0] + rotation: 0 + state: true +- name: blocks_delay_0 + id: blocks_delay + parameters: + affinity: '' + alias: '' + comment: '' + delay: '50' + maxoutbuf: '0' + minoutbuf: '0' + num_ports: '1' + type: float + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2624, 1352.0] + rotation: 0 + state: true +- name: blocks_throttle_0 + id: blocks_throttle + parameters: + affinity: '' + alias: '' + comment: '' + ignoretag: 'True' + maxoutbuf: '0' + minoutbuf: '0' + samples_per_second: samp_rate + type: complex + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [464, 356.0] + rotation: 0 + state: enabled +- name: blocks_unpack_k_bits_bb_0 + id: blocks_unpack_k_bits_bb + parameters: + affinity: '' + alias: '' + comment: '' + k: '2' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2512, 456.0] + rotation: 0 + state: true +- name: blocks_unpack_k_bits_bb_0_0 + id: blocks_unpack_k_bits_bb + parameters: + affinity: '' + alias: '' + comment: '' + k: '2' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [248, 1336.0] + rotation: 0 + state: true +- name: blocks_unpack_k_bits_bb_0_1 + id: blocks_unpack_k_bits_bb + parameters: + affinity: '' + alias: '' + comment: '' + k: '2' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2448, 868.0] + rotation: 0 + state: true +- name: channels_channel_model_0 + id: channels_channel_model + parameters: + affinity: '' + alias: '' + block_tags: 'False' + comment: '' + epsilon: time_offset + freq_offset: freq_offset + maxoutbuf: '0' + minoutbuf: '0' + noise_voltage: noise_volt + seed: '0' + taps: chn_taps + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [648, 316.0] + rotation: 0 + state: enabled +- name: channels_fading_model_0 + id: channels_fading_model + parameters: + K: '4.0' + LOS: 'False' + N: '8' + affinity: '' + alias: '' + comment: '' + fDTs: '0' + maxoutbuf: '0' + minoutbuf: '0' + seed: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [952, 332.0] + rotation: 0 + state: true +- name: digital_cma_equalizer_cc_0 + id: digital_cma_equalizer_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: eq_mod + mu: eq_gain + num_taps: eq_ntaps + sps: '2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1648, 304.0] + rotation: 0 + state: true +- name: digital_cma_equalizer_cc_0_0 + id: digital_cma_equalizer_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: eq_mod + mu: eq_gain + num_taps: eq_ntaps + sps: '2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1600, 724.0] + rotation: 0 + state: true +- name: digital_constellation_decoder_cb_0 + id: digital_constellation_decoder_cb + parameters: + affinity: '' + alias: '' + comment: '' + constellation: const + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2288, 296.0] + rotation: 0 + state: true +- name: digital_constellation_decoder_cb_0_0 + id: digital_constellation_decoder_cb + parameters: + affinity: '' + alias: '' + comment: '' + constellation: const + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2224, 684.0] + rotation: 0 + state: true +- name: digital_constellation_modulator_0 + id: digital_constellation_modulator + parameters: + affinity: '' + alias: '' + comment: '' + constellation: const + differential: 'True' + excess_bw: excess_bw + log: 'False' + maxoutbuf: '0' + minoutbuf: '0' + samples_per_symbol: sps + verbose: 'False' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [224, 332.0] + rotation: 0 + state: enabled +- name: digital_costas_loop_cc_0 + id: digital_costas_loop_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + order: '4' + use_snr: 'False' + w: phase_bw + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1952, 296.0] + rotation: 0 + state: true +- name: digital_costas_loop_cc_0_0 + id: digital_costas_loop_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + order: '4' + use_snr: 'False' + w: phase_bw + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1936, 688.0] + rotation: 0 + state: true +- name: digital_diff_decoder_bb_0 + id: digital_diff_decoder_bb + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: '4' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2288, 360.0] + rotation: 180 + state: true +- name: digital_diff_decoder_bb_0_0 + id: digital_diff_decoder_bb + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: '4' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2264, 764.0] + rotation: 180 + state: true +- name: digital_map_bb_0 + id: digital_map_bb + parameters: + affinity: '' + alias: '' + comment: '' + map: '[0, 1, 3, 2]' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2304, 456.0] + rotation: 0 + state: true +- name: digital_map_bb_0_0 + id: digital_map_bb + parameters: + affinity: '' + alias: '' + comment: '' + map: '[0, 1, 3, 2]' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2272, 868.0] + rotation: 0 + state: true +- name: digital_pfb_clock_sync_xxx_0 + id: digital_pfb_clock_sync_xxx + parameters: + affinity: '' + alias: '' + comment: '' + filter_size: nfilts + init_phase: nfilts/2 + loop_bw: timing_loop_bw + max_dev: '1.5' + maxoutbuf: '0' + minoutbuf: '0' + osps: '2' + sps: sps * 1.001 + taps: rrc_taps + type: ccf + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1312, 324.0] + rotation: 0 + state: true +- name: digital_pfb_clock_sync_xxx_0_0 + id: digital_pfb_clock_sync_xxx + parameters: + affinity: '' + alias: '' + comment: '' + filter_size: nfilts + init_phase: nfilts/2 + loop_bw: timing_loop_bw + max_dev: '1.5' + maxoutbuf: '0' + minoutbuf: '0' + osps: '2' + sps: sps * 1.001 + taps: rrc_taps + type: ccf + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1088, 868.0] + rotation: 0 + state: true +- name: params + id: qtgui_tab_widget + parameters: + alias: '' + comment: '' + gui_hint: '' + label0: Channel + label1: Receiver + label10: Tab 10 + label11: Tab 11 + label12: Tab 12 + label13: Tab 13 + label14: Tab 14 + label15: Tab 15 + label16: Tab 16 + label17: Tab 17 + label18: Tab 18 + label19: Tab 19 + label2: Tab 2 + label3: Tab 3 + label4: Tab 4 + label5: Tab 5 + label6: Tab 6 + label7: Tab 7 + label8: Tab 8 + label9: Tab 9 + num_tabs: '2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [296, 12.0] + rotation: 0 + state: true +- name: plots + id: qtgui_tab_widget + parameters: + alias: '' + comment: '' + gui_hint: '' + label0: Constellations + label1: Frequency + label10: Tab 10 + label11: Tab 11 + label12: Tab 12 + label13: Tab 13 + label14: Tab 14 + label15: Tab 15 + label16: Tab 16 + label17: Tab 17 + label18: Tab 18 + label19: Tab 19 + label2: Time + label3: Tab 3 + label4: Tab 4 + label5: Tab 5 + label6: Tab 6 + label7: Tab 7 + label8: Tab 8 + label9: Tab 9 + num_tabs: '3' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [448, 12.0] + rotation: 0 + state: true +- name: qtgui_const_sink_x_0 + id: qtgui_const_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: '"blue"' + color10: '"red"' + color2: '"red"' + color3: '"red"' + color4: '"red"' + color5: '"red"' + color6: '"red"' + color7: '"red"' + color8: '"red"' + color9: '"red"' + comment: '' + grid: 'False' + gui_hint: 'plots@0: 0,0,1,1' + label1: Fading + label10: '' + label2: '' + label3: '' + label4: '' + label5: '' + label6: '' + label7: '' + label8: '' + label9: '' + legend: 'True' + marker1: '0' + marker10: '0' + marker2: '0' + marker3: '0' + marker4: '0' + marker5: '0' + marker6: '0' + marker7: '0' + marker8: '0' + marker9: '0' + name: '"Channel"' + nconnections: '2' + size: '2048' + style1: '0' + style10: '0' + style2: '0' + style3: '0' + style4: '0' + style5: '0' + style6: '0' + style7: '0' + style8: '0' + style9: '0' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: complex + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + xmax: '2' + xmin: '-2' + ymax: '2' + ymin: '-2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1044.0, -48] + rotation: 90 + state: enabled +- name: qtgui_const_sink_x_0_0 + id: qtgui_const_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: '"blue"' + color10: '"red"' + color2: '"red"' + color3: '"red"' + color4: '"red"' + color5: '"red"' + color6: '"red"' + color7: '"red"' + color8: '"red"' + color9: '"red"' + comment: '' + grid: 'False' + gui_hint: 'plots@0: 0,1,1,1' + label1: Fading + label10: '' + label2: '' + label3: '' + label4: '' + label5: '' + label6: '' + label7: '' + label8: '' + label9: '' + legend: 'True' + marker1: '0' + marker10: '0' + marker2: '0' + marker3: '0' + marker4: '0' + marker5: '0' + marker6: '0' + marker7: '0' + marker8: '0' + marker9: '0' + name: '"Synchronized"' + nconnections: '2' + size: '2048' + style1: '0' + style10: '0' + style2: '0' + style3: '0' + style4: '0' + style5: '0' + style6: '0' + style7: '0' + style8: '0' + style9: '0' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: complex + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + xmax: '2' + xmin: '-2' + ymax: '2' + ymin: '-2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1572.0, 80] + rotation: 90 + state: enabled +- name: qtgui_const_sink_x_1 + id: qtgui_const_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: '"blue"' + color10: '"red"' + color2: '"red"' + color3: '"red"' + color4: '"red"' + color5: '"red"' + color6: '"red"' + color7: '"red"' + color8: '"red"' + color9: '"red"' + comment: '' + grid: 'False' + gui_hint: 'plots@0: 1,0,1,1' + label1: Fading + label10: '' + label2: '' + label3: '' + label4: '' + label5: '' + label6: '' + label7: '' + label8: '' + label9: '' + legend: 'True' + marker1: '0' + marker10: '0' + marker2: '0' + marker3: '0' + marker4: '0' + marker5: '0' + marker6: '0' + marker7: '0' + marker8: '0' + marker9: '0' + name: '"Equalized"' + nconnections: '2' + size: '1024' + style1: '0' + style10: '0' + style2: '0' + style3: '0' + style4: '0' + style5: '0' + style6: '0' + style7: '0' + style8: '0' + style9: '0' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: complex + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + xmax: '2' + xmin: '-2' + ymax: '2' + ymin: '-2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1828.0, 96] + rotation: 90 + state: true +- name: qtgui_const_sink_x_2 + id: qtgui_const_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: '"blue"' + color10: '"red"' + color2: '"red"' + color3: '"red"' + color4: '"red"' + color5: '"red"' + color6: '"red"' + color7: '"red"' + color8: '"red"' + color9: '"red"' + comment: '' + grid: 'False' + gui_hint: 'plots@0: 1,1,1,1' + label1: Fading + label10: '' + label2: '' + label3: '' + label4: '' + label5: '' + label6: '' + label7: '' + label8: '' + label9: '' + legend: 'True' + marker1: '0' + marker10: '0' + marker2: '0' + marker3: '0' + marker4: '0' + marker5: '0' + marker6: '0' + marker7: '0' + marker8: '0' + marker9: '0' + name: '"Locked"' + nconnections: '2' + size: '1024' + style1: '0' + style10: '0' + style2: '0' + style3: '0' + style4: '0' + style5: '0' + style6: '0' + style7: '0' + style8: '0' + style9: '0' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: complex + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + xmax: '2' + xmin: '-2' + ymax: '2' + ymin: '-2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2188.0, 0] + rotation: 90 + state: true +- name: qtgui_freq_sink_x_0 + id: qtgui_freq_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + average: '1.0' + axislabels: 'True' + bw: samp_rate + color1: '"blue"' + color10: '"dark blue"' + color2: '"red"' + color3: '"green"' + color4: '"black"' + color5: '"cyan"' + color6: '"magenta"' + color7: '"yellow"' + color8: '"dark red"' + color9: '"dark green"' + comment: '' + ctrlpanel: 'False' + fc: '0' + fftsize: '1024' + freqhalf: 'True' + grid: 'False' + gui_hint: 'plots@1: 0,0,1,1' + label: Relative Gain + label1: Fading + label10: '''''' + label2: '''''' + label3: '''''' + label4: '''''' + label5: '''''' + label6: '''''' + label7: '''''' + label8: '''''' + label9: '''''' + legend: 'True' + maxoutbuf: '0' + minoutbuf: '0' + name: '"Channel"' + nconnections: '2' + showports: 'False' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_tag: '""' + type: complex + units: dB + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + wintype: firdes.WIN_BLACKMAN_hARRIS + ymax: '10' + ymin: '-140' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1112.0, 608] + rotation: 270 + state: true +- name: qtgui_freq_sink_x_2_1 + id: qtgui_freq_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + average: '1.0' + axislabels: 'True' + bw: samp_rate + color1: '"blue"' + color10: '"dark blue"' + color2: '"red"' + color3: '"green"' + color4: '"black"' + color5: '"cyan"' + color6: '"magenta"' + color7: '"yellow"' + color8: '"dark red"' + color9: '"dark green"' + comment: '' + ctrlpanel: 'False' + fc: '0' + fftsize: '1024' + freqhalf: 'True' + grid: 'False' + gui_hint: '' + label: Relative Gain + label1: Fading + label10: '''''' + label2: '''''' + label3: '''''' + label4: '''''' + label5: '''''' + label6: '''''' + label7: '''''' + label8: '''''' + label9: '''''' + legend: 'True' + maxoutbuf: '0' + minoutbuf: '0' + name: '""' + nconnections: '2' + showports: 'False' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_tag: '""' + type: float + units: dB + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + wintype: firdes.WIN_BLACKMAN_hARRIS + ymax: '10' + ymin: '-140' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2848, 488.0] + rotation: 0 + state: true +- name: qtgui_time_sink_x_0 + id: qtgui_time_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: blue + color10: dark blue + color2: red + color3: green + color4: black + color5: cyan + color6: magenta + color7: yellow + color8: dark red + color9: dark green + comment: '' + ctrlpanel: 'False' + entags: 'True' + grid: 'False' + gui_hint: 'plots@2: 0,0,1,1' + label1: Received + label10: Signal 10 + label2: Sent + label3: Signal 3 + label4: Signal 4 + label5: Signal 5 + label6: Signal 6 + label7: Signal 7 + label8: Signal 8 + label9: Signal 9 + legend: 'True' + marker1: '-1' + marker10: '-1' + marker2: '-1' + marker3: '-1' + marker4: '-1' + marker5: '-1' + marker6: '-1' + marker7: '-1' + marker8: '-1' + marker9: '-1' + name: '"Decoded"' + nconnections: '3' + size: '1024' + srate: samp_rate + stemplot: 'False' + style1: '1' + style10: '1' + style2: '1' + style3: '1' + style4: '1' + style5: '1' + style6: '1' + style7: '1' + style8: '1' + style9: '1' + tr_chan: '0' + tr_delay: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: float + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + ylabel: Amplitude + ymax: '1' + ymin: '-1' + yunit: '""' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2816, 288.0] + rotation: 0 + state: true + +connections: +- [analog_random_source_x_0, '0', blocks_unpack_k_bits_bb_0_0, '0'] +- [analog_random_source_x_0, '0', digital_constellation_modulator_0, '0'] +- [blocks_char_to_float_0, '0', qtgui_freq_sink_x_2_1, '0'] +- [blocks_char_to_float_0, '0', qtgui_time_sink_x_0, '0'] +- [blocks_char_to_float_0_0, '0', blocks_delay_0, '0'] +- [blocks_char_to_float_0_1, '0', qtgui_freq_sink_x_2_1, '1'] +- [blocks_char_to_float_0_1, '0', qtgui_time_sink_x_0, '2'] +- [blocks_delay_0, '0', qtgui_time_sink_x_0, '1'] +- [blocks_throttle_0, '0', channels_channel_model_0, '0'] +- [blocks_unpack_k_bits_bb_0, '0', blocks_char_to_float_0, '0'] +- [blocks_unpack_k_bits_bb_0_0, '0', blocks_char_to_float_0_0, '0'] +- [blocks_unpack_k_bits_bb_0_1, '0', blocks_char_to_float_0_1, '0'] +- [channels_channel_model_0, '0', channels_fading_model_0, '0'] +- [channels_channel_model_0, '0', digital_pfb_clock_sync_xxx_0_0, '0'] +- [channels_channel_model_0, '0', qtgui_const_sink_x_0, '1'] +- [channels_channel_model_0, '0', qtgui_freq_sink_x_0, '1'] +- [channels_fading_model_0, '0', digital_pfb_clock_sync_xxx_0, '0'] +- [channels_fading_model_0, '0', qtgui_const_sink_x_0, '0'] +- [channels_fading_model_0, '0', qtgui_freq_sink_x_0, '0'] +- [digital_cma_equalizer_cc_0, '0', digital_costas_loop_cc_0, '0'] +- [digital_cma_equalizer_cc_0, '0', qtgui_const_sink_x_1, '0'] +- [digital_cma_equalizer_cc_0_0, '0', digital_costas_loop_cc_0_0, '0'] +- [digital_cma_equalizer_cc_0_0, '0', qtgui_const_sink_x_1, '1'] +- [digital_constellation_decoder_cb_0, '0', digital_diff_decoder_bb_0, '0'] +- [digital_constellation_decoder_cb_0_0, '0', digital_diff_decoder_bb_0_0, '0'] +- [digital_constellation_modulator_0, '0', blocks_throttle_0, '0'] +- [digital_costas_loop_cc_0, '0', digital_constellation_decoder_cb_0, '0'] +- [digital_costas_loop_cc_0, '0', qtgui_const_sink_x_2, '0'] +- [digital_costas_loop_cc_0_0, '0', digital_constellation_decoder_cb_0_0, '0'] +- [digital_costas_loop_cc_0_0, '0', qtgui_const_sink_x_2, '1'] +- [digital_diff_decoder_bb_0, '0', digital_map_bb_0, '0'] +- [digital_diff_decoder_bb_0_0, '0', digital_map_bb_0_0, '0'] +- [digital_map_bb_0, '0', blocks_unpack_k_bits_bb_0, '0'] +- [digital_map_bb_0_0, '0', blocks_unpack_k_bits_bb_0_1, '0'] +- [digital_pfb_clock_sync_xxx_0, '0', digital_cma_equalizer_cc_0, '0'] +- [digital_pfb_clock_sync_xxx_0, '0', qtgui_const_sink_x_0_0, '0'] +- [digital_pfb_clock_sync_xxx_0_0, '0', digital_cma_equalizer_cc_0_0, '0'] +- [digital_pfb_clock_sync_xxx_0_0, '0', qtgui_const_sink_x_0_0, '1'] + +metadata: + file_format: 1 diff --git a/simulation/QAM_Fading/Alte_versionen/qam_fading_V2.grc b/simulation/QAM_Fading/Alte_versionen/qam_fading_V2.grc new file mode 100644 index 0000000..16fa2e3 --- /dev/null +++ b/simulation/QAM_Fading/Alte_versionen/qam_fading_V2.grc @@ -0,0 +1,1539 @@ +options: + parameters: + author: Pross Naoki, Halter Sara Cinzia + category: '[GRC Hier Blocks]' + cmake_opt: '' + comment: '' + copyright: '' + description: '' + gen_cmake: 'On' + gen_linking: dynamic + generate_options: qt_gui + hier_block_src_path: '.:' + id: qam_fading + max_nouts: '0' + output_language: python + placement: (0,0) + qt_qss_theme: '' + realtime_scheduling: '1' + run: 'True' + run_command: '{python} -u {filename}' + run_options: prompt + sizing_mode: fixed + thread_safe_setters: '' + title: QAM mit Fading + window_size: '' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [8, 8] + rotation: 0 + state: enabled + +blocks: +- name: LOS_NLOS + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@2: 0,1,1,1' + label: LOS_NLOS + min_len: '200' + orient: Qt.Horizontal + rangeType: int + start: '0' + step: '1' + stop: '1' + value: '1' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1104, 484.0] + rotation: 0 + state: true +- name: amp_1 + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@2: 1,0,1,1' + label: Ampliude + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: '0.1' + stop: '5' + value: '0.2' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [984, 612.0] + rotation: 0 + state: true +- name: chn_taps + id: variable + parameters: + comment: '' + value: '[1.0 + 0.0j, ]' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [672, 236.0] + rotation: 0 + state: true +- name: const + id: variable_constellation + parameters: + comment: '' + const_points: '[-1-1j, -1+1j, 1+1j, 1-1j]' + dims: '1' + precision: '8' + rot_sym: '4' + soft_dec_lut: None + sym_map: '[0, 1, 3, 2]' + type: 16qam + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [224, 428.0] + rotation: 0 + state: true +- name: eq_gain + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@1: 0,0,1,1' + label: Equalizer Rate + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: '.001' + stop: '.1' + value: '.01' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1744, 452.0] + rotation: 0 + state: true +- name: eq_mod + id: variable + parameters: + comment: '' + value: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1744, 376.0] + rotation: 0 + state: true +- name: eq_ntaps + id: variable + parameters: + comment: '' + value: '15' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1824, 376.0] + rotation: 0 + state: true +- name: excess_bw + id: variable + parameters: + comment: '' + value: 350e-3 + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [320, 268.0] + rotation: 0 + state: true +- name: fading_1 + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@2: 0,0,1,1' + label: Fading + min_len: '200' + orient: Qt.Horizontal + rangeType: int + start: '1' + step: '1' + stop: '30' + value: '2' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [984, 484.0] + rotation: 0 + state: true +- name: freq_offset + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@0: 1,0,1,1' + label: Frequency Offset + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: -100e-3 + step: 1e-3 + stop: 100e-3 + value: '0' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [712, 476.0] + rotation: 0 + state: true +- name: nfilts + id: variable + parameters: + comment: '' + value: '32' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1408, 104.0] + rotation: 0 + state: true +- name: noise_volt + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@0: 0,0,1,1' + label: Noise Voltage + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: '0.01' + stop: '1' + value: '0.0001' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [576, 476.0] + rotation: 0 + state: true +- name: phase_bw + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@1: 1,0,1,1' + label: Phase Bandwidth + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: '.01' + stop: '1' + value: 2 * 3.141592653589793 / 100 + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2048, 420.0] + rotation: 0 + state: true +- name: rrc_taps + id: variable + parameters: + comment: '' + value: firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), excess_bw, 45*nfilts) + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1488, 104.0] + rotation: 0 + state: true +- name: samp_rate + id: variable + parameters: + comment: '' + value: '32000' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [192, 12.0] + rotation: 0 + state: enabled +- name: sps + id: variable + parameters: + comment: '' + value: '4' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [224, 268.0] + rotation: 0 + state: true +- name: time_offset + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@0: 0,1,1,1' + label: Timing Offset + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0.999' + step: '0.0001' + stop: '1.001' + value: '1.0' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [576, 620.0] + rotation: 0 + state: true +- name: timing_loop_bw + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@0: 1,1,1,1' + label: Time Bandwidth + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: 10e-3 + stop: 200e-3 + value: 2 * 3.141592653589793 / 100 + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1408, 164.0] + rotation: 0 + state: true +- name: analog_random_source_x_0 + id: analog_random_source_x + parameters: + affinity: '' + alias: '' + comment: '' + max: '256' + maxoutbuf: '0' + min: '0' + minoutbuf: '0' + num_samps: '1000' + repeat: 'True' + type: byte + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [32, 332.0] + rotation: 0 + state: enabled +- name: blocks_char_to_float_0 + id: blocks_char_to_float + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + scale: '1' + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2688, 272.0] + rotation: 0 + state: true +- name: blocks_char_to_float_0_0 + id: blocks_char_to_float + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + scale: '1' + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [424, 1336.0] + rotation: 0 + state: true +- name: blocks_char_to_float_0_1 + id: blocks_char_to_float + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + scale: '1' + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2640, 672.0] + rotation: 0 + state: true +- name: blocks_delay_0 + id: blocks_delay + parameters: + affinity: '' + alias: '' + comment: '' + delay: '50' + maxoutbuf: '0' + minoutbuf: '0' + num_ports: '1' + type: float + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2736, 1360.0] + rotation: 0 + state: true +- name: blocks_file_sink_0 + id: blocks_file_sink + parameters: + affinity: '' + alias: '' + append: 'False' + comment: '' + file: /home/sara/Documents/Fading/simulation/QAM_Fading/qam_fading_V2_output.grc + type: float + unbuffered: 'False' + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2880, 84.0] + rotation: 0 + state: disabled +- name: blocks_throttle_0 + id: blocks_throttle + parameters: + affinity: '' + alias: '' + comment: '' + ignoretag: 'True' + maxoutbuf: '0' + minoutbuf: '0' + samples_per_second: samp_rate + type: complex + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [464, 356.0] + rotation: 0 + state: enabled +- name: blocks_unpack_k_bits_bb_0 + id: blocks_unpack_k_bits_bb + parameters: + affinity: '' + alias: '' + comment: '' + k: '2' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2608, 432.0] + rotation: 0 + state: true +- name: blocks_unpack_k_bits_bb_0_0 + id: blocks_unpack_k_bits_bb + parameters: + affinity: '' + alias: '' + comment: '' + k: '2' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [248, 1336.0] + rotation: 0 + state: true +- name: blocks_unpack_k_bits_bb_0_1 + id: blocks_unpack_k_bits_bb + parameters: + affinity: '' + alias: '' + comment: '' + k: '2' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2544, 848.0] + rotation: 0 + state: true +- name: channels_channel_model_0 + id: channels_channel_model + parameters: + affinity: '' + alias: '' + block_tags: 'False' + comment: '' + epsilon: time_offset + freq_offset: freq_offset + maxoutbuf: '0' + minoutbuf: '0' + noise_voltage: noise_volt + seed: '0' + taps: chn_taps + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [648, 316.0] + rotation: 0 + state: enabled +- name: digital_cma_equalizer_cc_0 + id: digital_cma_equalizer_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: eq_mod + mu: eq_gain + num_taps: eq_ntaps + sps: '2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1744, 276.0] + rotation: 0 + state: true +- name: digital_cma_equalizer_cc_0_0 + id: digital_cma_equalizer_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: eq_mod + mu: eq_gain + num_taps: eq_ntaps + sps: '2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1664, 932.0] + rotation: 0 + state: true +- name: digital_constellation_decoder_cb_0 + id: digital_constellation_decoder_cb + parameters: + affinity: '' + alias: '' + comment: '' + constellation: const + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2384, 272.0] + rotation: 0 + state: true +- name: digital_constellation_decoder_cb_0_0 + id: digital_constellation_decoder_cb + parameters: + affinity: '' + alias: '' + comment: '' + constellation: const + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2320, 656.0] + rotation: 0 + state: true +- name: digital_constellation_modulator_0 + id: digital_constellation_modulator + parameters: + affinity: '' + alias: '' + comment: '' + constellation: const + differential: 'True' + excess_bw: excess_bw + log: 'False' + maxoutbuf: '0' + minoutbuf: '0' + samples_per_symbol: sps + verbose: 'False' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [224, 332.0] + rotation: 0 + state: enabled +- name: digital_costas_loop_cc_0 + id: digital_costas_loop_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + order: '4' + use_snr: 'False' + w: phase_bw + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2048, 264.0] + rotation: 0 + state: true +- name: digital_costas_loop_cc_0_0 + id: digital_costas_loop_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + order: '4' + use_snr: 'False' + w: phase_bw + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1984, 928.0] + rotation: 0 + state: true +- name: digital_diff_decoder_bb_0 + id: digital_diff_decoder_bb + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: '4' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2384, 336.0] + rotation: 180 + state: true +- name: digital_diff_decoder_bb_0_0 + id: digital_diff_decoder_bb + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: '4' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2352, 736.0] + rotation: 180 + state: true +- name: digital_map_bb_0 + id: digital_map_bb + parameters: + affinity: '' + alias: '' + comment: '' + map: '[0, 1, 3, 2]' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2400, 432.0] + rotation: 0 + state: true +- name: digital_map_bb_0_0 + id: digital_map_bb + parameters: + affinity: '' + alias: '' + comment: '' + map: '[0, 1, 3, 2]' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2368, 848.0] + rotation: 0 + state: true +- name: digital_pfb_clock_sync_xxx_0 + id: digital_pfb_clock_sync_xxx + parameters: + affinity: '' + alias: '' + comment: '' + filter_size: nfilts + init_phase: nfilts/2 + loop_bw: timing_loop_bw + max_dev: '1.5' + maxoutbuf: '0' + minoutbuf: '0' + osps: '1' + sps: sps + taps: rrc_taps + type: ccf + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1408, 300.0] + rotation: 0 + state: true +- name: digital_pfb_clock_sync_xxx_0_0 + id: digital_pfb_clock_sync_xxx + parameters: + affinity: '' + alias: '' + comment: '' + filter_size: nfilts + init_phase: nfilts/2 + loop_bw: timing_loop_bw + max_dev: '1.5' + maxoutbuf: '0' + minoutbuf: '0' + osps: '1' + sps: 'sps ' + taps: rrc_taps + type: ccf + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1136, 956.0] + rotation: 0 + state: true +- name: import_0 + id: import + parameters: + alias: '' + comment: '' + imports: import numpy as np + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [600, 20.0] + rotation: 0 + state: true +- name: interp_fir_filter_xxx_0 + id: interp_fir_filter_xxx + parameters: + affinity: '' + alias: '' + comment: '' + interp: '1' + maxoutbuf: '0' + minoutbuf: '0' + samp_delay: '0' + taps: '[LOS_NLOS]+(([0]*fading_1)+[amp_1])' + type: ccc + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1000, 348.0] + rotation: 0 + state: enabled +- name: params + id: qtgui_tab_widget + parameters: + alias: '' + comment: '' + gui_hint: '' + label0: Channel + label1: Receiver + label10: Tab 10 + label11: Tab 11 + label12: Tab 12 + label13: Tab 13 + label14: Tab 14 + label15: Tab 15 + label16: Tab 16 + label17: Tab 17 + label18: Tab 18 + label19: Tab 19 + label2: Fading + label3: Tab 3 + label4: Tab 4 + label5: Tab 5 + label6: Tab 6 + label7: Tab 7 + label8: Tab 8 + label9: Tab 9 + num_tabs: '3' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [296, 12.0] + rotation: 0 + state: true +- name: plots + id: qtgui_tab_widget + parameters: + alias: '' + comment: '' + gui_hint: '' + label0: Constellations + label1: Frequency + label10: Tab 10 + label11: Tab 11 + label12: Tab 12 + label13: Tab 13 + label14: Tab 14 + label15: Tab 15 + label16: Tab 16 + label17: Tab 17 + label18: Tab 18 + label19: Tab 19 + label2: Time + label3: Tab 3 + label4: Tab 4 + label5: Tab 5 + label6: Tab 6 + label7: Tab 7 + label8: Tab 8 + label9: Tab 9 + num_tabs: '3' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [448, 12.0] + rotation: 0 + state: true +- name: qtgui_const_sink_x_0 + id: qtgui_const_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: '"blue"' + color10: '"red"' + color2: '"red"' + color3: '"red"' + color4: '"red"' + color5: '"red"' + color6: '"red"' + color7: '"red"' + color8: '"red"' + color9: '"red"' + comment: '' + grid: 'False' + gui_hint: 'plots@0: 0,0,1,1' + label1: fading + label10: '' + label2: normal + label3: '' + label4: '' + label5: '' + label6: '' + label7: '' + label8: '' + label9: '' + legend: 'True' + marker1: '0' + marker10: '0' + marker2: '0' + marker3: '0' + marker4: '0' + marker5: '0' + marker6: '0' + marker7: '0' + marker8: '0' + marker9: '0' + name: '"Channel"' + nconnections: '2' + size: '2048' + style1: '0' + style10: '0' + style2: '0' + style3: '0' + style4: '0' + style5: '0' + style6: '0' + style7: '0' + style8: '0' + style9: '0' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: complex + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + xmax: '2' + xmin: '-2' + ymax: '2' + ymin: '-2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1052.0, -48] + rotation: 90 + state: enabled +- name: qtgui_const_sink_x_0_0 + id: qtgui_const_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: '"blue"' + color10: '"red"' + color2: '"red"' + color3: '"red"' + color4: '"red"' + color5: '"red"' + color6: '"red"' + color7: '"red"' + color8: '"red"' + color9: '"red"' + comment: '' + grid: 'False' + gui_hint: 'plots@0: 0,1,1,1' + label1: fading + label10: '' + label2: normal + label3: '' + label4: '' + label5: '' + label6: '' + label7: '' + label8: '' + label9: '' + legend: 'True' + marker1: '0' + marker10: '0' + marker2: '0' + marker3: '0' + marker4: '0' + marker5: '0' + marker6: '0' + marker7: '0' + marker8: '0' + marker9: '0' + name: '"Synchronized"' + nconnections: '2' + size: '2048' + style1: '0' + style10: '0' + style2: '0' + style3: '0' + style4: '0' + style5: '0' + style6: '0' + style7: '0' + style8: '0' + style9: '0' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: complex + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + xmax: '2' + xmin: '-2' + ymax: '2' + ymin: '-2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1656.0, 56] + rotation: 90 + state: enabled +- name: qtgui_const_sink_x_1 + id: qtgui_const_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: '"blue"' + color10: '"red"' + color2: '"red"' + color3: '"red"' + color4: '"red"' + color5: '"red"' + color6: '"red"' + color7: '"red"' + color8: '"red"' + color9: '"red"' + comment: '' + grid: 'False' + gui_hint: 'plots@0: 1,0,1,1' + label1: fading + label10: '' + label2: normal + label3: '' + label4: '' + label5: '' + label6: '' + label7: '' + label8: '' + label9: '' + legend: 'True' + marker1: '0' + marker10: '0' + marker2: '0' + marker3: '0' + marker4: '0' + marker5: '0' + marker6: '0' + marker7: '0' + marker8: '0' + marker9: '0' + name: '"Equalized"' + nconnections: '2' + size: '1024' + style1: '0' + style10: '0' + style2: '0' + style3: '0' + style4: '0' + style5: '0' + style6: '0' + style7: '0' + style8: '0' + style9: '0' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: complex + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + xmax: '2' + xmin: '-2' + ymax: '2' + ymin: '-2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1896.0, 24] + rotation: 90 + state: true +- name: qtgui_const_sink_x_2 + id: qtgui_const_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: '"blue"' + color10: '"red"' + color2: '"red"' + color3: '"red"' + color4: '"red"' + color5: '"red"' + color6: '"red"' + color7: '"red"' + color8: '"red"' + color9: '"red"' + comment: '' + grid: 'False' + gui_hint: 'plots@0: 1,1,1,1' + label1: fading + label10: '' + label2: normal + label3: '' + label4: '' + label5: '' + label6: '' + label7: '' + label8: '' + label9: '' + legend: 'True' + marker1: '0' + marker10: '0' + marker2: '0' + marker3: '0' + marker4: '0' + marker5: '0' + marker6: '0' + marker7: '0' + marker8: '0' + marker9: '0' + name: '"Locked"' + nconnections: '2' + size: '1024' + style1: '0' + style10: '0' + style2: '0' + style3: '0' + style4: '0' + style5: '0' + style6: '0' + style7: '0' + style8: '0' + style9: '0' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: complex + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + xmax: '2' + xmin: '-2' + ymax: '2' + ymin: '-2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2280.0, -24] + rotation: 90 + state: true +- name: qtgui_freq_sink_x_0 + id: qtgui_freq_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + average: '1.0' + axislabels: 'True' + bw: samp_rate + color1: '"blue"' + color10: '"dark blue"' + color2: '"red"' + color3: '"green"' + color4: '"black"' + color5: '"cyan"' + color6: '"magenta"' + color7: '"yellow"' + color8: '"dark red"' + color9: '"dark green"' + comment: '' + ctrlpanel: 'False' + fc: '0' + fftsize: '1024' + freqhalf: 'True' + grid: 'False' + gui_hint: 'plots@1: 0,0,1,1' + label: Relative Gain + label1: Fading + label10: '''''' + label2: '''''' + label3: '''''' + label4: '''''' + label5: '''''' + label6: '''''' + label7: '''''' + label8: '''''' + label9: '''''' + legend: 'True' + maxoutbuf: '0' + minoutbuf: '0' + name: '"Channel"' + nconnections: '2' + showports: 'False' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_tag: '""' + type: complex + units: dB + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + wintype: firdes.WIN_BLACKMAN_hARRIS + ymax: '10' + ymin: '-140' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1256.0, 560] + rotation: 270 + state: true +- name: qtgui_freq_sink_x_2_1 + id: qtgui_freq_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + average: '1.0' + axislabels: 'True' + bw: samp_rate + color1: '"blue"' + color10: '"dark blue"' + color2: '"red"' + color3: '"green"' + color4: '"black"' + color5: '"cyan"' + color6: '"magenta"' + color7: '"yellow"' + color8: '"dark red"' + color9: '"dark green"' + comment: '' + ctrlpanel: 'False' + fc: '0' + fftsize: '1024' + freqhalf: 'True' + grid: 'False' + gui_hint: 'plots@1: 1,0,1,1' + label: Relative Gain + label1: Fading + label10: '''''' + label2: '''''' + label3: '''''' + label4: '''''' + label5: '''''' + label6: '''''' + label7: '''''' + label8: '''''' + label9: '''''' + legend: 'True' + maxoutbuf: '0' + minoutbuf: '0' + name: '""' + nconnections: '2' + showports: 'False' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_tag: '""' + type: float + units: dB + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + wintype: firdes.WIN_BLACKMAN_hARRIS + ymax: '10' + ymin: '-140' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2944, 456.0] + rotation: 0 + state: true +- name: qtgui_time_sink_x_0 + id: qtgui_time_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: blue + color10: dark blue + color2: red + color3: green + color4: black + color5: cyan + color6: magenta + color7: yellow + color8: dark red + color9: dark green + comment: '' + ctrlpanel: 'False' + entags: 'True' + grid: 'False' + gui_hint: 'plots@2: 0,0,1,1' + label1: Received + label10: Signal 10 + label2: Sent + label3: Signal 3 + label4: Signal 4 + label5: Signal 5 + label6: Signal 6 + label7: Signal 7 + label8: Signal 8 + label9: Signal 9 + legend: 'True' + marker1: '-1' + marker10: '-1' + marker2: '-1' + marker3: '-1' + marker4: '-1' + marker5: '-1' + marker6: '-1' + marker7: '-1' + marker8: '-1' + marker9: '-1' + name: '"Decoded"' + nconnections: '3' + size: '1024' + srate: samp_rate + stemplot: 'False' + style1: '1' + style10: '1' + style2: '1' + style3: '1' + style4: '1' + style5: '1' + style6: '1' + style7: '1' + style8: '1' + style9: '1' + tr_chan: '0' + tr_delay: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: float + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + ylabel: Amplitude + ymax: '1' + ymin: '-1' + yunit: '""' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2912, 260.0] + rotation: 0 + state: true + +connections: +- [analog_random_source_x_0, '0', blocks_unpack_k_bits_bb_0_0, '0'] +- [analog_random_source_x_0, '0', digital_constellation_modulator_0, '0'] +- [blocks_char_to_float_0, '0', blocks_file_sink_0, '0'] +- [blocks_char_to_float_0, '0', qtgui_freq_sink_x_2_1, '0'] +- [blocks_char_to_float_0, '0', qtgui_time_sink_x_0, '0'] +- [blocks_char_to_float_0_0, '0', blocks_delay_0, '0'] +- [blocks_char_to_float_0_1, '0', qtgui_freq_sink_x_2_1, '1'] +- [blocks_char_to_float_0_1, '0', qtgui_time_sink_x_0, '2'] +- [blocks_delay_0, '0', qtgui_time_sink_x_0, '1'] +- [blocks_throttle_0, '0', channels_channel_model_0, '0'] +- [blocks_unpack_k_bits_bb_0, '0', blocks_char_to_float_0, '0'] +- [blocks_unpack_k_bits_bb_0_0, '0', blocks_char_to_float_0_0, '0'] +- [blocks_unpack_k_bits_bb_0_1, '0', blocks_char_to_float_0_1, '0'] +- [channels_channel_model_0, '0', digital_pfb_clock_sync_xxx_0_0, '0'] +- [channels_channel_model_0, '0', interp_fir_filter_xxx_0, '0'] +- [channels_channel_model_0, '0', qtgui_const_sink_x_0, '1'] +- [channels_channel_model_0, '0', qtgui_freq_sink_x_0, '1'] +- [digital_cma_equalizer_cc_0, '0', digital_costas_loop_cc_0, '0'] +- [digital_cma_equalizer_cc_0, '0', qtgui_const_sink_x_1, '0'] +- [digital_cma_equalizer_cc_0_0, '0', digital_costas_loop_cc_0_0, '0'] +- [digital_cma_equalizer_cc_0_0, '0', qtgui_const_sink_x_1, '1'] +- [digital_constellation_decoder_cb_0, '0', digital_diff_decoder_bb_0, '0'] +- [digital_constellation_decoder_cb_0_0, '0', digital_diff_decoder_bb_0_0, '0'] +- [digital_constellation_modulator_0, '0', blocks_throttle_0, '0'] +- [digital_costas_loop_cc_0, '0', digital_constellation_decoder_cb_0, '0'] +- [digital_costas_loop_cc_0, '0', qtgui_const_sink_x_2, '0'] +- [digital_costas_loop_cc_0_0, '0', digital_constellation_decoder_cb_0_0, '0'] +- [digital_costas_loop_cc_0_0, '0', qtgui_const_sink_x_2, '1'] +- [digital_diff_decoder_bb_0, '0', digital_map_bb_0, '0'] +- [digital_diff_decoder_bb_0_0, '0', digital_map_bb_0_0, '0'] +- [digital_map_bb_0, '0', blocks_unpack_k_bits_bb_0, '0'] +- [digital_map_bb_0_0, '0', blocks_unpack_k_bits_bb_0_1, '0'] +- [digital_pfb_clock_sync_xxx_0, '0', digital_cma_equalizer_cc_0, '0'] +- [digital_pfb_clock_sync_xxx_0, '0', qtgui_const_sink_x_0_0, '0'] +- [digital_pfb_clock_sync_xxx_0_0, '0', digital_cma_equalizer_cc_0_0, '0'] +- [digital_pfb_clock_sync_xxx_0_0, '0', qtgui_const_sink_x_0_0, '1'] +- [interp_fir_filter_xxx_0, '0', digital_pfb_clock_sync_xxx_0, '0'] +- [interp_fir_filter_xxx_0, '0', qtgui_const_sink_x_0, '0'] +- [interp_fir_filter_xxx_0, '0', qtgui_freq_sink_x_0, '0'] + +metadata: + file_format: 1 diff --git a/simulation/QAM_Fading/Alte_versionen/qam_fading_V2_mehrere.grc b/simulation/QAM_Fading/Alte_versionen/qam_fading_V2_mehrere.grc new file mode 100644 index 0000000..d5444ad --- /dev/null +++ b/simulation/QAM_Fading/Alte_versionen/qam_fading_V2_mehrere.grc @@ -0,0 +1,1623 @@ +options: + parameters: + author: Pross Naoki, Halter Sara Cinzia + category: '[GRC Hier Blocks]' + cmake_opt: '' + comment: '' + copyright: '' + description: '' + gen_cmake: 'On' + gen_linking: dynamic + generate_options: qt_gui + hier_block_src_path: '.:' + id: qam_fading + max_nouts: '0' + output_language: python + placement: (0,0) + qt_qss_theme: '' + realtime_scheduling: '1' + run: 'True' + run_command: '{python} -u {filename}' + run_options: prompt + sizing_mode: fixed + thread_safe_setters: '' + title: QAM mit Fading + window_size: '' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [8, 8] + rotation: 0 + state: enabled + +blocks: +- name: LOS_NLOS + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@2: 0,0,1,1' + label: LOS_NLOS + min_len: '200' + orient: Qt.Horizontal + rangeType: int + start: '0' + step: '1' + stop: '1' + value: '1' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [944, 444.0] + rotation: 0 + state: true +- name: amp_1 + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@2: 1,1,1,1' + label: Ampliude + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: '0.1' + stop: '5' + value: '0.2' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1056, 580.0] + rotation: 0 + state: true +- name: amp_2 + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@2: 2,1,1,1' + label: Ampliude 2 + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: '0.1' + stop: '5' + value: '0' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1064, 716.0] + rotation: 0 + state: true +- name: amp_3 + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@2: 3,1,1,1' + label: Ampliude 3 + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: '0.1' + stop: '5' + value: '0' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1064, 852.0] + rotation: 0 + state: true +- name: chn_taps + id: variable + parameters: + comment: '' + value: '[1.0 + 0.0j, ]' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [672, 236.0] + rotation: 0 + state: true +- name: const + id: variable_constellation + parameters: + comment: '' + const_points: '[-1-1j, -1+1j, 1+1j, 1-1j]' + dims: '1' + precision: '8' + rot_sym: '4' + soft_dec_lut: None + sym_map: '[0, 1, 3, 2]' + type: 16qam + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [224, 428.0] + rotation: 0 + state: true +- name: eq_gain + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@1: 0,0,1,1' + label: Equalizer Rate + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: '.001' + stop: '.1' + value: '.01' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1744, 452.0] + rotation: 0 + state: true +- name: eq_mod + id: variable + parameters: + comment: '' + value: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1744, 376.0] + rotation: 0 + state: true +- name: eq_ntaps + id: variable + parameters: + comment: '' + value: '15' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1824, 376.0] + rotation: 0 + state: true +- name: excess_bw + id: variable + parameters: + comment: '' + value: 350e-3 + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [320, 268.0] + rotation: 0 + state: true +- name: fading_1 + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@2: 1,0,1,1' + label: Fading + min_len: '200' + orient: Qt.Horizontal + rangeType: int + start: '1' + step: '1' + stop: '30' + value: '2' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [944, 580.0] + rotation: 0 + state: true +- name: fading_2 + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@2: 2,0,1,1' + label: Fading 2 + min_len: '200' + orient: Qt.Horizontal + rangeType: int + start: '0' + step: '1' + stop: '30' + value: '0' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [944, 716.0] + rotation: 0 + state: true +- name: fading_3 + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@2: 3,0,1,1' + label: Fading 3 + min_len: '200' + orient: Qt.Horizontal + rangeType: int + start: '0' + step: '1' + stop: '30' + value: '0' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [944, 852.0] + rotation: 0 + state: true +- name: freq_offset + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@0: 1,0,1,1' + label: Frequency Offset + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: -100e-3 + step: 1e-3 + stop: 100e-3 + value: '0' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [712, 476.0] + rotation: 0 + state: true +- name: nfilts + id: variable + parameters: + comment: '' + value: '32' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1408, 104.0] + rotation: 0 + state: true +- name: noise_volt + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@0: 0,0,1,1' + label: Noise Voltage + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: '0.01' + stop: '1' + value: '0.0001' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [576, 476.0] + rotation: 0 + state: true +- name: phase_bw + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@1: 1,0,1,1' + label: Phase Bandwidth + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: '.01' + stop: '1' + value: 2 * 3.141592653589793 / 100 + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2048, 420.0] + rotation: 0 + state: true +- name: rrc_taps + id: variable + parameters: + comment: '' + value: firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), excess_bw, 45*nfilts) + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1488, 104.0] + rotation: 0 + state: true +- name: samp_rate + id: variable + parameters: + comment: '' + value: '32000' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [192, 12.0] + rotation: 0 + state: enabled +- name: sps + id: variable + parameters: + comment: '' + value: '4' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [224, 268.0] + rotation: 0 + state: true +- name: time_offset + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@0: 0,1,1,1' + label: Timing Offset + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0.999' + step: '0.0001' + stop: '1.001' + value: '1.0' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [576, 620.0] + rotation: 0 + state: true +- name: timing_loop_bw + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@0: 1,1,1,1' + label: Time Bandwidth + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: 10e-3 + stop: 200e-3 + value: 2 * 3.141592653589793 / 100 + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1408, 164.0] + rotation: 0 + state: true +- name: analog_random_source_x_0 + id: analog_random_source_x + parameters: + affinity: '' + alias: '' + comment: '' + max: '256' + maxoutbuf: '0' + min: '0' + minoutbuf: '0' + num_samps: '1000' + repeat: 'True' + type: byte + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [32, 332.0] + rotation: 0 + state: enabled +- name: blocks_char_to_float_0 + id: blocks_char_to_float + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + scale: '1' + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2688, 272.0] + rotation: 0 + state: true +- name: blocks_char_to_float_0_0 + id: blocks_char_to_float + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + scale: '1' + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [424, 1336.0] + rotation: 0 + state: true +- name: blocks_char_to_float_0_1 + id: blocks_char_to_float + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + scale: '1' + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2640, 672.0] + rotation: 0 + state: true +- name: blocks_delay_0 + id: blocks_delay + parameters: + affinity: '' + alias: '' + comment: '' + delay: '50' + maxoutbuf: '0' + minoutbuf: '0' + num_ports: '1' + type: float + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2736, 1360.0] + rotation: 0 + state: true +- name: blocks_file_sink_0 + id: blocks_file_sink + parameters: + affinity: '' + alias: '' + append: 'False' + comment: '' + file: /home/sara/Documents/Fading/simulation/QAM_Fading/qam_fading_V2_output.grc + type: float + unbuffered: 'False' + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2880, 84.0] + rotation: 0 + state: disabled +- name: blocks_throttle_0 + id: blocks_throttle + parameters: + affinity: '' + alias: '' + comment: '' + ignoretag: 'True' + maxoutbuf: '0' + minoutbuf: '0' + samples_per_second: samp_rate + type: complex + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [464, 356.0] + rotation: 0 + state: enabled +- name: blocks_unpack_k_bits_bb_0 + id: blocks_unpack_k_bits_bb + parameters: + affinity: '' + alias: '' + comment: '' + k: '2' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2608, 432.0] + rotation: 0 + state: true +- name: blocks_unpack_k_bits_bb_0_0 + id: blocks_unpack_k_bits_bb + parameters: + affinity: '' + alias: '' + comment: '' + k: '2' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [248, 1336.0] + rotation: 0 + state: true +- name: blocks_unpack_k_bits_bb_0_1 + id: blocks_unpack_k_bits_bb + parameters: + affinity: '' + alias: '' + comment: '' + k: '2' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2544, 848.0] + rotation: 0 + state: true +- name: channels_channel_model_0 + id: channels_channel_model + parameters: + affinity: '' + alias: '' + block_tags: 'False' + comment: '' + epsilon: time_offset + freq_offset: freq_offset + maxoutbuf: '0' + minoutbuf: '0' + noise_voltage: noise_volt + seed: '0' + taps: chn_taps + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [648, 316.0] + rotation: 0 + state: enabled +- name: digital_cma_equalizer_cc_0 + id: digital_cma_equalizer_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: eq_mod + mu: eq_gain + num_taps: eq_ntaps + sps: '2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1744, 276.0] + rotation: 0 + state: true +- name: digital_cma_equalizer_cc_0_0 + id: digital_cma_equalizer_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: eq_mod + mu: eq_gain + num_taps: eq_ntaps + sps: '2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1664, 932.0] + rotation: 0 + state: true +- name: digital_constellation_decoder_cb_0 + id: digital_constellation_decoder_cb + parameters: + affinity: '' + alias: '' + comment: '' + constellation: const + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2384, 272.0] + rotation: 0 + state: true +- name: digital_constellation_decoder_cb_0_0 + id: digital_constellation_decoder_cb + parameters: + affinity: '' + alias: '' + comment: '' + constellation: const + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2320, 656.0] + rotation: 0 + state: true +- name: digital_constellation_modulator_0 + id: digital_constellation_modulator + parameters: + affinity: '' + alias: '' + comment: '' + constellation: const + differential: 'True' + excess_bw: excess_bw + log: 'False' + maxoutbuf: '0' + minoutbuf: '0' + samples_per_symbol: sps + verbose: 'False' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [224, 332.0] + rotation: 0 + state: enabled +- name: digital_costas_loop_cc_0 + id: digital_costas_loop_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + order: '4' + use_snr: 'False' + w: phase_bw + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2048, 264.0] + rotation: 0 + state: true +- name: digital_costas_loop_cc_0_0 + id: digital_costas_loop_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + order: '4' + use_snr: 'False' + w: phase_bw + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1984, 928.0] + rotation: 0 + state: true +- name: digital_diff_decoder_bb_0 + id: digital_diff_decoder_bb + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: '4' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2384, 336.0] + rotation: 180 + state: true +- name: digital_diff_decoder_bb_0_0 + id: digital_diff_decoder_bb + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: '4' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2352, 736.0] + rotation: 180 + state: true +- name: digital_map_bb_0 + id: digital_map_bb + parameters: + affinity: '' + alias: '' + comment: '' + map: '[0, 1, 3, 2]' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2400, 432.0] + rotation: 0 + state: true +- name: digital_map_bb_0_0 + id: digital_map_bb + parameters: + affinity: '' + alias: '' + comment: '' + map: '[0, 1, 3, 2]' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2368, 848.0] + rotation: 0 + state: true +- name: digital_pfb_clock_sync_xxx_0 + id: digital_pfb_clock_sync_xxx + parameters: + affinity: '' + alias: '' + comment: '' + filter_size: nfilts + init_phase: nfilts/2 + loop_bw: timing_loop_bw + max_dev: '1.5' + maxoutbuf: '0' + minoutbuf: '0' + osps: '1' + sps: sps + taps: rrc_taps + type: ccf + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1408, 300.0] + rotation: 0 + state: true +- name: digital_pfb_clock_sync_xxx_0_0 + id: digital_pfb_clock_sync_xxx + parameters: + affinity: '' + alias: '' + comment: '' + filter_size: nfilts + init_phase: nfilts/2 + loop_bw: timing_loop_bw + max_dev: '1.5' + maxoutbuf: '0' + minoutbuf: '0' + osps: '1' + sps: 'sps ' + taps: rrc_taps + type: ccf + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1016, 1204.0] + rotation: 0 + state: true +- name: import_0 + id: import + parameters: + alias: '' + comment: '' + imports: import numpy as np + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [600, 20.0] + rotation: 0 + state: true +- name: interp_fir_filter_xxx_0 + id: interp_fir_filter_xxx + parameters: + affinity: '' + alias: '' + comment: '' + interp: '1' + maxoutbuf: '0' + minoutbuf: '0' + samp_delay: '0' + taps: '[LOS_NLOS]+(([0]*fading_1)+[amp_1])+(([0]*fading_2)+[amp_2])+(([0]*fading_3)+[amp_3])' + type: ccc + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [992, 340.0] + rotation: 0 + state: enabled +- name: params + id: qtgui_tab_widget + parameters: + alias: '' + comment: '' + gui_hint: '' + label0: Channel + label1: Receiver + label10: Tab 10 + label11: Tab 11 + label12: Tab 12 + label13: Tab 13 + label14: Tab 14 + label15: Tab 15 + label16: Tab 16 + label17: Tab 17 + label18: Tab 18 + label19: Tab 19 + label2: Fading + label3: Tab 3 + label4: Tab 4 + label5: Tab 5 + label6: Tab 6 + label7: Tab 7 + label8: Tab 8 + label9: Tab 9 + num_tabs: '3' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [296, 12.0] + rotation: 0 + state: true +- name: plots + id: qtgui_tab_widget + parameters: + alias: '' + comment: '' + gui_hint: '' + label0: Constellations + label1: Frequency + label10: Tab 10 + label11: Tab 11 + label12: Tab 12 + label13: Tab 13 + label14: Tab 14 + label15: Tab 15 + label16: Tab 16 + label17: Tab 17 + label18: Tab 18 + label19: Tab 19 + label2: Time + label3: Tab 3 + label4: Tab 4 + label5: Tab 5 + label6: Tab 6 + label7: Tab 7 + label8: Tab 8 + label9: Tab 9 + num_tabs: '3' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [448, 12.0] + rotation: 0 + state: true +- name: qtgui_const_sink_x_0 + id: qtgui_const_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: '"blue"' + color10: '"red"' + color2: '"red"' + color3: '"red"' + color4: '"red"' + color5: '"red"' + color6: '"red"' + color7: '"red"' + color8: '"red"' + color9: '"red"' + comment: '' + grid: 'False' + gui_hint: 'plots@0: 0,0,1,1' + label1: fading + label10: '' + label2: normal + label3: '' + label4: '' + label5: '' + label6: '' + label7: '' + label8: '' + label9: '' + legend: 'True' + marker1: '0' + marker10: '0' + marker2: '0' + marker3: '0' + marker4: '0' + marker5: '0' + marker6: '0' + marker7: '0' + marker8: '0' + marker9: '0' + name: '"Channel"' + nconnections: '2' + size: '2048' + style1: '0' + style10: '0' + style2: '0' + style3: '0' + style4: '0' + style5: '0' + style6: '0' + style7: '0' + style8: '0' + style9: '0' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: complex + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + xmax: '2' + xmin: '-2' + ymax: '2' + ymin: '-2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1052.0, -48] + rotation: 90 + state: enabled +- name: qtgui_const_sink_x_0_0 + id: qtgui_const_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: '"blue"' + color10: '"red"' + color2: '"red"' + color3: '"red"' + color4: '"red"' + color5: '"red"' + color6: '"red"' + color7: '"red"' + color8: '"red"' + color9: '"red"' + comment: '' + grid: 'False' + gui_hint: 'plots@0: 0,1,1,1' + label1: fading + label10: '' + label2: normal + label3: '' + label4: '' + label5: '' + label6: '' + label7: '' + label8: '' + label9: '' + legend: 'True' + marker1: '0' + marker10: '0' + marker2: '0' + marker3: '0' + marker4: '0' + marker5: '0' + marker6: '0' + marker7: '0' + marker8: '0' + marker9: '0' + name: '"Synchronized"' + nconnections: '2' + size: '2048' + style1: '0' + style10: '0' + style2: '0' + style3: '0' + style4: '0' + style5: '0' + style6: '0' + style7: '0' + style8: '0' + style9: '0' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: complex + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + xmax: '2' + xmin: '-2' + ymax: '2' + ymin: '-2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1656.0, 56] + rotation: 90 + state: enabled +- name: qtgui_const_sink_x_1 + id: qtgui_const_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: '"blue"' + color10: '"red"' + color2: '"red"' + color3: '"red"' + color4: '"red"' + color5: '"red"' + color6: '"red"' + color7: '"red"' + color8: '"red"' + color9: '"red"' + comment: '' + grid: 'False' + gui_hint: 'plots@0: 1,0,1,1' + label1: fading + label10: '' + label2: normal + label3: '' + label4: '' + label5: '' + label6: '' + label7: '' + label8: '' + label9: '' + legend: 'True' + marker1: '0' + marker10: '0' + marker2: '0' + marker3: '0' + marker4: '0' + marker5: '0' + marker6: '0' + marker7: '0' + marker8: '0' + marker9: '0' + name: '"Equalized"' + nconnections: '2' + size: '1024' + style1: '0' + style10: '0' + style2: '0' + style3: '0' + style4: '0' + style5: '0' + style6: '0' + style7: '0' + style8: '0' + style9: '0' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: complex + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + xmax: '2' + xmin: '-2' + ymax: '2' + ymin: '-2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1896.0, 24] + rotation: 90 + state: true +- name: qtgui_const_sink_x_2 + id: qtgui_const_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: '"blue"' + color10: '"red"' + color2: '"red"' + color3: '"red"' + color4: '"red"' + color5: '"red"' + color6: '"red"' + color7: '"red"' + color8: '"red"' + color9: '"red"' + comment: '' + grid: 'False' + gui_hint: 'plots@0: 1,1,1,1' + label1: fading + label10: '' + label2: normal + label3: '' + label4: '' + label5: '' + label6: '' + label7: '' + label8: '' + label9: '' + legend: 'True' + marker1: '0' + marker10: '0' + marker2: '0' + marker3: '0' + marker4: '0' + marker5: '0' + marker6: '0' + marker7: '0' + marker8: '0' + marker9: '0' + name: '"Locked"' + nconnections: '2' + size: '1024' + style1: '0' + style10: '0' + style2: '0' + style3: '0' + style4: '0' + style5: '0' + style6: '0' + style7: '0' + style8: '0' + style9: '0' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: complex + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + xmax: '2' + xmin: '-2' + ymax: '2' + ymin: '-2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2280.0, -24] + rotation: 90 + state: true +- name: qtgui_freq_sink_x_0 + id: qtgui_freq_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + average: '1.0' + axislabels: 'True' + bw: samp_rate + color1: '"blue"' + color10: '"dark blue"' + color2: '"red"' + color3: '"green"' + color4: '"black"' + color5: '"cyan"' + color6: '"magenta"' + color7: '"yellow"' + color8: '"dark red"' + color9: '"dark green"' + comment: '' + ctrlpanel: 'False' + fc: '0' + fftsize: '1024' + freqhalf: 'True' + grid: 'False' + gui_hint: 'plots@1: 0,0,1,1' + label: Relative Gain + label1: Fading + label10: '''''' + label2: '''''' + label3: '''''' + label4: '''''' + label5: '''''' + label6: '''''' + label7: '''''' + label8: '''''' + label9: '''''' + legend: 'True' + maxoutbuf: '0' + minoutbuf: '0' + name: '"Channel"' + nconnections: '2' + showports: 'False' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_tag: '""' + type: complex + units: dB + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + wintype: firdes.WIN_BLACKMAN_hARRIS + ymax: '10' + ymin: '-140' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1256.0, 560] + rotation: 270 + state: true +- name: qtgui_freq_sink_x_2_1 + id: qtgui_freq_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + average: '1.0' + axislabels: 'True' + bw: samp_rate + color1: '"blue"' + color10: '"dark blue"' + color2: '"red"' + color3: '"green"' + color4: '"black"' + color5: '"cyan"' + color6: '"magenta"' + color7: '"yellow"' + color8: '"dark red"' + color9: '"dark green"' + comment: '' + ctrlpanel: 'False' + fc: '0' + fftsize: '1024' + freqhalf: 'True' + grid: 'False' + gui_hint: 'plots@1: 1,0,1,1' + label: Relative Gain + label1: Fading + label10: '''''' + label2: '''''' + label3: '''''' + label4: '''''' + label5: '''''' + label6: '''''' + label7: '''''' + label8: '''''' + label9: '''''' + legend: 'True' + maxoutbuf: '0' + minoutbuf: '0' + name: '""' + nconnections: '2' + showports: 'False' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_tag: '""' + type: float + units: dB + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + wintype: firdes.WIN_BLACKMAN_hARRIS + ymax: '10' + ymin: '-140' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2944, 456.0] + rotation: 0 + state: true +- name: qtgui_time_sink_x_0 + id: qtgui_time_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: blue + color10: dark blue + color2: red + color3: green + color4: black + color5: cyan + color6: magenta + color7: yellow + color8: dark red + color9: dark green + comment: '' + ctrlpanel: 'False' + entags: 'True' + grid: 'False' + gui_hint: 'plots@2: 0,0,1,1' + label1: Received + label10: Signal 10 + label2: Sent + label3: Signal 3 + label4: Signal 4 + label5: Signal 5 + label6: Signal 6 + label7: Signal 7 + label8: Signal 8 + label9: Signal 9 + legend: 'True' + marker1: '-1' + marker10: '-1' + marker2: '-1' + marker3: '-1' + marker4: '-1' + marker5: '-1' + marker6: '-1' + marker7: '-1' + marker8: '-1' + marker9: '-1' + name: '"Decoded"' + nconnections: '3' + size: '1024' + srate: samp_rate + stemplot: 'False' + style1: '1' + style10: '1' + style2: '1' + style3: '1' + style4: '1' + style5: '1' + style6: '1' + style7: '1' + style8: '1' + style9: '1' + tr_chan: '0' + tr_delay: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: float + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + ylabel: Amplitude + ymax: '1' + ymin: '-1' + yunit: '""' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2912, 260.0] + rotation: 0 + state: true + +connections: +- [analog_random_source_x_0, '0', blocks_unpack_k_bits_bb_0_0, '0'] +- [analog_random_source_x_0, '0', digital_constellation_modulator_0, '0'] +- [blocks_char_to_float_0, '0', blocks_file_sink_0, '0'] +- [blocks_char_to_float_0, '0', qtgui_freq_sink_x_2_1, '0'] +- [blocks_char_to_float_0, '0', qtgui_time_sink_x_0, '0'] +- [blocks_char_to_float_0_0, '0', blocks_delay_0, '0'] +- [blocks_char_to_float_0_1, '0', qtgui_freq_sink_x_2_1, '1'] +- [blocks_char_to_float_0_1, '0', qtgui_time_sink_x_0, '2'] +- [blocks_delay_0, '0', qtgui_time_sink_x_0, '1'] +- [blocks_throttle_0, '0', channels_channel_model_0, '0'] +- [blocks_unpack_k_bits_bb_0, '0', blocks_char_to_float_0, '0'] +- [blocks_unpack_k_bits_bb_0_0, '0', blocks_char_to_float_0_0, '0'] +- [blocks_unpack_k_bits_bb_0_1, '0', blocks_char_to_float_0_1, '0'] +- [channels_channel_model_0, '0', digital_pfb_clock_sync_xxx_0_0, '0'] +- [channels_channel_model_0, '0', interp_fir_filter_xxx_0, '0'] +- [channels_channel_model_0, '0', qtgui_const_sink_x_0, '1'] +- [channels_channel_model_0, '0', qtgui_freq_sink_x_0, '1'] +- [digital_cma_equalizer_cc_0, '0', digital_costas_loop_cc_0, '0'] +- [digital_cma_equalizer_cc_0, '0', qtgui_const_sink_x_1, '0'] +- [digital_cma_equalizer_cc_0_0, '0', digital_costas_loop_cc_0_0, '0'] +- [digital_cma_equalizer_cc_0_0, '0', qtgui_const_sink_x_1, '1'] +- [digital_constellation_decoder_cb_0, '0', digital_diff_decoder_bb_0, '0'] +- [digital_constellation_decoder_cb_0_0, '0', digital_diff_decoder_bb_0_0, '0'] +- [digital_constellation_modulator_0, '0', blocks_throttle_0, '0'] +- [digital_costas_loop_cc_0, '0', digital_constellation_decoder_cb_0, '0'] +- [digital_costas_loop_cc_0, '0', qtgui_const_sink_x_2, '0'] +- [digital_costas_loop_cc_0_0, '0', digital_constellation_decoder_cb_0_0, '0'] +- [digital_costas_loop_cc_0_0, '0', qtgui_const_sink_x_2, '1'] +- [digital_diff_decoder_bb_0, '0', digital_map_bb_0, '0'] +- [digital_diff_decoder_bb_0_0, '0', digital_map_bb_0_0, '0'] +- [digital_map_bb_0, '0', blocks_unpack_k_bits_bb_0, '0'] +- [digital_map_bb_0_0, '0', blocks_unpack_k_bits_bb_0_1, '0'] +- [digital_pfb_clock_sync_xxx_0, '0', digital_cma_equalizer_cc_0, '0'] +- [digital_pfb_clock_sync_xxx_0, '0', qtgui_const_sink_x_0_0, '0'] +- [digital_pfb_clock_sync_xxx_0_0, '0', digital_cma_equalizer_cc_0_0, '0'] +- [digital_pfb_clock_sync_xxx_0_0, '0', qtgui_const_sink_x_0_0, '1'] +- [interp_fir_filter_xxx_0, '0', digital_pfb_clock_sync_xxx_0, '0'] +- [interp_fir_filter_xxx_0, '0', qtgui_const_sink_x_0, '0'] +- [interp_fir_filter_xxx_0, '0', qtgui_freq_sink_x_0, '0'] + +metadata: + file_format: 1 diff --git a/simulation/QAM_Fading/Alte_versionen/qam_fading_frequency_selectiv.grc b/simulation/QAM_Fading/Alte_versionen/qam_fading_frequency_selectiv.grc new file mode 100644 index 0000000..fc3cebd --- /dev/null +++ b/simulation/QAM_Fading/Alte_versionen/qam_fading_frequency_selectiv.grc @@ -0,0 +1,1448 @@ +options: + parameters: + author: Pross Naoki, Halter Sara Cinzia + category: '[GRC Hier Blocks]' + cmake_opt: '' + comment: '' + copyright: '' + description: '' + gen_cmake: 'On' + gen_linking: dynamic + generate_options: qt_gui + hier_block_src_path: '.:' + id: qam_fading + max_nouts: '0' + output_language: python + placement: (0,0) + qt_qss_theme: '' + realtime_scheduling: '1' + run: 'True' + run_command: '{python} -u {filename}' + run_options: prompt + sizing_mode: fixed + thread_safe_setters: '' + title: QAM mit Fading + window_size: '' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [8, 8] + rotation: 0 + state: enabled + +blocks: +- name: chn_taps + id: variable + parameters: + comment: '' + value: '[1.0 + 0.0j, ]' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [672, 236.0] + rotation: 0 + state: true +- name: const + id: variable_constellation + parameters: + comment: '' + const_points: '[-1-1j, -1+1j, 1+1j, 1-1j]' + dims: '1' + precision: '8' + rot_sym: '4' + soft_dec_lut: None + sym_map: '[0, 1, 3, 2]' + type: qpsk + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [224, 428.0] + rotation: 0 + state: true +- name: eq_gain + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@1: 0,0,1,1' + label: Equalizer Rate + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: '.001' + stop: '.1' + value: '.01' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1648, 476.0] + rotation: 0 + state: true +- name: eq_mod + id: variable + parameters: + comment: '' + value: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1648, 400.0] + rotation: 0 + state: true +- name: eq_ntaps + id: variable + parameters: + comment: '' + value: '15' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1728, 400.0] + rotation: 0 + state: true +- name: excess_bw + id: variable + parameters: + comment: '' + value: 350e-3 + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [320, 268.0] + rotation: 0 + state: true +- name: freq_offset + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@0: 1,0,1,1' + label: Frequency Offset + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: -100e-3 + step: 1e-3 + stop: 100e-3 + value: '0' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [712, 476.0] + rotation: 0 + state: true +- name: nfilts + id: variable + parameters: + comment: '' + value: '32' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1312, 132.0] + rotation: 0 + state: true +- name: noise_volt + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@0: 0,0,1,1' + label: Noise Voltage + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: '0.01' + stop: '1' + value: '0.0001' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [576, 476.0] + rotation: 0 + state: true +- name: phase_bw + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@1: 1,0,1,1' + label: Phase Bandwidth + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: '.01' + stop: '1' + value: 2 * 3.141592653589793 / 100 + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1952, 444.0] + rotation: 0 + state: true +- name: rrc_taps + id: variable + parameters: + comment: '' + value: firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), excess_bw, 45*nfilts) + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1376, 132.0] + rotation: 0 + state: true +- name: samp_rate + id: variable + parameters: + comment: '' + value: '32000' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [192, 12.0] + rotation: 0 + state: enabled +- name: sps + id: variable + parameters: + comment: '' + value: '4' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [224, 268.0] + rotation: 0 + state: true +- name: time_offset + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@0: 0,1,1,1' + label: Timing Offset + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0.999' + step: '0.0001' + stop: '1.001' + value: '1.0' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [576, 620.0] + rotation: 0 + state: true +- name: timing_loop_bw + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: 'params@0: 1,1,1,1' + label: Time Bandwidth + min_len: '200' + orient: Qt.Horizontal + rangeType: float + start: '0' + step: 10e-3 + stop: 200e-3 + value: 2 * 3.141592653589793 / 100 + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1312, 196.0] + rotation: 0 + state: true +- name: analog_random_source_x_0 + id: analog_random_source_x + parameters: + affinity: '' + alias: '' + comment: '' + max: '256' + maxoutbuf: '0' + min: '0' + minoutbuf: '0' + num_samps: '1000' + repeat: 'True' + type: byte + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [32, 332.0] + rotation: 0 + state: enabled +- name: blocks_char_to_float_0 + id: blocks_char_to_float + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + scale: '1' + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2592, 296.0] + rotation: 0 + state: true +- name: blocks_char_to_float_0_0 + id: blocks_char_to_float + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + scale: '1' + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [424, 1336.0] + rotation: 0 + state: true +- name: blocks_char_to_float_0_1 + id: blocks_char_to_float + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + scale: '1' + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2544, 692.0] + rotation: 0 + state: true +- name: blocks_delay_0 + id: blocks_delay + parameters: + affinity: '' + alias: '' + comment: '' + delay: '50' + maxoutbuf: '0' + minoutbuf: '0' + num_ports: '1' + type: float + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2624, 1352.0] + rotation: 0 + state: true +- name: blocks_throttle_0 + id: blocks_throttle + parameters: + affinity: '' + alias: '' + comment: '' + ignoretag: 'True' + maxoutbuf: '0' + minoutbuf: '0' + samples_per_second: samp_rate + type: complex + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [464, 356.0] + rotation: 0 + state: enabled +- name: blocks_unpack_k_bits_bb_0 + id: blocks_unpack_k_bits_bb + parameters: + affinity: '' + alias: '' + comment: '' + k: '2' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2512, 456.0] + rotation: 0 + state: true +- name: blocks_unpack_k_bits_bb_0_0 + id: blocks_unpack_k_bits_bb + parameters: + affinity: '' + alias: '' + comment: '' + k: '2' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [248, 1336.0] + rotation: 0 + state: true +- name: blocks_unpack_k_bits_bb_0_1 + id: blocks_unpack_k_bits_bb + parameters: + affinity: '' + alias: '' + comment: '' + k: '2' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2448, 868.0] + rotation: 0 + state: true +- name: channels_channel_model_0 + id: channels_channel_model + parameters: + affinity: '' + alias: '' + block_tags: 'False' + comment: '' + epsilon: time_offset + freq_offset: freq_offset + maxoutbuf: '0' + minoutbuf: '0' + noise_voltage: noise_volt + seed: '0' + taps: chn_taps + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [648, 316.0] + rotation: 0 + state: enabled +- name: channels_selective_fading_model_0 + id: channels_selective_fading_model + parameters: + K: '4.0' + LOS: 'False' + N: '8' + affinity: '' + alias: '' + comment: '' + delays: (0.0,0.1,1.3) + fDTs: '0' + mags: (1,0.99,0.97) + maxoutbuf: '0' + minoutbuf: '0' + ntaps: '4' + seed: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [944, 316.0] + rotation: 0 + state: true +- name: digital_cma_equalizer_cc_0 + id: digital_cma_equalizer_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: eq_mod + mu: eq_gain + num_taps: eq_ntaps + sps: '2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1648, 304.0] + rotation: 0 + state: true +- name: digital_cma_equalizer_cc_0_0 + id: digital_cma_equalizer_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: eq_mod + mu: eq_gain + num_taps: eq_ntaps + sps: '2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1600, 724.0] + rotation: 0 + state: true +- name: digital_constellation_decoder_cb_0 + id: digital_constellation_decoder_cb + parameters: + affinity: '' + alias: '' + comment: '' + constellation: const + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2288, 296.0] + rotation: 0 + state: true +- name: digital_constellation_decoder_cb_0_0 + id: digital_constellation_decoder_cb + parameters: + affinity: '' + alias: '' + comment: '' + constellation: const + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2224, 684.0] + rotation: 0 + state: true +- name: digital_constellation_modulator_0 + id: digital_constellation_modulator + parameters: + affinity: '' + alias: '' + comment: '' + constellation: const + differential: 'True' + excess_bw: excess_bw + log: 'False' + maxoutbuf: '0' + minoutbuf: '0' + samples_per_symbol: sps + verbose: 'False' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [224, 332.0] + rotation: 0 + state: enabled +- name: digital_costas_loop_cc_0 + id: digital_costas_loop_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + order: '4' + use_snr: 'False' + w: phase_bw + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1952, 296.0] + rotation: 0 + state: true +- name: digital_costas_loop_cc_0_0 + id: digital_costas_loop_cc + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + order: '4' + use_snr: 'False' + w: phase_bw + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1936, 688.0] + rotation: 0 + state: true +- name: digital_diff_decoder_bb_0 + id: digital_diff_decoder_bb + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: '4' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2288, 360.0] + rotation: 180 + state: true +- name: digital_diff_decoder_bb_0_0 + id: digital_diff_decoder_bb + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + modulus: '4' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2264, 764.0] + rotation: 180 + state: true +- name: digital_map_bb_0 + id: digital_map_bb + parameters: + affinity: '' + alias: '' + comment: '' + map: '[0, 1, 3, 2]' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2304, 456.0] + rotation: 0 + state: true +- name: digital_map_bb_0_0 + id: digital_map_bb + parameters: + affinity: '' + alias: '' + comment: '' + map: '[0, 1, 3, 2]' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2272, 868.0] + rotation: 0 + state: true +- name: digital_pfb_clock_sync_xxx_0 + id: digital_pfb_clock_sync_xxx + parameters: + affinity: '' + alias: '' + comment: '' + filter_size: nfilts + init_phase: nfilts/2 + loop_bw: timing_loop_bw + max_dev: '1.5' + maxoutbuf: '0' + minoutbuf: '0' + osps: '1' + sps: sps * 1.001 + taps: rrc_taps + type: ccf + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1312, 324.0] + rotation: 0 + state: true +- name: digital_pfb_clock_sync_xxx_0_0 + id: digital_pfb_clock_sync_xxx + parameters: + affinity: '' + alias: '' + comment: '' + filter_size: nfilts + init_phase: nfilts/2 + loop_bw: timing_loop_bw + max_dev: '1.5' + maxoutbuf: '0' + minoutbuf: '0' + osps: '1' + sps: sps * 1.001 + taps: rrc_taps + type: ccf + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1088, 868.0] + rotation: 0 + state: true +- name: params + id: qtgui_tab_widget + parameters: + alias: '' + comment: '' + gui_hint: '' + label0: Channel + label1: Receiver + label10: Tab 10 + label11: Tab 11 + label12: Tab 12 + label13: Tab 13 + label14: Tab 14 + label15: Tab 15 + label16: Tab 16 + label17: Tab 17 + label18: Tab 18 + label19: Tab 19 + label2: Tab 2 + label3: Tab 3 + label4: Tab 4 + label5: Tab 5 + label6: Tab 6 + label7: Tab 7 + label8: Tab 8 + label9: Tab 9 + num_tabs: '2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [296, 12.0] + rotation: 0 + state: true +- name: plots + id: qtgui_tab_widget + parameters: + alias: '' + comment: '' + gui_hint: '' + label0: Constellations + label1: Frequency + label10: Tab 10 + label11: Tab 11 + label12: Tab 12 + label13: Tab 13 + label14: Tab 14 + label15: Tab 15 + label16: Tab 16 + label17: Tab 17 + label18: Tab 18 + label19: Tab 19 + label2: Time + label3: Tab 3 + label4: Tab 4 + label5: Tab 5 + label6: Tab 6 + label7: Tab 7 + label8: Tab 8 + label9: Tab 9 + num_tabs: '3' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [448, 12.0] + rotation: 0 + state: true +- name: qtgui_const_sink_x_0 + id: qtgui_const_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: '"blue"' + color10: '"red"' + color2: '"red"' + color3: '"red"' + color4: '"red"' + color5: '"red"' + color6: '"red"' + color7: '"red"' + color8: '"red"' + color9: '"red"' + comment: '' + grid: 'False' + gui_hint: 'plots@0: 0,0,1,1' + label1: Fading + label10: '' + label2: '' + label3: '' + label4: '' + label5: '' + label6: '' + label7: '' + label8: '' + label9: '' + legend: 'True' + marker1: '0' + marker10: '0' + marker2: '0' + marker3: '0' + marker4: '0' + marker5: '0' + marker6: '0' + marker7: '0' + marker8: '0' + marker9: '0' + name: '"Channel"' + nconnections: '2' + size: '2048' + style1: '0' + style10: '0' + style2: '0' + style3: '0' + style4: '0' + style5: '0' + style6: '0' + style7: '0' + style8: '0' + style9: '0' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: complex + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + xmax: '2' + xmin: '-2' + ymax: '2' + ymin: '-2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1044.0, -48] + rotation: 90 + state: enabled +- name: qtgui_const_sink_x_0_0 + id: qtgui_const_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: '"blue"' + color10: '"red"' + color2: '"red"' + color3: '"red"' + color4: '"red"' + color5: '"red"' + color6: '"red"' + color7: '"red"' + color8: '"red"' + color9: '"red"' + comment: '' + grid: 'False' + gui_hint: 'plots@0: 0,1,1,1' + label1: Fading + label10: '' + label2: '' + label3: '' + label4: '' + label5: '' + label6: '' + label7: '' + label8: '' + label9: '' + legend: 'True' + marker1: '0' + marker10: '0' + marker2: '0' + marker3: '0' + marker4: '0' + marker5: '0' + marker6: '0' + marker7: '0' + marker8: '0' + marker9: '0' + name: '"Synchronized"' + nconnections: '2' + size: '2048' + style1: '0' + style10: '0' + style2: '0' + style3: '0' + style4: '0' + style5: '0' + style6: '0' + style7: '0' + style8: '0' + style9: '0' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: complex + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + xmax: '2' + xmin: '-2' + ymax: '2' + ymin: '-2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1572.0, 80] + rotation: 90 + state: enabled +- name: qtgui_const_sink_x_1 + id: qtgui_const_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: '"blue"' + color10: '"red"' + color2: '"red"' + color3: '"red"' + color4: '"red"' + color5: '"red"' + color6: '"red"' + color7: '"red"' + color8: '"red"' + color9: '"red"' + comment: '' + grid: 'False' + gui_hint: 'plots@0: 1,0,1,1' + label1: Fading + label10: '' + label2: '' + label3: '' + label4: '' + label5: '' + label6: '' + label7: '' + label8: '' + label9: '' + legend: 'True' + marker1: '0' + marker10: '0' + marker2: '0' + marker3: '0' + marker4: '0' + marker5: '0' + marker6: '0' + marker7: '0' + marker8: '0' + marker9: '0' + name: '"Equalized"' + nconnections: '2' + size: '1024' + style1: '0' + style10: '0' + style2: '0' + style3: '0' + style4: '0' + style5: '0' + style6: '0' + style7: '0' + style8: '0' + style9: '0' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: complex + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + xmax: '2' + xmin: '-2' + ymax: '2' + ymin: '-2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1828.0, 96] + rotation: 90 + state: true +- name: qtgui_const_sink_x_2 + id: qtgui_const_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: '"blue"' + color10: '"red"' + color2: '"red"' + color3: '"red"' + color4: '"red"' + color5: '"red"' + color6: '"red"' + color7: '"red"' + color8: '"red"' + color9: '"red"' + comment: '' + grid: 'False' + gui_hint: 'plots@0: 1,1,1,1' + label1: Fading + label10: '' + label2: '' + label3: '' + label4: '' + label5: '' + label6: '' + label7: '' + label8: '' + label9: '' + legend: 'True' + marker1: '0' + marker10: '0' + marker2: '0' + marker3: '0' + marker4: '0' + marker5: '0' + marker6: '0' + marker7: '0' + marker8: '0' + marker9: '0' + name: '"Locked"' + nconnections: '2' + size: '1024' + style1: '0' + style10: '0' + style2: '0' + style3: '0' + style4: '0' + style5: '0' + style6: '0' + style7: '0' + style8: '0' + style9: '0' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: complex + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + xmax: '2' + xmin: '-2' + ymax: '2' + ymin: '-2' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2188.0, 0] + rotation: 90 + state: true +- name: qtgui_freq_sink_x_0 + id: qtgui_freq_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + average: '1.0' + axislabels: 'True' + bw: samp_rate + color1: '"blue"' + color10: '"dark blue"' + color2: '"red"' + color3: '"green"' + color4: '"black"' + color5: '"cyan"' + color6: '"magenta"' + color7: '"yellow"' + color8: '"dark red"' + color9: '"dark green"' + comment: '' + ctrlpanel: 'False' + fc: '0' + fftsize: '1024' + freqhalf: 'True' + grid: 'False' + gui_hint: 'plots@1: 0,0,1,1' + label: Relative Gain + label1: Fading + label10: '''''' + label2: '''''' + label3: '''''' + label4: '''''' + label5: '''''' + label6: '''''' + label7: '''''' + label8: '''''' + label9: '''''' + legend: 'True' + maxoutbuf: '0' + minoutbuf: '0' + name: '"Channel"' + nconnections: '2' + showports: 'False' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_tag: '""' + type: complex + units: dB + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + wintype: firdes.WIN_BLACKMAN_hARRIS + ymax: '10' + ymin: '-140' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1024.0, 624] + rotation: 270 + state: true +- name: qtgui_freq_sink_x_2_1 + id: qtgui_freq_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + average: '1.0' + axislabels: 'True' + bw: samp_rate + color1: '"blue"' + color10: '"dark blue"' + color2: '"red"' + color3: '"green"' + color4: '"black"' + color5: '"cyan"' + color6: '"magenta"' + color7: '"yellow"' + color8: '"dark red"' + color9: '"dark green"' + comment: '' + ctrlpanel: 'False' + fc: '0' + fftsize: '1024' + freqhalf: 'True' + grid: 'False' + gui_hint: '' + label: Relative Gain + label1: Fading + label10: '''''' + label2: '''''' + label3: '''''' + label4: '''''' + label5: '''''' + label6: '''''' + label7: '''''' + label8: '''''' + label9: '''''' + legend: 'True' + maxoutbuf: '0' + minoutbuf: '0' + name: '""' + nconnections: '2' + showports: 'False' + tr_chan: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_tag: '""' + type: float + units: dB + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + wintype: firdes.WIN_BLACKMAN_hARRIS + ymax: '10' + ymin: '-140' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2848, 488.0] + rotation: 0 + state: true +- name: qtgui_time_sink_x_0 + id: qtgui_time_sink_x + parameters: + affinity: '' + alias: '' + alpha1: '1.0' + alpha10: '1.0' + alpha2: '1.0' + alpha3: '1.0' + alpha4: '1.0' + alpha5: '1.0' + alpha6: '1.0' + alpha7: '1.0' + alpha8: '1.0' + alpha9: '1.0' + autoscale: 'False' + axislabels: 'True' + color1: blue + color10: dark blue + color2: red + color3: green + color4: black + color5: cyan + color6: magenta + color7: yellow + color8: dark red + color9: dark green + comment: '' + ctrlpanel: 'False' + entags: 'True' + grid: 'False' + gui_hint: 'plots@2: 0,0,1,1' + label1: Received + label10: Signal 10 + label2: Sent + label3: Signal 3 + label4: Signal 4 + label5: Signal 5 + label6: Signal 6 + label7: Signal 7 + label8: Signal 8 + label9: Signal 9 + legend: 'True' + marker1: '-1' + marker10: '-1' + marker2: '-1' + marker3: '-1' + marker4: '-1' + marker5: '-1' + marker6: '-1' + marker7: '-1' + marker8: '-1' + marker9: '-1' + name: '"Decoded"' + nconnections: '3' + size: '1024' + srate: samp_rate + stemplot: 'False' + style1: '1' + style10: '1' + style2: '1' + style3: '1' + style4: '1' + style5: '1' + style6: '1' + style7: '1' + style8: '1' + style9: '1' + tr_chan: '0' + tr_delay: '0' + tr_level: '0.0' + tr_mode: qtgui.TRIG_MODE_FREE + tr_slope: qtgui.TRIG_SLOPE_POS + tr_tag: '""' + type: float + update_time: '0.10' + width1: '1' + width10: '1' + width2: '1' + width3: '1' + width4: '1' + width5: '1' + width6: '1' + width7: '1' + width8: '1' + width9: '1' + ylabel: Amplitude + ymax: '1' + ymin: '-1' + yunit: '""' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [2816, 288.0] + rotation: 0 + state: true + +connections: +- [analog_random_source_x_0, '0', blocks_unpack_k_bits_bb_0_0, '0'] +- [analog_random_source_x_0, '0', digital_constellation_modulator_0, '0'] +- [blocks_char_to_float_0, '0', qtgui_freq_sink_x_2_1, '0'] +- [blocks_char_to_float_0, '0', qtgui_time_sink_x_0, '0'] +- [blocks_char_to_float_0_0, '0', blocks_delay_0, '0'] +- [blocks_char_to_float_0_1, '0', qtgui_freq_sink_x_2_1, '1'] +- [blocks_char_to_float_0_1, '0', qtgui_time_sink_x_0, '2'] +- [blocks_delay_0, '0', qtgui_time_sink_x_0, '1'] +- [blocks_throttle_0, '0', channels_channel_model_0, '0'] +- [blocks_unpack_k_bits_bb_0, '0', blocks_char_to_float_0, '0'] +- [blocks_unpack_k_bits_bb_0_0, '0', blocks_char_to_float_0_0, '0'] +- [blocks_unpack_k_bits_bb_0_1, '0', blocks_char_to_float_0_1, '0'] +- [channels_channel_model_0, '0', channels_selective_fading_model_0, '0'] +- [channels_channel_model_0, '0', digital_pfb_clock_sync_xxx_0_0, '0'] +- [channels_channel_model_0, '0', qtgui_const_sink_x_0, '1'] +- [channels_channel_model_0, '0', qtgui_freq_sink_x_0, '1'] +- [channels_selective_fading_model_0, '0', digital_pfb_clock_sync_xxx_0, '0'] +- [channels_selective_fading_model_0, '0', qtgui_const_sink_x_0, '0'] +- [channels_selective_fading_model_0, '0', qtgui_freq_sink_x_0, '0'] +- [digital_cma_equalizer_cc_0, '0', digital_costas_loop_cc_0, '0'] +- [digital_cma_equalizer_cc_0, '0', qtgui_const_sink_x_1, '0'] +- [digital_cma_equalizer_cc_0_0, '0', digital_costas_loop_cc_0_0, '0'] +- [digital_cma_equalizer_cc_0_0, '0', qtgui_const_sink_x_1, '1'] +- [digital_constellation_decoder_cb_0, '0', digital_diff_decoder_bb_0, '0'] +- [digital_constellation_decoder_cb_0_0, '0', digital_diff_decoder_bb_0_0, '0'] +- [digital_constellation_modulator_0, '0', blocks_throttle_0, '0'] +- [digital_costas_loop_cc_0, '0', digital_constellation_decoder_cb_0, '0'] +- [digital_costas_loop_cc_0, '0', qtgui_const_sink_x_2, '0'] +- [digital_costas_loop_cc_0_0, '0', digital_constellation_decoder_cb_0_0, '0'] +- [digital_costas_loop_cc_0_0, '0', qtgui_const_sink_x_2, '1'] +- [digital_diff_decoder_bb_0, '0', digital_map_bb_0, '0'] +- [digital_diff_decoder_bb_0_0, '0', digital_map_bb_0_0, '0'] +- [digital_map_bb_0, '0', blocks_unpack_k_bits_bb_0, '0'] +- [digital_map_bb_0_0, '0', blocks_unpack_k_bits_bb_0_1, '0'] +- [digital_pfb_clock_sync_xxx_0, '0', digital_cma_equalizer_cc_0, '0'] +- [digital_pfb_clock_sync_xxx_0, '0', qtgui_const_sink_x_0_0, '0'] +- [digital_pfb_clock_sync_xxx_0_0, '0', digital_cma_equalizer_cc_0_0, '0'] +- [digital_pfb_clock_sync_xxx_0_0, '0', qtgui_const_sink_x_0_0, '1'] + +metadata: + file_format: 1 diff --git a/simulation/QAM_Fading/epy_block_0.py b/simulation/QAM_Fading/epy_block_0.py deleted file mode 100644 index 48fe6e9..0000000 --- a/simulation/QAM_Fading/epy_block_0.py +++ /dev/null @@ -1,74 +0,0 @@ -""" -Embedded Python Blocks: - -Each time this file is saved, GRC will instantiate the first class it finds -to get ports and parameters of your block. The arguments to __init__ will -be the parameters. All of them are required to have default values! -""" - -import numpy as np -from numpy.fft import fft,ifft,fftshift -from gnuradio import gr - - -class blk(gr.sync_block): # other base classes are basic_block, decim_block, interp_block - """Embedded Python Block example - a simple multiply const""" - - def __init__(self, amplitudes=[], delays=[], los=True): # only default arguments here - """arguments to this function show up as parameters in GRC""" - gr.sync_block.__init__( - self, - name='Embedded Python Block', # will show up in GRC - in_sig=[np.complex64], - out_sig=[np.complex64] - ) - # if an attribute with the same name as a parameter is found, - # a callback is registered (properties work, too). - self.amplitudes = amplitudes - self.delays = delays - self.temp = [0] - # if los: - # self.amplitudes.append(1) - # self.delays.append(0) - self.los= 1 - #self.fir = - - def work(self, input_items, output_items): - """example: multiply with constant""" - inp = input_items[0] - oup = output_items[0] - - if len(self.amplitudes) != len(self.delays): - raise Exception("Amplitudes and Delay length dont match") - - # raise Exception("Delay length can't be one") - #if np.min(self.delays)<=1: - # raise Exception("Delay length can't be one") - max_len = np.max(self.delays) - sum_x = np.zeros(max_len) - for(a,d) in zip(self.amplitudes,self.delays): - # if d-1 <= 0: - # x = np.concatenate([[a], np.zeros(max_len-1)]) - # else: - x = np.concatenate([np.zeros(d-1), [a], np.zeros(max_len-d)]) - sum_x += x - - sum_x[0] = self.los - print(sum_x) - - #H_int = fft(sum_x) - - #h = ifft(H_int) - - #h[0]=1 - - y = np.convolve(inp, sum_x) - - y+=np.concatenate([self.temp,np.zeros(len(y)-len(self.temp))]) - - - oup[:] = y[:len(inp)] - self.temp = y[len(inp):] - - - return len(oup) \ No newline at end of file diff --git a/simulation/QAM_Fading/qam_fading_FIR_Filter_v1.grc b/simulation/QAM_Fading/qam_fading_FIR_Filter_v1.grc deleted file mode 100644 index ffc47f6..0000000 --- a/simulation/QAM_Fading/qam_fading_FIR_Filter_v1.grc +++ /dev/null @@ -1,1445 +0,0 @@ -options: - parameters: - author: Pross Naoki, Halter Sara Cinzia - category: '[GRC Hier Blocks]' - cmake_opt: '' - comment: '' - copyright: '' - description: '' - gen_cmake: 'On' - gen_linking: dynamic - generate_options: qt_gui - hier_block_src_path: '.:' - id: qam_fading - max_nouts: '0' - output_language: python - placement: (0,0) - qt_qss_theme: '' - realtime_scheduling: '1' - run: 'True' - run_command: '{python} -u {filename}' - run_options: prompt - sizing_mode: fixed - thread_safe_setters: '' - title: QAM mit Fading - window_size: '' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [8, 8] - rotation: 0 - state: enabled - -blocks: -- name: chn_taps - id: variable - parameters: - comment: '' - value: '[1.0 + 0.0j, ]' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [672, 236.0] - rotation: 0 - state: true -- name: const - id: variable_constellation - parameters: - comment: '' - const_points: '[-1-1j, -1+1j, 1+1j, 1-1j]' - dims: '1' - precision: '8' - rot_sym: '4' - soft_dec_lut: None - sym_map: '[0, 1, 3, 2]' - type: qpsk - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [224, 428.0] - rotation: 0 - state: true -- name: eq_gain - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@1: 0,0,1,1' - label: Equalizer Rate - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: '.001' - stop: '.1' - value: '.01' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1648, 476.0] - rotation: 0 - state: true -- name: eq_mod - id: variable - parameters: - comment: '' - value: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1648, 400.0] - rotation: 0 - state: true -- name: eq_ntaps - id: variable - parameters: - comment: '' - value: '15' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1728, 400.0] - rotation: 0 - state: true -- name: excess_bw - id: variable - parameters: - comment: '' - value: 350e-3 - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [320, 268.0] - rotation: 0 - state: true -- name: freq_offset - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@0: 1,0,1,1' - label: Frequency Offset - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: -100e-3 - step: 1e-3 - stop: 100e-3 - value: '0' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [712, 476.0] - rotation: 0 - state: true -- name: nfilts - id: variable - parameters: - comment: '' - value: '32' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1312, 132.0] - rotation: 0 - state: true -- name: noise_volt - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@0: 0,0,1,1' - label: Noise Voltage - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: '0.01' - stop: '1' - value: '0.0001' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [576, 476.0] - rotation: 0 - state: true -- name: phase_bw - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@1: 1,0,1,1' - label: Phase Bandwidth - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: '.01' - stop: '1' - value: 2 * 3.141592653589793 / 100 - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1952, 444.0] - rotation: 0 - state: true -- name: rrc_taps - id: variable - parameters: - comment: '' - value: firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), excess_bw, 45*nfilts) - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1376, 132.0] - rotation: 0 - state: true -- name: samp_rate - id: variable - parameters: - comment: '' - value: '32000' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [192, 12.0] - rotation: 0 - state: enabled -- name: sps - id: variable - parameters: - comment: '' - value: '4' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [224, 268.0] - rotation: 0 - state: true -- name: time_offset - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@0: 0,1,1,1' - label: Timing Offset - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0.999' - step: '0.0001' - stop: '1.001' - value: '1.0' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [576, 620.0] - rotation: 0 - state: true -- name: timing_loop_bw - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@0: 1,1,1,1' - label: Time Bandwidth - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: 10e-3 - stop: 200e-3 - value: 2 * 3.141592653589793 / 100 - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1312, 196.0] - rotation: 0 - state: true -- name: analog_random_source_x_0 - id: analog_random_source_x - parameters: - affinity: '' - alias: '' - comment: '' - max: '256' - maxoutbuf: '0' - min: '0' - minoutbuf: '0' - num_samps: '1000' - repeat: 'True' - type: byte - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [32, 332.0] - rotation: 0 - state: enabled -- name: blocks_char_to_float_0 - id: blocks_char_to_float - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - scale: '1' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2592, 296.0] - rotation: 0 - state: true -- name: blocks_char_to_float_0_0 - id: blocks_char_to_float - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - scale: '1' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [424, 1336.0] - rotation: 0 - state: true -- name: blocks_char_to_float_0_1 - id: blocks_char_to_float - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - scale: '1' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2544, 692.0] - rotation: 0 - state: true -- name: blocks_delay_0 - id: blocks_delay - parameters: - affinity: '' - alias: '' - comment: '' - delay: '50' - maxoutbuf: '0' - minoutbuf: '0' - num_ports: '1' - type: float - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2624, 1352.0] - rotation: 0 - state: true -- name: blocks_throttle_0 - id: blocks_throttle - parameters: - affinity: '' - alias: '' - comment: '' - ignoretag: 'True' - maxoutbuf: '0' - minoutbuf: '0' - samples_per_second: samp_rate - type: complex - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [464, 356.0] - rotation: 0 - state: enabled -- name: blocks_unpack_k_bits_bb_0 - id: blocks_unpack_k_bits_bb - parameters: - affinity: '' - alias: '' - comment: '' - k: '2' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2512, 456.0] - rotation: 0 - state: true -- name: blocks_unpack_k_bits_bb_0_0 - id: blocks_unpack_k_bits_bb - parameters: - affinity: '' - alias: '' - comment: '' - k: '2' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [248, 1336.0] - rotation: 0 - state: true -- name: blocks_unpack_k_bits_bb_0_1 - id: blocks_unpack_k_bits_bb - parameters: - affinity: '' - alias: '' - comment: '' - k: '2' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2448, 868.0] - rotation: 0 - state: true -- name: channels_channel_model_0 - id: channels_channel_model - parameters: - affinity: '' - alias: '' - block_tags: 'False' - comment: '' - epsilon: time_offset - freq_offset: freq_offset - maxoutbuf: '0' - minoutbuf: '0' - noise_voltage: noise_volt - seed: '0' - taps: chn_taps - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [648, 316.0] - rotation: 0 - state: enabled -- name: channels_fading_model_0 - id: channels_fading_model - parameters: - K: '4.0' - LOS: 'False' - N: '8' - affinity: '' - alias: '' - comment: '' - fDTs: '0' - maxoutbuf: '0' - minoutbuf: '0' - seed: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [952, 332.0] - rotation: 0 - state: true -- name: digital_cma_equalizer_cc_0 - id: digital_cma_equalizer_cc - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - modulus: eq_mod - mu: eq_gain - num_taps: eq_ntaps - sps: '2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1648, 304.0] - rotation: 0 - state: true -- name: digital_cma_equalizer_cc_0_0 - id: digital_cma_equalizer_cc - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - modulus: eq_mod - mu: eq_gain - num_taps: eq_ntaps - sps: '2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1600, 724.0] - rotation: 0 - state: true -- name: digital_constellation_decoder_cb_0 - id: digital_constellation_decoder_cb - parameters: - affinity: '' - alias: '' - comment: '' - constellation: const - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2288, 296.0] - rotation: 0 - state: true -- name: digital_constellation_decoder_cb_0_0 - id: digital_constellation_decoder_cb - parameters: - affinity: '' - alias: '' - comment: '' - constellation: const - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2224, 684.0] - rotation: 0 - state: true -- name: digital_constellation_modulator_0 - id: digital_constellation_modulator - parameters: - affinity: '' - alias: '' - comment: '' - constellation: const - differential: 'True' - excess_bw: excess_bw - log: 'False' - maxoutbuf: '0' - minoutbuf: '0' - samples_per_symbol: sps - verbose: 'False' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [224, 332.0] - rotation: 0 - state: enabled -- name: digital_costas_loop_cc_0 - id: digital_costas_loop_cc - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - order: '4' - use_snr: 'False' - w: phase_bw - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1952, 296.0] - rotation: 0 - state: true -- name: digital_costas_loop_cc_0_0 - id: digital_costas_loop_cc - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - order: '4' - use_snr: 'False' - w: phase_bw - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1936, 688.0] - rotation: 0 - state: true -- name: digital_diff_decoder_bb_0 - id: digital_diff_decoder_bb - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - modulus: '4' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2288, 360.0] - rotation: 180 - state: true -- name: digital_diff_decoder_bb_0_0 - id: digital_diff_decoder_bb - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - modulus: '4' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2264, 764.0] - rotation: 180 - state: true -- name: digital_map_bb_0 - id: digital_map_bb - parameters: - affinity: '' - alias: '' - comment: '' - map: '[0, 1, 3, 2]' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2304, 456.0] - rotation: 0 - state: true -- name: digital_map_bb_0_0 - id: digital_map_bb - parameters: - affinity: '' - alias: '' - comment: '' - map: '[0, 1, 3, 2]' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2272, 868.0] - rotation: 0 - state: true -- name: digital_pfb_clock_sync_xxx_0 - id: digital_pfb_clock_sync_xxx - parameters: - affinity: '' - alias: '' - comment: '' - filter_size: nfilts - init_phase: nfilts/2 - loop_bw: timing_loop_bw - max_dev: '1.5' - maxoutbuf: '0' - minoutbuf: '0' - osps: '2' - sps: sps * 1.001 - taps: rrc_taps - type: ccf - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1312, 324.0] - rotation: 0 - state: true -- name: digital_pfb_clock_sync_xxx_0_0 - id: digital_pfb_clock_sync_xxx - parameters: - affinity: '' - alias: '' - comment: '' - filter_size: nfilts - init_phase: nfilts/2 - loop_bw: timing_loop_bw - max_dev: '1.5' - maxoutbuf: '0' - minoutbuf: '0' - osps: '2' - sps: sps * 1.001 - taps: rrc_taps - type: ccf - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1088, 868.0] - rotation: 0 - state: true -- name: params - id: qtgui_tab_widget - parameters: - alias: '' - comment: '' - gui_hint: '' - label0: Channel - label1: Receiver - label10: Tab 10 - label11: Tab 11 - label12: Tab 12 - label13: Tab 13 - label14: Tab 14 - label15: Tab 15 - label16: Tab 16 - label17: Tab 17 - label18: Tab 18 - label19: Tab 19 - label2: Tab 2 - label3: Tab 3 - label4: Tab 4 - label5: Tab 5 - label6: Tab 6 - label7: Tab 7 - label8: Tab 8 - label9: Tab 9 - num_tabs: '2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [296, 12.0] - rotation: 0 - state: true -- name: plots - id: qtgui_tab_widget - parameters: - alias: '' - comment: '' - gui_hint: '' - label0: Constellations - label1: Frequency - label10: Tab 10 - label11: Tab 11 - label12: Tab 12 - label13: Tab 13 - label14: Tab 14 - label15: Tab 15 - label16: Tab 16 - label17: Tab 17 - label18: Tab 18 - label19: Tab 19 - label2: Time - label3: Tab 3 - label4: Tab 4 - label5: Tab 5 - label6: Tab 6 - label7: Tab 7 - label8: Tab 8 - label9: Tab 9 - num_tabs: '3' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [448, 12.0] - rotation: 0 - state: true -- name: qtgui_const_sink_x_0 - id: qtgui_const_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: '"blue"' - color10: '"red"' - color2: '"red"' - color3: '"red"' - color4: '"red"' - color5: '"red"' - color6: '"red"' - color7: '"red"' - color8: '"red"' - color9: '"red"' - comment: '' - grid: 'False' - gui_hint: 'plots@0: 0,0,1,1' - label1: Fading - label10: '' - label2: '' - label3: '' - label4: '' - label5: '' - label6: '' - label7: '' - label8: '' - label9: '' - legend: 'True' - marker1: '0' - marker10: '0' - marker2: '0' - marker3: '0' - marker4: '0' - marker5: '0' - marker6: '0' - marker7: '0' - marker8: '0' - marker9: '0' - name: '"Channel"' - nconnections: '2' - size: '2048' - style1: '0' - style10: '0' - style2: '0' - style3: '0' - style4: '0' - style5: '0' - style6: '0' - style7: '0' - style8: '0' - style9: '0' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: complex - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - xmax: '2' - xmin: '-2' - ymax: '2' - ymin: '-2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1044.0, -48] - rotation: 90 - state: enabled -- name: qtgui_const_sink_x_0_0 - id: qtgui_const_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: '"blue"' - color10: '"red"' - color2: '"red"' - color3: '"red"' - color4: '"red"' - color5: '"red"' - color6: '"red"' - color7: '"red"' - color8: '"red"' - color9: '"red"' - comment: '' - grid: 'False' - gui_hint: 'plots@0: 0,1,1,1' - label1: Fading - label10: '' - label2: '' - label3: '' - label4: '' - label5: '' - label6: '' - label7: '' - label8: '' - label9: '' - legend: 'True' - marker1: '0' - marker10: '0' - marker2: '0' - marker3: '0' - marker4: '0' - marker5: '0' - marker6: '0' - marker7: '0' - marker8: '0' - marker9: '0' - name: '"Synchronized"' - nconnections: '2' - size: '2048' - style1: '0' - style10: '0' - style2: '0' - style3: '0' - style4: '0' - style5: '0' - style6: '0' - style7: '0' - style8: '0' - style9: '0' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: complex - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - xmax: '2' - xmin: '-2' - ymax: '2' - ymin: '-2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1572.0, 80] - rotation: 90 - state: enabled -- name: qtgui_const_sink_x_1 - id: qtgui_const_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: '"blue"' - color10: '"red"' - color2: '"red"' - color3: '"red"' - color4: '"red"' - color5: '"red"' - color6: '"red"' - color7: '"red"' - color8: '"red"' - color9: '"red"' - comment: '' - grid: 'False' - gui_hint: 'plots@0: 1,0,1,1' - label1: Fading - label10: '' - label2: '' - label3: '' - label4: '' - label5: '' - label6: '' - label7: '' - label8: '' - label9: '' - legend: 'True' - marker1: '0' - marker10: '0' - marker2: '0' - marker3: '0' - marker4: '0' - marker5: '0' - marker6: '0' - marker7: '0' - marker8: '0' - marker9: '0' - name: '"Equalized"' - nconnections: '2' - size: '1024' - style1: '0' - style10: '0' - style2: '0' - style3: '0' - style4: '0' - style5: '0' - style6: '0' - style7: '0' - style8: '0' - style9: '0' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: complex - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - xmax: '2' - xmin: '-2' - ymax: '2' - ymin: '-2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1828.0, 96] - rotation: 90 - state: true -- name: qtgui_const_sink_x_2 - id: qtgui_const_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: '"blue"' - color10: '"red"' - color2: '"red"' - color3: '"red"' - color4: '"red"' - color5: '"red"' - color6: '"red"' - color7: '"red"' - color8: '"red"' - color9: '"red"' - comment: '' - grid: 'False' - gui_hint: 'plots@0: 1,1,1,1' - label1: Fading - label10: '' - label2: '' - label3: '' - label4: '' - label5: '' - label6: '' - label7: '' - label8: '' - label9: '' - legend: 'True' - marker1: '0' - marker10: '0' - marker2: '0' - marker3: '0' - marker4: '0' - marker5: '0' - marker6: '0' - marker7: '0' - marker8: '0' - marker9: '0' - name: '"Locked"' - nconnections: '2' - size: '1024' - style1: '0' - style10: '0' - style2: '0' - style3: '0' - style4: '0' - style5: '0' - style6: '0' - style7: '0' - style8: '0' - style9: '0' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: complex - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - xmax: '2' - xmin: '-2' - ymax: '2' - ymin: '-2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2188.0, 0] - rotation: 90 - state: true -- name: qtgui_freq_sink_x_0 - id: qtgui_freq_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - average: '1.0' - axislabels: 'True' - bw: samp_rate - color1: '"blue"' - color10: '"dark blue"' - color2: '"red"' - color3: '"green"' - color4: '"black"' - color5: '"cyan"' - color6: '"magenta"' - color7: '"yellow"' - color8: '"dark red"' - color9: '"dark green"' - comment: '' - ctrlpanel: 'False' - fc: '0' - fftsize: '1024' - freqhalf: 'True' - grid: 'False' - gui_hint: 'plots@1: 0,0,1,1' - label: Relative Gain - label1: Fading - label10: '''''' - label2: '''''' - label3: '''''' - label4: '''''' - label5: '''''' - label6: '''''' - label7: '''''' - label8: '''''' - label9: '''''' - legend: 'True' - maxoutbuf: '0' - minoutbuf: '0' - name: '"Channel"' - nconnections: '2' - showports: 'False' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_tag: '""' - type: complex - units: dB - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - wintype: firdes.WIN_BLACKMAN_hARRIS - ymax: '10' - ymin: '-140' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1112.0, 608] - rotation: 270 - state: true -- name: qtgui_freq_sink_x_2_1 - id: qtgui_freq_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - average: '1.0' - axislabels: 'True' - bw: samp_rate - color1: '"blue"' - color10: '"dark blue"' - color2: '"red"' - color3: '"green"' - color4: '"black"' - color5: '"cyan"' - color6: '"magenta"' - color7: '"yellow"' - color8: '"dark red"' - color9: '"dark green"' - comment: '' - ctrlpanel: 'False' - fc: '0' - fftsize: '1024' - freqhalf: 'True' - grid: 'False' - gui_hint: '' - label: Relative Gain - label1: Fading - label10: '''''' - label2: '''''' - label3: '''''' - label4: '''''' - label5: '''''' - label6: '''''' - label7: '''''' - label8: '''''' - label9: '''''' - legend: 'True' - maxoutbuf: '0' - minoutbuf: '0' - name: '""' - nconnections: '2' - showports: 'False' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_tag: '""' - type: float - units: dB - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - wintype: firdes.WIN_BLACKMAN_hARRIS - ymax: '10' - ymin: '-140' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2848, 488.0] - rotation: 0 - state: true -- name: qtgui_time_sink_x_0 - id: qtgui_time_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: blue - color10: dark blue - color2: red - color3: green - color4: black - color5: cyan - color6: magenta - color7: yellow - color8: dark red - color9: dark green - comment: '' - ctrlpanel: 'False' - entags: 'True' - grid: 'False' - gui_hint: 'plots@2: 0,0,1,1' - label1: Received - label10: Signal 10 - label2: Sent - label3: Signal 3 - label4: Signal 4 - label5: Signal 5 - label6: Signal 6 - label7: Signal 7 - label8: Signal 8 - label9: Signal 9 - legend: 'True' - marker1: '-1' - marker10: '-1' - marker2: '-1' - marker3: '-1' - marker4: '-1' - marker5: '-1' - marker6: '-1' - marker7: '-1' - marker8: '-1' - marker9: '-1' - name: '"Decoded"' - nconnections: '3' - size: '1024' - srate: samp_rate - stemplot: 'False' - style1: '1' - style10: '1' - style2: '1' - style3: '1' - style4: '1' - style5: '1' - style6: '1' - style7: '1' - style8: '1' - style9: '1' - tr_chan: '0' - tr_delay: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: float - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - ylabel: Amplitude - ymax: '1' - ymin: '-1' - yunit: '""' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2816, 288.0] - rotation: 0 - state: true - -connections: -- [analog_random_source_x_0, '0', blocks_unpack_k_bits_bb_0_0, '0'] -- [analog_random_source_x_0, '0', digital_constellation_modulator_0, '0'] -- [blocks_char_to_float_0, '0', qtgui_freq_sink_x_2_1, '0'] -- [blocks_char_to_float_0, '0', qtgui_time_sink_x_0, '0'] -- [blocks_char_to_float_0_0, '0', blocks_delay_0, '0'] -- [blocks_char_to_float_0_1, '0', qtgui_freq_sink_x_2_1, '1'] -- [blocks_char_to_float_0_1, '0', qtgui_time_sink_x_0, '2'] -- [blocks_delay_0, '0', qtgui_time_sink_x_0, '1'] -- [blocks_throttle_0, '0', channels_channel_model_0, '0'] -- [blocks_unpack_k_bits_bb_0, '0', blocks_char_to_float_0, '0'] -- [blocks_unpack_k_bits_bb_0_0, '0', blocks_char_to_float_0_0, '0'] -- [blocks_unpack_k_bits_bb_0_1, '0', blocks_char_to_float_0_1, '0'] -- [channels_channel_model_0, '0', channels_fading_model_0, '0'] -- [channels_channel_model_0, '0', digital_pfb_clock_sync_xxx_0_0, '0'] -- [channels_channel_model_0, '0', qtgui_const_sink_x_0, '1'] -- [channels_channel_model_0, '0', qtgui_freq_sink_x_0, '1'] -- [channels_fading_model_0, '0', digital_pfb_clock_sync_xxx_0, '0'] -- [channels_fading_model_0, '0', qtgui_const_sink_x_0, '0'] -- [channels_fading_model_0, '0', qtgui_freq_sink_x_0, '0'] -- [digital_cma_equalizer_cc_0, '0', digital_costas_loop_cc_0, '0'] -- [digital_cma_equalizer_cc_0, '0', qtgui_const_sink_x_1, '0'] -- [digital_cma_equalizer_cc_0_0, '0', digital_costas_loop_cc_0_0, '0'] -- [digital_cma_equalizer_cc_0_0, '0', qtgui_const_sink_x_1, '1'] -- [digital_constellation_decoder_cb_0, '0', digital_diff_decoder_bb_0, '0'] -- [digital_constellation_decoder_cb_0_0, '0', digital_diff_decoder_bb_0_0, '0'] -- [digital_constellation_modulator_0, '0', blocks_throttle_0, '0'] -- [digital_costas_loop_cc_0, '0', digital_constellation_decoder_cb_0, '0'] -- [digital_costas_loop_cc_0, '0', qtgui_const_sink_x_2, '0'] -- [digital_costas_loop_cc_0_0, '0', digital_constellation_decoder_cb_0_0, '0'] -- [digital_costas_loop_cc_0_0, '0', qtgui_const_sink_x_2, '1'] -- [digital_diff_decoder_bb_0, '0', digital_map_bb_0, '0'] -- [digital_diff_decoder_bb_0_0, '0', digital_map_bb_0_0, '0'] -- [digital_map_bb_0, '0', blocks_unpack_k_bits_bb_0, '0'] -- [digital_map_bb_0_0, '0', blocks_unpack_k_bits_bb_0_1, '0'] -- [digital_pfb_clock_sync_xxx_0, '0', digital_cma_equalizer_cc_0, '0'] -- [digital_pfb_clock_sync_xxx_0, '0', qtgui_const_sink_x_0_0, '0'] -- [digital_pfb_clock_sync_xxx_0_0, '0', digital_cma_equalizer_cc_0_0, '0'] -- [digital_pfb_clock_sync_xxx_0_0, '0', qtgui_const_sink_x_0_0, '1'] - -metadata: - file_format: 1 diff --git a/simulation/QAM_Fading/qam_fading_V2.grc b/simulation/QAM_Fading/qam_fading_V2.grc deleted file mode 100644 index 16fa2e3..0000000 --- a/simulation/QAM_Fading/qam_fading_V2.grc +++ /dev/null @@ -1,1539 +0,0 @@ -options: - parameters: - author: Pross Naoki, Halter Sara Cinzia - category: '[GRC Hier Blocks]' - cmake_opt: '' - comment: '' - copyright: '' - description: '' - gen_cmake: 'On' - gen_linking: dynamic - generate_options: qt_gui - hier_block_src_path: '.:' - id: qam_fading - max_nouts: '0' - output_language: python - placement: (0,0) - qt_qss_theme: '' - realtime_scheduling: '1' - run: 'True' - run_command: '{python} -u {filename}' - run_options: prompt - sizing_mode: fixed - thread_safe_setters: '' - title: QAM mit Fading - window_size: '' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [8, 8] - rotation: 0 - state: enabled - -blocks: -- name: LOS_NLOS - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@2: 0,1,1,1' - label: LOS_NLOS - min_len: '200' - orient: Qt.Horizontal - rangeType: int - start: '0' - step: '1' - stop: '1' - value: '1' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1104, 484.0] - rotation: 0 - state: true -- name: amp_1 - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@2: 1,0,1,1' - label: Ampliude - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: '0.1' - stop: '5' - value: '0.2' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [984, 612.0] - rotation: 0 - state: true -- name: chn_taps - id: variable - parameters: - comment: '' - value: '[1.0 + 0.0j, ]' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [672, 236.0] - rotation: 0 - state: true -- name: const - id: variable_constellation - parameters: - comment: '' - const_points: '[-1-1j, -1+1j, 1+1j, 1-1j]' - dims: '1' - precision: '8' - rot_sym: '4' - soft_dec_lut: None - sym_map: '[0, 1, 3, 2]' - type: 16qam - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [224, 428.0] - rotation: 0 - state: true -- name: eq_gain - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@1: 0,0,1,1' - label: Equalizer Rate - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: '.001' - stop: '.1' - value: '.01' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1744, 452.0] - rotation: 0 - state: true -- name: eq_mod - id: variable - parameters: - comment: '' - value: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1744, 376.0] - rotation: 0 - state: true -- name: eq_ntaps - id: variable - parameters: - comment: '' - value: '15' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1824, 376.0] - rotation: 0 - state: true -- name: excess_bw - id: variable - parameters: - comment: '' - value: 350e-3 - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [320, 268.0] - rotation: 0 - state: true -- name: fading_1 - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@2: 0,0,1,1' - label: Fading - min_len: '200' - orient: Qt.Horizontal - rangeType: int - start: '1' - step: '1' - stop: '30' - value: '2' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [984, 484.0] - rotation: 0 - state: true -- name: freq_offset - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@0: 1,0,1,1' - label: Frequency Offset - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: -100e-3 - step: 1e-3 - stop: 100e-3 - value: '0' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [712, 476.0] - rotation: 0 - state: true -- name: nfilts - id: variable - parameters: - comment: '' - value: '32' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1408, 104.0] - rotation: 0 - state: true -- name: noise_volt - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@0: 0,0,1,1' - label: Noise Voltage - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: '0.01' - stop: '1' - value: '0.0001' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [576, 476.0] - rotation: 0 - state: true -- name: phase_bw - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@1: 1,0,1,1' - label: Phase Bandwidth - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: '.01' - stop: '1' - value: 2 * 3.141592653589793 / 100 - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2048, 420.0] - rotation: 0 - state: true -- name: rrc_taps - id: variable - parameters: - comment: '' - value: firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), excess_bw, 45*nfilts) - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1488, 104.0] - rotation: 0 - state: true -- name: samp_rate - id: variable - parameters: - comment: '' - value: '32000' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [192, 12.0] - rotation: 0 - state: enabled -- name: sps - id: variable - parameters: - comment: '' - value: '4' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [224, 268.0] - rotation: 0 - state: true -- name: time_offset - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@0: 0,1,1,1' - label: Timing Offset - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0.999' - step: '0.0001' - stop: '1.001' - value: '1.0' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [576, 620.0] - rotation: 0 - state: true -- name: timing_loop_bw - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@0: 1,1,1,1' - label: Time Bandwidth - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: 10e-3 - stop: 200e-3 - value: 2 * 3.141592653589793 / 100 - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1408, 164.0] - rotation: 0 - state: true -- name: analog_random_source_x_0 - id: analog_random_source_x - parameters: - affinity: '' - alias: '' - comment: '' - max: '256' - maxoutbuf: '0' - min: '0' - minoutbuf: '0' - num_samps: '1000' - repeat: 'True' - type: byte - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [32, 332.0] - rotation: 0 - state: enabled -- name: blocks_char_to_float_0 - id: blocks_char_to_float - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - scale: '1' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2688, 272.0] - rotation: 0 - state: true -- name: blocks_char_to_float_0_0 - id: blocks_char_to_float - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - scale: '1' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [424, 1336.0] - rotation: 0 - state: true -- name: blocks_char_to_float_0_1 - id: blocks_char_to_float - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - scale: '1' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2640, 672.0] - rotation: 0 - state: true -- name: blocks_delay_0 - id: blocks_delay - parameters: - affinity: '' - alias: '' - comment: '' - delay: '50' - maxoutbuf: '0' - minoutbuf: '0' - num_ports: '1' - type: float - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2736, 1360.0] - rotation: 0 - state: true -- name: blocks_file_sink_0 - id: blocks_file_sink - parameters: - affinity: '' - alias: '' - append: 'False' - comment: '' - file: /home/sara/Documents/Fading/simulation/QAM_Fading/qam_fading_V2_output.grc - type: float - unbuffered: 'False' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2880, 84.0] - rotation: 0 - state: disabled -- name: blocks_throttle_0 - id: blocks_throttle - parameters: - affinity: '' - alias: '' - comment: '' - ignoretag: 'True' - maxoutbuf: '0' - minoutbuf: '0' - samples_per_second: samp_rate - type: complex - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [464, 356.0] - rotation: 0 - state: enabled -- name: blocks_unpack_k_bits_bb_0 - id: blocks_unpack_k_bits_bb - parameters: - affinity: '' - alias: '' - comment: '' - k: '2' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2608, 432.0] - rotation: 0 - state: true -- name: blocks_unpack_k_bits_bb_0_0 - id: blocks_unpack_k_bits_bb - parameters: - affinity: '' - alias: '' - comment: '' - k: '2' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [248, 1336.0] - rotation: 0 - state: true -- name: blocks_unpack_k_bits_bb_0_1 - id: blocks_unpack_k_bits_bb - parameters: - affinity: '' - alias: '' - comment: '' - k: '2' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2544, 848.0] - rotation: 0 - state: true -- name: channels_channel_model_0 - id: channels_channel_model - parameters: - affinity: '' - alias: '' - block_tags: 'False' - comment: '' - epsilon: time_offset - freq_offset: freq_offset - maxoutbuf: '0' - minoutbuf: '0' - noise_voltage: noise_volt - seed: '0' - taps: chn_taps - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [648, 316.0] - rotation: 0 - state: enabled -- name: digital_cma_equalizer_cc_0 - id: digital_cma_equalizer_cc - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - modulus: eq_mod - mu: eq_gain - num_taps: eq_ntaps - sps: '2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1744, 276.0] - rotation: 0 - state: true -- name: digital_cma_equalizer_cc_0_0 - id: digital_cma_equalizer_cc - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - modulus: eq_mod - mu: eq_gain - num_taps: eq_ntaps - sps: '2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1664, 932.0] - rotation: 0 - state: true -- name: digital_constellation_decoder_cb_0 - id: digital_constellation_decoder_cb - parameters: - affinity: '' - alias: '' - comment: '' - constellation: const - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2384, 272.0] - rotation: 0 - state: true -- name: digital_constellation_decoder_cb_0_0 - id: digital_constellation_decoder_cb - parameters: - affinity: '' - alias: '' - comment: '' - constellation: const - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2320, 656.0] - rotation: 0 - state: true -- name: digital_constellation_modulator_0 - id: digital_constellation_modulator - parameters: - affinity: '' - alias: '' - comment: '' - constellation: const - differential: 'True' - excess_bw: excess_bw - log: 'False' - maxoutbuf: '0' - minoutbuf: '0' - samples_per_symbol: sps - verbose: 'False' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [224, 332.0] - rotation: 0 - state: enabled -- name: digital_costas_loop_cc_0 - id: digital_costas_loop_cc - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - order: '4' - use_snr: 'False' - w: phase_bw - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2048, 264.0] - rotation: 0 - state: true -- name: digital_costas_loop_cc_0_0 - id: digital_costas_loop_cc - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - order: '4' - use_snr: 'False' - w: phase_bw - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1984, 928.0] - rotation: 0 - state: true -- name: digital_diff_decoder_bb_0 - id: digital_diff_decoder_bb - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - modulus: '4' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2384, 336.0] - rotation: 180 - state: true -- name: digital_diff_decoder_bb_0_0 - id: digital_diff_decoder_bb - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - modulus: '4' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2352, 736.0] - rotation: 180 - state: true -- name: digital_map_bb_0 - id: digital_map_bb - parameters: - affinity: '' - alias: '' - comment: '' - map: '[0, 1, 3, 2]' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2400, 432.0] - rotation: 0 - state: true -- name: digital_map_bb_0_0 - id: digital_map_bb - parameters: - affinity: '' - alias: '' - comment: '' - map: '[0, 1, 3, 2]' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2368, 848.0] - rotation: 0 - state: true -- name: digital_pfb_clock_sync_xxx_0 - id: digital_pfb_clock_sync_xxx - parameters: - affinity: '' - alias: '' - comment: '' - filter_size: nfilts - init_phase: nfilts/2 - loop_bw: timing_loop_bw - max_dev: '1.5' - maxoutbuf: '0' - minoutbuf: '0' - osps: '1' - sps: sps - taps: rrc_taps - type: ccf - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1408, 300.0] - rotation: 0 - state: true -- name: digital_pfb_clock_sync_xxx_0_0 - id: digital_pfb_clock_sync_xxx - parameters: - affinity: '' - alias: '' - comment: '' - filter_size: nfilts - init_phase: nfilts/2 - loop_bw: timing_loop_bw - max_dev: '1.5' - maxoutbuf: '0' - minoutbuf: '0' - osps: '1' - sps: 'sps ' - taps: rrc_taps - type: ccf - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1136, 956.0] - rotation: 0 - state: true -- name: import_0 - id: import - parameters: - alias: '' - comment: '' - imports: import numpy as np - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [600, 20.0] - rotation: 0 - state: true -- name: interp_fir_filter_xxx_0 - id: interp_fir_filter_xxx - parameters: - affinity: '' - alias: '' - comment: '' - interp: '1' - maxoutbuf: '0' - minoutbuf: '0' - samp_delay: '0' - taps: '[LOS_NLOS]+(([0]*fading_1)+[amp_1])' - type: ccc - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1000, 348.0] - rotation: 0 - state: enabled -- name: params - id: qtgui_tab_widget - parameters: - alias: '' - comment: '' - gui_hint: '' - label0: Channel - label1: Receiver - label10: Tab 10 - label11: Tab 11 - label12: Tab 12 - label13: Tab 13 - label14: Tab 14 - label15: Tab 15 - label16: Tab 16 - label17: Tab 17 - label18: Tab 18 - label19: Tab 19 - label2: Fading - label3: Tab 3 - label4: Tab 4 - label5: Tab 5 - label6: Tab 6 - label7: Tab 7 - label8: Tab 8 - label9: Tab 9 - num_tabs: '3' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [296, 12.0] - rotation: 0 - state: true -- name: plots - id: qtgui_tab_widget - parameters: - alias: '' - comment: '' - gui_hint: '' - label0: Constellations - label1: Frequency - label10: Tab 10 - label11: Tab 11 - label12: Tab 12 - label13: Tab 13 - label14: Tab 14 - label15: Tab 15 - label16: Tab 16 - label17: Tab 17 - label18: Tab 18 - label19: Tab 19 - label2: Time - label3: Tab 3 - label4: Tab 4 - label5: Tab 5 - label6: Tab 6 - label7: Tab 7 - label8: Tab 8 - label9: Tab 9 - num_tabs: '3' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [448, 12.0] - rotation: 0 - state: true -- name: qtgui_const_sink_x_0 - id: qtgui_const_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: '"blue"' - color10: '"red"' - color2: '"red"' - color3: '"red"' - color4: '"red"' - color5: '"red"' - color6: '"red"' - color7: '"red"' - color8: '"red"' - color9: '"red"' - comment: '' - grid: 'False' - gui_hint: 'plots@0: 0,0,1,1' - label1: fading - label10: '' - label2: normal - label3: '' - label4: '' - label5: '' - label6: '' - label7: '' - label8: '' - label9: '' - legend: 'True' - marker1: '0' - marker10: '0' - marker2: '0' - marker3: '0' - marker4: '0' - marker5: '0' - marker6: '0' - marker7: '0' - marker8: '0' - marker9: '0' - name: '"Channel"' - nconnections: '2' - size: '2048' - style1: '0' - style10: '0' - style2: '0' - style3: '0' - style4: '0' - style5: '0' - style6: '0' - style7: '0' - style8: '0' - style9: '0' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: complex - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - xmax: '2' - xmin: '-2' - ymax: '2' - ymin: '-2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1052.0, -48] - rotation: 90 - state: enabled -- name: qtgui_const_sink_x_0_0 - id: qtgui_const_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: '"blue"' - color10: '"red"' - color2: '"red"' - color3: '"red"' - color4: '"red"' - color5: '"red"' - color6: '"red"' - color7: '"red"' - color8: '"red"' - color9: '"red"' - comment: '' - grid: 'False' - gui_hint: 'plots@0: 0,1,1,1' - label1: fading - label10: '' - label2: normal - label3: '' - label4: '' - label5: '' - label6: '' - label7: '' - label8: '' - label9: '' - legend: 'True' - marker1: '0' - marker10: '0' - marker2: '0' - marker3: '0' - marker4: '0' - marker5: '0' - marker6: '0' - marker7: '0' - marker8: '0' - marker9: '0' - name: '"Synchronized"' - nconnections: '2' - size: '2048' - style1: '0' - style10: '0' - style2: '0' - style3: '0' - style4: '0' - style5: '0' - style6: '0' - style7: '0' - style8: '0' - style9: '0' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: complex - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - xmax: '2' - xmin: '-2' - ymax: '2' - ymin: '-2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1656.0, 56] - rotation: 90 - state: enabled -- name: qtgui_const_sink_x_1 - id: qtgui_const_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: '"blue"' - color10: '"red"' - color2: '"red"' - color3: '"red"' - color4: '"red"' - color5: '"red"' - color6: '"red"' - color7: '"red"' - color8: '"red"' - color9: '"red"' - comment: '' - grid: 'False' - gui_hint: 'plots@0: 1,0,1,1' - label1: fading - label10: '' - label2: normal - label3: '' - label4: '' - label5: '' - label6: '' - label7: '' - label8: '' - label9: '' - legend: 'True' - marker1: '0' - marker10: '0' - marker2: '0' - marker3: '0' - marker4: '0' - marker5: '0' - marker6: '0' - marker7: '0' - marker8: '0' - marker9: '0' - name: '"Equalized"' - nconnections: '2' - size: '1024' - style1: '0' - style10: '0' - style2: '0' - style3: '0' - style4: '0' - style5: '0' - style6: '0' - style7: '0' - style8: '0' - style9: '0' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: complex - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - xmax: '2' - xmin: '-2' - ymax: '2' - ymin: '-2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1896.0, 24] - rotation: 90 - state: true -- name: qtgui_const_sink_x_2 - id: qtgui_const_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: '"blue"' - color10: '"red"' - color2: '"red"' - color3: '"red"' - color4: '"red"' - color5: '"red"' - color6: '"red"' - color7: '"red"' - color8: '"red"' - color9: '"red"' - comment: '' - grid: 'False' - gui_hint: 'plots@0: 1,1,1,1' - label1: fading - label10: '' - label2: normal - label3: '' - label4: '' - label5: '' - label6: '' - label7: '' - label8: '' - label9: '' - legend: 'True' - marker1: '0' - marker10: '0' - marker2: '0' - marker3: '0' - marker4: '0' - marker5: '0' - marker6: '0' - marker7: '0' - marker8: '0' - marker9: '0' - name: '"Locked"' - nconnections: '2' - size: '1024' - style1: '0' - style10: '0' - style2: '0' - style3: '0' - style4: '0' - style5: '0' - style6: '0' - style7: '0' - style8: '0' - style9: '0' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: complex - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - xmax: '2' - xmin: '-2' - ymax: '2' - ymin: '-2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2280.0, -24] - rotation: 90 - state: true -- name: qtgui_freq_sink_x_0 - id: qtgui_freq_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - average: '1.0' - axislabels: 'True' - bw: samp_rate - color1: '"blue"' - color10: '"dark blue"' - color2: '"red"' - color3: '"green"' - color4: '"black"' - color5: '"cyan"' - color6: '"magenta"' - color7: '"yellow"' - color8: '"dark red"' - color9: '"dark green"' - comment: '' - ctrlpanel: 'False' - fc: '0' - fftsize: '1024' - freqhalf: 'True' - grid: 'False' - gui_hint: 'plots@1: 0,0,1,1' - label: Relative Gain - label1: Fading - label10: '''''' - label2: '''''' - label3: '''''' - label4: '''''' - label5: '''''' - label6: '''''' - label7: '''''' - label8: '''''' - label9: '''''' - legend: 'True' - maxoutbuf: '0' - minoutbuf: '0' - name: '"Channel"' - nconnections: '2' - showports: 'False' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_tag: '""' - type: complex - units: dB - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - wintype: firdes.WIN_BLACKMAN_hARRIS - ymax: '10' - ymin: '-140' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1256.0, 560] - rotation: 270 - state: true -- name: qtgui_freq_sink_x_2_1 - id: qtgui_freq_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - average: '1.0' - axislabels: 'True' - bw: samp_rate - color1: '"blue"' - color10: '"dark blue"' - color2: '"red"' - color3: '"green"' - color4: '"black"' - color5: '"cyan"' - color6: '"magenta"' - color7: '"yellow"' - color8: '"dark red"' - color9: '"dark green"' - comment: '' - ctrlpanel: 'False' - fc: '0' - fftsize: '1024' - freqhalf: 'True' - grid: 'False' - gui_hint: 'plots@1: 1,0,1,1' - label: Relative Gain - label1: Fading - label10: '''''' - label2: '''''' - label3: '''''' - label4: '''''' - label5: '''''' - label6: '''''' - label7: '''''' - label8: '''''' - label9: '''''' - legend: 'True' - maxoutbuf: '0' - minoutbuf: '0' - name: '""' - nconnections: '2' - showports: 'False' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_tag: '""' - type: float - units: dB - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - wintype: firdes.WIN_BLACKMAN_hARRIS - ymax: '10' - ymin: '-140' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2944, 456.0] - rotation: 0 - state: true -- name: qtgui_time_sink_x_0 - id: qtgui_time_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: blue - color10: dark blue - color2: red - color3: green - color4: black - color5: cyan - color6: magenta - color7: yellow - color8: dark red - color9: dark green - comment: '' - ctrlpanel: 'False' - entags: 'True' - grid: 'False' - gui_hint: 'plots@2: 0,0,1,1' - label1: Received - label10: Signal 10 - label2: Sent - label3: Signal 3 - label4: Signal 4 - label5: Signal 5 - label6: Signal 6 - label7: Signal 7 - label8: Signal 8 - label9: Signal 9 - legend: 'True' - marker1: '-1' - marker10: '-1' - marker2: '-1' - marker3: '-1' - marker4: '-1' - marker5: '-1' - marker6: '-1' - marker7: '-1' - marker8: '-1' - marker9: '-1' - name: '"Decoded"' - nconnections: '3' - size: '1024' - srate: samp_rate - stemplot: 'False' - style1: '1' - style10: '1' - style2: '1' - style3: '1' - style4: '1' - style5: '1' - style6: '1' - style7: '1' - style8: '1' - style9: '1' - tr_chan: '0' - tr_delay: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: float - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - ylabel: Amplitude - ymax: '1' - ymin: '-1' - yunit: '""' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2912, 260.0] - rotation: 0 - state: true - -connections: -- [analog_random_source_x_0, '0', blocks_unpack_k_bits_bb_0_0, '0'] -- [analog_random_source_x_0, '0', digital_constellation_modulator_0, '0'] -- [blocks_char_to_float_0, '0', blocks_file_sink_0, '0'] -- [blocks_char_to_float_0, '0', qtgui_freq_sink_x_2_1, '0'] -- [blocks_char_to_float_0, '0', qtgui_time_sink_x_0, '0'] -- [blocks_char_to_float_0_0, '0', blocks_delay_0, '0'] -- [blocks_char_to_float_0_1, '0', qtgui_freq_sink_x_2_1, '1'] -- [blocks_char_to_float_0_1, '0', qtgui_time_sink_x_0, '2'] -- [blocks_delay_0, '0', qtgui_time_sink_x_0, '1'] -- [blocks_throttle_0, '0', channels_channel_model_0, '0'] -- [blocks_unpack_k_bits_bb_0, '0', blocks_char_to_float_0, '0'] -- [blocks_unpack_k_bits_bb_0_0, '0', blocks_char_to_float_0_0, '0'] -- [blocks_unpack_k_bits_bb_0_1, '0', blocks_char_to_float_0_1, '0'] -- [channels_channel_model_0, '0', digital_pfb_clock_sync_xxx_0_0, '0'] -- [channels_channel_model_0, '0', interp_fir_filter_xxx_0, '0'] -- [channels_channel_model_0, '0', qtgui_const_sink_x_0, '1'] -- [channels_channel_model_0, '0', qtgui_freq_sink_x_0, '1'] -- [digital_cma_equalizer_cc_0, '0', digital_costas_loop_cc_0, '0'] -- [digital_cma_equalizer_cc_0, '0', qtgui_const_sink_x_1, '0'] -- [digital_cma_equalizer_cc_0_0, '0', digital_costas_loop_cc_0_0, '0'] -- [digital_cma_equalizer_cc_0_0, '0', qtgui_const_sink_x_1, '1'] -- [digital_constellation_decoder_cb_0, '0', digital_diff_decoder_bb_0, '0'] -- [digital_constellation_decoder_cb_0_0, '0', digital_diff_decoder_bb_0_0, '0'] -- [digital_constellation_modulator_0, '0', blocks_throttle_0, '0'] -- [digital_costas_loop_cc_0, '0', digital_constellation_decoder_cb_0, '0'] -- [digital_costas_loop_cc_0, '0', qtgui_const_sink_x_2, '0'] -- [digital_costas_loop_cc_0_0, '0', digital_constellation_decoder_cb_0_0, '0'] -- [digital_costas_loop_cc_0_0, '0', qtgui_const_sink_x_2, '1'] -- [digital_diff_decoder_bb_0, '0', digital_map_bb_0, '0'] -- [digital_diff_decoder_bb_0_0, '0', digital_map_bb_0_0, '0'] -- [digital_map_bb_0, '0', blocks_unpack_k_bits_bb_0, '0'] -- [digital_map_bb_0_0, '0', blocks_unpack_k_bits_bb_0_1, '0'] -- [digital_pfb_clock_sync_xxx_0, '0', digital_cma_equalizer_cc_0, '0'] -- [digital_pfb_clock_sync_xxx_0, '0', qtgui_const_sink_x_0_0, '0'] -- [digital_pfb_clock_sync_xxx_0_0, '0', digital_cma_equalizer_cc_0_0, '0'] -- [digital_pfb_clock_sync_xxx_0_0, '0', qtgui_const_sink_x_0_0, '1'] -- [interp_fir_filter_xxx_0, '0', digital_pfb_clock_sync_xxx_0, '0'] -- [interp_fir_filter_xxx_0, '0', qtgui_const_sink_x_0, '0'] -- [interp_fir_filter_xxx_0, '0', qtgui_freq_sink_x_0, '0'] - -metadata: - file_format: 1 diff --git a/simulation/QAM_Fading/qam_fading_V2_mehrere.grc b/simulation/QAM_Fading/qam_fading_V2_mehrere.grc deleted file mode 100644 index d5444ad..0000000 --- a/simulation/QAM_Fading/qam_fading_V2_mehrere.grc +++ /dev/null @@ -1,1623 +0,0 @@ -options: - parameters: - author: Pross Naoki, Halter Sara Cinzia - category: '[GRC Hier Blocks]' - cmake_opt: '' - comment: '' - copyright: '' - description: '' - gen_cmake: 'On' - gen_linking: dynamic - generate_options: qt_gui - hier_block_src_path: '.:' - id: qam_fading - max_nouts: '0' - output_language: python - placement: (0,0) - qt_qss_theme: '' - realtime_scheduling: '1' - run: 'True' - run_command: '{python} -u {filename}' - run_options: prompt - sizing_mode: fixed - thread_safe_setters: '' - title: QAM mit Fading - window_size: '' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [8, 8] - rotation: 0 - state: enabled - -blocks: -- name: LOS_NLOS - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@2: 0,0,1,1' - label: LOS_NLOS - min_len: '200' - orient: Qt.Horizontal - rangeType: int - start: '0' - step: '1' - stop: '1' - value: '1' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [944, 444.0] - rotation: 0 - state: true -- name: amp_1 - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@2: 1,1,1,1' - label: Ampliude - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: '0.1' - stop: '5' - value: '0.2' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1056, 580.0] - rotation: 0 - state: true -- name: amp_2 - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@2: 2,1,1,1' - label: Ampliude 2 - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: '0.1' - stop: '5' - value: '0' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1064, 716.0] - rotation: 0 - state: true -- name: amp_3 - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@2: 3,1,1,1' - label: Ampliude 3 - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: '0.1' - stop: '5' - value: '0' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1064, 852.0] - rotation: 0 - state: true -- name: chn_taps - id: variable - parameters: - comment: '' - value: '[1.0 + 0.0j, ]' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [672, 236.0] - rotation: 0 - state: true -- name: const - id: variable_constellation - parameters: - comment: '' - const_points: '[-1-1j, -1+1j, 1+1j, 1-1j]' - dims: '1' - precision: '8' - rot_sym: '4' - soft_dec_lut: None - sym_map: '[0, 1, 3, 2]' - type: 16qam - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [224, 428.0] - rotation: 0 - state: true -- name: eq_gain - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@1: 0,0,1,1' - label: Equalizer Rate - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: '.001' - stop: '.1' - value: '.01' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1744, 452.0] - rotation: 0 - state: true -- name: eq_mod - id: variable - parameters: - comment: '' - value: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1744, 376.0] - rotation: 0 - state: true -- name: eq_ntaps - id: variable - parameters: - comment: '' - value: '15' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1824, 376.0] - rotation: 0 - state: true -- name: excess_bw - id: variable - parameters: - comment: '' - value: 350e-3 - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [320, 268.0] - rotation: 0 - state: true -- name: fading_1 - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@2: 1,0,1,1' - label: Fading - min_len: '200' - orient: Qt.Horizontal - rangeType: int - start: '1' - step: '1' - stop: '30' - value: '2' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [944, 580.0] - rotation: 0 - state: true -- name: fading_2 - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@2: 2,0,1,1' - label: Fading 2 - min_len: '200' - orient: Qt.Horizontal - rangeType: int - start: '0' - step: '1' - stop: '30' - value: '0' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [944, 716.0] - rotation: 0 - state: true -- name: fading_3 - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@2: 3,0,1,1' - label: Fading 3 - min_len: '200' - orient: Qt.Horizontal - rangeType: int - start: '0' - step: '1' - stop: '30' - value: '0' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [944, 852.0] - rotation: 0 - state: true -- name: freq_offset - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@0: 1,0,1,1' - label: Frequency Offset - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: -100e-3 - step: 1e-3 - stop: 100e-3 - value: '0' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [712, 476.0] - rotation: 0 - state: true -- name: nfilts - id: variable - parameters: - comment: '' - value: '32' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1408, 104.0] - rotation: 0 - state: true -- name: noise_volt - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@0: 0,0,1,1' - label: Noise Voltage - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: '0.01' - stop: '1' - value: '0.0001' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [576, 476.0] - rotation: 0 - state: true -- name: phase_bw - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@1: 1,0,1,1' - label: Phase Bandwidth - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: '.01' - stop: '1' - value: 2 * 3.141592653589793 / 100 - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2048, 420.0] - rotation: 0 - state: true -- name: rrc_taps - id: variable - parameters: - comment: '' - value: firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), excess_bw, 45*nfilts) - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1488, 104.0] - rotation: 0 - state: true -- name: samp_rate - id: variable - parameters: - comment: '' - value: '32000' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [192, 12.0] - rotation: 0 - state: enabled -- name: sps - id: variable - parameters: - comment: '' - value: '4' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [224, 268.0] - rotation: 0 - state: true -- name: time_offset - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@0: 0,1,1,1' - label: Timing Offset - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0.999' - step: '0.0001' - stop: '1.001' - value: '1.0' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [576, 620.0] - rotation: 0 - state: true -- name: timing_loop_bw - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@0: 1,1,1,1' - label: Time Bandwidth - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: 10e-3 - stop: 200e-3 - value: 2 * 3.141592653589793 / 100 - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1408, 164.0] - rotation: 0 - state: true -- name: analog_random_source_x_0 - id: analog_random_source_x - parameters: - affinity: '' - alias: '' - comment: '' - max: '256' - maxoutbuf: '0' - min: '0' - minoutbuf: '0' - num_samps: '1000' - repeat: 'True' - type: byte - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [32, 332.0] - rotation: 0 - state: enabled -- name: blocks_char_to_float_0 - id: blocks_char_to_float - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - scale: '1' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2688, 272.0] - rotation: 0 - state: true -- name: blocks_char_to_float_0_0 - id: blocks_char_to_float - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - scale: '1' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [424, 1336.0] - rotation: 0 - state: true -- name: blocks_char_to_float_0_1 - id: blocks_char_to_float - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - scale: '1' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2640, 672.0] - rotation: 0 - state: true -- name: blocks_delay_0 - id: blocks_delay - parameters: - affinity: '' - alias: '' - comment: '' - delay: '50' - maxoutbuf: '0' - minoutbuf: '0' - num_ports: '1' - type: float - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2736, 1360.0] - rotation: 0 - state: true -- name: blocks_file_sink_0 - id: blocks_file_sink - parameters: - affinity: '' - alias: '' - append: 'False' - comment: '' - file: /home/sara/Documents/Fading/simulation/QAM_Fading/qam_fading_V2_output.grc - type: float - unbuffered: 'False' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2880, 84.0] - rotation: 0 - state: disabled -- name: blocks_throttle_0 - id: blocks_throttle - parameters: - affinity: '' - alias: '' - comment: '' - ignoretag: 'True' - maxoutbuf: '0' - minoutbuf: '0' - samples_per_second: samp_rate - type: complex - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [464, 356.0] - rotation: 0 - state: enabled -- name: blocks_unpack_k_bits_bb_0 - id: blocks_unpack_k_bits_bb - parameters: - affinity: '' - alias: '' - comment: '' - k: '2' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2608, 432.0] - rotation: 0 - state: true -- name: blocks_unpack_k_bits_bb_0_0 - id: blocks_unpack_k_bits_bb - parameters: - affinity: '' - alias: '' - comment: '' - k: '2' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [248, 1336.0] - rotation: 0 - state: true -- name: blocks_unpack_k_bits_bb_0_1 - id: blocks_unpack_k_bits_bb - parameters: - affinity: '' - alias: '' - comment: '' - k: '2' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2544, 848.0] - rotation: 0 - state: true -- name: channels_channel_model_0 - id: channels_channel_model - parameters: - affinity: '' - alias: '' - block_tags: 'False' - comment: '' - epsilon: time_offset - freq_offset: freq_offset - maxoutbuf: '0' - minoutbuf: '0' - noise_voltage: noise_volt - seed: '0' - taps: chn_taps - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [648, 316.0] - rotation: 0 - state: enabled -- name: digital_cma_equalizer_cc_0 - id: digital_cma_equalizer_cc - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - modulus: eq_mod - mu: eq_gain - num_taps: eq_ntaps - sps: '2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1744, 276.0] - rotation: 0 - state: true -- name: digital_cma_equalizer_cc_0_0 - id: digital_cma_equalizer_cc - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - modulus: eq_mod - mu: eq_gain - num_taps: eq_ntaps - sps: '2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1664, 932.0] - rotation: 0 - state: true -- name: digital_constellation_decoder_cb_0 - id: digital_constellation_decoder_cb - parameters: - affinity: '' - alias: '' - comment: '' - constellation: const - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2384, 272.0] - rotation: 0 - state: true -- name: digital_constellation_decoder_cb_0_0 - id: digital_constellation_decoder_cb - parameters: - affinity: '' - alias: '' - comment: '' - constellation: const - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2320, 656.0] - rotation: 0 - state: true -- name: digital_constellation_modulator_0 - id: digital_constellation_modulator - parameters: - affinity: '' - alias: '' - comment: '' - constellation: const - differential: 'True' - excess_bw: excess_bw - log: 'False' - maxoutbuf: '0' - minoutbuf: '0' - samples_per_symbol: sps - verbose: 'False' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [224, 332.0] - rotation: 0 - state: enabled -- name: digital_costas_loop_cc_0 - id: digital_costas_loop_cc - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - order: '4' - use_snr: 'False' - w: phase_bw - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2048, 264.0] - rotation: 0 - state: true -- name: digital_costas_loop_cc_0_0 - id: digital_costas_loop_cc - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - order: '4' - use_snr: 'False' - w: phase_bw - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1984, 928.0] - rotation: 0 - state: true -- name: digital_diff_decoder_bb_0 - id: digital_diff_decoder_bb - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - modulus: '4' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2384, 336.0] - rotation: 180 - state: true -- name: digital_diff_decoder_bb_0_0 - id: digital_diff_decoder_bb - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - modulus: '4' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2352, 736.0] - rotation: 180 - state: true -- name: digital_map_bb_0 - id: digital_map_bb - parameters: - affinity: '' - alias: '' - comment: '' - map: '[0, 1, 3, 2]' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2400, 432.0] - rotation: 0 - state: true -- name: digital_map_bb_0_0 - id: digital_map_bb - parameters: - affinity: '' - alias: '' - comment: '' - map: '[0, 1, 3, 2]' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2368, 848.0] - rotation: 0 - state: true -- name: digital_pfb_clock_sync_xxx_0 - id: digital_pfb_clock_sync_xxx - parameters: - affinity: '' - alias: '' - comment: '' - filter_size: nfilts - init_phase: nfilts/2 - loop_bw: timing_loop_bw - max_dev: '1.5' - maxoutbuf: '0' - minoutbuf: '0' - osps: '1' - sps: sps - taps: rrc_taps - type: ccf - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1408, 300.0] - rotation: 0 - state: true -- name: digital_pfb_clock_sync_xxx_0_0 - id: digital_pfb_clock_sync_xxx - parameters: - affinity: '' - alias: '' - comment: '' - filter_size: nfilts - init_phase: nfilts/2 - loop_bw: timing_loop_bw - max_dev: '1.5' - maxoutbuf: '0' - minoutbuf: '0' - osps: '1' - sps: 'sps ' - taps: rrc_taps - type: ccf - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1016, 1204.0] - rotation: 0 - state: true -- name: import_0 - id: import - parameters: - alias: '' - comment: '' - imports: import numpy as np - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [600, 20.0] - rotation: 0 - state: true -- name: interp_fir_filter_xxx_0 - id: interp_fir_filter_xxx - parameters: - affinity: '' - alias: '' - comment: '' - interp: '1' - maxoutbuf: '0' - minoutbuf: '0' - samp_delay: '0' - taps: '[LOS_NLOS]+(([0]*fading_1)+[amp_1])+(([0]*fading_2)+[amp_2])+(([0]*fading_3)+[amp_3])' - type: ccc - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [992, 340.0] - rotation: 0 - state: enabled -- name: params - id: qtgui_tab_widget - parameters: - alias: '' - comment: '' - gui_hint: '' - label0: Channel - label1: Receiver - label10: Tab 10 - label11: Tab 11 - label12: Tab 12 - label13: Tab 13 - label14: Tab 14 - label15: Tab 15 - label16: Tab 16 - label17: Tab 17 - label18: Tab 18 - label19: Tab 19 - label2: Fading - label3: Tab 3 - label4: Tab 4 - label5: Tab 5 - label6: Tab 6 - label7: Tab 7 - label8: Tab 8 - label9: Tab 9 - num_tabs: '3' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [296, 12.0] - rotation: 0 - state: true -- name: plots - id: qtgui_tab_widget - parameters: - alias: '' - comment: '' - gui_hint: '' - label0: Constellations - label1: Frequency - label10: Tab 10 - label11: Tab 11 - label12: Tab 12 - label13: Tab 13 - label14: Tab 14 - label15: Tab 15 - label16: Tab 16 - label17: Tab 17 - label18: Tab 18 - label19: Tab 19 - label2: Time - label3: Tab 3 - label4: Tab 4 - label5: Tab 5 - label6: Tab 6 - label7: Tab 7 - label8: Tab 8 - label9: Tab 9 - num_tabs: '3' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [448, 12.0] - rotation: 0 - state: true -- name: qtgui_const_sink_x_0 - id: qtgui_const_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: '"blue"' - color10: '"red"' - color2: '"red"' - color3: '"red"' - color4: '"red"' - color5: '"red"' - color6: '"red"' - color7: '"red"' - color8: '"red"' - color9: '"red"' - comment: '' - grid: 'False' - gui_hint: 'plots@0: 0,0,1,1' - label1: fading - label10: '' - label2: normal - label3: '' - label4: '' - label5: '' - label6: '' - label7: '' - label8: '' - label9: '' - legend: 'True' - marker1: '0' - marker10: '0' - marker2: '0' - marker3: '0' - marker4: '0' - marker5: '0' - marker6: '0' - marker7: '0' - marker8: '0' - marker9: '0' - name: '"Channel"' - nconnections: '2' - size: '2048' - style1: '0' - style10: '0' - style2: '0' - style3: '0' - style4: '0' - style5: '0' - style6: '0' - style7: '0' - style8: '0' - style9: '0' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: complex - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - xmax: '2' - xmin: '-2' - ymax: '2' - ymin: '-2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1052.0, -48] - rotation: 90 - state: enabled -- name: qtgui_const_sink_x_0_0 - id: qtgui_const_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: '"blue"' - color10: '"red"' - color2: '"red"' - color3: '"red"' - color4: '"red"' - color5: '"red"' - color6: '"red"' - color7: '"red"' - color8: '"red"' - color9: '"red"' - comment: '' - grid: 'False' - gui_hint: 'plots@0: 0,1,1,1' - label1: fading - label10: '' - label2: normal - label3: '' - label4: '' - label5: '' - label6: '' - label7: '' - label8: '' - label9: '' - legend: 'True' - marker1: '0' - marker10: '0' - marker2: '0' - marker3: '0' - marker4: '0' - marker5: '0' - marker6: '0' - marker7: '0' - marker8: '0' - marker9: '0' - name: '"Synchronized"' - nconnections: '2' - size: '2048' - style1: '0' - style10: '0' - style2: '0' - style3: '0' - style4: '0' - style5: '0' - style6: '0' - style7: '0' - style8: '0' - style9: '0' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: complex - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - xmax: '2' - xmin: '-2' - ymax: '2' - ymin: '-2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1656.0, 56] - rotation: 90 - state: enabled -- name: qtgui_const_sink_x_1 - id: qtgui_const_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: '"blue"' - color10: '"red"' - color2: '"red"' - color3: '"red"' - color4: '"red"' - color5: '"red"' - color6: '"red"' - color7: '"red"' - color8: '"red"' - color9: '"red"' - comment: '' - grid: 'False' - gui_hint: 'plots@0: 1,0,1,1' - label1: fading - label10: '' - label2: normal - label3: '' - label4: '' - label5: '' - label6: '' - label7: '' - label8: '' - label9: '' - legend: 'True' - marker1: '0' - marker10: '0' - marker2: '0' - marker3: '0' - marker4: '0' - marker5: '0' - marker6: '0' - marker7: '0' - marker8: '0' - marker9: '0' - name: '"Equalized"' - nconnections: '2' - size: '1024' - style1: '0' - style10: '0' - style2: '0' - style3: '0' - style4: '0' - style5: '0' - style6: '0' - style7: '0' - style8: '0' - style9: '0' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: complex - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - xmax: '2' - xmin: '-2' - ymax: '2' - ymin: '-2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1896.0, 24] - rotation: 90 - state: true -- name: qtgui_const_sink_x_2 - id: qtgui_const_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: '"blue"' - color10: '"red"' - color2: '"red"' - color3: '"red"' - color4: '"red"' - color5: '"red"' - color6: '"red"' - color7: '"red"' - color8: '"red"' - color9: '"red"' - comment: '' - grid: 'False' - gui_hint: 'plots@0: 1,1,1,1' - label1: fading - label10: '' - label2: normal - label3: '' - label4: '' - label5: '' - label6: '' - label7: '' - label8: '' - label9: '' - legend: 'True' - marker1: '0' - marker10: '0' - marker2: '0' - marker3: '0' - marker4: '0' - marker5: '0' - marker6: '0' - marker7: '0' - marker8: '0' - marker9: '0' - name: '"Locked"' - nconnections: '2' - size: '1024' - style1: '0' - style10: '0' - style2: '0' - style3: '0' - style4: '0' - style5: '0' - style6: '0' - style7: '0' - style8: '0' - style9: '0' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: complex - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - xmax: '2' - xmin: '-2' - ymax: '2' - ymin: '-2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2280.0, -24] - rotation: 90 - state: true -- name: qtgui_freq_sink_x_0 - id: qtgui_freq_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - average: '1.0' - axislabels: 'True' - bw: samp_rate - color1: '"blue"' - color10: '"dark blue"' - color2: '"red"' - color3: '"green"' - color4: '"black"' - color5: '"cyan"' - color6: '"magenta"' - color7: '"yellow"' - color8: '"dark red"' - color9: '"dark green"' - comment: '' - ctrlpanel: 'False' - fc: '0' - fftsize: '1024' - freqhalf: 'True' - grid: 'False' - gui_hint: 'plots@1: 0,0,1,1' - label: Relative Gain - label1: Fading - label10: '''''' - label2: '''''' - label3: '''''' - label4: '''''' - label5: '''''' - label6: '''''' - label7: '''''' - label8: '''''' - label9: '''''' - legend: 'True' - maxoutbuf: '0' - minoutbuf: '0' - name: '"Channel"' - nconnections: '2' - showports: 'False' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_tag: '""' - type: complex - units: dB - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - wintype: firdes.WIN_BLACKMAN_hARRIS - ymax: '10' - ymin: '-140' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1256.0, 560] - rotation: 270 - state: true -- name: qtgui_freq_sink_x_2_1 - id: qtgui_freq_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - average: '1.0' - axislabels: 'True' - bw: samp_rate - color1: '"blue"' - color10: '"dark blue"' - color2: '"red"' - color3: '"green"' - color4: '"black"' - color5: '"cyan"' - color6: '"magenta"' - color7: '"yellow"' - color8: '"dark red"' - color9: '"dark green"' - comment: '' - ctrlpanel: 'False' - fc: '0' - fftsize: '1024' - freqhalf: 'True' - grid: 'False' - gui_hint: 'plots@1: 1,0,1,1' - label: Relative Gain - label1: Fading - label10: '''''' - label2: '''''' - label3: '''''' - label4: '''''' - label5: '''''' - label6: '''''' - label7: '''''' - label8: '''''' - label9: '''''' - legend: 'True' - maxoutbuf: '0' - minoutbuf: '0' - name: '""' - nconnections: '2' - showports: 'False' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_tag: '""' - type: float - units: dB - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - wintype: firdes.WIN_BLACKMAN_hARRIS - ymax: '10' - ymin: '-140' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2944, 456.0] - rotation: 0 - state: true -- name: qtgui_time_sink_x_0 - id: qtgui_time_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: blue - color10: dark blue - color2: red - color3: green - color4: black - color5: cyan - color6: magenta - color7: yellow - color8: dark red - color9: dark green - comment: '' - ctrlpanel: 'False' - entags: 'True' - grid: 'False' - gui_hint: 'plots@2: 0,0,1,1' - label1: Received - label10: Signal 10 - label2: Sent - label3: Signal 3 - label4: Signal 4 - label5: Signal 5 - label6: Signal 6 - label7: Signal 7 - label8: Signal 8 - label9: Signal 9 - legend: 'True' - marker1: '-1' - marker10: '-1' - marker2: '-1' - marker3: '-1' - marker4: '-1' - marker5: '-1' - marker6: '-1' - marker7: '-1' - marker8: '-1' - marker9: '-1' - name: '"Decoded"' - nconnections: '3' - size: '1024' - srate: samp_rate - stemplot: 'False' - style1: '1' - style10: '1' - style2: '1' - style3: '1' - style4: '1' - style5: '1' - style6: '1' - style7: '1' - style8: '1' - style9: '1' - tr_chan: '0' - tr_delay: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: float - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - ylabel: Amplitude - ymax: '1' - ymin: '-1' - yunit: '""' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2912, 260.0] - rotation: 0 - state: true - -connections: -- [analog_random_source_x_0, '0', blocks_unpack_k_bits_bb_0_0, '0'] -- [analog_random_source_x_0, '0', digital_constellation_modulator_0, '0'] -- [blocks_char_to_float_0, '0', blocks_file_sink_0, '0'] -- [blocks_char_to_float_0, '0', qtgui_freq_sink_x_2_1, '0'] -- [blocks_char_to_float_0, '0', qtgui_time_sink_x_0, '0'] -- [blocks_char_to_float_0_0, '0', blocks_delay_0, '0'] -- [blocks_char_to_float_0_1, '0', qtgui_freq_sink_x_2_1, '1'] -- [blocks_char_to_float_0_1, '0', qtgui_time_sink_x_0, '2'] -- [blocks_delay_0, '0', qtgui_time_sink_x_0, '1'] -- [blocks_throttle_0, '0', channels_channel_model_0, '0'] -- [blocks_unpack_k_bits_bb_0, '0', blocks_char_to_float_0, '0'] -- [blocks_unpack_k_bits_bb_0_0, '0', blocks_char_to_float_0_0, '0'] -- [blocks_unpack_k_bits_bb_0_1, '0', blocks_char_to_float_0_1, '0'] -- [channels_channel_model_0, '0', digital_pfb_clock_sync_xxx_0_0, '0'] -- [channels_channel_model_0, '0', interp_fir_filter_xxx_0, '0'] -- [channels_channel_model_0, '0', qtgui_const_sink_x_0, '1'] -- [channels_channel_model_0, '0', qtgui_freq_sink_x_0, '1'] -- [digital_cma_equalizer_cc_0, '0', digital_costas_loop_cc_0, '0'] -- [digital_cma_equalizer_cc_0, '0', qtgui_const_sink_x_1, '0'] -- [digital_cma_equalizer_cc_0_0, '0', digital_costas_loop_cc_0_0, '0'] -- [digital_cma_equalizer_cc_0_0, '0', qtgui_const_sink_x_1, '1'] -- [digital_constellation_decoder_cb_0, '0', digital_diff_decoder_bb_0, '0'] -- [digital_constellation_decoder_cb_0_0, '0', digital_diff_decoder_bb_0_0, '0'] -- [digital_constellation_modulator_0, '0', blocks_throttle_0, '0'] -- [digital_costas_loop_cc_0, '0', digital_constellation_decoder_cb_0, '0'] -- [digital_costas_loop_cc_0, '0', qtgui_const_sink_x_2, '0'] -- [digital_costas_loop_cc_0_0, '0', digital_constellation_decoder_cb_0_0, '0'] -- [digital_costas_loop_cc_0_0, '0', qtgui_const_sink_x_2, '1'] -- [digital_diff_decoder_bb_0, '0', digital_map_bb_0, '0'] -- [digital_diff_decoder_bb_0_0, '0', digital_map_bb_0_0, '0'] -- [digital_map_bb_0, '0', blocks_unpack_k_bits_bb_0, '0'] -- [digital_map_bb_0_0, '0', blocks_unpack_k_bits_bb_0_1, '0'] -- [digital_pfb_clock_sync_xxx_0, '0', digital_cma_equalizer_cc_0, '0'] -- [digital_pfb_clock_sync_xxx_0, '0', qtgui_const_sink_x_0_0, '0'] -- [digital_pfb_clock_sync_xxx_0_0, '0', digital_cma_equalizer_cc_0_0, '0'] -- [digital_pfb_clock_sync_xxx_0_0, '0', qtgui_const_sink_x_0_0, '1'] -- [interp_fir_filter_xxx_0, '0', digital_pfb_clock_sync_xxx_0, '0'] -- [interp_fir_filter_xxx_0, '0', qtgui_const_sink_x_0, '0'] -- [interp_fir_filter_xxx_0, '0', qtgui_freq_sink_x_0, '0'] - -metadata: - file_format: 1 diff --git a/simulation/QAM_Fading/qam_fading_frequency_selectiv.grc b/simulation/QAM_Fading/qam_fading_frequency_selectiv.grc index fc3cebd..ce87db8 100644 --- a/simulation/QAM_Fading/qam_fading_frequency_selectiv.grc +++ b/simulation/QAM_Fading/qam_fading_frequency_selectiv.grc @@ -453,24 +453,24 @@ blocks: - name: channels_selective_fading_model_0 id: channels_selective_fading_model parameters: - K: '4.0' - LOS: 'False' + K: '4' + LOS: 'True' N: '8' affinity: '' alias: '' comment: '' - delays: (0.0,0.1,1.3) + delays: (0,0.3e-6) fDTs: '0' - mags: (1,0.99,0.97) + mags: (1,0.39) maxoutbuf: '0' minoutbuf: '0' - ntaps: '4' + ntaps: '3' seed: '0' states: bus_sink: false bus_source: false bus_structure: null - coordinate: [944, 316.0] + coordinate: [976, 308.0] rotation: 0 state: true - name: digital_cma_equalizer_cc_0 @@ -700,7 +700,7 @@ blocks: maxoutbuf: '0' minoutbuf: '0' osps: '1' - sps: sps * 1.001 + sps: 'sps ' taps: rrc_taps type: ccf states: @@ -867,7 +867,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1044.0, -48] + coordinate: [1036.0, -64] rotation: 90 state: enabled - name: qtgui_const_sink_x_0_0 @@ -1223,7 +1223,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1024.0, 624] + coordinate: [1080.0, 656] rotation: 270 state: true - name: qtgui_freq_sink_x_2_1 @@ -1305,7 +1305,7 @@ blocks: bus_structure: null coordinate: [2848, 488.0] rotation: 0 - state: true + state: disabled - name: qtgui_time_sink_x_0 id: qtgui_time_sink_x parameters: diff --git a/simulation/QAM_Fading/qam_fading_frequency_selectiv_copy.grc b/simulation/QAM_Fading/qam_fading_frequency_selectiv_copy.grc deleted file mode 100644 index ce87db8..0000000 --- a/simulation/QAM_Fading/qam_fading_frequency_selectiv_copy.grc +++ /dev/null @@ -1,1448 +0,0 @@ -options: - parameters: - author: Pross Naoki, Halter Sara Cinzia - category: '[GRC Hier Blocks]' - cmake_opt: '' - comment: '' - copyright: '' - description: '' - gen_cmake: 'On' - gen_linking: dynamic - generate_options: qt_gui - hier_block_src_path: '.:' - id: qam_fading - max_nouts: '0' - output_language: python - placement: (0,0) - qt_qss_theme: '' - realtime_scheduling: '1' - run: 'True' - run_command: '{python} -u {filename}' - run_options: prompt - sizing_mode: fixed - thread_safe_setters: '' - title: QAM mit Fading - window_size: '' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [8, 8] - rotation: 0 - state: enabled - -blocks: -- name: chn_taps - id: variable - parameters: - comment: '' - value: '[1.0 + 0.0j, ]' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [672, 236.0] - rotation: 0 - state: true -- name: const - id: variable_constellation - parameters: - comment: '' - const_points: '[-1-1j, -1+1j, 1+1j, 1-1j]' - dims: '1' - precision: '8' - rot_sym: '4' - soft_dec_lut: None - sym_map: '[0, 1, 3, 2]' - type: qpsk - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [224, 428.0] - rotation: 0 - state: true -- name: eq_gain - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@1: 0,0,1,1' - label: Equalizer Rate - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: '.001' - stop: '.1' - value: '.01' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1648, 476.0] - rotation: 0 - state: true -- name: eq_mod - id: variable - parameters: - comment: '' - value: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1648, 400.0] - rotation: 0 - state: true -- name: eq_ntaps - id: variable - parameters: - comment: '' - value: '15' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1728, 400.0] - rotation: 0 - state: true -- name: excess_bw - id: variable - parameters: - comment: '' - value: 350e-3 - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [320, 268.0] - rotation: 0 - state: true -- name: freq_offset - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@0: 1,0,1,1' - label: Frequency Offset - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: -100e-3 - step: 1e-3 - stop: 100e-3 - value: '0' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [712, 476.0] - rotation: 0 - state: true -- name: nfilts - id: variable - parameters: - comment: '' - value: '32' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1312, 132.0] - rotation: 0 - state: true -- name: noise_volt - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@0: 0,0,1,1' - label: Noise Voltage - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: '0.01' - stop: '1' - value: '0.0001' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [576, 476.0] - rotation: 0 - state: true -- name: phase_bw - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@1: 1,0,1,1' - label: Phase Bandwidth - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: '.01' - stop: '1' - value: 2 * 3.141592653589793 / 100 - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1952, 444.0] - rotation: 0 - state: true -- name: rrc_taps - id: variable - parameters: - comment: '' - value: firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), excess_bw, 45*nfilts) - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1376, 132.0] - rotation: 0 - state: true -- name: samp_rate - id: variable - parameters: - comment: '' - value: '32000' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [192, 12.0] - rotation: 0 - state: enabled -- name: sps - id: variable - parameters: - comment: '' - value: '4' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [224, 268.0] - rotation: 0 - state: true -- name: time_offset - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@0: 0,1,1,1' - label: Timing Offset - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0.999' - step: '0.0001' - stop: '1.001' - value: '1.0' - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [576, 620.0] - rotation: 0 - state: true -- name: timing_loop_bw - id: variable_qtgui_range - parameters: - comment: '' - gui_hint: 'params@0: 1,1,1,1' - label: Time Bandwidth - min_len: '200' - orient: Qt.Horizontal - rangeType: float - start: '0' - step: 10e-3 - stop: 200e-3 - value: 2 * 3.141592653589793 / 100 - widget: counter_slider - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1312, 196.0] - rotation: 0 - state: true -- name: analog_random_source_x_0 - id: analog_random_source_x - parameters: - affinity: '' - alias: '' - comment: '' - max: '256' - maxoutbuf: '0' - min: '0' - minoutbuf: '0' - num_samps: '1000' - repeat: 'True' - type: byte - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [32, 332.0] - rotation: 0 - state: enabled -- name: blocks_char_to_float_0 - id: blocks_char_to_float - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - scale: '1' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2592, 296.0] - rotation: 0 - state: true -- name: blocks_char_to_float_0_0 - id: blocks_char_to_float - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - scale: '1' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [424, 1336.0] - rotation: 0 - state: true -- name: blocks_char_to_float_0_1 - id: blocks_char_to_float - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - scale: '1' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2544, 692.0] - rotation: 0 - state: true -- name: blocks_delay_0 - id: blocks_delay - parameters: - affinity: '' - alias: '' - comment: '' - delay: '50' - maxoutbuf: '0' - minoutbuf: '0' - num_ports: '1' - type: float - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2624, 1352.0] - rotation: 0 - state: true -- name: blocks_throttle_0 - id: blocks_throttle - parameters: - affinity: '' - alias: '' - comment: '' - ignoretag: 'True' - maxoutbuf: '0' - minoutbuf: '0' - samples_per_second: samp_rate - type: complex - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [464, 356.0] - rotation: 0 - state: enabled -- name: blocks_unpack_k_bits_bb_0 - id: blocks_unpack_k_bits_bb - parameters: - affinity: '' - alias: '' - comment: '' - k: '2' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2512, 456.0] - rotation: 0 - state: true -- name: blocks_unpack_k_bits_bb_0_0 - id: blocks_unpack_k_bits_bb - parameters: - affinity: '' - alias: '' - comment: '' - k: '2' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [248, 1336.0] - rotation: 0 - state: true -- name: blocks_unpack_k_bits_bb_0_1 - id: blocks_unpack_k_bits_bb - parameters: - affinity: '' - alias: '' - comment: '' - k: '2' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2448, 868.0] - rotation: 0 - state: true -- name: channels_channel_model_0 - id: channels_channel_model - parameters: - affinity: '' - alias: '' - block_tags: 'False' - comment: '' - epsilon: time_offset - freq_offset: freq_offset - maxoutbuf: '0' - minoutbuf: '0' - noise_voltage: noise_volt - seed: '0' - taps: chn_taps - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [648, 316.0] - rotation: 0 - state: enabled -- name: channels_selective_fading_model_0 - id: channels_selective_fading_model - parameters: - K: '4' - LOS: 'True' - N: '8' - affinity: '' - alias: '' - comment: '' - delays: (0,0.3e-6) - fDTs: '0' - mags: (1,0.39) - maxoutbuf: '0' - minoutbuf: '0' - ntaps: '3' - seed: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [976, 308.0] - rotation: 0 - state: true -- name: digital_cma_equalizer_cc_0 - id: digital_cma_equalizer_cc - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - modulus: eq_mod - mu: eq_gain - num_taps: eq_ntaps - sps: '2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1648, 304.0] - rotation: 0 - state: true -- name: digital_cma_equalizer_cc_0_0 - id: digital_cma_equalizer_cc - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - modulus: eq_mod - mu: eq_gain - num_taps: eq_ntaps - sps: '2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1600, 724.0] - rotation: 0 - state: true -- name: digital_constellation_decoder_cb_0 - id: digital_constellation_decoder_cb - parameters: - affinity: '' - alias: '' - comment: '' - constellation: const - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2288, 296.0] - rotation: 0 - state: true -- name: digital_constellation_decoder_cb_0_0 - id: digital_constellation_decoder_cb - parameters: - affinity: '' - alias: '' - comment: '' - constellation: const - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2224, 684.0] - rotation: 0 - state: true -- name: digital_constellation_modulator_0 - id: digital_constellation_modulator - parameters: - affinity: '' - alias: '' - comment: '' - constellation: const - differential: 'True' - excess_bw: excess_bw - log: 'False' - maxoutbuf: '0' - minoutbuf: '0' - samples_per_symbol: sps - verbose: 'False' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [224, 332.0] - rotation: 0 - state: enabled -- name: digital_costas_loop_cc_0 - id: digital_costas_loop_cc - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - order: '4' - use_snr: 'False' - w: phase_bw - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1952, 296.0] - rotation: 0 - state: true -- name: digital_costas_loop_cc_0_0 - id: digital_costas_loop_cc - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - order: '4' - use_snr: 'False' - w: phase_bw - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1936, 688.0] - rotation: 0 - state: true -- name: digital_diff_decoder_bb_0 - id: digital_diff_decoder_bb - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - modulus: '4' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2288, 360.0] - rotation: 180 - state: true -- name: digital_diff_decoder_bb_0_0 - id: digital_diff_decoder_bb - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - modulus: '4' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2264, 764.0] - rotation: 180 - state: true -- name: digital_map_bb_0 - id: digital_map_bb - parameters: - affinity: '' - alias: '' - comment: '' - map: '[0, 1, 3, 2]' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2304, 456.0] - rotation: 0 - state: true -- name: digital_map_bb_0_0 - id: digital_map_bb - parameters: - affinity: '' - alias: '' - comment: '' - map: '[0, 1, 3, 2]' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2272, 868.0] - rotation: 0 - state: true -- name: digital_pfb_clock_sync_xxx_0 - id: digital_pfb_clock_sync_xxx - parameters: - affinity: '' - alias: '' - comment: '' - filter_size: nfilts - init_phase: nfilts/2 - loop_bw: timing_loop_bw - max_dev: '1.5' - maxoutbuf: '0' - minoutbuf: '0' - osps: '1' - sps: sps * 1.001 - taps: rrc_taps - type: ccf - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1312, 324.0] - rotation: 0 - state: true -- name: digital_pfb_clock_sync_xxx_0_0 - id: digital_pfb_clock_sync_xxx - parameters: - affinity: '' - alias: '' - comment: '' - filter_size: nfilts - init_phase: nfilts/2 - loop_bw: timing_loop_bw - max_dev: '1.5' - maxoutbuf: '0' - minoutbuf: '0' - osps: '1' - sps: 'sps ' - taps: rrc_taps - type: ccf - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1088, 868.0] - rotation: 0 - state: true -- name: params - id: qtgui_tab_widget - parameters: - alias: '' - comment: '' - gui_hint: '' - label0: Channel - label1: Receiver - label10: Tab 10 - label11: Tab 11 - label12: Tab 12 - label13: Tab 13 - label14: Tab 14 - label15: Tab 15 - label16: Tab 16 - label17: Tab 17 - label18: Tab 18 - label19: Tab 19 - label2: Tab 2 - label3: Tab 3 - label4: Tab 4 - label5: Tab 5 - label6: Tab 6 - label7: Tab 7 - label8: Tab 8 - label9: Tab 9 - num_tabs: '2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [296, 12.0] - rotation: 0 - state: true -- name: plots - id: qtgui_tab_widget - parameters: - alias: '' - comment: '' - gui_hint: '' - label0: Constellations - label1: Frequency - label10: Tab 10 - label11: Tab 11 - label12: Tab 12 - label13: Tab 13 - label14: Tab 14 - label15: Tab 15 - label16: Tab 16 - label17: Tab 17 - label18: Tab 18 - label19: Tab 19 - label2: Time - label3: Tab 3 - label4: Tab 4 - label5: Tab 5 - label6: Tab 6 - label7: Tab 7 - label8: Tab 8 - label9: Tab 9 - num_tabs: '3' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [448, 12.0] - rotation: 0 - state: true -- name: qtgui_const_sink_x_0 - id: qtgui_const_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: '"blue"' - color10: '"red"' - color2: '"red"' - color3: '"red"' - color4: '"red"' - color5: '"red"' - color6: '"red"' - color7: '"red"' - color8: '"red"' - color9: '"red"' - comment: '' - grid: 'False' - gui_hint: 'plots@0: 0,0,1,1' - label1: Fading - label10: '' - label2: '' - label3: '' - label4: '' - label5: '' - label6: '' - label7: '' - label8: '' - label9: '' - legend: 'True' - marker1: '0' - marker10: '0' - marker2: '0' - marker3: '0' - marker4: '0' - marker5: '0' - marker6: '0' - marker7: '0' - marker8: '0' - marker9: '0' - name: '"Channel"' - nconnections: '2' - size: '2048' - style1: '0' - style10: '0' - style2: '0' - style3: '0' - style4: '0' - style5: '0' - style6: '0' - style7: '0' - style8: '0' - style9: '0' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: complex - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - xmax: '2' - xmin: '-2' - ymax: '2' - ymin: '-2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1036.0, -64] - rotation: 90 - state: enabled -- name: qtgui_const_sink_x_0_0 - id: qtgui_const_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: '"blue"' - color10: '"red"' - color2: '"red"' - color3: '"red"' - color4: '"red"' - color5: '"red"' - color6: '"red"' - color7: '"red"' - color8: '"red"' - color9: '"red"' - comment: '' - grid: 'False' - gui_hint: 'plots@0: 0,1,1,1' - label1: Fading - label10: '' - label2: '' - label3: '' - label4: '' - label5: '' - label6: '' - label7: '' - label8: '' - label9: '' - legend: 'True' - marker1: '0' - marker10: '0' - marker2: '0' - marker3: '0' - marker4: '0' - marker5: '0' - marker6: '0' - marker7: '0' - marker8: '0' - marker9: '0' - name: '"Synchronized"' - nconnections: '2' - size: '2048' - style1: '0' - style10: '0' - style2: '0' - style3: '0' - style4: '0' - style5: '0' - style6: '0' - style7: '0' - style8: '0' - style9: '0' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: complex - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - xmax: '2' - xmin: '-2' - ymax: '2' - ymin: '-2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1572.0, 80] - rotation: 90 - state: enabled -- name: qtgui_const_sink_x_1 - id: qtgui_const_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: '"blue"' - color10: '"red"' - color2: '"red"' - color3: '"red"' - color4: '"red"' - color5: '"red"' - color6: '"red"' - color7: '"red"' - color8: '"red"' - color9: '"red"' - comment: '' - grid: 'False' - gui_hint: 'plots@0: 1,0,1,1' - label1: Fading - label10: '' - label2: '' - label3: '' - label4: '' - label5: '' - label6: '' - label7: '' - label8: '' - label9: '' - legend: 'True' - marker1: '0' - marker10: '0' - marker2: '0' - marker3: '0' - marker4: '0' - marker5: '0' - marker6: '0' - marker7: '0' - marker8: '0' - marker9: '0' - name: '"Equalized"' - nconnections: '2' - size: '1024' - style1: '0' - style10: '0' - style2: '0' - style3: '0' - style4: '0' - style5: '0' - style6: '0' - style7: '0' - style8: '0' - style9: '0' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: complex - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - xmax: '2' - xmin: '-2' - ymax: '2' - ymin: '-2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1828.0, 96] - rotation: 90 - state: true -- name: qtgui_const_sink_x_2 - id: qtgui_const_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: '"blue"' - color10: '"red"' - color2: '"red"' - color3: '"red"' - color4: '"red"' - color5: '"red"' - color6: '"red"' - color7: '"red"' - color8: '"red"' - color9: '"red"' - comment: '' - grid: 'False' - gui_hint: 'plots@0: 1,1,1,1' - label1: Fading - label10: '' - label2: '' - label3: '' - label4: '' - label5: '' - label6: '' - label7: '' - label8: '' - label9: '' - legend: 'True' - marker1: '0' - marker10: '0' - marker2: '0' - marker3: '0' - marker4: '0' - marker5: '0' - marker6: '0' - marker7: '0' - marker8: '0' - marker9: '0' - name: '"Locked"' - nconnections: '2' - size: '1024' - style1: '0' - style10: '0' - style2: '0' - style3: '0' - style4: '0' - style5: '0' - style6: '0' - style7: '0' - style8: '0' - style9: '0' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: complex - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - xmax: '2' - xmin: '-2' - ymax: '2' - ymin: '-2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2188.0, 0] - rotation: 90 - state: true -- name: qtgui_freq_sink_x_0 - id: qtgui_freq_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - average: '1.0' - axislabels: 'True' - bw: samp_rate - color1: '"blue"' - color10: '"dark blue"' - color2: '"red"' - color3: '"green"' - color4: '"black"' - color5: '"cyan"' - color6: '"magenta"' - color7: '"yellow"' - color8: '"dark red"' - color9: '"dark green"' - comment: '' - ctrlpanel: 'False' - fc: '0' - fftsize: '1024' - freqhalf: 'True' - grid: 'False' - gui_hint: 'plots@1: 0,0,1,1' - label: Relative Gain - label1: Fading - label10: '''''' - label2: '''''' - label3: '''''' - label4: '''''' - label5: '''''' - label6: '''''' - label7: '''''' - label8: '''''' - label9: '''''' - legend: 'True' - maxoutbuf: '0' - minoutbuf: '0' - name: '"Channel"' - nconnections: '2' - showports: 'False' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_tag: '""' - type: complex - units: dB - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - wintype: firdes.WIN_BLACKMAN_hARRIS - ymax: '10' - ymin: '-140' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1080.0, 656] - rotation: 270 - state: true -- name: qtgui_freq_sink_x_2_1 - id: qtgui_freq_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - average: '1.0' - axislabels: 'True' - bw: samp_rate - color1: '"blue"' - color10: '"dark blue"' - color2: '"red"' - color3: '"green"' - color4: '"black"' - color5: '"cyan"' - color6: '"magenta"' - color7: '"yellow"' - color8: '"dark red"' - color9: '"dark green"' - comment: '' - ctrlpanel: 'False' - fc: '0' - fftsize: '1024' - freqhalf: 'True' - grid: 'False' - gui_hint: '' - label: Relative Gain - label1: Fading - label10: '''''' - label2: '''''' - label3: '''''' - label4: '''''' - label5: '''''' - label6: '''''' - label7: '''''' - label8: '''''' - label9: '''''' - legend: 'True' - maxoutbuf: '0' - minoutbuf: '0' - name: '""' - nconnections: '2' - showports: 'False' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_tag: '""' - type: float - units: dB - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - wintype: firdes.WIN_BLACKMAN_hARRIS - ymax: '10' - ymin: '-140' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2848, 488.0] - rotation: 0 - state: disabled -- name: qtgui_time_sink_x_0 - id: qtgui_time_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'False' - axislabels: 'True' - color1: blue - color10: dark blue - color2: red - color3: green - color4: black - color5: cyan - color6: magenta - color7: yellow - color8: dark red - color9: dark green - comment: '' - ctrlpanel: 'False' - entags: 'True' - grid: 'False' - gui_hint: 'plots@2: 0,0,1,1' - label1: Received - label10: Signal 10 - label2: Sent - label3: Signal 3 - label4: Signal 4 - label5: Signal 5 - label6: Signal 6 - label7: Signal 7 - label8: Signal 8 - label9: Signal 9 - legend: 'True' - marker1: '-1' - marker10: '-1' - marker2: '-1' - marker3: '-1' - marker4: '-1' - marker5: '-1' - marker6: '-1' - marker7: '-1' - marker8: '-1' - marker9: '-1' - name: '"Decoded"' - nconnections: '3' - size: '1024' - srate: samp_rate - stemplot: 'False' - style1: '1' - style10: '1' - style2: '1' - style3: '1' - style4: '1' - style5: '1' - style6: '1' - style7: '1' - style8: '1' - style9: '1' - tr_chan: '0' - tr_delay: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: float - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - ylabel: Amplitude - ymax: '1' - ymin: '-1' - yunit: '""' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [2816, 288.0] - rotation: 0 - state: true - -connections: -- [analog_random_source_x_0, '0', blocks_unpack_k_bits_bb_0_0, '0'] -- [analog_random_source_x_0, '0', digital_constellation_modulator_0, '0'] -- [blocks_char_to_float_0, '0', qtgui_freq_sink_x_2_1, '0'] -- [blocks_char_to_float_0, '0', qtgui_time_sink_x_0, '0'] -- [blocks_char_to_float_0_0, '0', blocks_delay_0, '0'] -- [blocks_char_to_float_0_1, '0', qtgui_freq_sink_x_2_1, '1'] -- [blocks_char_to_float_0_1, '0', qtgui_time_sink_x_0, '2'] -- [blocks_delay_0, '0', qtgui_time_sink_x_0, '1'] -- [blocks_throttle_0, '0', channels_channel_model_0, '0'] -- [blocks_unpack_k_bits_bb_0, '0', blocks_char_to_float_0, '0'] -- [blocks_unpack_k_bits_bb_0_0, '0', blocks_char_to_float_0_0, '0'] -- [blocks_unpack_k_bits_bb_0_1, '0', blocks_char_to_float_0_1, '0'] -- [channels_channel_model_0, '0', channels_selective_fading_model_0, '0'] -- [channels_channel_model_0, '0', digital_pfb_clock_sync_xxx_0_0, '0'] -- [channels_channel_model_0, '0', qtgui_const_sink_x_0, '1'] -- [channels_channel_model_0, '0', qtgui_freq_sink_x_0, '1'] -- [channels_selective_fading_model_0, '0', digital_pfb_clock_sync_xxx_0, '0'] -- [channels_selective_fading_model_0, '0', qtgui_const_sink_x_0, '0'] -- [channels_selective_fading_model_0, '0', qtgui_freq_sink_x_0, '0'] -- [digital_cma_equalizer_cc_0, '0', digital_costas_loop_cc_0, '0'] -- [digital_cma_equalizer_cc_0, '0', qtgui_const_sink_x_1, '0'] -- [digital_cma_equalizer_cc_0_0, '0', digital_costas_loop_cc_0_0, '0'] -- [digital_cma_equalizer_cc_0_0, '0', qtgui_const_sink_x_1, '1'] -- [digital_constellation_decoder_cb_0, '0', digital_diff_decoder_bb_0, '0'] -- [digital_constellation_decoder_cb_0_0, '0', digital_diff_decoder_bb_0_0, '0'] -- [digital_constellation_modulator_0, '0', blocks_throttle_0, '0'] -- [digital_costas_loop_cc_0, '0', digital_constellation_decoder_cb_0, '0'] -- [digital_costas_loop_cc_0, '0', qtgui_const_sink_x_2, '0'] -- [digital_costas_loop_cc_0_0, '0', digital_constellation_decoder_cb_0_0, '0'] -- [digital_costas_loop_cc_0_0, '0', qtgui_const_sink_x_2, '1'] -- [digital_diff_decoder_bb_0, '0', digital_map_bb_0, '0'] -- [digital_diff_decoder_bb_0_0, '0', digital_map_bb_0_0, '0'] -- [digital_map_bb_0, '0', blocks_unpack_k_bits_bb_0, '0'] -- [digital_map_bb_0_0, '0', blocks_unpack_k_bits_bb_0_1, '0'] -- [digital_pfb_clock_sync_xxx_0, '0', digital_cma_equalizer_cc_0, '0'] -- [digital_pfb_clock_sync_xxx_0, '0', qtgui_const_sink_x_0_0, '0'] -- [digital_pfb_clock_sync_xxx_0_0, '0', digital_cma_equalizer_cc_0_0, '0'] -- [digital_pfb_clock_sync_xxx_0_0, '0', qtgui_const_sink_x_0_0, '1'] - -metadata: - file_format: 1 diff --git a/src/gr-fadingui/grc/fadingui_ber.block.yml b/src/gr-fadingui/grc/fadingui_ber.block.yml index 3383df5..3070311 100644 --- a/src/gr-fadingui/grc/fadingui_ber.block.yml +++ b/src/gr-fadingui/grc/fadingui_ber.block.yml @@ -4,7 +4,7 @@ category: '[fadingui]' templates: imports: import fadingui - make: fadingui.ber(vgl=${vgl}) + make: fadingui.ber(vgl=${vgl}, vlen=${vlen}) # Make one 'parameters' list entry for every parameter you want settable from the GUI. # Keys include: @@ -12,12 +12,12 @@ templates: # * label (label shown in the GUI) # * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...) parameters: - - id: vgl - label: Vergleichsparameter - dtype: raw -# - id: ... -# label: ... -# dtype: ... +- id: vgl + label: Vergleichsparameter + dtype: raw +- id: vlen + label: Vec Length + dtype: int # Make one 'inputs' list entry per input and one 'outputs' list entry per output. # Keys include: @@ -30,7 +30,7 @@ inputs: - label: in domain: stream dtype: byte - + vlen: ${vlen} # 'file_format' specifies the version of the GRC yml format used in the file # and should usually not be changed. diff --git a/src/gr-fadingui/python/ber.py b/src/gr-fadingui/python/ber.py index 387b75f..e966f17 100644 --- a/src/gr-fadingui/python/ber.py +++ b/src/gr-fadingui/python/ber.py @@ -30,26 +30,29 @@ class ber(gr.sync_block): """ docstring for block ber """ - def __init__(self, vgl): + def __init__(self, vgl, vlen): gr.sync_block.__init__(self, name="ber", - in_sig=[np.byte, ], + in_sig=[np.dtype(str(vlen) + "b")], out_sig=None) self.vgl=vgl - - + self.vlen=vlen def work(self, input_items, output_items): + inp = input_items[0] - # <+signal processing here+> - - v = self.vgl^inp - v_array= np.array(v,dtype = np.uint8) - - ber = sum(np.unpackbits(v_array)) - - - log.debug(ber) + ber_tot = 0 + log.debug(f"Length: {len(inp)}") + log.debug(f"Inp_vector:{inp}") + + for i in inp: + log.debug(f"In Schlaufe{i}") + v = np.array(self.vgl, dtype=np.uint8)^np.array(i, dtype=np.uint8) + ber = sum(np.unpackbits(v)) + log.debug(f"BER {ber} in Paket {i}") + ber_tot+=ber + log.debug(f"BER Total{ber_tot}") + return len(input_items[0]) diff --git a/src/gr-fadingui/python/qa_ber.py b/src/gr-fadingui/python/qa_ber.py index 8b6d56e..cb6c198 100755 --- a/src/gr-fadingui/python/qa_ber.py +++ b/src/gr-fadingui/python/qa_ber.py @@ -22,6 +22,7 @@ from gnuradio import gr, gr_unittest from gnuradio import blocks from ber import ber +import numpy as np class qa_ber(gr_unittest.TestCase): @@ -32,9 +33,15 @@ class qa_ber(gr_unittest.TestCase): self.tb = None def test_001_t(self): - # set up fg - self.tb.run() - # check data + # pattern = np.array([0xaa], dtype=np.uint8) + # testdata = np.array([0xc0, 0xfa, 0xae] * 4, dtype=np.uint8) + + # src = blocks.vector_source_b(testdata) + # op = ber(pattern) + + # self.tb.connect(src, op) + # self.tb.run() + pass if __name__ == '__main__': diff --git a/tests/BER/Bit_error.grc b/tests/BER/Bit_error.grc index 04c624b..1a1a891 100644 --- a/tests/BER/Bit_error.grc +++ b/tests/BER/Bit_error.grc @@ -56,6 +56,49 @@ blocks: coordinate: [216, 396.0] rotation: 0 state: enabled +- name: vlen + id: variable + parameters: + comment: '' + value: '10' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [216, 196.0] + rotation: 0 + state: true +- name: wrong + id: variable + parameters: + comment: '' + value: list(np.random.randint(0, 255, dtype=np.uint8, size=10)) + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [216, 460.0] + rotation: 0 + state: true +- name: blocks_throttle_0 + id: blocks_throttle + parameters: + affinity: '' + alias: '' + comment: '' + ignoretag: 'True' + maxoutbuf: '0' + minoutbuf: '0' + samples_per_second: samp_rate + type: byte + vlen: vlen + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [448, 292.0] + rotation: 0 + state: true - name: blocks_vector_source_x_0 id: blocks_vector_source_x parameters: @@ -67,8 +110,8 @@ blocks: repeat: 'True' tags: '[]' type: byte - vector: testvec * 1600 - vlen: '1' + vector: testvec + list(np.random.randint(0, 255, dtype=np.uint8, size=10)) + vlen: vlen states: bus_sink: false bus_source: false @@ -83,16 +126,31 @@ blocks: alias: '' comment: '' vgl: testvec + vlen: vlen + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [672, 292.0] + rotation: 0 + state: true +- name: import_0 + id: import + parameters: + alias: '' + comment: '' + imports: import numpy as np states: bus_sink: false bus_source: false bus_structure: null - coordinate: [704, 296.0] + coordinate: [328, 20.0] rotation: 0 state: true connections: -- [blocks_vector_source_x_0, '0', fadingui_ber_0, '0'] +- [blocks_throttle_0, '0', fadingui_ber_0, '0'] +- [blocks_vector_source_x_0, '0', blocks_throttle_0, '0'] metadata: file_format: 1 diff --git a/tests/BER/Test_Bit_Errorrate.py b/tests/BER/Test_Bit_Errorrate.py index 4022997..a861ae7 100755 --- a/tests/BER/Test_Bit_Errorrate.py +++ b/tests/BER/Test_Bit_Errorrate.py @@ -31,6 +31,7 @@ from argparse import ArgumentParser from gnuradio.eng_arg import eng_float, intx from gnuradio import eng_notation import fadingui +import numpy as np from gnuradio import qtgui @@ -70,21 +71,25 @@ class Test_Bit_Errorrate(gr.top_block, Qt.QWidget): ################################################## # Variables ################################################## + self.wrong = wrong = list(np.random.randint(0, 255, dtype=np.uint8, size=10)) + self.vlen = vlen = 10 self.testvec = testvec = [31, 53] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3] self.samp_rate = samp_rate = 32000 ################################################## # Blocks ################################################## - self.fadingui_ber_0 = fadingui.ber(vgl=testvec) - self.blocks_vector_source_x_0 = blocks.vector_source_b(testvec * 1600, True, 1, []) + self.fadingui_ber_0 = fadingui.ber(vgl=testvec, vlen=vlen) + self.blocks_vector_source_x_0 = blocks.vector_source_b(testvec + list(np.random.randint(0, 255, dtype=np.uint8, size=10)), True, vlen, []) + self.blocks_throttle_0 = blocks.throttle(gr.sizeof_char*vlen, samp_rate,True) ################################################## # Connections ################################################## - self.connect((self.blocks_vector_source_x_0, 0), (self.fadingui_ber_0, 0)) + self.connect((self.blocks_throttle_0, 0), (self.fadingui_ber_0, 0)) + self.connect((self.blocks_vector_source_x_0, 0), (self.blocks_throttle_0, 0)) def closeEvent(self, event): @@ -92,18 +97,31 @@ class Test_Bit_Errorrate(gr.top_block, Qt.QWidget): self.settings.setValue("geometry", self.saveGeometry()) event.accept() + def get_wrong(self): + return self.wrong + + def set_wrong(self, wrong): + self.wrong = wrong + + def get_vlen(self): + return self.vlen + + def set_vlen(self, vlen): + self.vlen = vlen + def get_testvec(self): return self.testvec def set_testvec(self, testvec): self.testvec = testvec - self.blocks_vector_source_x_0.set_data(self.testvec * 1600, []) + self.blocks_vector_source_x_0.set_data(self.testvec + list(np.random.randint(0, 255, dtype=np.uint8, size=10)), []) def get_samp_rate(self): return self.samp_rate def set_samp_rate(self, samp_rate): self.samp_rate = samp_rate + self.blocks_throttle_0.set_sample_rate(self.samp_rate) -- cgit v1.2.1 From eb385ffb0c3c41d7097fb74260f3a39c2aaeb926 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 3 Dec 2021 21:55:18 +0100 Subject: Remove frequency LPF and clean up --- tests/correlator/correlator.grc | 94 ++++++++++++++++++++--------------------- tests/correlator/epy_block_0.py | 40 ++++++------------ 2 files changed, 58 insertions(+), 76 deletions(-) diff --git a/tests/correlator/correlator.grc b/tests/correlator/correlator.grc index 0f82f27..beea007 100644 --- a/tests/correlator/correlator.grc +++ b/tests/correlator/correlator.grc @@ -193,7 +193,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1032, 1176.0] + coordinate: [1080, 1176.0] rotation: 0 state: enabled - name: blocks_multiply_const_vxx_0 @@ -505,36 +505,34 @@ blocks: parameters: _source_code: "import pmt\n\nimport numpy as np\nfrom gnuradio import gr\n\n\n\ class blk(gr.sync_block):\n def __init__(self):\n gr.sync_block.__init__(\n\ - \ self,\n name='Phase Lock',\n in_sig=[np.complex64],\n\ - \ out_sig=[np.complex64]\n )\n\n # we need to keep\ - \ track of the aboslute number of samples that have\n # been processed,\ - \ because tags have an absolute offset\n self.counter: np.uint64 = 0\n\ - \n # because we do block processing, we need to keep track of the last\ - \ tag\n # of the previous block to correct the first values of the next\ - \ block\n self.last = None\n\n # both the phase and frequency\ - \ corrections should go through a low pass\n # filter to avoid werid\ - \ jumps in the correction. to do that, there are\n # two buffers with\ - \ an index\n self.index = 0\n self.length = 5\n self.freq\ - \ = np.zeros(self.length)\n\n def lpf_freq(self, new_sample):\n #\ - \ save new sample\n self.freq[self.index] = new_sample\n # increment\ - \ index\n self.index = (self.index + 1) % self.length\n\n return\ - \ np.sum(self.freq) / self.length\n\n def block_phase(self, start, end):\n\ - \ # compute number of samples in block\n nsamples = end.offset\ - \ - start.offset\n\n # unpack pmt values into start and end phase\n \ - \ sphase = pmt.to_python(start.value)\n ephase = pmt.to_python(end.value)\n\ - \n # compute frequency offset between start and end\n # and run\ - \ it through a low pass filter (mean)\n phasediff = ephase - sphase\n\ - \n if phasediff > np.pi:\n phasediff -= 2*np.pi\n\n \ - \ elif phasediff < -np.pi:\n phasediff += 2*np.pi\n\n freq\ - \ = phasediff / nsamples\n # freq = self.lpf_freq(freq)\n\n #\ - \ debugging\n print(f\"Correction for block of {nsamples:2d} samples\ - \ is \" \\\n f\"sphase={sphase: .4f} rad and freq={freq*1e3: .4f}\ - \ milli rad / sample\")\n\n # compute block values\n return sphase\ - \ * np.ones(nsamples) + freq * np.arange(0, nsamples)\n\n def work(self,\ - \ input_items, output_items):\n # FIXME: replace class counter with local\ - \ variable\n self.counter = self.nitems_written(0)\n\n # nicer\ - \ aliases\n inp = input_items[0]\n out = output_items[0]\n\n \ - \ # read phase tags\n is_phase = lambda tag: pmt.to_python(tag.key)\ + \ self,\n name='Phase and Frequency Correction',\n \ + \ in_sig=[np.complex64],\n out_sig=[np.complex64]\n \ + \ )\n\n # tags should not be propagated, we then output our own tags\n\ + \ self.set_tag_propagation_policy(gr.TPP_DONT)\n\n # because we\ + \ do block processing, we need to keep track of the last tag\n # of the\ + \ previous block to correct the first values of the next block\n self.last\ + \ = None\n self.lastfreq = 0\n\n def block_phase(self, start, end):\n\ + \ \"\"\"\n Compute a vector for the phase and frequency correction\ + \ for the samples\n between two tags (start and end).\n\n @param\ + \ start Tag where the samples should start to be corrected\n @param end\ + \ Tag where to stop correcting\n\n @return A vector of phase values\ + \ for each sample. If we call the ouput\n `phase' to correct\ + \ the samples between the start and end tags,\n TODO: finish\n\ + \ \"\"\"\n # compute number of samples in block\n nsamples\ + \ = end.offset - start.offset\n\n # unpack pmt values into start and\ + \ end phase\n sphase = pmt.to_python(start.value)\n ephase = pmt.to_python(end.value)\n\ + \n # compute frequency offset between start and end\n phasediff\ + \ = ephase - sphase\n\n if phasediff > np.pi:\n phasediff\ + \ -= 2*np.pi\n\n elif phasediff < -np.pi:\n phasediff += 2*np.pi\n\ + \n freq = phasediff / nsamples\n\n # save this one for the last\ + \ block (see variable `end' in self.work)\n self.lastfreq = freq\n\n\ + \ # debugging\n print(f\"Correction for block of {nsamples:2d}\ + \ samples is \" \\\n f\"sphase={sphase: .4f} rad and freq={freq*1e3:\ + \ .4f} milli rad / sample\")\n\n # compute block values\n return\ + \ sphase * np.ones(nsamples) + freq * np.arange(0, nsamples)\n\n def work(self,\ + \ input_items, output_items):\n counter = self.nitems_written(0)\n\n\ + \ # nicer aliases\n inp = input_items[0]\n out = output_items[0]\n\ + \n # read phase tags\n is_phase = lambda tag: pmt.to_python(tag.key)\ \ == \"phase_est\"\n tags = list(filter(is_phase, self.get_tags_in_window(0,\ \ 0, len(inp))))\n\n if not tags:\n print(f\"There were no\ \ tags in {len(inp)} samples!\")\n out[:] = inp\n return\ @@ -546,32 +544,32 @@ blocks: \ (start, end) in pairs ]\n middle = np.concatenate(blocks) if blocks\ \ else []\n\n # compute values at the end, we do not have informations\ \ about the future\n # but we can use the frequency of the last block\ - \ to approximate\n nback = len(inp) - (tags[-1].offset - self.counter)\n\ - \ print(f\"Processing {nback} samples at the back of the buffer\")\n\ - \ endfreq = self.lpf_freq(self.freq[-1])\n end = np.ones(nback)\ - \ * pmt.to_python(tags[-1].value) + endfreq * np.arange(0, nback)\n\n \ - \ # compute the \"start\", using the last tag from the previous call\n \ - \ nfront = tags[0].offset - self.counter\n print(f\"Processing {nfront}\ - \ samples at the front of the buffer\")\n start = self.block_phase(self.last,\ - \ tags[0])[-nfront:] \\\n if self.last and nfront else np.zeros(nfront)\n\ - \n # compute correction\n correction = np.exp(-1j * np.concatenate([start,\ + \ to approximate\n nback = len(inp) - (tags[-1].offset - counter)\n \ + \ print(f\"Processing {nback} samples at the back of the buffer\")\n \ + \ end = np.ones(nback) * pmt.to_python(tags[-1].value) \\\n \ + \ + self.lastfreq * np.arange(0, nback)\n\n # compute the \"start\"\ + , using the last tag from the previous call\n nfront = tags[0].offset\ + \ - counter\n print(f\"Processing {nfront} samples at the front of the\ + \ buffer\")\n start = self.block_phase(self.last, tags[0])[-nfront:]\ + \ \\\n if self.last and nfront else np.zeros(nfront)\n\n \ + \ # compute correction\n correction = np.exp(-1j * np.concatenate([start,\ \ middle, end]))\n length = len(correction)\n\n # write outputs\n\ - \ out[:length] = inp[:length] * correction\n self.counter += len(inp)\n\ - \n # save last tag for next call\n self.last = tags[-1]\n\n \ - \ # FIXME: should return `length' but then the last sample is not\n \ - \ # included and self.last does something weird\n return len(out)\n" + \ out[:length] = inp[:length] * correction\n\n # save last tag\ + \ for next call\n self.last = tags[-1]\n\n # FIXME: should return\ + \ `length' but then the last sample is not\n # included and self.last\ + \ does something weird\n return len(out)\n" affinity: '' alias: '' comment: '' maxoutbuf: '0' minoutbuf: '0' states: - _io_cache: ('Phase Lock', 'blk', [], [('0', 'complex', 1)], [('0', 'complex', - 1)], '', []) + _io_cache: ('Phase and Frequency Correction', 'blk', [], [('0', 'complex', 1)], + [('0', 'complex', 1)], '', []) bus_sink: false bus_source: false bus_structure: null - coordinate: [1208, 912.0] + coordinate: [1072, 912.0] rotation: 0 state: enabled - name: epy_block_1 @@ -1099,7 +1097,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1376, 1152.0] + coordinate: [1376, 1156.0] rotation: 0 state: enabled - name: qtgui_time_sink_x_0_0_0 diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py index a581a3a..ddae02a 100644 --- a/tests/correlator/epy_block_0.py +++ b/tests/correlator/epy_block_0.py @@ -8,33 +8,18 @@ class blk(gr.sync_block): def __init__(self): gr.sync_block.__init__( self, - name='Phase Lock', + name='Phase and Frequency Correction', in_sig=[np.complex64], out_sig=[np.complex64] ) - # we need to keep track of the aboslute number of samples that have - # been processed, because tags have an absolute offset - self.counter: np.uint64 = 0 + # tags should not be propagated, we then output our own tags + self.set_tag_propagation_policy(gr.TPP_DONT) # because we do block processing, we need to keep track of the last tag # of the previous block to correct the first values of the next block self.last = None - - # both the phase and frequency corrections should go through a low pass - # filter to avoid werid jumps in the correction. to do that, there are - # two buffers with an index - self.index = 0 - self.length = 5 - self.freq = np.zeros(self.length) - - def lpf_freq(self, new_sample): - # save new sample - self.freq[self.index] = new_sample - # increment index - self.index = (self.index + 1) % self.length - - return np.sum(self.freq) / self.length + self.lastfreq = 0 def block_phase(self, start, end): # compute number of samples in block @@ -45,7 +30,6 @@ class blk(gr.sync_block): ephase = pmt.to_python(end.value) # compute frequency offset between start and end - # and run it through a low pass filter (mean) phasediff = ephase - sphase if phasediff > np.pi: @@ -55,7 +39,9 @@ class blk(gr.sync_block): phasediff += 2*np.pi freq = phasediff / nsamples - # freq = self.lpf_freq(freq) + + # save this one for the last block (see variable `end' in self.work) + self.lastfreq = freq # debugging print(f"Correction for block of {nsamples:2d} samples is " \ @@ -65,8 +51,7 @@ class blk(gr.sync_block): return sphase * np.ones(nsamples) + freq * np.arange(0, nsamples) def work(self, input_items, output_items): - # FIXME: replace class counter with local variable - self.counter = self.nitems_written(0) + counter = self.nitems_written(0) # nicer aliases inp = input_items[0] @@ -93,13 +78,13 @@ class blk(gr.sync_block): # compute values at the end, we do not have informations about the future # but we can use the frequency of the last block to approximate - nback = len(inp) - (tags[-1].offset - self.counter) + nback = len(inp) - (tags[-1].offset - counter) print(f"Processing {nback} samples at the back of the buffer") - endfreq = self.lpf_freq(self.freq[-1]) - end = np.ones(nback) * pmt.to_python(tags[-1].value) + endfreq * np.arange(0, nback) + end = np.ones(nback) * pmt.to_python(tags[-1].value) \ + + self.lastfreq * np.arange(0, nback) # compute the "start", using the last tag from the previous call - nfront = tags[0].offset - self.counter + nfront = tags[0].offset - counter print(f"Processing {nfront} samples at the front of the buffer") start = self.block_phase(self.last, tags[0])[-nfront:] \ if self.last and nfront else np.zeros(nfront) @@ -110,7 +95,6 @@ class blk(gr.sync_block): # write outputs out[:length] = inp[:length] * correction - self.counter += len(inp) # save last tag for next call self.last = tags[-1] -- cgit v1.2.1 From 2d02a9787d3bbd7320f23a3c65ee8e8ed0369c1e Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 3 Dec 2021 22:19:57 +0100 Subject: Replace DearPyGui Sink with Network Sink --- src/gr-fadingui/grc/CMakeLists.txt | 4 +- .../grc/fadingui_dearpygui_sink.block.yml | 38 -------------- src/gr-fadingui/grc/fadingui_netsink.block.yml | 48 ++++++++++++++++++ src/gr-fadingui/python/CMakeLists.txt | 4 +- src/gr-fadingui/python/__init__.py | 3 +- src/gr-fadingui/python/dearpygui_sink.py | 36 ------------- src/gr-fadingui/python/netsink.py | 59 ++++++++++++++++++++++ tests/sockets/send.py | 21 ++++++++ 8 files changed, 134 insertions(+), 79 deletions(-) delete mode 100644 src/gr-fadingui/grc/fadingui_dearpygui_sink.block.yml create mode 100644 src/gr-fadingui/grc/fadingui_netsink.block.yml delete mode 100644 src/gr-fadingui/python/dearpygui_sink.py create mode 100644 src/gr-fadingui/python/netsink.py create mode 100644 tests/sockets/send.py diff --git a/src/gr-fadingui/grc/CMakeLists.txt b/src/gr-fadingui/grc/CMakeLists.txt index 297ae8d..79c1a31 100644 --- a/src/gr-fadingui/grc/CMakeLists.txt +++ b/src/gr-fadingui/grc/CMakeLists.txt @@ -19,9 +19,9 @@ # Boston, MA 02110-1301, USA. install(FILES fadingui_datasource.block.yml - fadingui_dearpygui_sink.block.yml fadingui_deframer.block.yml fadingui_frame_obj.block.yml fadingui_multipath_fading.block.yml - fadingui_ber.block.yml DESTINATION share/gnuradio/grc/blocks + fadingui_ber.block.yml + fadingui_netsink.block.yml DESTINATION share/gnuradio/grc/blocks ) diff --git a/src/gr-fadingui/grc/fadingui_dearpygui_sink.block.yml b/src/gr-fadingui/grc/fadingui_dearpygui_sink.block.yml deleted file mode 100644 index dbe6198..0000000 --- a/src/gr-fadingui/grc/fadingui_dearpygui_sink.block.yml +++ /dev/null @@ -1,38 +0,0 @@ -id: fadingui_dearpygui_sink -label: UI Sink -category: '[fadingui]' - -templates: - imports: import fadingui - make: fadingui.dearpygui_sink(sock_addr=${sock_addr}, ui_element_id=${ui_element_id}) - -# Make one 'parameters' list entry for every parameter you want settable from the GUI. -# Keys include: -# * id (makes the value accessible as \$keyname, e.g. in the make entry) -# * label (label shown in the GUI) -# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...) -parameters: -- id: sock_addr - label: Socket address - dtype: string - default: udp:// - -- id: ui_element_id - label: UI element ID - dtype: raw - - -# Make one 'inputs' list entry per input and one 'outputs' list entry per output. -# Keys include: -# * label (an identifier for the GUI) -# * domain (optional - stream or message. Default is stream) -# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...) -# * vlen (optional - data stream vector length. Default is 1) -# * optional (optional - set to 1 for optional inputs. Default is 0) -inputs: -- label: in - dtype: complex - -# 'file_format' specifies the version of the GRC yml format used in the file -# and should usually not be changed. -file_format: 1 diff --git a/src/gr-fadingui/grc/fadingui_netsink.block.yml b/src/gr-fadingui/grc/fadingui_netsink.block.yml new file mode 100644 index 0000000..4e5b01b --- /dev/null +++ b/src/gr-fadingui/grc/fadingui_netsink.block.yml @@ -0,0 +1,48 @@ +id: fadingui_netsink +label: Network Sink +category: '[fadingui]' +flags: [ python ] + +templates: + imports: import fadingui + make: fadingui.netsink(${address}, ${dtype}, ${vlen}) + +# Make one 'parameters' list entry for every parameter you want settable from the GUI. +# Keys include: +# * id (makes the value accessible as \$keyname, e.g. in the make entry) +# * label (label shown in the GUI) +# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...) +parameters: +- id: dtype + label: Type + dtype: enum + options: [complex, float, int, short, byte] + option_attributes: + size: [gr.sizeof_gr_complex, gr.sizeof_floar, gr.sizeof_int, gr.sizeof_short, gr.sizeof_char ] + hide: part +- id: vlen + label: Vec Length + dtype: int + default: 1 + hide: ${ 'part' if vlen == 1 else 'none' } +- id: address + label: Address + dtype: string + default: "udp://localhost:31415" + +# Make one 'inputs' list entry per input and one 'outputs' list entry per output. +# Keys include: +# * label (an identifier for the GUI) +# * domain (optional - stream or message. Default is stream) +# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...) +# * vlen (optional - data stream vector length. Default is 1) +# * optional (optional - set to 1 for optional inputs. Default is 0) +inputs: +- label: in + domain: stream + dtype: ${dtype} + vlen: ${vlen} + +# 'file_format' specifies the version of the GRC yml format used in the file +# and should usually not be changed. +file_format: 1 diff --git a/src/gr-fadingui/python/CMakeLists.txt b/src/gr-fadingui/python/CMakeLists.txt index e04eb5b..bf484cc 100644 --- a/src/gr-fadingui/python/CMakeLists.txt +++ b/src/gr-fadingui/python/CMakeLists.txt @@ -34,11 +34,11 @@ GR_PYTHON_INSTALL( __init__.py logger.py datasource.py - dearpygui_sink.py deframer.py frame_obj.py multipath_fading.py - ber.py DESTINATION ${GR_PYTHON_DIR}/fadingui + ber.py + netsink.py DESTINATION ${GR_PYTHON_DIR}/fadingui ) ######################################################################## diff --git a/src/gr-fadingui/python/__init__.py b/src/gr-fadingui/python/__init__.py index 9fe45d5..56dbdd3 100644 --- a/src/gr-fadingui/python/__init__.py +++ b/src/gr-fadingui/python/__init__.py @@ -33,11 +33,12 @@ except ImportError: # import any pure python here from .datasource import datasource -from .dearpygui_sink import dearpygui_sink + from .deframer import deframer from .frame_obj import frame_obj from .multipath_fading import multipath_fading from .ber import ber +from .netsink import netsink # diff --git a/src/gr-fadingui/python/dearpygui_sink.py b/src/gr-fadingui/python/dearpygui_sink.py deleted file mode 100644 index 6153611..0000000 --- a/src/gr-fadingui/python/dearpygui_sink.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# Copyright 2021 Naoki Pross. - -import socket -from urllib.parse import urlparse - -import numpy as np -from gnuradio import gr - -class dearpygui_sink(gr.sync_block): - """ - DearPyGUI Sink - """ - def __init__(self, sock_addr, ui_element_id): - gr.sync_block.__init__(self, - name="dearpygui_sink", - in_sig=[np.complex64], - out_sig=None) - - # sockets - self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - self.srv = urlparse(sock_addr) - - def send(self, value): - data = value.tobytes() - sent = self.socket.sendto(data, (self.srv.hostname, self.srv.port)) - - return len(data) == sent - - def work(self, input_items, output_items): - in0 = input_items[0] - self.send(in0) - return len(input_items[0]) - diff --git a/src/gr-fadingui/python/netsink.py b/src/gr-fadingui/python/netsink.py new file mode 100644 index 0000000..9df81f5 --- /dev/null +++ b/src/gr-fadingui/python/netsink.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2021 Sara Cinzia Halter, Naoki Pross. + +import socket +from urllib.parse import urlparse + +import numpy as np +from gnuradio import gr + +class netsink(gr.sync_block): + """ + Sink that sends the data over the network using UDP. + Keep in mind that is quite slow. + """ + def __init__(self, address, dtype, vlen): + gr.sync_block.__init__(self, + name="Network Sink", + in_sig=[], + out_sig=None) + + # Create a socket and parse remote machine url + self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.url = urlparse(sock_addr) + self.srv = (self.srv.hostname, self.srv.port) + + def send(self, data): + """ + Send the data to self.srv + + @param data Data as python bytes + @return Number of bytes that were actually sent + """ + assert type(data) == bytes + return self.socket.sendto(data, self.srv) + + def encode(self, data): + """ + Encode the data into a dead simple format + + @param data Array like type + @return Bytes of ASCII encoded comma separated string of numbers + """ + # no data (what are you doing?) + if not data: + return bytes() + + values = "[" + ",".join(map(str, data)) + "]" + return bytes(values, "ascii") + + def work(self, input_items, output_items): + inp = input_items[0] + + # TODO: Check that inp has a reasonable size + self.send(self.encode(inp)) + + return len(input_items[0]) + diff --git a/tests/sockets/send.py b/tests/sockets/send.py new file mode 100644 index 0000000..87faf5d --- /dev/null +++ b/tests/sockets/send.py @@ -0,0 +1,21 @@ +import socket +from urllib.parse import urlparse + +import numpy as np + +remote = "upd://localhost:31415" +url = urlparse(remote) + +print(url.hostname) +print(url.port) + +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +sock.connect((url.hostname, url.port)) + +# sent some text +sock.send(bytes("hello", "ascii")) + +arr = np.arange(0, 10) +print(arr) + +sock.send(arr.tobytes()) -- cgit v1.2.1 From 97217d7eb3d0dbd07ea7deea1ec13620b8676e2d Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 3 Dec 2021 22:57:16 +0100 Subject: Fix network sink block The block can be tested with: $ netcat -l4kuv localhost 31415 | hexdump -C --- src/gr-fadingui/grc/fadingui_netsink.block.yml | 23 +++++++++-------- src/gr-fadingui/python/netsink.py | 35 ++++++++++++++++++-------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/gr-fadingui/grc/fadingui_netsink.block.yml b/src/gr-fadingui/grc/fadingui_netsink.block.yml index 4e5b01b..a23dc52 100644 --- a/src/gr-fadingui/grc/fadingui_netsink.block.yml +++ b/src/gr-fadingui/grc/fadingui_netsink.block.yml @@ -4,8 +4,10 @@ category: '[fadingui]' flags: [ python ] templates: - imports: import fadingui - make: fadingui.netsink(${address}, ${dtype}, ${vlen}) + imports: |- + import fadingui + import numpy as np + make: fadingui.netsink(address=${address}, dtype=${type}, vlen=${veclen}) # Make one 'parameters' list entry for every parameter you want settable from the GUI. # Keys include: @@ -13,18 +15,19 @@ templates: # * label (label shown in the GUI) # * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...) parameters: -- id: dtype +- id: type label: Type dtype: enum - options: [complex, float, int, short, byte] + options: [complex, float, int, np.short, np.byte] + option_labels: [complex, float, int, short, byte] option_attributes: - size: [gr.sizeof_gr_complex, gr.sizeof_floar, gr.sizeof_int, gr.sizeof_short, gr.sizeof_char ] + size: [gr.sizeof_gr_complex, gr.sizeof_float, gr.sizeof_int, gr.sizeof_short, gr.sizeof_char] hide: part -- id: vlen +- id: veclen label: Vec Length dtype: int - default: 1 - hide: ${ 'part' if vlen == 1 else 'none' } + default: '1' + hide: ${ 'part' if veclen == 1 else 'none' } - id: address label: Address dtype: string @@ -40,8 +43,8 @@ parameters: inputs: - label: in domain: stream - dtype: ${dtype} - vlen: ${vlen} + dtype: ${type} + vlen: ${veclen} # 'file_format' specifies the version of the GRC yml format used in the file # and should usually not be changed. diff --git a/src/gr-fadingui/python/netsink.py b/src/gr-fadingui/python/netsink.py index 9df81f5..d2dfc92 100644 --- a/src/gr-fadingui/python/netsink.py +++ b/src/gr-fadingui/python/netsink.py @@ -15,15 +15,18 @@ class netsink(gr.sync_block): Keep in mind that is quite slow. """ def __init__(self, address, dtype, vlen): + dt = np.dtype(dtype, (vlen,)) if vlen > 1 else dtype + print(dt) + gr.sync_block.__init__(self, name="Network Sink", - in_sig=[], + in_sig=[dt], out_sig=None) # Create a socket and parse remote machine url self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - self.url = urlparse(sock_addr) - self.srv = (self.srv.hostname, self.srv.port) + self.url = urlparse(address) + self.srv = (self.url.hostname, self.url.port) def send(self, data): """ @@ -42,18 +45,30 @@ class netsink(gr.sync_block): @param data Array like type @return Bytes of ASCII encoded comma separated string of numbers """ - # no data (what are you doing?) - if not data: - return bytes() - + # FIXME: this could be (very) slow, is there a faster way with numpy? values = "[" + ",".join(map(str, data)) + "]" return bytes(values, "ascii") def work(self, input_items, output_items): + # FIXME: it is probably better NOT to send *every* sample inp = input_items[0] + inp_len = len(inp) + blocksize = 1024 + + # Check that the packet is not huge + if len(inp) < blocksize: + self.send(self.encode(inp)) + else: + # compute how to split inp into blocks + nblocks = inp_len // blocksize + index = blocksize * nblocks - # TODO: Check that inp has a reasonable size - self.send(self.encode(inp)) + # send blocks + blocks = np.array(inp[:index]).reshape((blocksize, nblocks)) + for block in blocks: + self.send(self.encode(block)) - return len(input_items[0]) + # sent the rest + self.send(self.encode(inp[index:])) + return len(inp) -- cgit v1.2.1 From 13a2fda61a5cb1e6d3f807d0acda42c45e128434 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 3 Dec 2021 23:46:33 +0100 Subject: Fix correlation peak detector and add frame_start tags --- tests/correlator/correlator.grc | 502 ++++++++++------------------------------ tests/correlator/correlator.py | 17 +- tests/correlator/epy_block_0.py | 32 ++- 3 files changed, 157 insertions(+), 394 deletions(-) diff --git a/tests/correlator/correlator.grc b/tests/correlator/correlator.grc index beea007..c34e5a9 100644 --- a/tests/correlator/correlator.grc +++ b/tests/correlator/correlator.grc @@ -36,15 +36,15 @@ blocks: id: variable parameters: comment: '' - value: '[(-1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), + value: .5 * np.array([(-1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (-1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), - (1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j)]' + (1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j)]) states: bus_sink: false bus_source: false bus_structure: null - coordinate: [768, 1016.0] + coordinate: [792, 788.0] rotation: 0 state: enabled - name: const @@ -101,7 +101,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [48, 440.0] + coordinate: [784, 1052.0] rotation: 0 state: enabled - name: rrc_taps @@ -164,22 +164,6 @@ blocks: coordinate: [224, 936.0] rotation: 0 state: enabled -- name: blocks_complex_to_magphase_0 - id: blocks_complex_to_magphase - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1040, 568.0] - rotation: 0 - state: disabled - name: blocks_complex_to_magphase_0_0 id: blocks_complex_to_magphase parameters: @@ -193,27 +177,9 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1080, 1176.0] + coordinate: [1056, 984.0] rotation: 0 state: enabled -- name: blocks_multiply_const_vxx_0 - id: blocks_multiply_const_vxx - parameters: - affinity: '' - alias: '' - comment: '' - const: 180 / 3.141592653589793 - maxoutbuf: '0' - minoutbuf: '0' - type: float - vlen: '1' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1288, 596.0] - rotation: 0 - state: disabled - name: blocks_multiply_const_vxx_0_0 id: blocks_multiply_const_vxx parameters: @@ -229,7 +195,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1376, 1248.0] + coordinate: [1312, 1076.0] rotation: 0 state: disabled - name: blocks_null_sink_3 @@ -246,7 +212,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1376, 1304.0] + coordinate: [1360, 1016.0] rotation: 0 state: true - name: blocks_null_source_0 @@ -294,7 +260,7 @@ blocks: affinity: '' alias: '' comment: '' - lengths: '[5, len(testvec)]' + lengths: '[0, len(testvec)]' maxoutbuf: '0' minoutbuf: '0' num_inputs: '2' @@ -307,6 +273,43 @@ blocks: coordinate: [288, 256.0] rotation: 0 state: enabled +- name: blocks_tag_debug_0 + id: blocks_tag_debug + parameters: + affinity: '' + alias: '' + comment: '' + display: 'True' + filter: '""' + name: '' + num_inputs: '1' + type: byte + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1208, 1164.0] + rotation: 0 + state: disabled +- name: blocks_tagged_stream_align_0 + id: blocks_tagged_stream_align + parameters: + affinity: '' + alias: '' + comment: '' + lengthtagname: frame_start + maxoutbuf: '0' + minoutbuf: '0' + type: byte + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [928, 1260.0] + rotation: 0 + state: true - name: blocks_throttle_0 id: blocks_throttle parameters: @@ -354,7 +357,7 @@ blocks: block_tags: 'False' comment: '' epsilon: '1.0' - freq_offset: '0.0001' + freq_offset: '0.002' maxoutbuf: '0' minoutbuf: '0' noise_voltage: '0.01' @@ -429,18 +432,18 @@ blocks: affinity: '' alias: '' comment: '' - mark_delay: '0' + mark_delay: len(access_code_symbols) // 2 maxoutbuf: '0' minoutbuf: '0' sps: '1' symbols: access_code_symbols - threshold: '.8' - threshold_method: digital.THRESHOLD_DYNAMIC + threshold: '.9' + threshold_method: digital.THRESHOLD_ABSOLUTE states: bus_sink: false bus_source: false bus_structure: null - coordinate: [768, 892.0] + coordinate: [792, 668.0] rotation: 0 state: enabled - name: digital_costas_loop_cc_0 @@ -458,7 +461,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1080, 1000.0] + coordinate: [1104, 808.0] rotation: 0 state: true - name: digital_map_bb_0 @@ -476,7 +479,7 @@ blocks: bus_structure: null coordinate: [496, 1260.0] rotation: 0 - state: bypassed + state: enabled - name: digital_pfb_clock_sync_xxx_0 id: digital_pfb_clock_sync_xxx parameters: @@ -504,31 +507,33 @@ blocks: id: epy_block parameters: _source_code: "import pmt\n\nimport numpy as np\nfrom gnuradio import gr\n\n\n\ - class blk(gr.sync_block):\n def __init__(self):\n gr.sync_block.__init__(\n\ - \ self,\n name='Phase and Frequency Correction',\n \ - \ in_sig=[np.complex64],\n out_sig=[np.complex64]\n \ - \ )\n\n # tags should not be propagated, we then output our own tags\n\ - \ self.set_tag_propagation_policy(gr.TPP_DONT)\n\n # because we\ - \ do block processing, we need to keep track of the last tag\n # of the\ - \ previous block to correct the first values of the next block\n self.last\ - \ = None\n self.lastfreq = 0\n\n def block_phase(self, start, end):\n\ - \ \"\"\"\n Compute a vector for the phase and frequency correction\ - \ for the samples\n between two tags (start and end).\n\n @param\ - \ start Tag where the samples should start to be corrected\n @param end\ - \ Tag where to stop correcting\n\n @return A vector of phase values\ - \ for each sample. If we call the ouput\n `phase' to correct\ - \ the samples between the start and end tags,\n TODO: finish\n\ - \ \"\"\"\n # compute number of samples in block\n nsamples\ - \ = end.offset - start.offset\n\n # unpack pmt values into start and\ - \ end phase\n sphase = pmt.to_python(start.value)\n ephase = pmt.to_python(end.value)\n\ + class blk(gr.sync_block):\n \"\"\"\n Apply phase and frequency correction\ + \ where there is a correlation peak tag.\n\n The correlation peak tags are\ + \ NOT propagated, and instead replaced with a\n frame_start tag.\n \"\"\ + \"\n def __init__(self):\n gr.sync_block.__init__(\n self,\n\ + \ name='Phase and Frequency Correction',\n in_sig=[np.complex64],\n\ + \ out_sig=[np.complex64]\n )\n\n # tags should not\ + \ be propagated, we then output our own tags\n self.set_tag_propagation_policy(gr.TPP_DONT)\n\ + \n # because we do block processing, we need to keep track of the last\ + \ tag\n # of the previous block to correct the first values of the next\ + \ block\n self.last = None\n self.lastfreq = 0\n\n def block_phase(self,\ + \ start, end):\n \"\"\"\n Compute a vector for the phase and frequency\ + \ correction for the samples\n between two tags (start and end).\n\n\ + \ @param start Tag where the samples should start to be corrected\n \ + \ @param end Tag where to stop correcting\n\n @return A vector\ + \ of phase values for each sample. To correct the samples\n the\ + \ data should be multiplied with np.exp(-1j * phase)\n \"\"\"\n \ + \ # compute number of samples between tags\n nsamples = end.offset\ + \ - start.offset\n\n # unpack pmt values into start and end phase\n \ + \ sphase = pmt.to_python(start.value)\n ephase = pmt.to_python(end.value)\n\ \n # compute frequency offset between start and end\n phasediff\ \ = ephase - sphase\n\n if phasediff > np.pi:\n phasediff\ \ -= 2*np.pi\n\n elif phasediff < -np.pi:\n phasediff += 2*np.pi\n\ \n freq = phasediff / nsamples\n\n # save this one for the last\ \ block (see variable `end' in self.work)\n self.lastfreq = freq\n\n\ - \ # debugging\n print(f\"Correction for block of {nsamples:2d}\ + \ # debugging\n print(f\"Correction for chunk of {nsamples:2d}\ \ samples is \" \\\n f\"sphase={sphase: .4f} rad and freq={freq*1e3:\ - \ .4f} milli rad / sample\")\n\n # compute block values\n return\ + \ .4f} milli rad / sample\")\n\n # compute chunk values\n return\ \ sphase * np.ones(nsamples) + freq * np.arange(0, nsamples)\n\n def work(self,\ \ input_items, output_items):\n counter = self.nitems_written(0)\n\n\ \ # nicer aliases\n inp = input_items[0]\n out = output_items[0]\n\ @@ -540,14 +545,14 @@ blocks: \ = {tags[-1].offset - tags[0].offset} \" \\\n f\"samples out of\ \ {len(inp)} input samples\")\n\n # compute \"the middle\"\n enough_samples\ \ = lambda pair: ((pair[1].offset - pair[0].offset) > 0)\n pairs = list(filter(enough_samples,\ - \ zip(tags, tags[1:])))\n blocks = [ self.block_phase(start, end) for\ - \ (start, end) in pairs ]\n middle = np.concatenate(blocks) if blocks\ + \ zip(tags, tags[1:])))\n chunks = [ self.block_phase(start, end) for\ + \ (start, end) in pairs ]\n middle = np.concatenate(chunks) if chunks\ \ else []\n\n # compute values at the end, we do not have informations\ - \ about the future\n # but we can use the frequency of the last block\ - \ to approximate\n nback = len(inp) - (tags[-1].offset - counter)\n \ - \ print(f\"Processing {nback} samples at the back of the buffer\")\n \ - \ end = np.ones(nback) * pmt.to_python(tags[-1].value) \\\n \ - \ + self.lastfreq * np.arange(0, nback)\n\n # compute the \"start\"\ + \ about the future\n # but we can use the frequency of the last tag to\ + \ approximate\n nback = len(inp) - (tags[-1].offset - counter)\n \ + \ print(f\"Processing {nback} samples at the back of the buffer\")\n \ + \ end = np.ones(nback) * pmt.to_python(tags[-1].value) \\\n \ + \ + self.lastfreq * np.arange(0, nback)\n\n # compute the \"start\"\ , using the last tag from the previous call\n nfront = tags[0].offset\ \ - counter\n print(f\"Processing {nfront} samples at the front of the\ \ buffer\")\n start = self.block_phase(self.last, tags[0])[-nfront:]\ @@ -555,9 +560,11 @@ blocks: \ # compute correction\n correction = np.exp(-1j * np.concatenate([start,\ \ middle, end]))\n length = len(correction)\n\n # write outputs\n\ \ out[:length] = inp[:length] * correction\n\n # save last tag\ - \ for next call\n self.last = tags[-1]\n\n # FIXME: should return\ - \ `length' but then the last sample is not\n # included and self.last\ - \ does something weird\n return len(out)\n" + \ for next call\n self.last = tags[-1]\n\n # add tags\n \ + \ for tag in tags:\n self.add_item_tag(0, tag.offset, pmt.intern(\"\ + frame_start\"), pmt.PMT_T)\n\n # FIXME: should return `length' but then\ + \ the last sample is not\n # included and self.last does something\ + \ weird\n return len(out)\n" affinity: '' alias: '' comment: '' @@ -565,11 +572,13 @@ blocks: minoutbuf: '0' states: _io_cache: ('Phase and Frequency Correction', 'blk', [], [('0', 'complex', 1)], - [('0', 'complex', 1)], '', []) + [('0', 'complex', 1)], '\n Apply phase and frequency correction where there + is a correlation peak tag.\n\n The correlation peak tags are NOT propagated, + and instead replaced with a\n frame_start tag.\n ', []) bus_sink: false bus_source: false bus_structure: null - coordinate: [1072, 912.0] + coordinate: [1088, 688.0] rotation: 0 state: enabled - name: epy_block_1 @@ -595,7 +604,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [920, 1264.0] + coordinate: [1232, 1264.0] rotation: 0 state: true - name: fir_filter_xxx_1 @@ -614,7 +623,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [776, 692.0] + coordinate: [784, 988.0] rotation: 0 state: disabled - name: import_0 @@ -630,6 +639,23 @@ blocks: coordinate: [184, 12.0] rotation: 0 state: true +- name: note_0 + id: note + parameters: + alias: '' + comment: 'THIS FLOWGRAPH MUST BE RUN + + FROM THE TERMINAL BECAUSE + + IT HAS A HUGE OUTPUT (PRINT)' + note: README + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [280, 12.0] + rotation: 0 + state: true - name: qtgui_const_sink_x_0 id: qtgui_const_sink_x parameters: @@ -719,7 +745,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [768, 592.0] + coordinate: [792, 572.0] rotation: 0 state: enabled - name: qtgui_const_sink_x_0_0 @@ -811,198 +837,9 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1408, 964.0] + coordinate: [1416, 772.0] rotation: 0 state: enabled -- name: qtgui_const_sink_x_1 - id: qtgui_const_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '.5' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'True' - axislabels: 'True' - color1: '"blue"' - color10: '"red"' - color2: '"red"' - color3: '"red"' - color4: '"red"' - color5: '"red"' - color6: '"red"' - color7: '"red"' - color8: '"red"' - color9: '"red"' - comment: '' - grid: 'True' - gui_hint: 2,1,2,1 - label1: '' - label10: '' - label2: '' - label3: '' - label4: '' - label5: '' - label6: '' - label7: '' - label8: '' - label9: '' - legend: 'True' - marker1: '9' - marker10: '0' - marker2: '0' - marker3: '0' - marker4: '0' - marker5: '0' - marker6: '0' - marker7: '0' - marker8: '0' - marker9: '0' - name: '"Cross Correlation"' - nconnections: '1' - size: '1024' - style1: '2' - style10: '0' - style2: '0' - style3: '0' - style4: '0' - style5: '0' - style6: '0' - style7: '0' - style8: '0' - style9: '0' - tr_chan: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: complex - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - xmax: '2' - xmin: '-2' - ymax: '2' - ymin: '-2' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1040, 480.0] - rotation: 0 - state: disabled -- name: qtgui_time_sink_x_0 - id: qtgui_time_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'True' - axislabels: 'True' - color1: blue - color10: dark blue - color2: red - color3: green - color4: black - color5: cyan - color6: magenta - color7: yellow - color8: dark red - color9: dark green - comment: '' - ctrlpanel: 'False' - entags: 'True' - grid: 'False' - gui_hint: 2,0,1,1 - label1: Signal 1 - label10: Signal 10 - label2: Signal 2 - label3: Signal 3 - label4: Signal 4 - label5: Signal 5 - label6: Signal 6 - label7: Signal 7 - label8: Signal 8 - label9: Signal 9 - legend: 'True' - marker1: '-1' - marker10: '-1' - marker2: '-1' - marker3: '-1' - marker4: '-1' - marker5: '-1' - marker6: '-1' - marker7: '-1' - marker8: '-1' - marker9: '-1' - name: '""' - nconnections: '1' - size: '1024' - srate: samp_rate - stemplot: 'False' - style1: '1' - style10: '1' - style2: '1' - style3: '1' - style4: '1' - style5: '1' - style6: '1' - style7: '1' - style8: '1' - style9: '1' - tr_chan: '0' - tr_delay: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: float - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - ylabel: XC Magnitude - ymax: '20' - ymin: '0' - yunit: '""' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1312, 480.0] - rotation: 0 - state: disabled - name: qtgui_time_sink_x_0_0 id: qtgui_time_sink_x parameters: @@ -1097,7 +934,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1376, 1156.0] + coordinate: [1472, 964.0] rotation: 0 state: enabled - name: qtgui_time_sink_x_0_0_0 @@ -1194,7 +1031,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1072, 788.0] + coordinate: [1096, 572.0] rotation: 0 state: enabled - name: qtgui_time_sink_x_1_0 @@ -1291,7 +1128,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [800, 320.0] + coordinate: [800, 172.0] rotation: 0 state: enabled - name: qtgui_time_sink_x_1_1 @@ -1388,104 +1225,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [768, 480.0] - rotation: 0 - state: disabled -- name: qtgui_time_sink_x_2 - id: qtgui_time_sink_x - parameters: - affinity: '' - alias: '' - alpha1: '1.0' - alpha10: '1.0' - alpha2: '1.0' - alpha3: '1.0' - alpha4: '1.0' - alpha5: '1.0' - alpha6: '1.0' - alpha7: '1.0' - alpha8: '1.0' - alpha9: '1.0' - autoscale: 'True' - axislabels: 'True' - color1: blue - color10: dark blue - color2: red - color3: green - color4: black - color5: cyan - color6: magenta - color7: yellow - color8: dark red - color9: dark green - comment: '' - ctrlpanel: 'False' - entags: 'True' - grid: 'False' - gui_hint: 3,0,1,1 - label1: Signal 1 - label10: Signal 10 - label2: Signal 2 - label3: Signal 3 - label4: Signal 4 - label5: Signal 5 - label6: Signal 6 - label7: Signal 7 - label8: Signal 8 - label9: Signal 9 - legend: 'True' - marker1: '-1' - marker10: '-1' - marker2: '-1' - marker3: '-1' - marker4: '-1' - marker5: '-1' - marker6: '-1' - marker7: '-1' - marker8: '-1' - marker9: '-1' - name: '""' - nconnections: '1' - size: '1024' - srate: samp_rate - stemplot: 'False' - style1: '1' - style10: '1' - style2: '1' - style3: '1' - style4: '1' - style5: '1' - style6: '1' - style7: '1' - style8: '1' - style9: '1' - tr_chan: '0' - tr_delay: '0' - tr_level: '0.0' - tr_mode: qtgui.TRIG_MODE_FREE - tr_slope: qtgui.TRIG_SLOPE_POS - tr_tag: '""' - type: float - update_time: '0.10' - width1: '1' - width10: '1' - width2: '1' - width3: '1' - width4: '1' - width5: '1' - width6: '1' - width7: '1' - width8: '1' - width9: '1' - ylabel: XC Phase - ymax: '1' - ymin: '-1' - yunit: '""' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [1488, 580.0] + coordinate: [792, 484.0] rotation: 0 state: disabled - name: qtgui_time_sink_x_2_0 @@ -1582,7 +1322,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1552, 1232.0] + coordinate: [1472, 1060.0] rotation: 0 state: disabled - name: virtual_sink_0 @@ -1608,7 +1348,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [1400, 828.0] + coordinate: [1416, 684.0] rotation: 0 state: true - name: virtual_source_0 @@ -1639,16 +1379,15 @@ blocks: state: true connections: -- [blocks_complex_to_magphase_0, '0', qtgui_time_sink_x_0, '0'] -- [blocks_complex_to_magphase_0, '1', blocks_multiply_const_vxx_0, '0'] - [blocks_complex_to_magphase_0_0, '0', qtgui_time_sink_x_0_0, '0'] - [blocks_complex_to_magphase_0_0, '1', blocks_multiply_const_vxx_0_0, '0'] - [blocks_complex_to_magphase_0_0, '1', blocks_null_sink_3, '0'] -- [blocks_multiply_const_vxx_0, '0', qtgui_time_sink_x_2, '0'] - [blocks_multiply_const_vxx_0_0, '0', qtgui_time_sink_x_2_0, '0'] - [blocks_null_source_0, '0', blocks_stream_mux_0, '0'] -- [blocks_repack_bits_bb_0, '0', epy_block_1, '0'] +- [blocks_repack_bits_bb_0, '0', blocks_tagged_stream_align_0, '0'] - [blocks_stream_mux_0, '0', digital_constellation_modulator_0, '0'] +- [blocks_tagged_stream_align_0, '0', blocks_tag_debug_0, '0'] +- [blocks_tagged_stream_align_0, '0', epy_block_1, '0'] - [blocks_throttle_0, '0', virtual_sink_0, '0'] - [blocks_vector_source_x_0, '0', blocks_stream_mux_0, '1'] - [channels_channel_model_0, '0', blocks_throttle_0, '0'] @@ -1668,8 +1407,7 @@ connections: - [digital_pfb_clock_sync_xxx_0, '0', digital_cma_equalizer_cc_0, '0'] - [epy_block_0, '0', qtgui_const_sink_x_0_0, '0'] - [epy_block_0, '0', virtual_sink_3, '0'] -- [fir_filter_xxx_1, '0', blocks_complex_to_magphase_0, '0'] -- [fir_filter_xxx_1, '0', qtgui_const_sink_x_1, '0'] +- [fir_filter_xxx_1, '0', blocks_complex_to_magphase_0_0, '0'] - [virtual_source_0, '0', digital_pfb_clock_sync_xxx_0, '0'] - [virtual_source_1, '0', digital_constellation_decoder_cb_0, '0'] diff --git a/tests/correlator/correlator.py b/tests/correlator/correlator.py index 255010a..d9dedb2 100755 --- a/tests/correlator/correlator.py +++ b/tests/correlator/correlator.py @@ -85,7 +85,7 @@ class correlator(gr.top_block, Qt.QWidget): self.rrc_taps = rrc_taps = firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), excess_bw, 45*nfilts) self.revconj_access_code_symbols = revconj_access_code_symbols = [(1.4142135623730951+1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (-1.4142135623730951+1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (-1.4142135623730951+1.4142135623730951j)] self.const = const = digital.constellation_qpsk().base() - self.access_code_symbols = access_code_symbols = [(-1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (-1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j)] + self.access_code_symbols = access_code_symbols = .5 * np.array([(-1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (-1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j)]) ################################################## # Blocks @@ -332,8 +332,9 @@ class correlator(gr.top_block, Qt.QWidget): self.epy_block_1 = epy_block_1.blk() self.epy_block_0 = epy_block_0.blk() self.digital_pfb_clock_sync_xxx_0 = digital.pfb_clock_sync_ccf(sps, timing_loop_bw, rrc_taps, nfilts, 16, 1.5, 1) + self.digital_map_bb_0 = digital.map_bb([0, 1, 3, 2]) self.digital_costas_loop_cc_0 = digital.costas_loop_cc(2 * 3.141592653589793 / 100, 4, False) - self.digital_corr_est_cc_0 = digital.corr_est_cc(access_code_symbols, 1, 0, .8, digital.THRESHOLD_DYNAMIC) + self.digital_corr_est_cc_0 = digital.corr_est_cc(access_code_symbols, 1, len(access_code_symbols) // 2, .9, digital.THRESHOLD_ABSOLUTE) self.digital_constellation_modulator_0 = digital.generic_mod( constellation=const, differential=False, @@ -346,14 +347,15 @@ class correlator(gr.top_block, Qt.QWidget): self.digital_cma_equalizer_cc_0 = digital.cma_equalizer_cc(15, 1, .002, 1) self.channels_channel_model_0 = channels.channel_model( noise_voltage=0.01, - frequency_offset=0.0001, + frequency_offset=0.002, epsilon=1.0, taps=[np.exp(1j * 30 / 180 * np.pi)], noise_seed=243, block_tags=False) self.blocks_vector_source_x_0 = blocks.vector_source_b(testvec * 500, True, 1, []) self.blocks_throttle_0 = blocks.throttle(gr.sizeof_gr_complex*1, samp_rate,True) - self.blocks_stream_mux_0 = blocks.stream_mux(gr.sizeof_char*1, [5, len(testvec)]) + self.blocks_tagged_stream_align_0 = blocks.tagged_stream_align(gr.sizeof_char*1, 'frame_start') + self.blocks_stream_mux_0 = blocks.stream_mux(gr.sizeof_char*1, [0, len(testvec)]) self.blocks_repack_bits_bb_0 = blocks.repack_bits_bb(2, 8, "", False, gr.GR_MSB_FIRST) self.blocks_null_source_0 = blocks.null_source(gr.sizeof_char*1) self.blocks_null_sink_3 = blocks.null_sink(gr.sizeof_float*1) @@ -367,14 +369,15 @@ class correlator(gr.top_block, Qt.QWidget): self.connect((self.blocks_complex_to_magphase_0_0, 1), (self.blocks_null_sink_3, 0)) self.connect((self.blocks_complex_to_magphase_0_0, 0), (self.qtgui_time_sink_x_0_0, 0)) self.connect((self.blocks_null_source_0, 0), (self.blocks_stream_mux_0, 0)) - self.connect((self.blocks_repack_bits_bb_0, 0), (self.epy_block_1, 0)) + self.connect((self.blocks_repack_bits_bb_0, 0), (self.blocks_tagged_stream_align_0, 0)) self.connect((self.blocks_stream_mux_0, 0), (self.digital_constellation_modulator_0, 0)) + self.connect((self.blocks_tagged_stream_align_0, 0), (self.epy_block_1, 0)) self.connect((self.blocks_throttle_0, 0), (self.digital_pfb_clock_sync_xxx_0, 0)) self.connect((self.blocks_vector_source_x_0, 0), (self.blocks_stream_mux_0, 1)) self.connect((self.channels_channel_model_0, 0), (self.blocks_throttle_0, 0)) self.connect((self.digital_cma_equalizer_cc_0, 0), (self.digital_corr_est_cc_0, 0)) self.connect((self.digital_cma_equalizer_cc_0, 0), (self.qtgui_const_sink_x_0, 0)) - self.connect((self.digital_constellation_decoder_cb_0, 0), (self.blocks_repack_bits_bb_0, 0)) + self.connect((self.digital_constellation_decoder_cb_0, 0), (self.digital_map_bb_0, 0)) self.connect((self.digital_constellation_modulator_0, 0), (self.channels_channel_model_0, 0)) self.connect((self.digital_constellation_modulator_0, 0), (self.qtgui_time_sink_x_1_0, 0)) self.connect((self.digital_corr_est_cc_0, 1), (self.blocks_complex_to_magphase_0_0, 0)) @@ -382,6 +385,7 @@ class correlator(gr.top_block, Qt.QWidget): self.connect((self.digital_corr_est_cc_0, 0), (self.epy_block_0, 0)) self.connect((self.digital_corr_est_cc_0, 0), (self.qtgui_time_sink_x_0_0_0, 0)) self.connect((self.digital_costas_loop_cc_0, 0), (self.qtgui_const_sink_x_0_0, 1)) + self.connect((self.digital_map_bb_0, 0), (self.blocks_repack_bits_bb_0, 0)) self.connect((self.digital_pfb_clock_sync_xxx_0, 0), (self.digital_cma_equalizer_cc_0, 0)) self.connect((self.epy_block_0, 0), (self.digital_constellation_decoder_cb_0, 0)) self.connect((self.epy_block_0, 0), (self.qtgui_const_sink_x_0_0, 0)) @@ -463,6 +467,7 @@ class correlator(gr.top_block, Qt.QWidget): def set_access_code_symbols(self, access_code_symbols): self.access_code_symbols = access_code_symbols + self.digital_corr_est_cc_0.set_mark_delay(len(self.access_code_symbols) // 2) diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py index ddae02a..dbdadd1 100644 --- a/tests/correlator/epy_block_0.py +++ b/tests/correlator/epy_block_0.py @@ -5,6 +5,12 @@ from gnuradio import gr class blk(gr.sync_block): + """ + Apply phase and frequency correction where there is a correlation peak tag. + + The correlation peak tags are NOT propagated, and instead replaced with a + frame_start tag. + """ def __init__(self): gr.sync_block.__init__( self, @@ -22,7 +28,17 @@ class blk(gr.sync_block): self.lastfreq = 0 def block_phase(self, start, end): - # compute number of samples in block + """ + Compute a vector for the phase and frequency correction for the samples + between two tags (start and end). + + @param start Tag where the samples should start to be corrected + @param end Tag where to stop correcting + + @return A vector of phase values for each sample. To correct the samples + the data should be multiplied with np.exp(-1j * phase) + """ + # compute number of samples between tags nsamples = end.offset - start.offset # unpack pmt values into start and end phase @@ -44,10 +60,10 @@ class blk(gr.sync_block): self.lastfreq = freq # debugging - print(f"Correction for block of {nsamples:2d} samples is " \ + print(f"Correction for chunk of {nsamples:2d} samples is " \ f"sphase={sphase: .4f} rad and freq={freq*1e3: .4f} milli rad / sample") - # compute block values + # compute chunk values return sphase * np.ones(nsamples) + freq * np.arange(0, nsamples) def work(self, input_items, output_items): @@ -73,11 +89,11 @@ class blk(gr.sync_block): # compute "the middle" enough_samples = lambda pair: ((pair[1].offset - pair[0].offset) > 0) pairs = list(filter(enough_samples, zip(tags, tags[1:]))) - blocks = [ self.block_phase(start, end) for (start, end) in pairs ] - middle = np.concatenate(blocks) if blocks else [] + chunks = [ self.block_phase(start, end) for (start, end) in pairs ] + middle = np.concatenate(chunks) if chunks else [] # compute values at the end, we do not have informations about the future - # but we can use the frequency of the last block to approximate + # but we can use the frequency of the last tag to approximate nback = len(inp) - (tags[-1].offset - counter) print(f"Processing {nback} samples at the back of the buffer") end = np.ones(nback) * pmt.to_python(tags[-1].value) \ @@ -99,6 +115,10 @@ class blk(gr.sync_block): # save last tag for next call self.last = tags[-1] + # add tags + for tag in tags: + self.add_item_tag(0, tag.offset, pmt.intern("frame_start"), pmt.PMT_T) + # FIXME: should return `length' but then the last sample is not # included and self.last does something weird return len(out) -- cgit v1.2.1 From eca32bbd53d4fc51095700621525ac479f06c06c Mon Sep 17 00:00:00 2001 From: sara Date: Sat, 4 Dec 2021 15:19:24 +0100 Subject: Fix network sink block (again) --- src/gr-fadingui/grc/fadingui_netsink.block.yml | 5 ++--- src/gr-fadingui/python/netsink.py | 12 +++++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/gr-fadingui/grc/fadingui_netsink.block.yml b/src/gr-fadingui/grc/fadingui_netsink.block.yml index a23dc52..3cd8ae7 100644 --- a/src/gr-fadingui/grc/fadingui_netsink.block.yml +++ b/src/gr-fadingui/grc/fadingui_netsink.block.yml @@ -7,7 +7,7 @@ templates: imports: |- import fadingui import numpy as np - make: fadingui.netsink(address=${address}, dtype=${type}, vlen=${veclen}) + make: fadingui.netsink(address=${address}, dtype="${type}", vlen=${veclen}) # Make one 'parameters' list entry for every parameter you want settable from the GUI. # Keys include: @@ -18,8 +18,7 @@ parameters: - id: type label: Type dtype: enum - options: [complex, float, int, np.short, np.byte] - option_labels: [complex, float, int, short, byte] + options: [complex, float, int, short, byte] option_attributes: size: [gr.sizeof_gr_complex, gr.sizeof_float, gr.sizeof_int, gr.sizeof_short, gr.sizeof_char] hide: part diff --git a/src/gr-fadingui/python/netsink.py b/src/gr-fadingui/python/netsink.py index d2dfc92..130e5dc 100644 --- a/src/gr-fadingui/python/netsink.py +++ b/src/gr-fadingui/python/netsink.py @@ -15,7 +15,17 @@ class netsink(gr.sync_block): Keep in mind that is quite slow. """ def __init__(self, address, dtype, vlen): - dt = np.dtype(dtype, (vlen,)) if vlen > 1 else dtype + to_numpy = { + "complex": np.complex64, + "float": np.float32, + "int": np.int32, + "short": np.short, + "byte": np.byte, + } + + dt = to_numpy[dtype] + if vlen > 1: + dt = np.dtype(dt, (vlen,)) print(dt) gr.sync_block.__init__(self, -- cgit v1.2.1 From b39b8351476679e2f89cefade40a1eca2566067f Mon Sep 17 00:00:00 2001 From: sara Date: Sat, 4 Dec 2021 15:24:53 +0100 Subject: GNUR Radio Test Sockets --- tests/sockets/Socket_test.grc | 140 ++++++++++++++++++++++++++++++++++++ tests/sockets/Test_Bit_Errorrate.py | 139 +++++++++++++++++++++++++++++++++++ 2 files changed, 279 insertions(+) create mode 100644 tests/sockets/Socket_test.grc create mode 100755 tests/sockets/Test_Bit_Errorrate.py diff --git a/tests/sockets/Socket_test.grc b/tests/sockets/Socket_test.grc new file mode 100644 index 0000000..41c7f0a --- /dev/null +++ b/tests/sockets/Socket_test.grc @@ -0,0 +1,140 @@ +options: + parameters: + author: 'Sara Halter ' + category: '[GRC Hier Blocks]' + cmake_opt: '' + comment: '' + copyright: '' + description: '' + gen_cmake: 'On' + gen_linking: dynamic + generate_options: qt_gui + hier_block_src_path: '.:' + id: Test_Bit_Errorrate + max_nouts: '0' + output_language: python + placement: (0,0) + qt_qss_theme: '' + realtime_scheduling: '' + run: 'True' + run_command: '{python} -u {filename}' + run_options: prompt + sizing_mode: fixed + thread_safe_setters: '' + title: 'Bit Error Rate test ' + window_size: '' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [8, 8] + rotation: 0 + state: enabled + +blocks: +- name: samp_rate + id: variable + parameters: + comment: '' + value: '32000' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [184, 12] + rotation: 0 + state: enabled +- name: analog_noise_source_x_0 + id: analog_noise_source_x + parameters: + affinity: '' + alias: '' + amp: '1' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + noise_type: analog.GR_GAUSSIAN + seed: '0' + type: float + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [528, 108.0] + rotation: 0 + state: disabled +- name: blocks_null_source_0 + id: blocks_null_source + parameters: + affinity: '' + alias: '' + bus_structure_source: '[[0,],]' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + num_outputs: '1' + type: byte + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [552, 224.0] + rotation: 0 + state: true +- name: blocks_throttle_1 + id: blocks_throttle + parameters: + affinity: '' + alias: '' + comment: '' + ignoretag: 'True' + maxoutbuf: '0' + minoutbuf: '0' + samples_per_second: samp_rate + type: byte + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [800, 156.0] + rotation: 0 + state: true +- name: fadingui_netsink_0 + id: fadingui_netsink + parameters: + address: udp://localhost:31415 + affinity: '' + alias: '' + comment: '' + type: byte + veclen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1016, 156.0] + rotation: 0 + state: true +- name: import_0 + id: import + parameters: + alias: '' + comment: '' + imports: import numpy as np + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [328, 20.0] + rotation: 0 + state: true + +connections: +- [analog_noise_source_x_0, '0', blocks_throttle_1, '0'] +- [blocks_null_source_0, '0', blocks_throttle_1, '0'] +- [blocks_throttle_1, '0', fadingui_netsink_0, '0'] + +metadata: + file_format: 1 diff --git a/tests/sockets/Test_Bit_Errorrate.py b/tests/sockets/Test_Bit_Errorrate.py new file mode 100755 index 0000000..b545104 --- /dev/null +++ b/tests/sockets/Test_Bit_Errorrate.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# SPDX-License-Identifier: GPL-3.0 +# +# GNU Radio Python Flow Graph +# Title: Bit Error Rate test +# Author: Sara Halter +# GNU Radio version: 3.8.2.0 + +from distutils.version import StrictVersion + +if __name__ == '__main__': + import ctypes + import sys + if sys.platform.startswith('linux'): + try: + x11 = ctypes.cdll.LoadLibrary('libX11.so') + x11.XInitThreads() + except: + print("Warning: failed to XInitThreads()") + +from gnuradio import blocks +from gnuradio import gr +from gnuradio.filter import firdes +import sys +import signal +from PyQt5 import Qt +from argparse import ArgumentParser +from gnuradio.eng_arg import eng_float, intx +from gnuradio import eng_notation +import fadingui +import numpy as np + +from gnuradio import qtgui + +class Test_Bit_Errorrate(gr.top_block, Qt.QWidget): + + def __init__(self): + gr.top_block.__init__(self, "Bit Error Rate test ") + Qt.QWidget.__init__(self) + self.setWindowTitle("Bit Error Rate test ") + qtgui.util.check_set_qss() + try: + self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc')) + except: + pass + self.top_scroll_layout = Qt.QVBoxLayout() + self.setLayout(self.top_scroll_layout) + self.top_scroll = Qt.QScrollArea() + self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame) + self.top_scroll_layout.addWidget(self.top_scroll) + self.top_scroll.setWidgetResizable(True) + self.top_widget = Qt.QWidget() + self.top_scroll.setWidget(self.top_widget) + self.top_layout = Qt.QVBoxLayout(self.top_widget) + self.top_grid_layout = Qt.QGridLayout() + self.top_layout.addLayout(self.top_grid_layout) + + self.settings = Qt.QSettings("GNU Radio", "Test_Bit_Errorrate") + + try: + if StrictVersion(Qt.qVersion()) < StrictVersion("5.0.0"): + self.restoreGeometry(self.settings.value("geometry").toByteArray()) + else: + self.restoreGeometry(self.settings.value("geometry")) + except: + pass + + ################################################## + # Variables + ################################################## + self.samp_rate = samp_rate = 32000 + + ################################################## + # Blocks + ################################################## + self.fadingui_netsink_0 = fadingui.netsink(address='udp://localhost:31415', dtype="byte", vlen=1) + self.blocks_throttle_1 = blocks.throttle(gr.sizeof_char*1, samp_rate,True) + self.blocks_null_source_0 = blocks.null_source(gr.sizeof_char*1) + + + + ################################################## + # Connections + ################################################## + self.connect((self.blocks_null_source_0, 0), (self.blocks_throttle_1, 0)) + self.connect((self.blocks_throttle_1, 0), (self.fadingui_netsink_0, 0)) + + + def closeEvent(self, event): + self.settings = Qt.QSettings("GNU Radio", "Test_Bit_Errorrate") + self.settings.setValue("geometry", self.saveGeometry()) + event.accept() + + def get_samp_rate(self): + return self.samp_rate + + def set_samp_rate(self, samp_rate): + self.samp_rate = samp_rate + self.blocks_throttle_1.set_sample_rate(self.samp_rate) + + + + + +def main(top_block_cls=Test_Bit_Errorrate, options=None): + + if StrictVersion("4.5.0") <= StrictVersion(Qt.qVersion()) < StrictVersion("5.0.0"): + style = gr.prefs().get_string('qtgui', 'style', 'raster') + Qt.QApplication.setGraphicsSystem(style) + qapp = Qt.QApplication(sys.argv) + + tb = top_block_cls() + + tb.start() + + tb.show() + + def sig_handler(sig=None, frame=None): + Qt.QApplication.quit() + + signal.signal(signal.SIGINT, sig_handler) + signal.signal(signal.SIGTERM, sig_handler) + + timer = Qt.QTimer() + timer.start(500) + timer.timeout.connect(lambda: None) + + def quitting(): + tb.stop() + tb.wait() + + qapp.aboutToQuit.connect(quitting) + qapp.exec_() + +if __name__ == '__main__': + main() -- cgit v1.2.1 From 30012258948049da894e260d78551d1de44c2f50 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Sat, 4 Dec 2021 16:46:23 +0100 Subject: Update net.py to decode UDP data stream --- src/gui/gui.py | 7 ++-- src/gui/net.py | 67 +++++++++++++++++++----------- tests/sockets/Socket_test.grc | 24 +++++------ tests/sockets/Test_Bit_Errorrate.py | 83 ++++++------------------------------- 4 files changed, 71 insertions(+), 110 deletions(-) diff --git a/src/gui/gui.py b/src/gui/gui.py index b2cbebb..d817f63 100755 --- a/src/gui/gui.py +++ b/src/gui/gui.py @@ -98,7 +98,8 @@ with window(label="RX DSP Flow Graph", width=800, height=400, pos=(25,25), tag=" #================================================ # Network plots Window -recv_plot = net.network_plot(url="udp://localhost:31415", nsamples=100, label="Test", height=300, width=800) +recv_plot = net.network_plot(url="udp://localhost:31415", dtype=float, nsamples=100, \ + label="Test", height=300, width=800) plots = { recv_plot: "plt_ampl" @@ -107,9 +108,9 @@ plots = { with window(label="Time domain plots", width=800, height=400, pos=(850,25)): with recv_plot: add_plot_axis(mvXAxis, label="Time") - add_plot_axis(mvYAxis, label="Amplitude", tag="plt_ampl") + add_plot_axis(mvYAxis, label="Amplitude", tag="axis") - add_line_series(recv_plot.x_data, recv_plot.y_data, parent="plt_ampl") + add_line_series(recv_plot.xdata, recv_plot.ydata, parent="axis", tag="plt_ampl") #================================================ # Start GUI and main loop diff --git a/src/gui/net.py b/src/gui/net.py index 2c91bb8..c7008cd 100644 --- a/src/gui/net.py +++ b/src/gui/net.py @@ -1,6 +1,7 @@ import select import socket from urllib.parse import urlparse +import re import numpy as np from numpy_ringbuffer import RingBuffer @@ -11,9 +12,10 @@ class udpsource: """ Creates an UDP listening socket """ - def __init__(self, url): + def __init__(self, url, dtype): self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.url = urlparse(url) + self.dtype = dtype def __del__(self): self.sock.close() @@ -23,32 +25,46 @@ class udpsource: self.sock.bind((self.url.hostname, self.url.port)) # self.sock.listen() - def read(self, nbytes): - ready_to_read, ready_to_write, in_err = \ - select.select([self.sock], [], [], 1) - - if ready_to_read: - data = sock.recv(nbytes) - print(data) - else: + def read(self, nblocks): + ready, _, _ = select.select([self.sock], [], []) + if not ready: return None + # read from socket + blocksize = 1024 * 4 + string = ready[0].recv(nblocks * blocksize).decode("ascii") + + # decode string, remove empty values + chunks = filter(None, re.split(r"\[(.+?)\]", string)) + + def chunk_to_samples(chunk): + samples = chunk.split(",") + if samples: + return list(map(self.dtype, samples)) + + # convert each chunk into a list of samples + chunk_values = map(chunk_to_samples, chunks) + + # flatten list of lists into a single list + values = sum(chunk_values, []) + + return values class network_plot(udpsource): - def __init__(self, url, nsamples, **kwargs): - udpsource.__init__(self, url) + def __init__(self, url, dtype, nsamples, **kwargs): + udpsource.__init__(self, url, dtype) + # create buffers for x and y values self.nsamples = nsamples - self.plot = dpg.plot(**kwargs) - - # create buffer and fill with zeroes - self.buffer = RingBuffer(capacity=nsamples, dtype=(float, 2)) - for i in range(nsamples): - # TODO: remove random data used for testing - self.buffer.append(np.array([i, 1 + np.random.rand() / 5])) + self.xvalues = np.arange(0, self.nsamples) + self.yvalues = RingBuffer(capacity=self.nsamples, dtype=np.dtype(dtype)) + self.yvalues.extend(np.zeros(self.nsamples)) + # create a plot + self.plot = dpg.plot(**kwargs) self.bind() + # Map `with' expressions to the underlying plot def __enter__(self): return self.plot.__enter__() @@ -56,13 +72,16 @@ class network_plot(udpsource): self.plot.__exit__(t, val, tb) @property - def x_data(self): - return np.array(self.buffer[:,0]) + def xdata(self): + return self.xvalues @property - def y_data(self): - return np.array(self.buffer[:,1]) + def ydata(self): + return np.array(self.yvalues) def refresh_series(self, tag): - dpg.set_value(tag, [self.x_data, self.y_data]) - pass + new_values = self.read(1) + + if new_values: + self.yvalues.extendleft(new_values) + dpg.set_value(tag, [self.xdata, self.ydata]) diff --git a/tests/sockets/Socket_test.grc b/tests/sockets/Socket_test.grc index 41c7f0a..fbc3cdf 100644 --- a/tests/sockets/Socket_test.grc +++ b/tests/sockets/Socket_test.grc @@ -8,7 +8,7 @@ options: description: '' gen_cmake: 'On' gen_linking: dynamic - generate_options: qt_gui + generate_options: no_gui hier_block_src_path: '.:' id: Test_Bit_Errorrate max_nouts: '0' @@ -18,7 +18,7 @@ options: realtime_scheduling: '' run: 'True' run_command: '{python} -u {filename}' - run_options: prompt + run_options: run sizing_mode: fixed thread_safe_setters: '' title: 'Bit Error Rate test ' @@ -41,7 +41,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [184, 12] + coordinate: [216, 20.0] rotation: 0 state: enabled - name: analog_noise_source_x_0 @@ -60,9 +60,9 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [528, 108.0] + coordinate: [32, 148.0] rotation: 0 - state: disabled + state: enabled - name: blocks_null_source_0 id: blocks_null_source parameters: @@ -73,15 +73,15 @@ blocks: maxoutbuf: '0' minoutbuf: '0' num_outputs: '1' - type: byte + type: complex vlen: '1' states: bus_sink: false bus_source: false bus_structure: null - coordinate: [552, 224.0] + coordinate: [64, 264.0] rotation: 0 - state: true + state: disabled - name: blocks_throttle_1 id: blocks_throttle parameters: @@ -92,13 +92,13 @@ blocks: maxoutbuf: '0' minoutbuf: '0' samples_per_second: samp_rate - type: byte + type: float vlen: '1' states: bus_sink: false bus_source: false bus_structure: null - coordinate: [800, 156.0] + coordinate: [280, 164.0] rotation: 0 state: true - name: fadingui_netsink_0 @@ -108,13 +108,13 @@ blocks: affinity: '' alias: '' comment: '' - type: byte + type: float veclen: '1' states: bus_sink: false bus_source: false bus_structure: null - coordinate: [1016, 156.0] + coordinate: [504, 164.0] rotation: 0 state: true - name: import_0 diff --git a/tests/sockets/Test_Bit_Errorrate.py b/tests/sockets/Test_Bit_Errorrate.py index b545104..6a989df 100755 --- a/tests/sockets/Test_Bit_Errorrate.py +++ b/tests/sockets/Test_Bit_Errorrate.py @@ -9,64 +9,23 @@ # Author: Sara Halter # GNU Radio version: 3.8.2.0 -from distutils.version import StrictVersion - -if __name__ == '__main__': - import ctypes - import sys - if sys.platform.startswith('linux'): - try: - x11 = ctypes.cdll.LoadLibrary('libX11.so') - x11.XInitThreads() - except: - print("Warning: failed to XInitThreads()") - +from gnuradio import analog from gnuradio import blocks from gnuradio import gr from gnuradio.filter import firdes import sys import signal -from PyQt5 import Qt from argparse import ArgumentParser from gnuradio.eng_arg import eng_float, intx from gnuradio import eng_notation import fadingui import numpy as np -from gnuradio import qtgui -class Test_Bit_Errorrate(gr.top_block, Qt.QWidget): +class Test_Bit_Errorrate(gr.top_block): def __init__(self): gr.top_block.__init__(self, "Bit Error Rate test ") - Qt.QWidget.__init__(self) - self.setWindowTitle("Bit Error Rate test ") - qtgui.util.check_set_qss() - try: - self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc')) - except: - pass - self.top_scroll_layout = Qt.QVBoxLayout() - self.setLayout(self.top_scroll_layout) - self.top_scroll = Qt.QScrollArea() - self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame) - self.top_scroll_layout.addWidget(self.top_scroll) - self.top_scroll.setWidgetResizable(True) - self.top_widget = Qt.QWidget() - self.top_scroll.setWidget(self.top_widget) - self.top_layout = Qt.QVBoxLayout(self.top_widget) - self.top_grid_layout = Qt.QGridLayout() - self.top_layout.addLayout(self.top_grid_layout) - - self.settings = Qt.QSettings("GNU Radio", "Test_Bit_Errorrate") - - try: - if StrictVersion(Qt.qVersion()) < StrictVersion("5.0.0"): - self.restoreGeometry(self.settings.value("geometry").toByteArray()) - else: - self.restoreGeometry(self.settings.value("geometry")) - except: - pass ################################################## # Variables @@ -76,24 +35,19 @@ class Test_Bit_Errorrate(gr.top_block, Qt.QWidget): ################################################## # Blocks ################################################## - self.fadingui_netsink_0 = fadingui.netsink(address='udp://localhost:31415', dtype="byte", vlen=1) - self.blocks_throttle_1 = blocks.throttle(gr.sizeof_char*1, samp_rate,True) - self.blocks_null_source_0 = blocks.null_source(gr.sizeof_char*1) + self.fadingui_netsink_0 = fadingui.netsink(address='udp://localhost:31415', dtype="float", vlen=1) + self.blocks_throttle_1 = blocks.throttle(gr.sizeof_float*1, samp_rate,True) + self.analog_noise_source_x_0 = analog.noise_source_f(analog.GR_GAUSSIAN, 1, 0) ################################################## # Connections ################################################## - self.connect((self.blocks_null_source_0, 0), (self.blocks_throttle_1, 0)) + self.connect((self.analog_noise_source_x_0, 0), (self.blocks_throttle_1, 0)) self.connect((self.blocks_throttle_1, 0), (self.fadingui_netsink_0, 0)) - def closeEvent(self, event): - self.settings = Qt.QSettings("GNU Radio", "Test_Bit_Errorrate") - self.settings.setValue("geometry", self.saveGeometry()) - event.accept() - def get_samp_rate(self): return self.samp_rate @@ -106,34 +60,21 @@ class Test_Bit_Errorrate(gr.top_block, Qt.QWidget): def main(top_block_cls=Test_Bit_Errorrate, options=None): - - if StrictVersion("4.5.0") <= StrictVersion(Qt.qVersion()) < StrictVersion("5.0.0"): - style = gr.prefs().get_string('qtgui', 'style', 'raster') - Qt.QApplication.setGraphicsSystem(style) - qapp = Qt.QApplication(sys.argv) - tb = top_block_cls() - tb.start() - - tb.show() - def sig_handler(sig=None, frame=None): - Qt.QApplication.quit() + tb.stop() + tb.wait() + + sys.exit(0) signal.signal(signal.SIGINT, sig_handler) signal.signal(signal.SIGTERM, sig_handler) - timer = Qt.QTimer() - timer.start(500) - timer.timeout.connect(lambda: None) + tb.start() - def quitting(): - tb.stop() - tb.wait() + tb.wait() - qapp.aboutToQuit.connect(quitting) - qapp.exec_() if __name__ == '__main__': main() -- cgit v1.2.1