diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 3905aed5..ab23b5e7 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -38,11 +38,11 @@ jobs: uses: actions/checkout@v4.1.7 - name: apt installs - run: sudo apt update && sudo apt install -y texlive-latex-extra texlive-lang-cyrillic ghostscript + run: sudo apt update && sudo apt install -y texlive-latex-extra texlive-lang-cyrillic ghostscript libenchant-2-dev - - uses: actions/setup-python@v5.1.0 + - uses: actions/setup-python@v6.2.0 with: - python-version: '3.10' + python-version: '3.12' - name: pip installs run: pip install -r requirements.txt @@ -97,6 +97,16 @@ jobs: env: CREATOR_ID: ${{ secrets.CREATOR_ID }} + # Build a self-hosted JupyterLite environment into _build/jupyterlite so the + # interactive "run this code" links in the book point at our own deployment + # rather than a third-party demo site. Done last so its pip installs can't + # disturb the Sphinx builds above. + - name: Build JupyterLite + run: | + pip install -r requirements-jupyterlite.txt + jupyter lite build --contents jupyterlite --output-dir _build/jupyterlite + python jupyterlite/inject_branding.py _build/jupyterlite + - name: Upload artifact uses: actions/upload-pages-artifact@v3.0.1 with: @@ -104,7 +114,7 @@ jobs: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4.0.5 + uses: actions/deploy-pages@v5.0.0 - name: Get current date id: date diff --git a/.github/workflows/build-and-spell-check.yml b/.github/workflows/build-and-spell-check.yml index 7cecf2d5..c15fb450 100644 --- a/.github/workflows/build-and-spell-check.yml +++ b/.github/workflows/build-and-spell-check.yml @@ -10,11 +10,11 @@ jobs: uses: actions/checkout@v4.1.7 - name: apt installs - run: sudo apt update && sudo apt install -y texlive-latex-extra texlive-lang-cyrillic ghostscript + run: sudo apt update && sudo apt install -y texlive-latex-extra texlive-lang-cyrillic ghostscript libenchant-2-dev - - uses: actions/setup-python@v5.1.0 + - uses: actions/setup-python@v6.2.0 with: - python-version: '3.10' + python-version: '3.12' - name: pip installs run: pip install -r requirements.txt diff --git a/.vscode/settings.json b/.vscode/settings.json index c79ae069..b8fc1609 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,80 +1,9 @@ { "esbonio.sphinx.confDir": "", - "cSpell.words": [ - "arange", - "argmax", - "argsort", - "asarray", - "asmatrix", - "astype", - "AWGN", - "baseband", - "beamformer", - "beamformers", - "beamforming", - "boresight", - "bpsk", - "bytearray", - "CDMA", - "checkword", - "convolutional", - "Costas", - "datacast", - "dataword", - "demod", - "downconversion", - "dtype", - "endfire", - "Ettus", - "figsize", - "fillmein", - "firwin", - "fontsize", - "fromfile", - "Gbps", - "imag", - "lastseen", - "leftrightarrow", - "lfilter", - "linalg", - "linspace", - "mathrm", - "matplotlib", - "Mbps", - "mlen", - "multipath", - "MVDR", - "numpy", - "numtaps", - "Nyquist", - "OFDM", - "pinv", - "plen", - "postcostas", - "presync", - "pyplot", - "QPSK", - "radiotext", - "randint", - "randn", - "rgrids", - "Rinv", - "rlabel", - "savefig", - "scipy", - "thetamax", - "thetamin", - "Uplif", - "USRP", - "webp", - "wirelessly", - "xdata", - "xlabel", - "ydata", - "ylabel" - ], "githubPullRequests.ignoredPullRequestBranches": [ "master" ], - "python.analysis.typeCheckingMode": "basic" + "python.analysis.typeCheckingMode": "basic", + "editor.formatOnSave": false, + "editor.wordWrap": "on" } \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..a661808c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,66 @@ +# Repository Guidance for AI Contributors + +This repo is the source for the PySDR textbook, created using Sphinx. + +## Human Notes + +This section is for human reference only. It is not an instruction for agents and should not change behavior. + +Marc uses AI to help create the JavaScript mini-apps and solve issues like when certain things are not rendered correctly, he doesn't use it to write the actual content, other than spelling/grammar edits and scanning for bugs/incorrectness. + +## What to edit + +- Edit the `.rst` files under `content/` and the Sphinx config/templates under the repo root. +- Treat `_build/` as generated output. Do not edit it directly. +- Images (primarily in SVG format) referenced by the RST live in _images/ +- Python code used to produce images (primarily in SVG format) lives in figure-generating-scripts/ +- If you change a page, also check whether image assets, scripts, or config in `_static/`, `_images/`, `conf.py`, or `Makefile` need matching updates. + +## How to build locally + +If the prompt does not ask to build it, then don't build it. + +- Activate the project virtual environment which should be in the root of this repo under .venv + +- Build the site using: + +```bash +make fast-html +``` + +- The rendered HTML site will be in `_build/`. +- Open `_build/index.html` for the main site, or the relevant page under `_build/content/`. + +## Practical workflow + +- Make the source change. +- Run `make fast-html`. +- Inspect the generated HTML in `_build/` to verify the result. +- Keep changes minimal and aligned with the existing textbook style. + +## Writing Style + +Note to humans- This guidance is provided to AI to help edit, not actually write material, Marc's writes everything himself then uses AI for catching grammar issues and such. + +PySDR's prose is intentionally instructional, conversational, and example-driven. When editing chapter text, match these patterns: + +- Start with intuition before formalism. Explain the idea in plain language first, then introduce equations or code. +- Prefer short, direct paragraphs. Long sections are acceptable, but they should be broken up with transitions, examples, or figures. +- Use first-person plural sparingly but naturally (`we`, `let's`) to guide the reader through the material. +- Keep the tone approachable and lightly informal, but not casual or chatty. +- Use rhetorical questions and plain-English restatements when they help clarify a concept. +- Explain why a step matters, not just what the step is. +- Preserve the textbook’s teaching rhythm: concept, example, code, result, takeaway. +- Keep technical terminology precise, but avoid sounding overly academic or formal. +- When a section already has figures or code, make the surrounding prose point the reader to them and explain what they should notice. +- Avoid hype, filler, and motivational fluff. +- Lead with a concrete scenario before any equation. Pose a small "what if" with real numbers (e.g. "the emitter is 100 m closer to one sensor"), then generalize. Introduce the named concept (hyperbola, foci) in plain words before showing the formula. +- Read the equation back in plain English. Right after a .. math:: block, add a sentence translating it ("which reads: distance to one sensor minus distance to the other equals..."). +- Explain why, not just what. For each fact, give the intuition behind it (why a range difference can't exceed the baseline) rather than stating it as a rule. +- Define jargon inline the moment it appears ("the baseline," "ill-conditioned, meaning small errors move the estimate a lot") instead of assuming the reader knows it. +- Use second person and rhetorical questions to walk the reader through the reasoning as if thinking aloud. + +## Notes + +- This project uses Sphinx and a custom `conf.py`. +- The repository already contains scripts and generated assets for many figures, so prefer reusing existing conventions instead of introducing new build patterns. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 00000000..47dc3e3d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/Makefile b/Makefile index ed288b6e..cb639aa2 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ endif PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -EXTENSIONS = -D extensions=sphinx.ext.mathjax,sphinx.ext.autosectionlabel,sphinxcontrib.tikz -D tikz_includegraphics_path=_images -D tikz_tikzlibraries=positioning,shapes,arrows,snakes +EXTENSIONS = -D extensions=sphinx.ext.mathjax,sphinx.ext.autosectionlabel,sphinxcontrib.tikz,sphinxcontrib.mermaid -D tikz_includegraphics_path=_images -D tikz_tikzlibraries=positioning,shapes,arrows,snakes # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . diff --git a/README.md b/README.md index da0a1f3f..a7130685 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ -# PySDR Textbook Source Material - -This repo contains the source content used to generate the textbook [PySDR: A Guide to SDR and DSP using Python](https://pysdr.org) hosted at https://pysdr.org. - -Feel free to submit an issue, or even a Pull Request (PR) with fixes or improvements. Those who submit valuable feedback/fixes be permanently added to the acknowledgments section. Not good at Git but have changes to suggest? Feel free to email Marc at marc@pysdr.org. +# PySDR

+[PySDR: A Guide to SDR and DSP using Python](https://pysdr.org) is a guide to software-defined radio (SDR) and RF signal processing using Python code examples, live at https://pysdr.org. It is a free online textbook that provides a gentle introduction to wireless communications and SDR using an abundance of diagrams, animations, and code examples. From FFTs to filters to digital modulation to receiving and transmitting from SDRs in Python, PySDR has you covered! This repo specifically contains the source content used to generate the textbook, including the body text and Python scripts to generate the figures. For questions/comments/suggestions feel free to submit an issue at the top of this page, or if you want to propose a change to the textbook (e.g. fix or improvement), you can use a Pull Request. Those who submit valuable feedback/fixes be permanently added to the acknowledgments section. Not good at Git but have changes to suggest? Feel free to email Marc at marc@pysdr.org. + +You can also support PySDR through the [PySDR Patreon page](https://www.patreon.com/c/PySDR) or a [one-time donation](https://www.paypal.com/donate/?hosted_button_id=FH3LQCJRUVPWL). + ## Building Note that the website is now automatically built and deployed with each push/merge into master branch, using the GitHub action [build-and-deploy.yml](https://github.com/777arc/PySDR/blob/master/.github/workflows/build-and-deploy.yml) and the GitHub pages system for hosting the actual textbook. diff --git a/_images/2d_array_2d_doa_plot.svg b/_images/2d_array_2d_doa_plot.svg index 60878821..844371cc 100644 --- a/_images/2d_array_2d_doa_plot.svg +++ b/_images/2d_array_2d_doa_plot.svg @@ -1,1380 +1,1200 @@ - - - - - - - - 2025-06-20T02:09:40.562096 - image/svg+xml - - - Matplotlib v3.10.3, https://matplotlib.org/ - - - - - - - - - - - + + + + + + + + 2026-04-20T13:11:53.177106 + image/svg+xml + + + Matplotlib v3.10.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - - + + + + + + + + + + + + + - - + + + + + + + + + + + + + - - + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - + + + + + - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + diff --git a/_images/2d_array_3d_doa_plot.png b/_images/2d_array_3d_doa_plot.png index b964c6f6..b18bf406 100644 Binary files a/_images/2d_array_3d_doa_plot.png and b/_images/2d_array_3d_doa_plot.png differ diff --git a/_images/2d_array_ladder_pic.png b/_images/2d_array_ladder_pic.png new file mode 100644 index 00000000..fbc62164 Binary files /dev/null and b/_images/2d_array_ladder_pic.png differ diff --git a/_images/boxcar_sinc.svg b/_images/boxcar_sinc.svg new file mode 100644 index 00000000..4a4f59cd --- /dev/null +++ b/_images/boxcar_sinc.svg @@ -0,0 +1,1959 @@ + + + + + + + + 2026-07-02T00:41:36.986394 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/boxcar_sinc_animation.gif b/_images/boxcar_sinc_animation.gif new file mode 100644 index 00000000..92c12e84 Binary files /dev/null and b/_images/boxcar_sinc_animation.gif differ diff --git a/_images/central_limit_theorem.svg b/_images/central_limit_theorem.svg index 31a3e3f8..b1e4f4be 100644 --- a/_images/central_limit_theorem.svg +++ b/_images/central_limit_theorem.svg @@ -2,20 +2,20 @@ + inkscape:version="1.4 (86a8ad7, 2024-10-11)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> @@ -40,13 +40,17 @@ inkscape:window-height="992" id="namedview2198" showgrid="false" - inkscape:zoom="0.64744413" - inkscape:cx="688.7021" - inkscape:cy="387.7892" + inkscape:zoom="0.45781213" + inkscape:cx="556.99703" + inkscape:cy="242.45753" inkscape:window-x="72" - inkscape:window-y="27" + inkscape:window-y="0" inkscape:window-maximized="0" - inkscape:current-layer="svg2196" /> + inkscape:current-layer="svg2196" + inkscape:showpageshadow="2" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="pt" /> @@ -61,7 +65,7 @@ @@ -76,7 +80,7 @@ @@ -89,7 +93,9 @@ helper_size="0" apply_no_weight="true" apply_with_weight="true" - only_selected="false" /> + only_selected="false" + lpeversion="0" + uniform="false" /> - - + - - + + + + + + + + + + + + + + style="stroke-linecap:butt;stroke-linejoin:round" + transform="translate(-10.3,-6.8)"> @@ -2306,7 +2357,7 @@ style="stroke-linecap:butt;stroke-linejoin:round"> @@ -2315,7 +2366,7 @@ style="stroke-linecap:butt;stroke-linejoin:round"> @@ -2324,7 +2375,7 @@ style="stroke-linecap:butt;stroke-linejoin:round"> @@ -2333,14 +2384,15 @@ style="stroke-linecap:butt;stroke-linejoin:round"> + style="stroke-linecap:butt;stroke-linejoin:round" + transform="translate(-10.3,-6.8)"> @@ -3361,7 +3413,7 @@ style="stroke-linecap:butt;stroke-linejoin:round"> @@ -3370,7 +3422,7 @@ style="stroke-linecap:butt;stroke-linejoin:round"> @@ -3379,7 +3431,7 @@ style="stroke-linecap:butt;stroke-linejoin:round"> @@ -3388,14 +3440,15 @@ style="stroke-linecap:butt;stroke-linejoin:round"> + style="stroke-linecap:butt;stroke-linejoin:round" + transform="translate(-10.3,-6.8)"> @@ -6416,7 +6469,7 @@ style="stroke-linecap:butt;stroke-linejoin:round"> @@ -6425,7 +6478,7 @@ style="stroke-linecap:butt;stroke-linejoin:round"> @@ -6434,7 +6487,7 @@ style="stroke-linecap:butt;stroke-linejoin:round"> @@ -6443,14 +6496,15 @@ style="stroke-linecap:butt;stroke-linejoin:round"> + style="stroke-linecap:butt;stroke-linejoin:round" + transform="translate(-10.3,-6.8)"> @@ -8471,7 +8525,7 @@ style="stroke-linecap:butt;stroke-linejoin:round"> @@ -8480,7 +8534,7 @@ style="stroke-linecap:butt;stroke-linejoin:round"> @@ -8489,7 +8543,7 @@ style="stroke-linecap:butt;stroke-linejoin:round"> @@ -8498,66 +8552,15 @@ style="stroke-linecap:butt;stroke-linejoin:round"> - - - - - - - - - - - - - - - - + style="stroke-linecap:butt;stroke-linejoin:round" + transform="matrix(1.4778986,0,0,1.4778986,235.14552,335.88139)"> + style="stroke-linecap:butt;stroke-linejoin:round" + transform="matrix(1.4778986,0,0,1.4778986,235.14552,335.88139)"> @@ -9588,7 +9592,7 @@ + + + + + + - - - - - Normal Distribution - + diff --git a/_images/cpfsk_magnitude.svg b/_images/cpfsk_magnitude.svg new file mode 100644 index 00000000..e08a81dc --- /dev/null +++ b/_images/cpfsk_magnitude.svg @@ -0,0 +1,1737 @@ + + + + + + + + 2026-06-06T01:58:09.928135 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/detection_basic_1.svg b/_images/detection_basic_1.svg new file mode 100644 index 00000000..0faf6af4 --- /dev/null +++ b/_images/detection_basic_1.svg @@ -0,0 +1,6790 @@ + + + + + + + + 2026-02-03T19:39:10.038436 + image/svg+xml + + + Matplotlib v3.6.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/detection_basic_2.svg b/_images/detection_basic_2.svg new file mode 100644 index 00000000..e73e295d --- /dev/null +++ b/_images/detection_basic_2.svg @@ -0,0 +1,6683 @@ + + + + + + + + 2026-02-03T19:39:10.127980 + image/svg+xml + + + Matplotlib v3.6.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/detection_cfar.svg b/_images/detection_cfar.svg new file mode 100644 index 00000000..7e22ded1 --- /dev/null +++ b/_images/detection_cfar.svg @@ -0,0 +1,14057 @@ + + + + + + + + 2026-01-25T21:46:24.426568 + image/svg+xml + + + Matplotlib v3.6.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/detection_cfar2.svg b/_images/detection_cfar2.svg new file mode 100644 index 00000000..1259eed9 --- /dev/null +++ b/_images/detection_cfar2.svg @@ -0,0 +1,14259 @@ + + + + + + + + 2026-01-25T21:14:25.065560 + image/svg+xml + + + Matplotlib v3.6.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/detection_dsss.svg b/_images/detection_dsss.svg new file mode 100644 index 00000000..747adafc --- /dev/null +++ b/_images/detection_dsss.svg @@ -0,0 +1,1797 @@ + + + + + + + + 2026-01-25T21:18:47.096850 + image/svg+xml + + + Matplotlib v3.6.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/detection_freq_offset.svg b/_images/detection_freq_offset.svg new file mode 100644 index 00000000..3e5ac79f --- /dev/null +++ b/_images/detection_freq_offset.svg @@ -0,0 +1,1288 @@ + + + + + + + + 2026-01-25T21:16:20.059400 + image/svg+xml + + + Matplotlib v3.6.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/detection_freq_offset2.svg b/_images/detection_freq_offset2.svg new file mode 100644 index 00000000..798a0ec1 --- /dev/null +++ b/_images/detection_freq_offset2.svg @@ -0,0 +1,1399 @@ + + + + + + + + 2026-01-25T21:16:26.171610 + image/svg+xml + + + Matplotlib v3.6.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/detection_gps_2d_map.png b/_images/detection_gps_2d_map.png new file mode 100644 index 00000000..ad9ef9d8 Binary files /dev/null and b/_images/detection_gps_2d_map.png differ diff --git a/_images/detection_gps_code_phase_slice.svg b/_images/detection_gps_code_phase_slice.svg new file mode 100644 index 00000000..ae512500 --- /dev/null +++ b/_images/detection_gps_code_phase_slice.svg @@ -0,0 +1,3762 @@ + + + + + + + + 2026-03-21T02:47:59.745089 + image/svg+xml + + + Matplotlib v3.10.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/detection_gps_spectrogram.svg b/_images/detection_gps_spectrogram.svg new file mode 100644 index 00000000..f9cbf746 --- /dev/null +++ b/_images/detection_gps_spectrogram.svg @@ -0,0 +1,871 @@ + + + + + + + + 2026-03-21T02:24:00.638974 + image/svg+xml + + + Matplotlib v3.10.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/detection_pd_vs_snr.svg b/_images/detection_pd_vs_snr.svg new file mode 100644 index 00000000..fa419003 --- /dev/null +++ b/_images/detection_pd_vs_snr.svg @@ -0,0 +1,1922 @@ + + + + + + + + 2026-02-03T21:08:16.073111 + image/svg+xml + + + Matplotlib v3.6.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/detection_realtime.png b/_images/detection_realtime.png new file mode 100644 index 00000000..fd8541a5 Binary files /dev/null and b/_images/detection_realtime.png differ diff --git a/_images/eye_diagram.svg b/_images/eye_diagram.svg new file mode 100644 index 00000000..92ace775 --- /dev/null +++ b/_images/eye_diagram.svg @@ -0,0 +1,975 @@ + + + + + + + + 2026-07-22T07:31:31.520824 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/fpv_baseband_spectrum_after_demod.svg b/_images/fpv_baseband_spectrum_after_demod.svg new file mode 100644 index 00000000..c60299ec --- /dev/null +++ b/_images/fpv_baseband_spectrum_after_demod.svg @@ -0,0 +1,379 @@ + + + + Baseband spectrum of an analog FPV signal after FM demodulation + A frequency-domain plot from DC to 7 MHz showing the luminance band rolling off from DC to about 4.2 MHz, a chrominance cluster around the 3.58 MHz colour subcarrier, and a narrow audio FM subcarrier near 6.0 to 6.5 MHz. + + + + + + + + + + + + + + + + + + + + + + + 0 + 1 + 2 + 3 + 3.58 + 4 + 5 + 6 + 6.5 + 7 + level + frequency (MHz) + luminance (Y) + brightness · DC–~4.2 MHz + + + chrominance (C) + colour subcarrier 3.58 MHz + + + audio FM subcarrier + ≈6.0 / 6.5 MHz + + + + composite video baseband (Y + C) + + diff --git a/_images/fpv_image_no_sync.svg b/_images/fpv_image_no_sync.svg new file mode 100644 index 00000000..46cb6387 --- /dev/null +++ b/_images/fpv_image_no_sync.svg @@ -0,0 +1,43 @@ + + + + + + + + 2026-06-21T20:17:42.959991 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/fpv_image_one_frame.svg b/_images/fpv_image_one_frame.svg new file mode 100644 index 00000000..7ccfec29 --- /dev/null +++ b/_images/fpv_image_one_frame.svg @@ -0,0 +1,43 @@ + + + + + + + + 2026-06-21T20:19:35.654904 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/fpv_psd_after_fm_demod.svg b/_images/fpv_psd_after_fm_demod.svg new file mode 100644 index 00000000..f6bd30c6 --- /dev/null +++ b/_images/fpv_psd_after_fm_demod.svg @@ -0,0 +1,4951 @@ + + + + + + + + 2026-06-21T23:28:04.734346 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + Frequency [MHz] + + + + + + + + + + + + + + + + + −110 + + + + + + + + + + + + + −100 + + + + + + + + + + + + + −90 + + + + + + + + + + + + + −80 + + + + + + + + + + + + + −70 + + + + + + + + + + + + + −60 + + + + + + + + + + + + + −50 + + + + + + + + + + + + + −40 + + + + + + + + + + + + + −30 + + + + PSD [dB] + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/fpv_psd_after_fm_demod_harmomics.svg b/_images/fpv_psd_after_fm_demod_harmomics.svg new file mode 100644 index 00000000..acb1f6b6 --- /dev/null +++ b/_images/fpv_psd_after_fm_demod_harmomics.svg @@ -0,0 +1,4553 @@ + + + + + + + + 2026-06-21T20:26:44.474404 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/fpv_psd_raw_rf.svg b/_images/fpv_psd_raw_rf.svg new file mode 100644 index 00000000..ecbc2432 --- /dev/null +++ b/_images/fpv_psd_raw_rf.svg @@ -0,0 +1,3066 @@ + + + + + + + + 2026-06-21T23:25:24.909042 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + −4 + + + + + + + + + + + + + −3 + + + + + + + + + + + + + −2 + + + + + + + + + + + + + −1 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + Frequency [MHz] + + + + + + + + + + + + + + + + + −30 + + + + + + + + + + + + + −25 + + + + + + + + + + + + + −20 + + + + + + + + + + + + + −15 + + + + + + + + + + + + + −10 + + + + + + + + + + + + + −5 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 10 + + + + + + + + + + + + + 15 + + + + PSD [dB] + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/fpv_time_domain.svg b/_images/fpv_time_domain.svg new file mode 100644 index 00000000..91fced76 --- /dev/null +++ b/_images/fpv_time_domain.svg @@ -0,0 +1,10761 @@ + + + + + + + + 2026-06-21T20:29:05.274650 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/fpv_time_domain_one_line.svg b/_images/fpv_time_domain_one_line.svg new file mode 100644 index 00000000..783cf9d3 --- /dev/null +++ b/_images/fpv_time_domain_one_line.svg @@ -0,0 +1,1385 @@ + + + + + + + + 2026-06-21T20:28:53.900867 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/gaussian_IQ.png b/_images/gaussian_IQ.png new file mode 100644 index 00000000..74147280 Binary files /dev/null and b/_images/gaussian_IQ.png differ diff --git a/_images/gaussian_histogram.png b/_images/gaussian_histogram.png new file mode 100644 index 00000000..9544a26f Binary files /dev/null and b/_images/gaussian_histogram.png differ diff --git a/_images/gaussian_transformed.png b/_images/gaussian_transformed.png new file mode 100644 index 00000000..3b56ceb4 Binary files /dev/null and b/_images/gaussian_transformed.png differ diff --git a/_images/msk_magnitude.svg b/_images/msk_magnitude.svg new file mode 100644 index 00000000..37cff121 --- /dev/null +++ b/_images/msk_magnitude.svg @@ -0,0 +1,1674 @@ + + + + + + + + 2026-06-06T01:19:15.295396 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/msk_psd.svg b/_images/msk_psd.svg new file mode 100644 index 00000000..45fabb8a --- /dev/null +++ b/_images/msk_psd.svg @@ -0,0 +1,13840 @@ + + + + + + + + 2026-06-06T01:19:36.679178 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/msk_vs_qpsk_spectrum.svg b/_images/msk_vs_qpsk_spectrum.svg new file mode 100644 index 00000000..c802fb91 --- /dev/null +++ b/_images/msk_vs_qpsk_spectrum.svg @@ -0,0 +1,3058 @@ + + + + + + + + 2026-06-07T00:05:35.435816 + image/svg+xml + + + Matplotlib v3.6.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/oqpsk_magnitude.svg b/_images/oqpsk_magnitude.svg new file mode 100644 index 00000000..c6cea1f1 --- /dev/null +++ b/_images/oqpsk_magnitude.svg @@ -0,0 +1,1840 @@ + + + + + + + + 2026-06-06T00:53:57.171451 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/overlap_add.svg b/_images/overlap_add.svg new file mode 100644 index 00000000..38977ffe --- /dev/null +++ b/_images/overlap_add.svg @@ -0,0 +1,488 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1. Split input into blocks of length L + + + block 1 + + + block 2 + + + block 3 + + + + + L + + + filter each block with h (length M) + + 2. Each output is longer by M−1 (the tail) + + + + output 1 + + + + output 2 + + + + output 3 + + + + + M−1 + + + add the overlapping tails + + 3. Overlapping regions are summed + + + + + + + + + + + + purple = tail of one block added to the start of the next + diff --git a/_images/overlap_save.svg b/_images/overlap_save.svg new file mode 100644 index 00000000..6a0e9233 --- /dev/null +++ b/_images/overlap_save.svg @@ -0,0 +1,441 @@ + + + + + + + + + + + + + + + + + + + + + + 1. Blocks of length N overlap by M−1 new samples each step + + + + block 1 + + + + block 2 + + + + block 3 + + + + + + + + N (FFT size) + + + = last M−1 samples reused from previous block + + + FFT × H, then IFFT (circular convolution) + + 2. Circular convolution corrupts the first M−1 output samples + + + output 1 + + + output 2 + + + output 3 + + + = aliased samples, discarded + + + drop the first M−1, keep the rest + + 3. Keep the good samples → seamless output + + + + diff --git a/_images/qpsk_magnitude.svg b/_images/qpsk_magnitude.svg new file mode 100644 index 00000000..2cc6e697 --- /dev/null +++ b/_images/qpsk_magnitude.svg @@ -0,0 +1,1701 @@ + + + + + + + + 2026-06-06T00:53:49.557116 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/qpsk_psd.svg b/_images/qpsk_psd.svg new file mode 100644 index 00000000..d7434d22 --- /dev/null +++ b/_images/qpsk_psd.svg @@ -0,0 +1,12441 @@ + + + + + + + + 2026-06-06T01:22:44.106084 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/scf_freq_smoothing_ofdm_zoomed_in.svg b/_images/scf_freq_smoothing_ofdm_zoomed_in.svg index 7b492df2..f0069594 100644 --- a/_images/scf_freq_smoothing_ofdm_zoomed_in.svg +++ b/_images/scf_freq_smoothing_ofdm_zoomed_in.svg @@ -6,11 +6,11 @@ - 2024-06-20T00:25:48.294240 + 2026-01-23T13:53:18.154826 image/svg+xml - Matplotlib v3.9.0, https://matplotlib.org/ + Matplotlib v3.10.3, https://matplotlib.org/ @@ -37,20 +37,20 @@ L 62.86875 10.999219 z " style="fill: #ffffff"/> - + +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" id="image7350657125" transform="scale(1 -1) translate(0 -266.4)" x="62.86875" y="-10.711219" width="357.12" height="266.4"/> - - + @@ -113,16 +113,16 @@ z " transform="scale(0.015625)"/> - - - + + + - + @@ -155,54 +155,54 @@ z " transform="scale(0.015625)"/> - - - + + + - + - - + + - + - - + + - + - - + + @@ -566,30 +566,30 @@ z " transform="scale(0.015625)"/> - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -597,35 +597,35 @@ z - - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + @@ -843,37 +843,37 @@ z " transform="scale(0.015625)"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -900,7 +900,7 @@ L 419.98875 10.999219 - + diff --git a/_images/spectrogram.svg b/_images/spectrogram.svg index da7e657a..ff97f77b 100644 --- a/_images/spectrogram.svg +++ b/_images/spectrogram.svg @@ -1,16 +1,16 @@ - + - 2023-04-18T20:44:45.005374 + 2026-02-24T01:48:09.678494 image/svg+xml - Matplotlib v3.5.1, https://matplotlib.org/ + Matplotlib v3.10.3, https://matplotlib.org/ @@ -21,8 +21,8 @@ - - - + +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" id="imaged8420236fb" transform="scale(1 -1) translate(0 -266.4)" x="43.78125" y="-10.711219" width="357.12" height="266.4"/> - - + - + - - - + + + - + - + - - - + + + - + - + - - + + - + - + - - + + - + - + - - + + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + @@ -460,62 +460,62 @@ z - - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - + - - + + - + - - - - - - - + + + + + + + - - - - - - + + diff --git a/_images/tdoa_cramer_rao.svg b/_images/tdoa_cramer_rao.svg new file mode 100644 index 00000000..90e2e616 --- /dev/null +++ b/_images/tdoa_cramer_rao.svg @@ -0,0 +1,1468 @@ + + + + + + + + 2026-06-25T12:54:18.794956 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/tdoa_gdop.svg b/_images/tdoa_gdop.svg new file mode 100644 index 00000000..eb79e378 --- /dev/null +++ b/_images/tdoa_gdop.svg @@ -0,0 +1,1634 @@ + + + + + + + + 2026-06-23T03:53:09.404485 + image/svg+xml + + + Matplotlib v3.10.8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + −8 + + + + + + + + + + −6 + + + + + + + + + + −4 + + + + + + + + + + −2 + + + + + + + + + + 0 + + + + + + + + + + 2 + + + + + + + + + + 4 + + + + + + + + + + 6 + + + + + + + + + + 8 + + + + x + + + + + + + + + + + + + + −8 + + + + + + + + + + −6 + + + + + + + + + + −4 + + + + + + + + + + −2 + + + + + + + + + + 0 + + + + + + + + + + 2 + + + + + + + + + + 4 + + + + + + + + + + 6 + + + + + + + + + + 8 + + + + y + + + + + + + + + + + + + + + + + + + + + S1 + + + S2 + + + S3 + + + triangular array + + + + 2 + + + + + 3 + + + + + 5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + −8 + + + + + + + + + + −6 + + + + + + + + + + −4 + + + + + + + + + + −2 + + + + + + + + + + 0 + + + + + + + + + + 2 + + + + + + + + + + 4 + + + + + + + + + + 6 + + + + + + + + + + 8 + + + + x + + + + + + + + + + + −8 + + + + + + + + + + −6 + + + + + + + + + + −4 + + + + + + + + + + −2 + + + + + + + + + + 0 + + + + + + + + + + 2 + + + + + + + + + + 4 + + + + + + + + + + 6 + + + + + + + + + + 8 + + + + y + + + + + + + + + + + + + + + + + + + + + S1 + + + S2 + + + S3 + + + nearly collinear array + + + + 2 + + + + + 2 + + + + + 3 + + + + + 3 + + + + + 5 + + + + + 5 + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.2 + + + + + + + + + + 2 + + + + + + + + + + 3 + + + + + + + + + + 5 + + + + + + + + + + ≥8 + + + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 6 + + + + + + + + 7 + + + + + + + + + + + + GDOP (position error / range-difference error) + + + + + + + + + + + + + + + + diff --git a/_images/tdoa_hyperbola.svg b/_images/tdoa_hyperbola.svg new file mode 100644 index 00000000..282affa7 --- /dev/null +++ b/_images/tdoa_hyperbola.svg @@ -0,0 +1,768 @@ + + + + + + + + 2026-06-23T03:53:09.170870 + image/svg+xml + + + Matplotlib v3.10.8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + −3 + + + + + + + + + + + + + −2 + + + + + + + + + + + + + −1 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + x + + + + + + + + + + + + + + + + + −3 + + + + + + + + + + + + + −2 + + + + + + + + + + + + + −1 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + y + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + S₁ + + + S₂ + + + baseline + + + Δr > 0 + (source nearer S₁) + + + Δr < 0 + (source nearer S₂) + + + Δr = 0 + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/tdoa_principle.svg b/_images/tdoa_principle.svg new file mode 100644 index 00000000..a9bdac04 --- /dev/null +++ b/_images/tdoa_principle.svg @@ -0,0 +1,619 @@ + + + + + + + + 2026-06-23T03:58:57.663473 + image/svg+xml + + + Matplotlib v3.10.8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + wavefront + expands at + speed c + + + Source + (unknown position, + unknown transmit time t₀) + + + + + + r₁ + + + S₁ + + + + + + r₂ + + + S₂ + + + + + + r₃ + + + S₃ + + + The TDOA principle: different path lengths give different arrival times + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + time + + + + + + + t₀ (unknown + transmit time) + + + S₁ + + + t₁ + + + S₂ + + + t₂ + + + S₃ + + + t₃ + + + + + + + + τ₂₁ = t₂ − t₁ + + + + + + + + τ₃₁ = t₃ − t₁ + + + + TDOA measures only the gaps τ between arrivals — the unknown transmit time t₀ cancels in every difference. + + + + + + + + + + + diff --git a/_images/tdoa_python_heatmap.svg b/_images/tdoa_python_heatmap.svg new file mode 100644 index 00000000..e8909cb8 --- /dev/null +++ b/_images/tdoa_python_heatmap.svg @@ -0,0 +1,1452 @@ + + + + + + + + 2026-06-25T13:28:25.517802 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/tdoa_python_integer.svg b/_images/tdoa_python_integer.svg new file mode 100644 index 00000000..abdd2cf7 --- /dev/null +++ b/_images/tdoa_python_integer.svg @@ -0,0 +1,2078 @@ + + + + + + + + 2026-06-24T23:58:47.498877 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/tdoa_python_subsample.svg b/_images/tdoa_python_subsample.svg new file mode 100644 index 00000000..ecd3ceed --- /dev/null +++ b/_images/tdoa_python_subsample.svg @@ -0,0 +1,2494 @@ + + + + + + + + 2026-06-24T23:58:47.790598 + image/svg+xml + + + Matplotlib v3.10.9, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_static/custom.css b/_static/custom.css index 41f95939..39dfcaaf 100644 --- a/_static/custom.css +++ b/_static/custom.css @@ -198,6 +198,16 @@ canvas{ box-shadow: 3px 3px var(--shadow); box-sizing: border-box; } + +/* Mermaid diagrams inherit a light gray canvas from the extension defaults. + Force a white background so they match the rest of the textbook pages. */ +pre.mermaid, +pre.mermaid > svg, +.mermaid-container > pre, +.mermaid-container > pre > svg { + background-color: white !important; +} + .canvas-header{ margin: 10px 0 0 0; } @@ -286,3 +296,32 @@ canvas{ /* End of PhasedArrayVisualizer part */ +/* Collapsible "Specific SDRs" sidebar group (see js/sidebar_groups.js) */ +.sphinxsidebar .sdr-group-toggle { + cursor: pointer; + display: inline-block; + user-select: none; +} +.sphinxsidebar .sdr-caret { + display: inline-block; + width: 0; + height: 0; + margin-right: 6px; + border-left: 5px solid currentColor; + border-top: 4px solid transparent; + border-bottom: 4px solid transparent; + vertical-align: middle; + transition: transform 0.15s ease; +} +.sphinxsidebar .sdr-group.open .sdr-caret { + transform: rotate(90deg); +} +.sphinxsidebar .sdr-group-children { + display: none; + list-style: none; + margin: 0; + padding-left: 15px; +} +.sphinxsidebar .sdr-group.open .sdr-group-children { + display: block; +} diff --git a/_static/donate.svg b/_static/donate.svg new file mode 100644 index 00000000..7056fa56 --- /dev/null +++ b/_static/donate.svg @@ -0,0 +1,38 @@ + + + + + + diff --git a/_static/js/eye_diagram_app.js b/_static/js/eye_diagram_app.js new file mode 100644 index 00000000..8905ef40 --- /dev/null +++ b/_static/js/eye_diagram_app.js @@ -0,0 +1,364 @@ +// Interactive eye-diagram explorer for the Pulse Shaping chapter. +// Generates random real symbols (BPSK or 4-ASK), applies raised-cosine (or root-raised-cosine) +// pulse shaping, adds AWGN and timing jitter, then overlays short windows into a +// phosphor-style eye diagram with live eye-height/eye-width calipers. +// +// Usage in a page:
+ +function eye_diagram_app(containerId) { + const container = document.getElementById(containerId || "eyeApp") || document.body; + + // ---- inject scoped styles once (all rules are prefixed by .eye-diagram-app) ---- + if (!document.getElementById("eye-diagram-app-styles")) { + const style = document.createElement("style"); + style.id = "eye-diagram-app-styles"; + style.textContent = ` +.eye-diagram-app{--accent:#e6550d;max-width:1000px;margin:8px auto 4px;color:#222;font-family:sans-serif;} +.eye-diagram-app *{box-sizing:border-box;} +.eye-diagram-app .lab{display:grid;grid-template-columns:1fr 300px;gap:16px;align-items:start;} +@media (max-width:820px){.eye-diagram-app .lab{grid-template-columns:1fr;}} +.eye-diagram-app .screen{background:#fff;border:1px solid #ccc;border-radius:4px;padding:12px;} +.eye-diagram-app .screen-label{display:flex;justify-content:space-between;align-items:center; + font-size:12px;color:#555;margin:2px 2px 8px;} +.eye-diagram-app .screen-label .dot{width:8px;height:8px;border-radius:50%;background:#17c3b2; + display:inline-block;margin-right:6px;vertical-align:middle;} +.eye-diagram-app .canvas-holder{position:relative;border:1px solid #888;border-radius:4px;overflow:hidden;background:#070c14;line-height:0;} +.eye-diagram-app canvas{display:block;width:100%;height:auto;} +.eye-diagram-app .meters{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;margin-top:12px;} +.eye-diagram-app .meter{background:#f7f7f7;border:1px solid #ccc;border-radius:4px;padding:8px 10px;} +.eye-diagram-app .meter .k{font-size:11px;color:#666;} +.eye-diagram-app .meter .v{font-family:monospace;font-size:20px;font-weight:bold;margin-top:4px;color:#222;line-height:1;} +.eye-diagram-app .meter .v small{font-size:12px;color:#888;font-weight:normal;margin-left:2px;} +.eye-diagram-app .panel{background:#fafafa;border:1px solid #ccc;border-radius:4px;padding:14px;} +.eye-diagram-app .panel h2{font-size:13px;color:#333;margin:0 0 12px;font-weight:bold;} +.eye-diagram-app .seg{display:flex;gap:4px;margin-bottom:6px;} +.eye-diagram-app .seg button{flex:1;border:1px solid #bbb;background:#fff;color:#333; + font-family:sans-serif;font-weight:normal;font-size:13px;padding:6px 4px;border-radius:4px;cursor:pointer;} +.eye-diagram-app .seg button[aria-pressed="true"]{background:var(--accent);color:#fff;border-color:var(--accent);font-weight:bold;} +.eye-diagram-app .seg button:hover:not([aria-pressed="true"]){background:#f0f0f0;} +.eye-diagram-app .seg-hint{font-size:12px;color:#666;line-height:1.4;margin:0 0 14px;} +.eye-diagram-app .ctrl{margin-bottom:14px;} +.eye-diagram-app .ctrl .row{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:4px;} +.eye-diagram-app .ctrl label{font-size:13px;color:#333;} +.eye-diagram-app .ctrl .val{font-family:monospace;font-size:13px;color:var(--accent);font-weight:bold;} +.eye-diagram-app .ctrl .hint{font-size:11.5px;color:#777;margin-top:4px;line-height:1.4;} +.eye-diagram-app input[type=range]{width:100%;accent-color:var(--accent);cursor:pointer;margin:2px 0;} +.eye-diagram-app .actions{display:flex;gap:8px;margin-top:4px;} +.eye-diagram-app .actions button{flex:1;font-family:sans-serif;font-weight:normal;font-size:13px;padding:8px; + border:1px solid #bbb;background:#fff;color:#333;border-radius:4px;cursor:pointer;} +.eye-diagram-app .actions button:hover{background:#f0f0f0;}`; + document.head.appendChild(style); + } + + // ---- build DOM inside the container ---- + const root = document.createElement("div"); + root.className = "eye-diagram-app"; + root.innerHTML = ` +
+
+
Transmitted baseband
+
+ +
Eye diagram · overlaid bits
+
+ +
+
Eye height
%
+
Eye width
%UI
+
+
+ + +
`; + container.appendChild(root); + + const $ = (sel) => root.querySelector(sel); + + // ================= app logic (scoped to this container) ================= + const SPS = 40, SPAN = 8, L = SPS * SPAN; // samples/bit, filter half-span (symbols), half-taps + const VMIN = -2.25, VMAX = 2.25; + const TRACES = 46; // fresh bits drawn per frame + const STROKE = 'rgba(45,212,191,0.15)'; // additive teal; dense overlaps saturate to white + const BG = [7, 12, 20]; // phosphor background + + // heatmap color LUT (density → color): dark → blue → cyan → green → yellow → red + const HEAT_LUT = (() => { + const stops = [[0, [7, 12, 20]], [0.15, [26, 30, 120]], [0.38, [0, 150, 205]], + [0.58, [0, 200, 90]], [0.78, [245, 220, 40]], [1, [235, 60, 30]]]; + const lut = new Uint8ClampedArray(256 * 3); + for (let i = 0; i < 256; i++) { + const t = i / 255; let a = stops[0], b = stops[stops.length - 1]; + for (let s = 0; s < stops.length - 1; s++) { if (t >= stops[s][0] && t <= stops[s + 1][0]) { a = stops[s]; b = stops[s + 1]; break; } } + const f = (t - a[0]) / ((b[0] - a[0]) || 1); + lut[i * 3] = a[1][0] + (b[1][0] - a[1][0]) * f; + lut[i * 3 + 1] = a[1][1] + (b[1][1] - a[1][1]) * f; + lut[i * 3 + 2] = a[1][2] + (b[1][2] - a[1][2]) * f; + } + return lut; + })(); + let heatMax = 60, heatImg = null; // running density peak + reusable output buffer + + const eye = $('#ed-eye'), strip = $('#ed-strip'); + const ex = eye.getContext('2d'), sx = strip.getContext('2d'); + const EW = eye.width, EH = eye.height, SW = strip.width, SH = strip.height; + + // offscreen "phosphor" layer holds the persistent, additively-blended traces + const phos = document.createElement('canvas'); phos.width = EW; phos.height = EH; + const px = phos.getContext('2d'); + px.fillStyle = 'rgb(' + BG.join(',') + ')'; px.fillRect(0, 0, EW, EH); + + const params = { rolloff: 0.35, snr: 30, jitter: 0, persist: 0.9, shape: 'rc', levels: 2, heatmap: false }; + let running = true; + let stripWave = null, stripPtr = 0, stripDirty = true; + + // ---------- math ---------- + function randn() { let u = 0, v = 0; while (!u) u = Math.random(); while (!v) v = Math.random(); + return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v); } + const sinc = x => x === 0 ? 1 : Math.sin(Math.PI * x) / (Math.PI * x); + function rcTap(x, b) { if (x === 0) return 1; + const d = 1 - (2 * b * x) * (2 * b * x); + if (Math.abs(d) < 1e-8) return (Math.PI / 4) * sinc(1 / (2 * b)); + return sinc(x) * Math.cos(Math.PI * b * x) / d; } + function rrcTap(x, b) { if (x === 0) return 1 - b + 4 * b / Math.PI; + if (Math.abs(Math.abs(x) - 1 / (4 * b)) < 1e-8) { + const a = (1 + 2 / Math.PI) * Math.sin(Math.PI / (4 * b)); + const c = (1 - 2 / Math.PI) * Math.cos(Math.PI / (4 * b)); + return (b / Math.SQRT2) * (a + c); } + const p = Math.PI * x, num = Math.sin(p * (1 - b)) + 4 * b * x * Math.cos(p * (1 + b)); + const den = p * (1 - (4 * b * x) * (4 * b * x)); return num / den; } + const snrLin = () => Math.pow(10, params.snr / 10); + const LEVELSETS = { 2: [-1, 1], 4: [-1, -1 / 3, 1 / 3, 1] }; + const levelArr = () => LEVELSETS[params.levels]; + function meanSymPower() { const lv = levelArr(); let es = 0; for (const a of lv) es += a * a; return es / lv.length; } + const sigma = () => Math.sqrt(meanSymPower() / snrLin()); // SNR = mean symbol power / noise variance + + // ---------- pulse-shaping filter (cached) ---------- + let filt = null, filtDirty = true; + function buildFilter() { + const fn = params.shape === 'rrc' ? rrcTap : rcTap, b = params.rolloff; + const h = new Float32Array(2 * L + 1), c = fn(0, b); + for (let n = -L; n <= L; n++) h[n + L] = fn(n / SPS, b) / c; + filt = h; filtDirty = false; + } + function makeWaveform(bits, addNoise) { + if (filtDirty) buildFilter(); + const N = bits.length * SPS, out = new Float32Array(N); + for (let k = 0; k < bits.length; k++) { const a = bits[k], base = k * SPS + (SPS >> 1); + for (let n = -L; n <= L; n++) { const i = base + n; if (i >= 0 && i < N) out[i] += a * filt[n + L]; } } + if (addNoise) { const s = sigma(); for (let i = 0; i < N; i++) out[i] += randn() * s; } + return out; + } + function genSymbols(n) { const lv = levelArr(), m = lv.length, s = new Float32Array(n); for (let i = 0; i < n; i++) s[i] = lv[(Math.random() * m) | 0]; return s; } + + const mapX = t => ((t + 1) / 2) * (EW - 1); + const mapY = v => (1 - (v - VMIN) / (VMAX - VMIN)) * (EH - 1); + + // ---------- draw fresh traces onto the phosphor layer (native anti-aliased lines) ---------- + function drawTraces() { + const nT = params.levels === 4 ? 64 : TRACES; + const bits = genSymbols(nT + 2 * SPAN); + const wf = makeWaveform(bits, false); + const s = sigma(), js = params.jitter * SPS; + px.globalCompositeOperation = 'lighter'; + px.strokeStyle = STROKE; px.lineWidth = 1; px.lineJoin = 'round'; + for (let k = SPAN; k < bits.length - SPAN; k++) { + const c = k * SPS + (SPS >> 1), jsh = Math.round(js * randn()); + px.beginPath(); + for (let o = 0; o <= 2 * SPS; o++) { + let idx = c - SPS + o + jsh; if (idx < 0) idx = 0; else if (idx >= wf.length) idx = wf.length - 1; + const v = wf[idx] + randn() * s, x = mapX((o - SPS) / SPS), y = mapY(v); + if (o === 0) px.moveTo(x, y); else px.lineTo(x, y); + } + px.stroke(); + } + px.globalCompositeOperation = 'source-over'; + } + + // ---------- measurement (reads the rendered phosphor, throttled) ---------- + const wLum = (r, g, b) => 0.25 * r + 0.6 * g + 0.15 * b; + const BGL = wLum(BG[0], BG[1], BG[2]); + function measure() { + const d = px.getImageData(0, 0, EW, EH).data; + const cx = Math.round(mapX(0)), cy = Math.round(mapY(0)); + let mx = 0; for (let i = 0; i < d.length; i += 4) { const l = wLum(d[i], d[i + 1], d[i + 2]) - BGL; if (l > mx) mx = l; } + heatMax = mx; // reuse the peak density to normalize the heatmap + if (mx < 2) return { heightPct: 0, widthPct: 0, hPx: 0, wPx: 0, cx, cy }; + const thr = mx * 0.10; + const sig = (r, c) => { const i = (r * EW + c) * 4; return wLum(d[i], d[i + 1], d[i + 2]) - BGL; }; + const avgC = r => { let s = 0; for (let c = cx - 2; c <= cx + 2; c++) s += sig(r, c); return s * 0.2; }; + const avgR = c => { let s = 0; for (let r = cy - 2; r <= cy + 2; r++) s += sig(r, c); return s * 0.2; }; + let hPx = 0, wPx = 0; + if (avgC(cy) < thr) { let top = cy, bot = cy; while (top > 0 && avgC(top - 1) < thr) top--; while (bot < EH - 1 && avgC(bot + 1) < thr) bot++; hPx = bot - top; } + if (avgR(cx) < thr) { let l = cx, r = cx; while (l > 0 && avgR(l - 1) < thr) l--; while (r < EW - 1 && avgR(r + 1) < thr) r++; wPx = r - l; } + const hFrac = hPx / EH * (VMAX - VMIN); + return { heightPct: Math.max(0, hFrac / 2 * 100), widthPct: Math.max(0, wPx / EW * 2 * 100), hPx, wPx, cx, cy }; + } + + // ---------- overlays (grid, sampling line, calipers) ---------- + function cap(x, y, dir) { ex.beginPath(); + if (dir === 'h') { ex.moveTo(x - 6, y); ex.lineTo(x + 6, y); } else { ex.moveTo(x, y - 6); ex.lineTo(x, y + 6); } ex.stroke(); } + function drawOverlays(m) { + ex.save(); + ex.strokeStyle = 'rgba(120,140,175,0.14)'; ex.lineWidth = 1; + for (const t of [-1, -0.5, 0.5, 1]) { const x = mapX(t) | 0; ex.beginPath(); ex.moveTo(x + .5, 0); ex.lineTo(x + .5, EH); ex.stroke(); } + for (const v of [-1, 0, 1]) { const y = mapY(v) | 0; ex.beginPath(); ex.moveTo(0, y + .5); ex.lineTo(EW, y + .5); ex.stroke(); } + + ex.strokeStyle = 'rgba(230,85,13,0.65)'; ex.setLineDash([5, 5]); ex.lineWidth = 1.5; + ex.beginPath(); ex.moveTo(m.cx + .5, 0); ex.lineTo(m.cx + .5, EH); ex.stroke(); ex.setLineDash([]); + + if (m.hPx > 4 || m.wPx > 4) { + ex.strokeStyle = '#e6550d'; ex.lineWidth = 2; + const top = m.cy - m.hPx / 2, bot = m.cy + m.hPx / 2, l = m.cx - m.wPx / 2, r = m.cx + m.wPx / 2; + if (m.hPx > 4) { ex.beginPath(); ex.moveTo(m.cx, top); ex.lineTo(m.cx, bot); ex.stroke(); cap(m.cx, top, 'h'); cap(m.cx, bot, 'h'); } + if (m.wPx > 4) { ex.beginPath(); ex.moveTo(l, m.cy); ex.lineTo(r, m.cy); ex.stroke(); cap(l, m.cy, 'v'); cap(r, m.cy, 'v'); } + } + ex.fillStyle = 'rgba(150,166,196,0.8)'; ex.font = '11px "IBM Plex Mono",ui-monospace,monospace'; + ex.textAlign = 'center'; ex.fillText('sample here', m.cx, EH - 8); + ex.textAlign = 'left'; ex.fillText('−1 UI', 6, EH - 8); + ex.textAlign = 'right'; ex.fillText('+1 UI', EW - 6, EH - 8); + ex.restore(); + } + + // ---------- heatmap display (remap the phosphor density through a color LUT) ---------- + function applyHeatmap() { + const src = px.getImageData(0, 0, EW, EH).data; + if (!heatImg) heatImg = ex.createImageData(EW, EH); + const out = heatImg.data, norm = 1 / Math.max(heatMax, 8); + for (let i = 0; i < src.length; i += 4) { + let l = (wLum(src[i], src[i + 1], src[i + 2]) - BGL) * norm; + if (l < 0) l = 0; else if (l > 1) l = 1; + l = Math.sqrt(l); // gamma lift so faint traces are visible + const j = ((l * 255) | 0) * 3; + out[i] = HEAT_LUT[j]; out[i + 1] = HEAT_LUT[j + 1]; out[i + 2] = HEAT_LUT[j + 2]; out[i + 3] = 255; + } + ex.putImageData(heatImg, 0, 0); + } + + // ---------- render ---------- + let frameCount = 0, meas = { heightPct: 0, widthPct: 0, hPx: 0, wPx: 0, cx: Math.round(mapX(0)), cy: Math.round(mapY(0)) }; + function renderEye() { + px.globalCompositeOperation = 'source-over'; // fade previous traces (persistence) + px.fillStyle = 'rgba(' + BG[0] + ',' + BG[1] + ',' + BG[2] + ',' + (1 - params.persist).toFixed(3) + ')'; + px.fillRect(0, 0, EW, EH); + drawTraces(); + if ((frameCount++ % 6) === 0) meas = measure(); + ex.clearRect(0, 0, EW, EH); + if (params.heatmap) applyHeatmap(); else ex.drawImage(phos, 0, 0); + drawOverlays(meas); + updateMeters(meas); + } + function updateMeters(m) { + $('#ed-m-height').innerHTML = m.heightPct.toFixed(0) + '%'; + $('#ed-m-width').innerHTML = m.widthPct.toFixed(0) + '%UI'; + } + function clearPhosphor() { px.globalCompositeOperation = 'source-over'; px.fillStyle = 'rgb(' + BG.join(',') + ')'; px.fillRect(0, 0, EW, EH); } + + // ---------- transmitted-signal strip ---------- + function rebuildStrip() { stripWave = makeWaveform(genSymbols(200), true); stripPtr = 0; stripDirty = false; } + function renderStrip() { + if (stripDirty || !stripWave) rebuildStrip(); + const visible = 12 * SPS; + if (running) { stripPtr += Math.round(SPS / 6); if (stripPtr + visible >= stripWave.length) rebuildStrip(); } + sx.clearRect(0, 0, SW, SH); + sx.strokeStyle = 'rgba(120,140,175,0.10)'; sx.lineWidth = 1; + for (const v of [-1, 0, 1]) { const y = (1 - (v + 2.25) / 4.5) * SH | 0; sx.beginPath(); sx.moveTo(0, y + .5); sx.lineTo(SW, y + .5); sx.stroke(); } + sx.beginPath(); sx.lineWidth = 2; sx.strokeStyle = '#17c3b2'; sx.shadowBlur = 8; sx.shadowColor = 'rgba(23,195,178,0.6)'; + for (let i = 0; i < visible; i++) { const s = stripWave[stripPtr + i], x = i / visible * SW, y = (1 - (s + 2.25) / 4.5) * SH; + if (i === 0) sx.moveTo(x, y); else sx.lineTo(x, y); } + sx.stroke(); sx.shadowBlur = 0; + } + + function frame() { if (running) renderEye(); renderStrip(); requestAnimationFrame(frame); } + + // ---------- controls ---------- + function fill(el) { const min = +el.min, max = +el.max, v = +el.value; el.style.setProperty('--fill', ((v - min) / (max - min) * 100) + '%'); } + function bindRange(id, fmt, apply) { const el = $('#' + id), out = $('#' + id + '-v'); + const upd = () => { apply(+el.value); out.textContent = fmt(+el.value); fill(el); }; el.addEventListener('input', upd); upd(); } + bindRange('ed-rolloff', v => v.toFixed(2), v => { params.rolloff = v; filtDirty = true; stripDirty = true; }); + bindRange('ed-snr', v => v.toFixed(1) + ' dB', v => { params.snr = v; stripDirty = true; }); + bindRange('ed-jitter', v => v.toFixed(0) + '%', v => { params.jitter = v / 100; }); + bindRange('ed-persist', v => v < 0.8 ? 'Short' : v < 0.9 ? 'Medium' : v < 0.94 ? 'Long' : 'Very long', v => { params.persist = v; }); + + $('#ed-levels').addEventListener('click', e => { + const b = e.target.closest('button'); if (!b) return; + params.levels = +b.dataset.levels; stripDirty = true; clearPhosphor(); + [...e.currentTarget.children].forEach(x => x.setAttribute('aria-pressed', x === b)); + }); + + $('#ed-shape').addEventListener('click', e => { + const b = e.target.closest('button'); if (!b) return; + params.shape = b.dataset.shape; filtDirty = true; stripDirty = true; clearPhosphor(); + [...e.currentTarget.children].forEach(x => x.setAttribute('aria-pressed', x === b)); + }); + + $('#ed-view').addEventListener('click', e => { // Lines vs Heatmap: display-only, no phosphor reset needed + const b = e.target.closest('button'); if (!b) return; + params.heatmap = b.dataset.view === 'heat'; + [...e.currentTarget.children].forEach(x => x.setAttribute('aria-pressed', x === b)); + }); + + const runBtn = $('#ed-run'); + runBtn.addEventListener('click', () => { running = !running; runBtn.textContent = running ? 'Pause' : 'Run'; + runBtn.classList.toggle('paused', !running); runBtn.setAttribute('aria-pressed', running); }); + $('#ed-reset').addEventListener('click', () => { clearPhosphor(); + const set = (id, val) => { const el = $('#' + id); el.value = val; el.dispatchEvent(new Event('input')); }; + set('ed-rolloff', 0.35); set('ed-snr', 30); set('ed-jitter', 0); set('ed-persist', 0.9); + root.querySelector('[data-shape="rc"]').click(); + root.querySelector('[data-levels="2"]').click(); + root.querySelector('[data-view="lines"]').click(); }); + + if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) { + for (let i = 0; i < 26; i++) renderEye(); + running = false; runBtn.textContent = 'Run'; runBtn.classList.add('paused'); runBtn.setAttribute('aria-pressed', false); + } + requestAnimationFrame(frame); +} diff --git a/_static/js/sidebar_groups.js b/_static/js/sidebar_groups.js new file mode 100644 index 00000000..13e4cccd --- /dev/null +++ b/_static/js/sidebar_groups.js @@ -0,0 +1,86 @@ +// Groups the hardware SDRs chapters into a collapsible section in the left sidebar +// Expanded by default; the reader can expand/collapse in place without navigating away +// State is remembered across pages via localStorage. +(function () { + var GROUP_LABEL = 'Specific SDR Hardware'; + var FILES = ['pluto.html', 'usrp.html', 'bladerf.html', 'rtlsdr.html', 'hackrf.html']; + + function fileName(url) { + return (url || '').split('#')[0].split('?')[0].split('/').pop(); + } + + function init() { + var sidebar = document.querySelector('.sphinxsidebarwrapper') || document.body; + + // Collect the SDR chapter
  • items, keeping the order in FILES. + var byFile = {}; + sidebar.querySelectorAll('li.toctree-l1 > a[href]').forEach(function (a) { + var f = fileName(a.getAttribute('href')); + if (FILES.indexOf(f) !== -1) byFile[f] = a.parentElement; + }); + + // The chapter you're currently on is rendered as the "current" item with an + // href of "#" (plus a nested list of its sections), so it needs its own + // lookup rather than matching by filename. + var currentFile = fileName(window.location.pathname); + if (FILES.indexOf(currentFile) !== -1) { + var currentLi = sidebar.querySelector('li.toctree-l1.current'); + if (currentLi) byFile[currentFile] = currentLi; + } + + var lis = []; + FILES.forEach(function (f) { if (byFile[f]) lis.push(byFile[f]); }); + if (!lis.length) return; + + var firstLi = lis[0]; + var parentUl = firstLi.parentElement; + + // Build the collapsible group header and its (initially empty) child list. + var groupLi = document.createElement('li'); + groupLi.className = 'toctree-l1 sdr-group'; + + var toggle = document.createElement('a'); + toggle.href = '#'; + toggle.className = 'sdr-group-toggle'; + toggle.setAttribute('role', 'button'); + toggle.innerHTML = '' + GROUP_LABEL; + + var childUl = document.createElement('ul'); + childUl.className = 'sdr-group-children'; + + groupLi.appendChild(toggle); + groupLi.appendChild(childUl); + parentUl.insertBefore(groupLi, firstLi); + + // Keep them as toctree-l1 so they retain the full-size chapter text; + // indentation under the group is handled by .sdr-group-children CSS. + lis.forEach(function (li) { + childUl.appendChild(li); + }); + + function setOpen(open) { + groupLi.classList.toggle('open', open); + toggle.setAttribute('aria-expanded', open ? 'true' : 'false'); + } + + // Expanded by default. Stay open unless the reader explicitly collapsed it + // last time (stored === '0'); always open when on one of these pages. + var onSdrPage = FILES.indexOf(currentFile) !== -1; + var stored = null; + try { stored = window.localStorage.getItem('sdrGroupOpen'); } catch (e) {} + setOpen(onSdrPage || stored !== '0'); + + toggle.addEventListener('click', function (e) { + e.preventDefault(); + var open = !groupLi.classList.contains('open'); + setOpen(open); + try { window.localStorage.setItem('sdrGroupOpen', open ? '1' : '0'); } catch (e2) {} + }); + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } +})(); diff --git a/_static/js/tdoa.js b/_static/js/tdoa.js new file mode 100644 index 00000000..dcf15875 --- /dev/null +++ b/_static/js/tdoa.js @@ -0,0 +1,649 @@ +function tdoa_app(containerId) { + // ----- configuration ------------------------------------------------------- + const c = 3e8; // propagation speed [m/s] (free space / RF) + const W = 600; // canvas width [px] + const H = 480; // canvas height [px] + const worldSpan = 1000; // world width represented across the canvas [m] + const nodeRadius = 9; // hit/draw radius for draggable handles [px] + const edgeMargin = 12; // keep handles at least this far inside the canvas [px] + const maxSensors = 10; // upper bound on how many sensors the user can add + const palette = ["#e6550d", "#3182bd", "#31a354"]; // first few sensor-pair colors + + // heatmap: give each hyperbola some width and add them together so their + // overlap lights up where the emitter actually is + let heatHalfWidth = 150; // band half-width around each hyperbola [m] + const heatRes = 2; // pixel block size of the heatmap grid (quality vs speed) + const heatMaxAlpha = 0.55; // overlay opacity where every band coincides + + // Color for the k-th sensor pair: use the fixed palette first, then spread the + // remaining hues around the color wheel so every pair stays distinguishable. + function pairColor(k) { + if (k < palette.length) return palette[k]; + return `hsl(${(k * 47) % 360}, 65%, 45%)`; + } + + // ----- DOM setup ----------------------------------------------------------- + const container = document.getElementById(containerId || "tdoaApp") || document.body; + + // canvas sits in a flex row next to the noise slider on its right + const row = document.createElement("div"); + row.style.display = "flex"; + row.style.alignItems = "stretch"; + row.style.gap = "10px"; + container.appendChild(row); + + // wrapper lets us overlay controls (the Add-sensor button) on top of the canvas + const canvasWrap = document.createElement("div"); + canvasWrap.style.position = "relative"; + canvasWrap.style.lineHeight = "0"; // avoid extra space under the canvas + row.appendChild(canvasWrap); + + const canvas = document.createElement("canvas"); + canvas.width = W; + canvas.height = H; + canvas.style.border = "1px solid #888"; + canvas.style.touchAction = "none"; // let us handle touch-drag ourselves + canvas.style.cursor = "grab"; + canvasWrap.appendChild(canvas); + + // vertical noise slider: standard deviation of the Gaussian noise [m] + const sliderBox = document.createElement("div"); + sliderBox.style.display = "flex"; + sliderBox.style.flexDirection = "column"; + sliderBox.style.alignItems = "center"; + sliderBox.style.fontFamily = "sans-serif"; + sliderBox.style.fontSize = "12px"; + row.appendChild(sliderBox); + + const sliderLabel = document.createElement("div"); + sliderLabel.style.textAlign = "center"; + sliderLabel.style.marginBottom = "6px"; + sliderBox.appendChild(sliderLabel); + + let noiseStd = 0; // std dev of Gaussian noise added to each range diff [m] + function updateSliderLabel() { + sliderLabel.innerHTML = `Noise
    ${noiseStd.toFixed(0)} m`; + } + updateSliderLabel(); + + const slider = document.createElement("input"); + slider.type = "range"; + slider.min = "0"; + slider.max = "100"; + slider.step = "1"; + slider.value = "0"; + // make the range input vertical (with a fallback for older browsers) + slider.setAttribute("orient", "vertical"); + slider.style.writingMode = "vertical-lr"; + slider.style.direction = "rtl"; // 0 at the bottom, max at the top + slider.style.height = H / 2 + "px"; // half the canvas height + slider.style.width = "24px"; + sliderBox.appendChild(slider); + + slider.addEventListener("input", () => { + noiseStd = parseFloat(slider.value); + updateSliderLabel(); + render(); + }); + + // vertical dynamic-range slider: a gamma exponent applied to the heatmap + // intensity. Higher values darken the weak single bands and let only the + // strong overlaps near the emitter stand out; lower values flatten it out. + let heatGamma = 1.5; // exponent applied to the normalized heatmap intensity + const drBox = document.createElement("div"); + drBox.style.display = "flex"; + drBox.style.flexDirection = "column"; + drBox.style.alignItems = "center"; + drBox.style.fontFamily = "sans-serif"; + drBox.style.fontSize = "12px"; + row.appendChild(drBox); + + const drLabel = document.createElement("div"); + drLabel.style.textAlign = "center"; + drLabel.style.marginBottom = "6px"; + drBox.appendChild(drLabel); + + function updateDrLabel() { + drLabel.innerHTML = `Dyn.
    range
    ${heatGamma.toFixed(1)}`; + } + updateDrLabel(); + + const drSlider = document.createElement("input"); + drSlider.type = "range"; + drSlider.min = "0.5"; + drSlider.max = "5"; + drSlider.step = "0.1"; + drSlider.value = String(heatGamma); + drSlider.setAttribute("orient", "vertical"); + drSlider.style.writingMode = "vertical-lr"; + drSlider.style.direction = "rtl"; // low at the bottom, high at the top + drSlider.style.height = H / 2 + "px"; + drSlider.style.width = "24px"; + drBox.appendChild(drSlider); + + drSlider.addEventListener("input", () => { + heatGamma = parseFloat(drSlider.value); + updateDrLabel(); + render(false); // visual-only: keep the existing noise samples + }); + + // vertical width slider: half-width of the band drawn around each hyperbola. + // Wider bands overlap more readily (good with lots of noise); narrow bands + // pin the emitter down tightly. + const widthBox = document.createElement("div"); + widthBox.style.display = "flex"; + widthBox.style.flexDirection = "column"; + widthBox.style.alignItems = "center"; + widthBox.style.fontFamily = "sans-serif"; + widthBox.style.fontSize = "12px"; + row.appendChild(widthBox); + + const widthLabel = document.createElement("div"); + widthLabel.style.textAlign = "center"; + widthLabel.style.marginBottom = "6px"; + widthBox.appendChild(widthLabel); + + function updateWidthLabel() { + widthLabel.innerHTML = `Width
    ${heatHalfWidth.toFixed(0)} m`; + } + updateWidthLabel(); + + const widthSlider = document.createElement("input"); + widthSlider.type = "range"; + widthSlider.min = "10"; + widthSlider.max = "200"; + widthSlider.step = "5"; + widthSlider.value = String(heatHalfWidth); + widthSlider.setAttribute("orient", "vertical"); + widthSlider.style.writingMode = "vertical-lr"; + widthSlider.style.direction = "rtl"; // narrow at the bottom, wide at the top + widthSlider.style.height = H / 2 + "px"; + widthSlider.style.width = "24px"; + widthBox.appendChild(widthSlider); + + widthSlider.addEventListener("input", () => { + heatHalfWidth = parseFloat(widthSlider.value); + updateWidthLabel(); + render(false); // visual-only: keep the existing noise samples + }); + + // buttons to add/remove a sensor, overlaid on the top-left corner of the canvas + const addBtn = document.createElement("button"); + addBtn.style.position = "absolute"; + addBtn.style.top = "8px"; + addBtn.style.left = "8px"; + addBtn.style.fontFamily = "sans-serif"; + addBtn.style.fontSize = "13px"; + addBtn.style.lineHeight = "normal"; + addBtn.style.padding = "4px 10px"; + addBtn.style.cursor = "pointer"; + canvasWrap.appendChild(addBtn); + + const removeBtn = document.createElement("button"); + removeBtn.style.position = "absolute"; + removeBtn.style.top = "40px"; + removeBtn.style.left = "8px"; + removeBtn.style.fontFamily = "sans-serif"; + removeBtn.style.fontSize = "13px"; + removeBtn.style.lineHeight = "normal"; + removeBtn.style.padding = "4px 10px"; + removeBtn.style.cursor = "pointer"; + canvasWrap.appendChild(removeBtn); + + // checkbox to toggle the heatmap overlay, overlaid below the buttons + let showHeatmap = true; // heatmap is on by default + const heatToggle = document.createElement("label"); + heatToggle.style.position = "absolute"; + heatToggle.style.top = "72px"; + heatToggle.style.left = "8px"; + heatToggle.style.display = "flex"; + heatToggle.style.alignItems = "center"; + heatToggle.style.gap = "4px"; + heatToggle.style.fontFamily = "sans-serif"; + heatToggle.style.fontSize = "13px"; + heatToggle.style.color = "#222"; + heatToggle.style.cursor = "pointer"; + heatToggle.style.userSelect = "none"; + + const heatCheckbox = document.createElement("input"); + heatCheckbox.type = "checkbox"; + heatCheckbox.checked = showHeatmap; + heatCheckbox.style.cursor = "pointer"; + heatCheckbox.style.margin = "0"; + heatToggle.appendChild(heatCheckbox); + heatToggle.appendChild(document.createTextNode("Heatmap")); + canvasWrap.appendChild(heatToggle); + + heatCheckbox.addEventListener("change", () => { + showHeatmap = heatCheckbox.checked; + render(false); // visual-only: keep the existing noise samples + }); + + // collapsible details panel: a thick bar you click to reveal the text readout, + // collapsed by default to keep the figure compact + const details = document.createElement("details"); + details.style.marginTop = "8px"; + details.style.width = W + "px"; + details.style.border = "1px solid #ccc"; + details.style.borderRadius = "4px"; + details.style.overflow = "hidden"; + container.appendChild(details); + + const summary = document.createElement("summary"); + summary.textContent = "Show Debug Info"; + summary.style.cursor = "pointer"; + summary.style.userSelect = "none"; + summary.style.fontFamily = "sans-serif"; + summary.style.fontSize = "13px"; + summary.style.fontWeight = "bold"; + summary.style.padding = "10px 12px"; + summary.style.background = "#f0f0f0"; + summary.style.color = "#333"; + details.appendChild(summary); + + // swap the label between collapsed/expanded states + details.addEventListener("toggle", () => { + summary.textContent = details.open ? "Hide Debug Info" : "Show Debug Info"; + }); + + const readout = document.createElement("div"); + readout.style.fontFamily = "monospace"; + readout.style.fontSize = "13px"; + readout.style.padding = "8px 12px"; + details.appendChild(readout); + + const ctx = canvas.getContext("2d"); + + // ----- scene state (world coordinates, meters, origin at center) ----------- + // y points up in world coordinates (flipped when drawing to the canvas). + const emitter = { x: -155, y: 226, label: "Emitter" }; + const sensors = [ + { x: -350, y: -200, label: "Sensor 0" }, + { x: 350, y: -200, label: "Sensor 1" }, + { x: 0, y: 300, label: "Sensor 2" } + ]; + + // ----- coordinate transforms ---------------------------------------------- + const scale = W / worldSpan; // px per meter + function worldToPx(p) { + return { x: W / 2 + p.x * scale, y: H / 2 - p.y * scale }; + } + function pxToWorld(px) { + return { x: (px.x - W / 2) / scale, y: (H / 2 - px.y) / scale }; + } + + function dist(a, b) { + return Math.hypot(a.x - b.x, a.y - b.y); + } + + // ----- TDOA simulation ----------------------------------------------------- + // Standard normal sample via the Box-Muller transform. + function randn() { + let u = 0; + let v = 0; + while (u === 0) u = Math.random(); + while (v === 0) v = Math.random(); + return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v); + } + + // Every unique sensor pair (i < j); order matches the original [0,1],[0,2],[1,2]. + function sensorPairs() { + const pairs = []; + for (let i = 0; i < sensors.length; i++) { + for (let j = i + 1; j < sensors.length; j++) pairs.push([i, j]); + } + return pairs; + } + + // Returns the per-sensor TOA and, for each pair, the TDOA and range diff. + function simulate() { + const toa = sensors.map((s) => dist(emitter, s) / c); // seconds + const measurements = sensorPairs().map(([i, j]) => { + // ideal TDOA, then add Gaussian noise (slider sets its std dev in meters, + // so we convert that range error into the equivalent time error) + const tdoa = toa[i] - toa[j] + (noiseStd * randn()) / c; // seconds + return { i, j, tdoa, dr: c * tdoa }; // dr = r_i - r_j [m] + }); + return { toa, measurements }; + } + + // ----- hyperbola drawing --------------------------------------------------- + // Locus of points u with |u - s_i| - |u - s_j| = dr is a hyperbola with foci + // at the two sensors. We parametrize it in a frame centered on the midpoint + // of the foci, with the transverse axis along the baseline. + function drawHyperbola(si, sj, dr, color) { + const mid = { x: (si.x + sj.x) / 2, y: (si.y + sj.y) / 2 }; + const baseline = dist(si, sj); + const cFoci = baseline / 2; // half the focal separation + const a = dr / 2; // signed semi-transverse axis; sign picks the branch + if (Math.abs(a) >= cFoci) return; // |dr| can't exceed the baseline + const b = Math.sqrt(cFoci * cFoci - a * a); + + // Unit vector u from s_i toward s_j (axis), and perpendicular v. + const ux = (sj.x - si.x) / baseline; + const uy = (sj.y - si.y) / baseline; + const vx = -uy; + const vy = ux; + + // Sweep the parameter t; x = a*cosh(t) keeps us on the correct branch + // because a carries the sign of dr. + ctx.beginPath(); + let first = true; + for (let t = -3; t <= 3.0001; t += 0.05) { + const xl = a * Math.cosh(t); + const yl = b * Math.sinh(t); + const wx = mid.x + xl * ux + yl * vx; + const wy = mid.y + xl * uy + yl * vy; + const p = worldToPx({ x: wx, y: wy }); + if (first) { + ctx.moveTo(p.x, p.y); + first = false; + } else { + ctx.lineTo(p.x, p.y); + } + } + ctx.strokeStyle = color; + ctx.lineWidth = 2; + ctx.stroke(); + } + + // ----- heatmap ------------------------------------------------------------- + // Reuse the same hyperbolas, but instead of an infinitely thin curve give + // each one a band of width 2*heatHalfWidth whose intensity follows a raised + // sine (raised cosine): 1 right on the hyperbola, tapering to 0 at the band + // edges. Summing every band makes their common crossing — the emitter — the + // brightest spot. We compute on a coarse grid and let drawImage smooth it. + const heatCanvas = document.createElement("canvas"); + const heatCtx = heatCanvas.getContext("2d"); + + // warm colormap: yellow at low intensity ramping to red at high intensity + function heatColor(t) { + return [255, Math.round(220 * (1 - t)), Math.round(40 * (1 - t))]; + } + + function drawHeatmap(measurements) { + if (measurements.length === 0) return; + const gw = Math.ceil(W / heatRes); + const gh = Math.ceil(H / heatRes); + heatCanvas.width = gw; + heatCanvas.height = gh; + const img = heatCtx.createImageData(gw, gh); + const data = img.data; + const nPairs = measurements.length; + + for (let gy = 0; gy < gh; gy++) { + for (let gx = 0; gx < gw; gx++) { + // world coordinates at the center of this grid block + const w = pxToWorld({ + x: gx * heatRes + heatRes / 2, + y: gy * heatRes + heatRes / 2 + }); + + let sum = 0; + for (let k = 0; k < nPairs; k++) { + const m = measurements[k]; + const si = sensors[m.i]; + const sj = sensors[m.j]; + const ri = Math.hypot(w.x - si.x, w.y - si.y); + const rj = Math.hypot(w.x - sj.x, w.y - sj.y); + // how far this point's range difference is from the measured one; + // 0 means the point sits exactly on pair k's hyperbola + const residual = ri - rj - m.dr; + if (Math.abs(residual) < heatHalfWidth) { + sum += 0.5 * (1 + Math.cos((Math.PI * residual) / heatHalfWidth)); + } + } + + // normalized intensity (1 where all bands overlap, the emitter), then + // a gamma to set the dynamic range: >1 suppresses the weak bands + const norm = Math.pow(sum / nPairs, heatGamma); + const idx = (gy * gw + gx) * 4; + const rgb = heatColor(norm); + data[idx] = rgb[0]; + data[idx + 1] = rgb[1]; + data[idx + 2] = rgb[2]; + data[idx + 3] = Math.round(norm * heatMaxAlpha * 255); + } + } + heatCtx.putImageData(img, 0, 0); + + // scale the coarse buffer up to full size; bilinear smoothing hides the grid + ctx.imageSmoothingEnabled = true; + ctx.drawImage(heatCanvas, 0, 0, gw, gh, 0, 0, W, H); + } + + // ----- rendering ----------------------------------------------------------- + function drawGrid() { + ctx.clearRect(0, 0, W, H); + ctx.strokeStyle = "#eee"; + ctx.lineWidth = 1; + const step = 100 * scale; // grid every 100 m + for (let x = (W / 2) % step; x < W; x += step) { + ctx.beginPath(); + ctx.moveTo(x, 0); + ctx.lineTo(x, H); + ctx.stroke(); + } + for (let y = (H / 2) % step; y < H; y += step) { + ctx.beginPath(); + ctx.moveTo(0, y); + ctx.lineTo(W, y); + ctx.stroke(); + } + // axes + ctx.strokeStyle = "#ccc"; + ctx.beginPath(); + ctx.moveTo(W / 2, 0); + ctx.lineTo(W / 2, H); + ctx.moveTo(0, H / 2); + ctx.lineTo(W, H / 2); + ctx.stroke(); + + // axis labels + ctx.fillStyle = "#999"; + ctx.font = "13px sans-serif"; + ctx.textBaseline = "alphabetic"; + ctx.textAlign = "right"; + ctx.fillText("X", W - 6, H / 2 - 6); + ctx.textAlign = "left"; + ctx.fillText("Y", W / 2 + 6, 14); + ctx.textAlign = "left"; + } + + function drawSensor(s) { + const p = worldToPx(s); + ctx.fillStyle = "#222"; + ctx.beginPath(); + ctx.moveTo(p.x, p.y - nodeRadius); + ctx.lineTo(p.x + nodeRadius, p.y + nodeRadius); + ctx.lineTo(p.x - nodeRadius, p.y + nodeRadius); + ctx.closePath(); + ctx.fill(); + ctx.fillStyle = "#222"; + ctx.font = "bold 16px sans-serif"; + ctx.fillText(s.label, p.x + nodeRadius + 2, p.y - 2); + } + + // small label near a node showing its world coordinates in meters + function drawCoordTooltip(node) { + const p = worldToPx(node); + const text = `(${node.x.toFixed(0)}, ${node.y.toFixed(0)}) m`; + ctx.font = "12px monospace"; + ctx.textAlign = "left"; + ctx.textBaseline = "alphabetic"; + const padX = 5; + const padY = 3; + const tw = ctx.measureText(text).width; + const boxW = tw + padX * 2; + const boxH = 16 + padY * 2; + // sit the box just below the node, nudged on-screen if it would clip + let bx = p.x + nodeRadius + 2; + let by = p.y + nodeRadius + 2; + if (bx + boxW > W) bx = W - boxW; + if (by + boxH > H) by = p.y - nodeRadius - boxH - 2; + ctx.fillStyle = "rgba(0, 0, 0, 0.8)"; + ctx.fillRect(bx, by, boxW, boxH); + ctx.fillStyle = "#fff"; + ctx.fillText(text, bx + padX, by + boxH - padY - 3); + } + + function drawEmitter() { + const p = worldToPx(emitter); + // black outline, no fill, so the heatmap underneath stays visible + ctx.beginPath(); + ctx.arc(p.x, p.y, nodeRadius, 0, 2 * Math.PI); + ctx.strokeStyle = "#000"; + ctx.lineWidth = 2; + ctx.stroke(); + ctx.fillStyle = "#000"; + ctx.font = "bold 16px sans-serif"; + ctx.fillText(emitter.label, p.x + nodeRadius + 2, p.y - 2); + } + + // cache the last simulation so purely-visual changes (heatmap width, dynamic + // range, hover) can repaint without drawing fresh noise samples + let lastSim = null; + function render(resimulate = true) { + if (resimulate || !lastSim) lastSim = simulate(); + const { toa, measurements } = lastSim; + + drawGrid(); + if (showHeatmap) drawHeatmap(measurements); + measurements.forEach((m, k) => { + drawHyperbola(sensors[m.i], sensors[m.j], m.dr, pairColor(k)); + }); + sensors.forEach(drawSensor); + drawEmitter(); + + // coordinate tooltip for the node under the cursor (or being dragged) + const activeNode = dragTarget || hoverNode; + if (activeNode) drawCoordTooltip(activeNode); + + // text readout of the simulated quantities + let html = ""; + toa.forEach((t, i) => { + html += `TOA(${sensors[i].label}) = ${(t * 1e9).toFixed(1)} ns   (range ${dist(emitter, sensors[i]).toFixed(0)} m)
    `; + }); + measurements.forEach((m, k) => { + html += `TDOA(${sensors[m.i].label},${sensors[m.j].label}) = ${(m.tdoa * 1e9).toFixed(1)} ns   Δr = ${m.dr.toFixed(0)} m
    `; + }); + readout.innerHTML = html; + } + + // ----- dragging ------------------------------------------------------------ + let dragTarget = null; + let hoverNode = null; // node currently under the cursor (for the tooltip) + + function eventPx(e) { + const rect = canvas.getBoundingClientRect(); + const src = e.touches ? e.touches[0] : e; + return { x: src.clientX - rect.left, y: src.clientY - rect.top }; + } + + function pickNode(px) { + const all = [emitter, ...sensors]; + for (const node of all) { + if (dist(worldToPx(node), px) <= nodeRadius + 4) return node; + } + return null; + } + + function onDown(e) { + const px = eventPx(e); + dragTarget = pickNode(px); + if (dragTarget) { + canvas.style.cursor = "grabbing"; + e.preventDefault(); + } + } + + function onMove(e) { + const px = eventPx(e); + if (!dragTarget) { + const hit = pickNode(px); + canvas.style.cursor = hit ? "grab" : "default"; + // only repaint when the hovered node actually changes, so the tooltip + // appears/disappears without re-noising the scene on every mouse move + if (hit !== hoverNode) { + hoverNode = hit; + render(false); // visual-only: keep the existing noise samples + } + return; + } + // keep the handle inside the canvas (with a small margin) so it can't be + // dragged off-screen and lost + px.x = Math.max(edgeMargin, Math.min(W - edgeMargin, px.x)); + px.y = Math.max(edgeMargin, Math.min(H - edgeMargin, px.y)); + const w = pxToWorld(px); + dragTarget.x = w.x; + dragTarget.y = w.y; + render(); + e.preventDefault(); + } + + function onUp() { + dragTarget = null; + canvas.style.cursor = "grab"; + } + + canvas.addEventListener("mouseleave", () => { + if (hoverNode) { + hoverNode = null; + render(false); // visual-only: keep the existing noise samples + } + }); + + canvas.addEventListener("mousedown", onDown); + window.addEventListener("mousemove", onMove); + window.addEventListener("mouseup", onUp); + canvas.addEventListener("touchstart", onDown, { passive: false }); + canvas.addEventListener("touchmove", onMove, { passive: false }); + canvas.addEventListener("touchend", onUp); + + // ----- adding / removing sensors ------------------------------------------- + const minSensors = 2; // at least 2 sensors to form one TDOA pair + + function updateSensorButtons() { + const atMax = sensors.length >= maxSensors; + addBtn.disabled = atMax; + addBtn.textContent = atMax + ? `Max sensors reached (${maxSensors})` + : `Add sensor`; + + const atMin = sensors.length <= minSensors; + removeBtn.disabled = atMin; + removeBtn.textContent = atMin + ? `Min sensors reached (${minSensors})` + : "Remove sensor"; + } + + function addSensor() { + if (sensors.length >= maxSensors) return; + const idx = sensors.length; + // place the new sensor on a ring, stepping by the golden angle so successive + // sensors spread out rather than landing on top of each other + const ang = idx * 2.399963229728653; + const r = 320; + sensors.push({ + x: r * Math.cos(ang), + y: r * Math.sin(ang), + label: "Sensor " + idx + }); + updateSensorButtons(); + render(); + } + + function removeSensor() { + if (sensors.length <= minSensors) return; + sensors.pop(); // drop the most recently added sensor + updateSensorButtons(); + render(); + } + + addBtn.addEventListener("click", addSensor); + removeBtn.addEventListener("click", removeSensor); + updateSensorButtons(); + + // ----- go ------------------------------------------------------------------ + render(); +} diff --git a/_static/potik-icon.svg b/_static/potik-icon.svg new file mode 100644 index 00000000..c873cdb6 --- /dev/null +++ b/_static/potik-icon.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_static/python.svg b/_static/python.svg new file mode 100644 index 00000000..6b19282c --- /dev/null +++ b/_static/python.svg @@ -0,0 +1,43 @@ + + diff --git a/_templates/homepage.html b/_templates/homepage.html index 7974022c..7ec3a063 100644 --- a/_templates/homepage.html +++ b/_templates/homepage.html @@ -6,7 +6,7 @@

    PySDR: A Guide to SDR and DSP using Python

    Dr. Marc Lichtman - - + pysdr@vt.edu

    @@ -30,31 +30,18 @@

    - To get a quick taste of RF signal processing, try playing with the simulation below which shows the frequency and time domain of a signal - consisting of a tone and white Gaussian noise. + To get a quick taste of RF signal processing, try playing with the Potik simulation below which shows the frequency (top) and time domain (bottom) of a signal consisting of a tone plus white Gaussian noise. On the right side panel you can change the tone's frequency and the amount of noise.

    -
    - - - -
    -
    - - - -
    -
    - -
    -
    -
    -
    - -
    - - + + +
    diff --git a/_templates/homepage_ja.html b/_templates/homepage_ja.html index ff643ac6..db66f50f 100644 --- a/_templates/homepage_ja.html +++ b/_templates/homepage_ja.html @@ -6,7 +6,7 @@

    PySDR: Pythonで学ぶSDRとDSP入門

    Dr. Marc Lichtman - - + pysdr@vt.edu

    diff --git a/_templates/homepage_nl.html b/_templates/homepage_nl.html index 8c7b2840..778ef12b 100644 --- a/_templates/homepage_nl.html +++ b/_templates/homepage_nl.html @@ -6,7 +6,7 @@

    PySDR: Een handleiding voor SDRs en digitale sign Dr. Marc Lichtman - - + pysdr@vt.edu

    diff --git a/_templates/homepage_uk.html b/_templates/homepage_uk.html index e255b108..dccbea2a 100644 --- a/_templates/homepage_uk.html +++ b/_templates/homepage_uk.html @@ -6,7 +6,7 @@

    PySDR: Посібник із SDR та DSP з ви Dr. Marc Lichtman — - + pysdr@vt.edu

    diff --git a/_templates/homepage_zh.html b/_templates/homepage_zh.html index db4205fc..27407d7f 100644 --- a/_templates/homepage_zh.html +++ b/_templates/homepage_zh.html @@ -6,7 +6,7 @@

    PySDR:使用 Python 玩转 SDR 和 DSP

    Dr. Marc Lichtman - - + pysdr@vt.edu

    diff --git a/_templates/layout.html b/_templates/layout.html index da78e0bd..74762615 100644 --- a/_templates/layout.html +++ b/_templates/layout.html @@ -15,6 +15,17 @@ {{ super() }} +{# Description used for search-engine snippets and social link previews. #} +{%- set pysdr_description = "PySDR is a free online textbook (not a Python library!) that provides a gentle introduction to wireless communications and software-defined radio (SDR) using an abundance of diagrams, animations, and Python code examples." %} + + + + + + + + + + + + + +********************** +Formation de faisceaux adaptative +********************** + + +Le formateur de faisceaux conventionnel présenté précédemment est une méthode simple et efficace, mais il présente certaines limitations. Par exemple, il est peu performant en présence de plusieurs signaux provenant de directions différentes ou lorsque le niveau de bruit est élevé. Dans ces cas, il est nécessaire d'utiliser des techniques de formation de faisceaux plus avancées, souvent qualifiées de « adaptatives ». Le principe de la formation de faisceaux adaptative est d'utiliser le signal reçu pour calculer les pondérations, au lieu d'utiliser un ensemble fixe de pondérations comme avec le formateur de faisceaux conventionnel. Cela permet au formateur de faisceaux de s'adapter à l'environnement et d'offrir de meilleures performances, car les pondérations sont désormais basées sur les statistiques des données reçues. + +Les techniques de formation de faisceaux adaptatives se divisent en deux catégories : les méthodes classiques et les méthodes basées sur les sous-espaces. Les méthodes de sous-espaces telles que MUSIC et ESPRIT sont très puissantes, mais elles nécessitent d'estimer le nombre de signaux présents et requièrent au moins trois éléments pour fonctionner (quatre étant recommandés). + +La première technique de formation de faisceaux adaptatifs que nous allons étudier est MVDR, qui tend à être l'algorithme de référence lorsque l'on parle de formation de faisceaux adaptatifs. + + +********************** +Formateur de faisceau MVDR/Capon +********************** + +Nous allons maintenant examiner un formateur de faisceau légèrement plus complexe que la technique conventionnelle de sommation et de retard, mais généralement beaucoup plus performant : le formateur de faisceau à réponse sans distorsion à variance minimale (MVDR), également appelé formateur de faisceau Capon. Rappelons que la variance d'un signal correspond à sa puissance. Le principe du MVDR est de maintenir le signal à l'angle d'intérêt avec un gain fixe de 1 (0 dB), tout en minimisant la variance/puissance totale du signal formé. Si le signal d'intérêt est maintenu fixe, minimiser la puissance totale revient à minimiser autant que possible les interférences et le bruit. On le qualifie souvent de formateur de faisceau « statistiquement optimal ». + +Le formateur de faisceau MVDR/Capon peut être résumé par l'équation suivante : + +.. math:: + w_{mvdr} = \frac{R^{-1} s}{s^H R^{-1} s} + +Le vecteur :math:`s` est le vecteur de direction correspondant à la direction souhaitée et a été présenté au début de ce chapitre. :math:`R` est l'estimation de la matrice de covariance spatiale basée sur nos échantillons reçus, obtenue à l'aide de :math:`R = np.cov(X)` ou calculée manuellement en multipliant :math:`X` par sa transposée conjuguée complexe, c'est-à-dire :math:`R = X X^H`. La matrice de covariance spatiale est une matrice de taille :math:`Nr` x :math:`Nr` (3x3 dans les exemples précédents) qui indique la similarité des échantillons reçus des trois éléments. Bien que cette équation puisse paraître complexe au premier abord, il est utile de savoir que le dénominateur sert principalement à la mise à l'échelle, et que le numérateur, qui correspond à la matrice de covariance inversée multipliée par le vecteur de direction, est l'élément essentiel sur lequel il faut se concentrer. Cela étant dit, il est nécessaire d'inclure le dénominateur ; il agit comme une constante de normalisation afin que, lorsque :math:`R` varie au fil du temps, les poids conservent leur amplitude. + +.. raw:: html +
    + Pour ceux qui s'intéressent à la dérivation du MVDR, voir le développement suivant : + +**Sortie du beamforming** - La sortie du beamformer utilisant un vecteur de pondération :math:`\mathbf{w}` est donnée par : + +.. math:: + y(t) = \mathbf{w}^H \mathbf{x}(t) + + +**Problème d'optimisation** - L'objectif est de déterminer les pondérations du beamforming qui minimisent la puissance de sortie tout en assurant une réponse sans distorsion dans la direction souhaitée :math:`\theta_0`. Formellement, le problème peut être exprimé comme suit : + +.. math:: + + \min_{\mathbf{w}} \, \mathbf{w}^H \mathbf{R} \mathbf{w} \quad \text{subject to} \quad \mathbf{w}^H \mathbf{s} = 1 + +où : + +* :math:`\mathbf{R} = E[\mathbf{X}\mathbf{X}^H]` est la matrice de covariance des signaux reçus +* :math:`\mathbf{s}` est le vecteur de direction vers la direction du signal souhaité :math:`\theta_0` + +**Méthode Lagrangienne** - Introduisons un multiplieur lagrangien :math:`\lambda` et construisons le lagrangien : + +.. math:: + + L(\mathbf{w}, \lambda) = \mathbf{w}^H \mathbf{R} \mathbf{w} - \lambda (\mathbf{w}^H \mathbf{s} - 1) + +**Résolution de l'optimisation** - En dérivant le lagrangien par rapport à :math:`\mathbf{w^H}` et en annulant la dérivée, on obtient : + +.. math:: + + \frac{\partial L}{\partial \mathbf{w}^*} = 2\mathbf{R}\mathbf{w} - \lambda \mathbf{s} = 0 + + \mathbf{w} = \lambda \mathbf{s} \mathbf{{R^{-1}}} + + +Pour résoudre :math:`\lambda`, appliquons la contrainte :math:`\mathbf{w}^H \mathbf{s} = 1`: + +.. math:: + + \implies (\lambda \mathbf{s^{H}}\mathbf{{R^{-1}}})s = 1 + + \implies \lambda = \frac{1}{\mathbf{s}^{H}\mathbf{R}^{-1}\mathbf{s}} + + \mathbf{R}\mathbf{w} = \lambda \mathbf{s} + + \mathbf{w_{mvdr}} = \frac{\mathbf{R}^{-1} \mathbf{s}}{\mathbf{s}^H \mathbf{R}^{-1} \mathbf{s}} + +.. raw:: html +
    + Si la direction du signal d'intérêt est connue et reste constante, il suffit de calculer les pondérations une seule fois et de les utiliser pour recevoir ce signal. Même si la direction est constante, il est avantageux de recalculer périodiquement ces pondérations pour compenser les variations d'interférences et de bruit. C'est pourquoi on parle de formation de faisceaux « adaptative » pour ces formateurs de faisceaux numériques non conventionnels : ils utilisent les informations du signal reçu pour calculer les pondérations optimales. Pour rappel, la formation de faisceaux avec MVDR peut se faire en calculant ces pondérations et en les appliquant au signal avec :code:`w.conj().T @ X`, comme avec la méthode conventionnelle. Seule la méthode de calcul des pondérations diffère. + +Pour effectuer une détermination de la direction d'arrivée (DOA) avec le formateur de faisceaux MVDR, il suffit de répéter le calcul MVDR en balayant tous les angles d'intérêt. Autrement dit, on considère que le signal provient de l'angle :math:`\theta`, même si ce n'est pas le cas. Pour chaque angle, nous calculons les pondérations MVDR, puis nous les appliquons au signal reçu, et enfin nous calculons la puissance du signal. L'angle qui nous donne la puissance la plus élevée correspond à notre estimation de la direction d'arrivée (DOA). Mieux encore, nous pouvons tracer la puissance en fonction de l'angle pour visualiser le diagramme de rayonnement, comme nous l'avons fait précédemment avec le formateur de faisceau conventionnel. Ainsi, nous n'avons pas besoin de supposer le nombre de signaux présents. + +En Python, nous pouvons implémenter le formateur de faisceau MVDR/Capon comme suit, sous forme de fonction pour faciliter son utilisation ultérieure : + +.. code-block:: python + + # theta est la direction d'intérêt, en radians, et X est notre signal reçu + def w_mvdr(theta, X): + s = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta)) # Vecteur de direction dans la direction souhaitée theta + s = s.reshape(-1,1) # Transformation en vecteur colonne (taille 3x1) + R = (X @ X.conj().T)/X.shape[1] # Calcul de la matrice de covariance. Donne une matrice de covariance Nr x Nr des échantillons + Rinv = np.linalg.pinv(R) # 3x3. La pseudo-inverse est généralement plus performante/rapide qu'une véritable inverse. + w = (Rinv @ s)/(s.conj().T @ Rinv @ s) # Équation MVDR/Capon ! Le numérateur est de dimension 3x3 * 3x1, le dénominateur de dimension 1x3 * 3x3 * 3x1, ce qui donne un vecteur de pondération 3x1. + return w + +En utilisant ce formateur de faisceau MVDR dans le contexte de la DOA, on obtient l'exemple Python suivant : + +.. code-block:: python + + theta_scan = np.linspace(-1*np.pi, np.pi, 1000) # 1000 valeurs de theta différentes entre -180 et +180 degrés + results = [] + for theta_i in theta_scan: + w = w_mvdr(theta_i, X) # 3x1 + X_weighted = w.conj().T @ X # application des pondérations + power_dB = 10*np.log10(np.var(X_weighted)) # puissance du signal, en dB, pour faciliter la visualisation simultanée des lobes de petite et de grande taille + results.append(power_dB) + results -= np.max(results) # normalisation + + +Appliquée à l'exemple de simulation DOA précédent, cette méthode donne le résultat suivant : + +.. image:: ../_images/doa_capons.svg + :align: center + :target: ../_images/doa_capons.svg + +Cela semble fonctionner correctement, mais pour comparer cette technique à d'autres, il nous faut créer un problème plus intéressant. Créons une simulation avec un réseau de 8 éléments recevant trois signaux provenant d'angles différents : 20°, 25° et 40°. Le signal à 40° est reçu à une puissance bien inférieure aux deux autres, afin de complexifier la simulation. Notre objectif est de détecter les trois signaux, c'est-à-dire de repérer des pics significatifs (suffisamment élevés pour être extraits par un algorithme de détection de pics). Le code permettant de générer ce nouveau scénario est le suivant : + +.. code-block:: python + + Nr = 8 # 8 éléments + theta1 = 20 / 180 * np.pi # conversion en radians + theta2 = 25 / 180 * np.pi + theta3 = -40 / 180 * np.pi + s1 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta1)).reshape(-1,1) # 8x1 + s2 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta2)).reshape(-1,1) + s3 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta3)).reshape(-1,1) + # Nous utiliserons 3 fréquences différentes. 1xN + tonalité1 = np.exp(2j*np.pi*0.01e6*t).reshape(1,-1) + tonalité2 = np.exp(2j*np.pi*0.02e6*t).reshape(1,-1) + tonalité3 = np.exp(2j*np.pi*0.03e6*t).reshape(1,-1) + X = s1@tone1 + s2@tone2 + 0.1 * s3@tone3 # notez que la dernière valeur représente 1/10e de la puissance + n = np.random.randn(Nr, N) + 1j*np.random.randn(Nr, N) + X = X + 0.05*n # 8xN + +Vous pouvez placer ce code en haut de votre script, car nous générons un signal différent de celui de l'exemple original. Si nous appliquons notre formateur de faisceau MVDR à ce nouveau scénario, nous obtenons les résultats suivants : + +.. image:: ../_images/doa_capons2.svg + :align: center + :target: ../_images/doa_capons2.svg + +Il fonctionne plutôt bien : nous pouvons observer les deux signaux reçus, séparés de seulement 5 degrés, ainsi que le troisième signal (à -40° ou 320°) reçu à une puissance dix fois inférieure à celle des autres. Appliquons maintenant le formateur de faisceau conventionnel à ce même scénario : + +.. image:: ../_images/doa_complex_scenario.svg + :align: center + :target: ../_images/doa_complex_scenario.svg + +Bien que la forme du faisceau soit plutôt esthétique, il ne détecte pas du tout les trois signaux… En comparant ces deux résultats, nous pouvons constater l’avantage. + +Pour information, il est possible d'optimiser le calcul de la DOA avec MVDR grâce à une astuce. Rappelons que la puissance d'un signal est calculée en prenant sa variance, qui est la moyenne du carré de son amplitude (en supposant que la valeur moyenne de nos signaux est nulle, ce qui est presque toujours le cas pour les signaux RF en bande de base). On peut représenter la puissance de notre signal après pondération par l'équation suivante : + +.. math:: + + P_{mvdr} = \frac{1}{N} \sum_{n=0}^{N-1} \left| w^H_{mvdr} r_n \right|^2 + +Si l'on remplace la sommation par l'opérateur d'espérance et que l'on substitue l'équation des poids MVDR, on obtient : + +.. math:: + + P_{mvdr} & = E \left( \left| w^H_{mvdr} X_n \right| ^2 \right) \\ + & = w^H_{mvdr} E \left( X X^H \right) w_{mvdr}\\ + & = w^H_{mvdr} R w_{mvdr}\\ + & = \frac{s^H R^{-1} s}{s^H R^{-1} s} \cdot R \cdot \frac{R^{-1} s}{s^H R^{-1} s}\\ + & = \frac{s^H R^{-1} s}{(s^H R^{-1} s)(s^H) R^{-1} s)}\\ + & = \frac{1}{s^H R^{-1} s} + +Ce qui signifie que nous n'avons pas besoin d'appliquer les pondérations. Cette dernière équation de puissance ci-dessus peut être utilisée directement dans notre analyse DOA, ce qui nous permet d'économiser des calculs : + +.. code-block:: python + + def power_mvdr(theta, X): + s = np.exp(2j * np.pi * d * np.arange(r.shape[0]) * np.sin(theta)) # vecteur de direction dans la direction souhaitée theta + s = s.reshape(-1,1) # transformation en vecteur colonne (taille 3x1) + R = (X @ X.conj().T)/X.shape[1] # Calcul de la matrice de covariance. Donne une matrice de covariance Nr x Nr des échantillons + Rinv = np.linalg.pinv(R) # 3x3. La pseudo-inverse est généralement plus performante que l'inverse exacte. + return 1/(s.conj().T @ Rinv @ s).squeeze() + +Pour utiliser cette fonction dans la simulation précédente, au sein de la boucle for, il suffit d'effectuer le calcul suivant :code:`10*np.log10()`. C'est terminé ! Aucun poids n'est à appliquer ; nous avons omis de les calculer. + +Il existe de nombreux autres formateurs de faisceaux, mais nous allons maintenant examiner l'influence du nombre d'éléments sur la formation de faisceaux et la détermination de la direction d'arrivée (DOA). + + +********************** +Matrice de covariance +********************** + +Prenons un instant pour aborder la matrice de covariance spatiale, concept clé du *beamforming adaptatif*. Une matrice de covariance est une représentation mathématique de la similarité entre paires d'éléments d'un vecteur aléatoire (dans notre cas, les éléments de notre réseau, d'où le terme de matrice de covariance *spatiale*). Une matrice de covariance est toujours carrée, et les valeurs de sa diagonale correspondent à la covariance de chaque élément avec lui-même. Nous calculons une estimation de la matrice de covariance spatiale ; il ne s'agit que d'une estimation, compte tenu du nombre limité d'échantillons. + +De manière générale, la matrice de covariance est définie comme suit : +:math:`\mathrm{cov}(X) = E \left[ (X - E[X])(X - E[X])^H \right]` + +for wireless signals at baseband, :math:`E[X]` is typically zero or very close to zero, so this simplifies to: + +:math:`\mathrm{cov}(X) = E[X X^H]` + +Given a limited number of IQ samples, :math:`\boldsymbol{X}`, we can estimate this covariance, which we will denote as :math:`\hat{R}`: + +.. math:: + \hat{R} = \frac{\boldsymbol{X} \boldsymbol{X}^H}{N} + = \frac{1}{N} \sum^N_{n=1} X_n X_n^H + +where :math:`N` is the number of samples (not the number of elements). In Python this looks like: + +:code:`R = (X @ X.conj().T)/X.shape[1]` + +Alternatively, we can use the built-in NumPy function: + +:code:`R = np.cov(X)` + +As an example, we will look at the spatial covariance matrix for the scenario where we only had one transmitter and three elements: + +.. code-block:: python + + [[ 1.494+0.j 0.486+0.881j -0.543+0.839j] + [ 0.486-0.881j 1.517 +0.j 0.483+0.886j] + [-0.543-0.839j 0.483-0.886j 1.499+0.j ]] + + +Remarquez que les éléments diagonaux sont réels et sensiblement identiques. En effet, ils indiquent uniquement la puissance du signal reçu à chaque élément, qui sera sensiblement la même d'un élément à l'autre puisque leur gain est identique. Les éléments hors diagonale contiennent les valeurs importantes, même si l'examen des valeurs brutes ne nous apprend pas grand-chose, si ce n'est une forte corrélation entre les éléments. + +Dans le cadre de la formation de faisceaux adaptative, vous observerez un motif où l'on calcule l'inverse de la matrice de corrélation spatiale. Cette inverse indique la relation entre deux éléments après avoir éliminé l'influence des autres éléments. On l'appelle « matrice de précision » en statistiques et « matrice de blanchiment » en radar. + + +********************** +Formateur de faisceaux LCMV +********************** + +Bien que le MVDR soit puissant, que se passe-t-il si nous avons plusieurs signaux d'intérêts (SOI) ? Heureusement, grâce à une légère modification du MVDR, nous pouvons implémenter un schéma gérant plusieurs SOI, appelé formateur de faisceau à variance minimale contrainte linéaire (LCMV). Il s'agit d'une généralisation du MVDR, où l'on spécifie la réponse souhaitée pour plusieurs directions, un peu comme une version spatiale de la fonction `firwin2()` de SciPy pour ceux qui la connaissent. Le vecteur de pondération optimal pour le formateur de faisceau LCMV peut être résumé par l'équation suivante : + +.. math:: + w_{lcmv} = R^{-1} C [C^H R^{-1} C]^{-1} f + +où :math:`C` est une matrice comprenant les vecteurs de direction des SOI et des interférents correspondants, et :math:`f` est le vecteur de réponse souhaité. Le vecteur :math:`f` d'une ligne donnée prend la valeur 0 lorsque le vecteur de direction correspondant doit être annulé, et la valeur 1 lorsqu'un faisceau doit être dirigé vers cette ligne. Par exemple, avec deux sources d'intérêt et deux sources d'interférence, on peut définir :math:`f = [1,1,0,0]`. Le formateur de faisceaux LCMV est un outil puissant permettant de supprimer les interférences et le bruit provenant de plusieurs directions, tout en amplifiant le signal d'intérêt provenant également de plusieurs directions. Cependant, le nombre total d'annulations et de faisceaux pouvant être formés simultanément est limité par la taille du réseau (le nombre d'éléments). De plus, il est nécessaire de définir le vecteur de direction pour chaque source d'intérêt et chaque interféreur, ce qui n'est pas toujours possible en pratique. L'utilisation d'estimations peut dégrader les performances du formateur de faisceaux LCMV. C'est pourquoi nous préférons orienter les zones d'interférence nulle (ou « nulls ») à l'aide de la matrice de covariance spatiale :math:`R` (basée sur les statistiques du signal reçu), plutôt que de les « coder en dur » en estimant l'angle d'arrivée (AoA) de l'interférent (ce qui peut engendrer des erreurs) et en construisant le vecteur de direction dans cette direction, en ajoutant un 0 à :math:`f`. + +L'implémentation de LCMV en Python est très similaire à celle de MVDR, mais nous devons spécifier :math:`C`, composé de plusieurs vecteurs de direction potentiels, et :math:`f`, un tableau unidimensionnel de 1 et de 0, comme mentionné précédemment. L'extrait de code suivant illustre l'implémentation du formateur de faisceau LCMV pour deux angles d'incidence (15° et 60°). Rappelons que MVDR ne prend en charge qu'un seul angle d'incidence à la fois. Par conséquent, notre :math:`f` est initialisé à :math:`[1; 1]` sans zéros, car nous n'incluons aucune zone d'interférence nulle « codée en dur ». Nous allons simuler un scénario avec quatre interférents arrivant d'angles de -60, -30, 0 et 30 degrés. + +.. code-block:: python + + # Pointons vers le SOI à 15° et un autre SOI potentiel, non simulé, à 60°. + soi1_theta = 15 / 180 * np.pi # Conversion en radians + soi2_theta = 60 / 180 * np.pi + # Poids LCMV + R_inv = np.linalg.pinv(np.cov(X)) # 8x8 + s1 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(soi1_theta)).reshape(-1,1) # 8x1 + s2 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(soi2_theta)).reshape(-1,1) # 8x1 + C = np.concatenate((s1, s2), axis=1) # 8x2 + f = np.ones(2).reshape(-1,1) # 2x1 + + # Équation LCMV + # 8x8 8x2 2x8 8x8 8x2 2x1 + w = R_inv @ C @ np.linalg.pinv(C.conj().T @ R_inv @ C) @ f # Sortie : 8x1 + +Nous pouvons tracer le diagramme de rayonnement de :code:`w` à l'aide de la méthode FFT présentée précédemment : + +.. image:: ../_images/lcmv_beam_pattern.svg + :align: center + :target: ../_images/lcmv_beam_pattern.svg + :alt: Exemple de diagramme de rayonnement obtenu avec le formateur de faisceau LCMV + +Comme vous pouvez le constater, nous avons des faisceaux pointant dans les deux directions d'intérêt. Des points nuls sont ajoutés aux emplacements des interférents (comme pour le MVDR, il n'est pas nécessaire de spécifier la position des émetteurs ; le logiciel la détermine à partir du signal reçu). Des points verts et rouges sont ajoutés au graphique pour indiquer les angles d'arrivée (AoA) des SOI et des interférents, respectivement. + +.. raw:: html +
    + Pour le code complet, développez cette section + +.. code-block:: python + + # Simulation du signal reçu + Nr = 8 # 8 éléments + theta1 = -60 / 180 * np.pi # Conversion en radians + theta2 = -30 / 180 * np.pi + theta3 = 0 / 180 * np.pi + theta4 = 30 / 180 * np.pi + s1 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(the) + s2 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta2)).reshape(-1,1) + s3 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta3)).reshape(-1,1) + s4 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta4)).reshape(-1,1) + # we'll use 3 different frequencies. 1xN + tone1 = np.exp(2j*np.pi*0.01e6*t).reshape(1,-1) + tone2 = np.exp(2j*np.pi*0.02e6*t).reshape(1,-1) + tone3 = np.exp(2j*np.pi*0.03e6*t).reshape(1,-1) + tone4 = np.exp(2j*np.pi*0.04e6*t).reshape(1,-1) + X = s1 @ tone1 + s2 @ tone2 + s3 @ tone3 + s4 @ tone4 + n = np.random.randn(Nr, N) + 1j*np.random.randn(Nr, N) + X = X + 0.5*n # 8xN + + # Prenons comme exemples le SOI à 15 degrés, et un autre SOI potentiel que nous n'avons pas simulé à 60 degrés. + soi1_theta = 15 / 180 * np.pi # conversion en radians + soi2_theta = 60 / 180 * np.pi + + # Poids du LCMV + R_inv = np.linalg.pinv(np.cov(X)) # 8x8 + s1 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(soi1_theta)).reshape(-1,1) # 8x1 + s2 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(soi2_theta)).reshape(-1,1) # 8x1 + C = np.concatenate((s1, s2), axis=1) # 8x2 + f = np.ones(2).reshape(-1,1) # 2x1 + + # Équation du LCMV + # 8x8 8x2 2x8 8x8 8x2 2x1 + w = R_inv @ C @ np.linalg.pinv(C.conj().T @ R_inv @ C) @ f # la sortie est 8x1 + + # Tracé du diagramme de rayonnement + w = w.squeeze() # reduction à un tableau 1D + N_fft = 1024 + w_padded = np.concatenate((w, np.zeros(N_fft - Nr))) # zero pad à N_fft éléments pour obtenir un meilleur résolution dans la FFT + w_fft_dB = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(w_padded)))**2) # amplitude de la FFT en dB + w_fft_dB -= np.max(w_fft_dB) # normalisation à 0 dB au maximum + theta_bins = np.arcsin(np.linspace(-1, 1, N_fft)) # Associer les échantillons de la FFT à des angles en radians + fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}) + ax.plot(theta_bins, w_fft_dB) # MAKE SURE TO USE RADIAN FOR POLAR + # Add dots where interferers and SOIs are + ax.plot([theta1], [0], 'or') + ax.plot([theta2], [0], 'or') + ax.plot([theta3], [0], 'or') + ax.plot([theta4], [0], 'or') + ax.plot([soi1_theta], [0], 'og') + ax.plot([soi2_theta], [0], 'og') + ax.set_theta_zero_location('N') # Orienter 0 degré vers le haut + ax.set_theta_direction(-1) # Incrémenter dans le sens horaire + ax.set_thetagrids(np.arange(-90, 105, 15)) # c'est en degrés + ax.set_rlabel_position(55) # Éloigner les étiquettes de la grille des autres étiquettes + ax.set_thetamin(-90) # Afficher uniquement la moitié supérieure + ax.set_thetamax(90) + ax.set_ylim([-30, 1]) # En l'absence de bruit, réduire de 30 dB seulement + plt.show() + +.. image:: ../_images/doa_quiescent.svg + :align: center + :target: ../_images/doa_quiescent.svg + +.. raw:: html + +
    + +Il existe un cas d'utilisation particulier de LCMV auquel vous avez peut-être déjà pensé : supposons qu'au lieu de pointer le faisceau principal à exactement 20 degrés, vous souhaitiez un faisceau plus large que celui fourni par un formateur de faisceau classique. Pour ce faire, définissez le vecteur de réponse souhaité :code:`f` comme un vecteur de 1 sur une plage d'angles (par exemple, plusieurs valeurs entre 10 et 30 degrés) et de 0 ailleurs. Cet outil puissant permet de créer un diagramme de rayonnement plus large que le lobe principal d'un formateur de faisceau classique, ce qui est toujours un avantage dans les situations réelles où l'angle d'arrivée exact est inconnu. La même approche peut être utilisée pour créer un zéro dans une direction spécifique, réparti sur une plage d'angles relativement large. N'oubliez pas que cela nécessite plusieurs degrés de liberté ! À titre d'exemple, simulons un réseau de 18 éléments et définissons l'angle d'intérêt entre 15 et 30 degrés à l'aide de 4 valeurs différentes de θ, et un angle nul entre 45 et 60 degrés à l'aide de 4 autres valeurs différentes de θ. Nous ne simulerons aucun interférent réel. + +.. code-block:: python + + Nr = 18 + X = np.random.randn(Nr, N) + 1j*np.random.randn(Nr, N) # Simulation d'un signal reçu composé uniquement de bruit. + + # Poitons vers le SOI de 15 à 30 degrés en utilisant 4 thetas différents + soi_thetas = np.linspace(15, 30, 4) / 180 * np.pi # conversio en radians + + # Let's make a null from 45 to 60 degrees using 4 different thetas + null_thetas = np.linspace(45, 60, 4) / 180 * np.pi # convert to radians + + # poids LCMV + R_inv = np.linalg.pinv(np.cov(X)) + s = [] + for soi_theta in soi_thetas: + s.append(np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(soi_theta)).reshape(-1,1)) + for null_theta in null_thetas: + s.append(np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(null_theta)).reshape(-1,1)) + C = np.concatenate(s, axis=1) + f = np.asarray([1]*len(soi_thetas) + [0]*len(null_thetas)).reshape(-1,1) + w = R_inv @ C @ np.linalg.pinv(C.conj().T @ R_inv @ C) @ f # LCMV equation + + # Tracé du diagramme de rayonnement comme précédemment... + +.. image:: ../_images/lcmv_beam_pattern_spread.svg + :align: center + :target: ../_images/lcmv_beam_pattern_spread.svg + :alt: Exemple de diagramme de rayonnement lors de l'utilisation du formateur de faisceau LCMV avec un faisceau étalé et un point d'annulation étalé. + +Le faisceau et le point d'annulation sont répartis sur la plage demandée ! Essayez de modifier le nombre de θ pour le faisceau principal et/ou le point d'annulation, ainsi que le nombre d'éléments, afin de vérifier si les pondérations résultantes permettent d'obtenir la réponse souhaitée. + +******************* +Orientation du point d'annulation +******************* + +Maintenant que nous avons vu le LCMV, il est intéressant d'explorer une technique plus simple, utilisable avec les réseaux analogiques et numériques : l'orientation du point d'annulation. Il s'agit d'une extension du formateur de faisceau classique, permettant non seulement de diriger un faisceau dans la direction souhaitée, mais aussi de placer des points d'annulation à des angles spécifiques. Cette technique n'implique pas de modification des pondérations en fonction du signal reçu (par exemple, le coefficient de réflexion :code:`R` n'est jamais calculé) et n'est donc pas considérée comme adaptative. Dans la simulation ci-dessous, il n'est même pas nécessaire de simuler un signal : il suffit de paramétrer les poids de notre formateur de faisceau en utilisant la technique de suppression des zéros pour placer des zéros à des angles prédéfinis, puis de visualiser le diagramme de rayonnement. + +Les poids pour la suppression des zéros sont calculés en partant d'un formateur de faisceau conventionnel pointé dans la direction souhaitée, puis en utilisant l'équation d'annulation des lobes secondaires pour mettre à jour les poids afin d'inclure les zéros, un à un. L'équation d'annulation des lobes secondaires est : + +.. math:: + + w_{\text{new}} = w_{\text{orig}} - \frac{w_{\text{null}}^H w_{\text{orig}}}{w_{\text{null}}^H w_{\text{null}}} w_{\text{null}} + + +où :math:`w_{\text{null}}` représente le vecteur de direction dans la direction du point nul que l'on souhaite ajouter à :math:`w_{\text{orig}}`. Les pondérations sont mises à jour en soustrayant le vecteur de direction du point nul, mis à l'échelle, des pondérations actuelles. Le facteur d'échelle est calculé en projetant les pondérations actuelles sur le vecteur de direction du point nul, puis en divisant par la projection de ce vecteur sur lui-même. Cette opération est ensuite répétée pour chaque direction de point nul (:math:`w_{\text{orig}}` correspond initialement aux pondérations de formation de faisceau conventionnelles, mais est mis à jour après l'ajout de chaque point nul). Le processus complet se présente comme suit : + +.. math:: + + & \text{1:} \qquad w_{\text{orig}} = e^{2j \pi d k \sin(\theta_{SOI})} \qquad + + & \text{2:} \qquad w_{\text{null}} = e^{2j \pi d k \sin(\theta_{null})} \qquad + + & \text{3:} \qquad w_{\text{new}} = w_{\text{orig}} - \frac{w_{\text{null}}^H w_{\text{orig}}}{w_{\text{null}}^H w_{\text{null}}} w_{\text{null}} + + & \text{4:} \qquad w_{\text{orig}} = w_{\text{new}} \qquad \qquad \qquad + + & \text{5:} \qquad \text{Aller à 2: pour ajouter le prochain élément nul} + +Simulons un tableau de 8 éléments et insérons quatre éléments nuls : + +.. code-block:: python + + d = 0.5 + Nr = 8 + + theta_soi = 30 / 180 * np.pi # convert to radians + nulls_deg = [-60, -30, 0, 60] # degrees + nulls_rad = np.asarray(nulls_deg) / 180 * np.pi + + # Start out with conventional beamformer pointed at theta_soi + w = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta_soi)).reshape(-1,1) + + # Loop through nulls + for null_rad in nulls_rad: + # weights equal to steering vector in target null direction + w_null = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(null_rad)).reshape(-1,1) + + # scaling_factor (complex scalar) for w at nulled direction + scaling_factor = w_null.conj().T @ w / (w_null.conj().T @ w_null) + print("scaling_factor:", scaling_factor, scaling_factor.shape) + + # Update weights to include the null + w = w - w_null @ scaling_factor # sidelobe-canceler equation + + # Plot beam pattern + N_fft = 1024 + w_padded = np.concatenate((w.squeeze(), np.zeros(N_fft - Nr))) # zero pad to N_fft elements to get more resolution in the FFT + w_fft_dB = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(w_padded)))**2) # magnitude of fft in dB + w_fft_dB -= np.max(w_fft_dB) # normalize to 0 dB at peak + theta_bins = np.arcsin(np.linspace(-1, 1, N_fft)) # Map the FFT bins to angles in radians + + fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}) + ax.plot(theta_bins, w_fft_dB) + # Add dots where nulls and SOI are + for null_rad in nulls_rad: + ax.plot([null_rad], [0], 'or') + ax.plot([theta_soi], [0], 'og') + ax.set_theta_zero_location('N') # make 0 degrees point up + ax.set_theta_direction(-1) # increase clockwise + ax.set_thetagrids(np.arange(-90, 105, 15)) # it's in degrees + ax.set_rlabel_position(55) # Move grid labels away from other labels + ax.set_thetamin(-90) # only show top half + ax.set_thetamax(90) + ax.set_ylim([-40, 1]) # because there's no noise, only go down -40 dB + plt.show() + + + +On obtient le diagramme de rayonnement suivant. Vous remarquerez peut-être des zones sans interférence à des endroits non spécifiés ; c’est normal et dû au nombre limité d’éléments. Avec un nombre d’éléments insuffisant, il se peut également que les zones sans interférence ou le faisceau ne soient pas positionnés exactement comme prévu, ou que le diagramme ne réponde pas du tout aux critères en raison d’un manque de degrés de liberté (nombre d’éléments moins 1). + +.. image:: ../_images/null_steering.svg + :align: center + :target: ../_images/null_steering.svg + :alt: Example of null steering beamforming + +******************* +MUSIC +******************* + +Nous allons maintenant aborder un autre type de formateur de faisceau. Tous les précédents appartenaient à la catégorie « retard et sommation », mais nous allons maintenant explorer les méthodes de « sous-espace ». Celles-ci consistent à diviser le sous-espace du signal et le sous-espace du bruit, ce qui implique d'estimer le nombre de signaux reçus par le réseau pour obtenir un bon résultat. La classification multiple de signaux (MUSIC) est une méthode de sous-espace très répandue qui consiste à calculer les vecteurs propres de la matrice de covariance (une opération gourmande en ressources de calcul). Nous divisons les vecteurs propres en deux groupes : le sous-espace du signal et le sous-espace du bruit, puis nous projetons les vecteurs de direction dans le sous-espace du bruit et nous orientons le faisceau vers les zéros. Cela peut paraître complexe au premier abord, ce qui explique en partie pourquoi MUSIC semble parfois relever de la magie noire ! + +L'équation fondamentale de MUSIC est la suivante : + +.. math:: + + \hat{\theta} = \mathrm{argmax}\left(\frac{1}{s^H V_n V^H_n s}\right) + +où :math:`V_n` est la liste des vecteurs propres du sous-espace de bruit mentionnée précédemment (une matrice 2D). On la détermine en calculant d'abord les vecteurs propres de :math:`R`, ce qui se fait simplement avec :code:`w, v = np.linalg.eig(R)` en Python, puis en divisant les vecteurs (:code:`w`) en fonction du nombre de signaux que l'on estime reçus par le réseau. Il existe une astuce pour estimer ce nombre de signaux, que nous aborderons plus loin, mais il doit être compris entre 1 et :code:`Nr - 1`. Autrement dit, lors de la conception d'un réseau, le nombre d'éléments doit être supérieur de 1 au nombre de signaux attendus. Il est important de noter que, dans l'équation ci-dessus, V_n ne dépend pas du vecteur de direction s ; nous pouvons donc le précalculer avant de parcourir l'angle θ. Voici le code MUSIC complet : + +.. code-block:: python + + num_expected_signals = 3 # Try changing this! + + # part that doesn't change with theta_i + R = np.cov(X) # Calcul de la matrice de covariance gives a Nr x Nr covariance matrix + w, v = np.linalg.eig(R) # Décomposition en valeurs propres, v[:,i] est le vecteur propre correspondant à la valeur propre w[i] + eig_val_order = np.argsort(np.abs(w)) # find order of magnitude of eigenvalues + v = v[:, eig_val_order] # sort eigenvectors using this order + # We make a new eigenvector matrix representing the "noise subspace", it's just the rest of the eigenvalues + V = np.zeros((Nr, Nr - num_expected_signals), dtype=np.complex64) + for i in range(Nr - num_expected_signals): + V[:, i] = v[:, i] + + theta_scan = np.linspace(-1*np.pi, np.pi, 1000) # -180 to +180 degrees + results = [] + for theta_i in theta_scan: + s = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta_i)) # Steering Vector + s = s.reshape(-1,1) + metric = 1 / (s.conj().T @ V @ V.conj().T @ s) # The main MUSIC equation + metric = np.abs(metric.squeeze()) # take magnitude + metric = 10*np.log10(metric) # convert to dB + results.append(metric) + + results /= np.max(results) # normalize + +En appliquant cet algorithme au scénario complexe que nous avons utilisé, nous obtenons les résultats très précis suivants, qui démontrent la puissance de MUSIC : + +.. image:: ../_images/doa_music.svg + :align: center + :target: ../_images/doa_music.svg + :alt: Exemple de direction d'arrivée (DOA) avec l'algorithme de formation de faisceaux MUSIC + +Et si l'on ignorait le nombre de signaux présents ? Il existe une astuce : trier les amplitudes des valeurs propres par ordre décroissant et les représenter graphiquement (en dB, cela peut être utile). + +.. code-block:: python + + plot(10*np.log10(np.abs(w)),'.-') + +.. image:: ../_images/doa_eigenvalues.svg + :align: center + :target: ../_images/doa_eigenvalues.svg + +Les valeurs propres associées au sous-espace de bruit seront les plus petites et tendront toutes vers la même valeur. On peut donc considérer ces faibles valeurs comme un « plancher de bruit », et toute valeur propre supérieure à ce plancher représente un signal. Ici, on observe clairement la réception de trois signaux, et l'algorithme MUSIC doit être ajusté en conséquence. Si le nombre d'échantillons IQ à traiter est faible ou si le rapport signal/bruit (SNR) des signaux est faible, leur nombre peut être moins évident. N'hésitez pas à expérimenter en ajustant :code:`num_expected_signals` entre 1 et 7. Vous constaterez qu'une sous-estimation entraînera la perte de signaux, tandis qu'une surestimation n'aura qu'un impact mineur sur les performances. + +Une autre expérience intéressante à tenter avec MUSIC consiste à déterminer la distance angulaire minimale à laquelle deux signaux peuvent arriver tout en conservant leur distinction ; les techniques de sous-espace sont particulièrement performantes dans ce cas. L'animation ci-dessous illustre un exemple, avec un signal à 18 degrés et un autre dont l'angle d'arrivée varie lentement. + +.. image:: ../_images/doa_music_animation.gif + :scale: 100 % + :align: center + + + +*** +LMS +*** + + +Le formateur de faisceau LMS (Least Mean Squares) est un formateur de faisceau à faible complexité introduit par Bernard Widrow. Il se distingue des autres formateurs de faisceau présentés jusqu'ici par deux aspects : 1) il requiert la connaissance du signal d'intérêt (SOI), ou au moins d'une partie de celui-ci (par exemple, une séquence de synchronisation, des signaux pilotes, etc.) ; 2) il est itératif, ce qui signifie que les pondérations sont affinées au fil d'un certain nombre d'itérations. Son fonctionnement repose sur la minimisation de l'erreur quadratique moyenne entre le signal désiré (le SOI) et la sortie du formateur de faisceau (c'est-à-dire les pondérations appliquées aux échantillons reçus). L'implémentation classique du LMS consiste à traiter chaque échantillon reçu comme une nouvelle étape du processus itératif, en appliquant les pondérations actuelles à cet échantillon et en calculant l'erreur. Cette erreur sert ensuite à affiner les pondérations, et le processus se répète. Le formateur de faisceau LMS peut être utilisé aussi bien pour la formation de faisceaux analogiques que numériques. L'algorithme LMS est défini par l'équation suivante : + +.. math:: + + w_{n+1} = w_n + \mu \underbrace{\left(y_n - w_{n}^H x_n\right)^*}_{erreur} x_n + + +où :math:`w_n` représente le vecteur de poids à l'itération/échantillon :math:`n`, :math:`\mu` est le pas d'intégration, :math:`x_n` est l'échantillon reçu à :math:`n`, :math:`y_n` est la valeur attendue à cette itération (c'est-à-dire le SOI connu), et est le conjugué complexe. Ne vous laissez pas impressionner par :math:`w_{n}^H x_n`, il s'agit simplement de l'application des poids actuels au signal d'entrée, ce qui correspond à l'équation standard de formation de faisceau. Le pas d'intégration :math:`\mu` contrôle la vitesse de convergence des poids vers leurs valeurs optimales. Une petite valeur :math:`\mu` de ce pas entraînera une convergence lente (par exemple, vous risquez de ne pas atteindre les poids optimaux avant la disparition du signal connu), tandis qu'une grande valeur peut engendrer une instabilité de l'algorithme. L'algorithme LMS est un outil puissant pour la formation de faisceaux adaptative, mais il présente certaines limitations. Il nécessite un SOI connu, qui n'est pas toujours disponible en pratique, et une synchronisation temporelle et fréquentielle est nécessaire dans le cadre du processus LMS afin que le modèle du SOI soit aligné avec les échantillons reçus. + +Dans l'exemple de code Python ci-dessous, nous simulons un réseau à 8 éléments avec un signal d'intérêt (SOI) composé d'un code Gold répétitif transmis en BPSK. Les codes Gold sont utilisés en 5G et GPS et possèdent d'excellentes propriétés de corrélation croisée, ce qui les rend idéaux pour les signaux de synchronisation. La simulation inclut également deux sources d'interférence tonale, à 60° et -50°. Notez que cette simulation ne prend pas en compte les décalages temporels ou fréquentiels ; si tel était le cas, une synchronisation au SOI serait nécessaire dans le cadre du processus LMS (c'est-à-dire une formation de faisceau conjointe avec synchronisation). L'animation suivante illustre le balayage de l'angle d'arrivée du SOI et la représentation du diagramme de rayonnement généré par LMS après 10 000 échantillons. Observez comment LMS maintient le gain vers le SOI à 0 dB (sauf en présence d'une source d'interférence), tout en créant des zéros au niveau des sources d'interférence. + +.. image:: ../_images/doa_lms_animation.gif + :scale: 100 % + :align: center + +.. code-block:: python + + # Scénario + sample_rate = 1e6 + d = 0.5 # espacement d'une demi longueur d'onde + N = 100000 # nombre d'échantillons à simuler + Nr = 8 # éléments + theta_soi = 20 / 180 * np.pi # conversion en radians + theta2 = 60 / 180 * np.pi + theta3 = -50 / 180 * np.pi + t = np.arange(N)/sample_rate # vecteur temps + s1 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta_soi)).reshape(-1,1) # 8x1 + s2 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta2)).reshape(-1,1) + s3 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta3)).reshape(-1,1) + + # SOI est un gold_code, répété , de longueur 127 + gold_code = np.array([-1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1]) + soi_samples_per_symbol = 8 + soi = np.repeat(gold_code, soi_samples_per_symbol) + num_sequence_repeats = int(N / soi.shape[0]) + 1 # nombre de fois où répéter la séquence pour N échantillons + soi = np.tile(soi, num_sequence_repeats)[:N] # répétition de la séquence pour remplir le temps simulé, puis tronquez-la. + soi = soi.reshape(1, -1) # 1xN + + # Interférences, par exemple brouilleurs de tonalité, provenant de différentes directions + tone2 = np.exp(2j*np.pi*0.02e6*t).reshape(1,-1) + tone3 = np.exp(2j*np.pi*0.03e6*t).reshape(1,-1) + + # simulation du signal reçu + r = s1 @ soi + s2 @ tone2 + s3 @ tone3 + n = np.random.randn(Nr, N) + 1j*np.random.randn(Nr, N) + r = r + 0.5*n # 8xN + + # LMS, ne connaissant pas la direction du SOI mais connaissant le signal SOI lui-même + mu = 0.5e-5 # taille du pas LMS + w_lms = np.zeros((Nr, 1), dtype=np.complex128) # commencer par des zéros + + # Boucle sur les échantillons reçus + error_log = [] + for i in range(N): + r_sample = r[:, i].reshape(-1, 1) # 8x1 + soi_sample = soi[0, i] # scalar + y = w_lms.conj().T @ r_sample # application des poids + y = y.squeeze() # conversion en scalaire + error = soi_sample - y + error_log.append(np.abs(error)**2) + w_lms += mu * np.conj(error) * r_sample # Les poids restent de taille 8x1 + + w_lms /= np.linalg.norm(w_lms) # normalisation des poids + + plt.plot(error_log) + plt.xlabel('Iteration') + plt.ylabel('Erreur des Moindre carrés') + plt.show() + + # Tracer le diagramme de rayonnement comme indiqué précédemment + + +Essayez de modifier :code:`theta_soi`, la quantité de bruit (c'est-à-dire :code:`0.5*n`) et la taille du pas :code:`mu` pour voir comment l'algorithme LMS fonctionne. + + +******************************* +Données d'entraînement +******************************* + +Dans le cadre du traitement d'antennes, le concept d'« entraînement » consiste à établir la matrice de covariance R avant l'apparition potentielle d'une source d'intérêt (SOI). Cette approche est particulièrement utile en radar, où, la plupart du temps, aucune SOI n'est présente et où le processus de détection repose sur le test d'une série d'angles pour vérifier sa présence. Le calcul de R avant l'apparition de la SOI permet de calculer les pondérations, à l'aide de méthodes telles que MVDR, en ne considérant dans la matrice de covariance que les interférences et le bruit ambiant. Ainsi, MVDR ne risque pas de placer un zéro à proximité de la direction de la SOI. Les pondérations sont ensuite appliquées au signal reçu pour déterminer si la SOI est présente à cet angle. + +Pour illustrer l'intérêt des données d'entraînement, nous appliquerons MVDR à un enregistrement provenant d'une antenne réelle à 16 éléments (utilisant la plateforme QUAD-MxFE d'Analog Devices). Nous commencerons par effectuer une analyse MVDR classique, en utilisant l'intégralité du signal reçu pour calculer R et les pondérations. Nous utiliserons ensuite un enregistrement distinct, effectué avant l'activation du SOI, pour calculer R et les pondérations. + +Ces enregistrements ont été réalisés à une fréquence radio de 3,3 GHz, avec un réseau d'antennes espacées de 0,045 mètre, soit d = 0,495. Une fréquence d'échantillonnage de 30 MHz a été utilisée. Nous désignerons les trois signaux par A, B et C. Le signal C correspond au SOI, tandis que les signaux A et B représentent les interférences. Par conséquent, nous avons besoin d'un enregistrement contenant uniquement les séquences A et B afin de créer les données d'entraînement, sans que A et B ne se déplacent entre l'acquisition des données d'entraînement et l'enregistrement incluant C. Vous trouverez ci-dessous les liens vers les deux enregistrements nécessaires : + +https://github.com/777arc/777arc.github.io/raw/master/3p3G_A_B.npy + +https://github.com/777arc/777arc.github.io/raw/master/3p3G_A_B_C.npy + +Commençons par effectuer une reconstruction multivariée (MVDR) classique avec l'enregistrement A_B_C. Nous pouvons charger cet enregistrement, au format :code:`np.save()`, contenant un tableau 2D. La première dimension correspond au nombre d'éléments du tableau, et la seconde au nombre d'échantillons. + +.. code-block:: python + + import matplotlib.pyplot as plt + import numpy as np + + # Array params + center_freq = 3.3e9 + sample_rate = 30e6 + d = 0.045 * center_freq / 3e8 + print("d:", d) + + # Incluant les trois signaux, nous appellerons C notre SOI + filename = '3p3G_A_B_C.npy' + X = np.load(filename) + Nr = X.shape[0] + +Nous allons ensuite effectuer une analyse DOA de base avec MVDR, afin d'identifier les angles d'arrivée des trois signaux : + +.. code-block:: python + + # Perform DOA to find angle of arrival of C + theta_scan = np.linspace(-1*np.pi/2, np.pi/2, 10000) # between -90 and +90 degrees + results = [] + R = X @ X.conj().T # Calc covariance matrix. gives a Nr x Nr covariance matrix of the samples + Rinv = np.linalg.pinv(R) # pseudo-inverse tends to work better than a true inverse + for theta_i in theta_scan: + a = np.exp(2j * np.pi * d * np.arange(X.shape[0]) * np.sin(theta_i)) # steering vector in the desired direction theta_i + a = a.reshape(-1,1) # make into a column vector + power = 1/(a.conj().T @ Rinv @ a).squeeze() # MVDR power equation + power_dB = 10*np.log10(np.abs(power)) # power in signal, in dB so its easier to see small and large lobes at the same time + results.append(power_dB) + results -= np.max(results) # normalize to 0 dB at peak + +Dans ce cas précis, il est plus simple d'utiliser un diagramme rectangulaire plutôt qu'un diagramme polaire. Nous avons nommé les signaux A, B et C. + +.. image:: ../_images/DOA_without_training.svg + :align: center + :target: ../_images/DOA_without_training.svg + :alt: DOA sans données d'entraînement + +Ensuite, si nous voulons appeler C notre SOI et utiliser MVDR pour créer des pondérations qui annuleront A et B tout en préservant C, nous devons connaître l'angle d'arrivée exact de C. Nous allons le faire en utilisant un argmax sur les résultats DOA que nous venons de créer, mais seulement après avoir annulé les angles correspondant à A et B (nous faisons cela en fixant les 60 % supérieurs de nos résultats DOA à une valeur très faible). + +.. code-block:: python + + # Pull out angle of C, after zeroing out the angles that include the interferers + results_temp = np.array(results) + results_temp[int(len(results)*0.4):] = -9999*np.ones(int(len(results)*0.6)) + max_angle = theta_scan[np.argmax(results_temp)] # radians + print("max_angle:", max_angle) + +Il s'avère que C vaut -0,3407 radians ; c'est donc cette valeur qu'il faut utiliser pour calculer les pondérations MVDR. Vous avez déjà effectué cette opération à maintes reprises, il s'agit simplement de l'équation MVDR. + +.. code-block:: python + + # Calcul des poids MVDR + s = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(max_angle)) # steering vector in the desired direction theta + s = s.reshape(-1,1) # make into a column vector + w = (Rinv @ s)/(s.conj().T @ Rinv @ s) # MVDR/Capon equation + +Enfin, traçons le diagramme de rayonnement des pondérations MVDR que nous venons de calculer, ainsi que les résultats DOA obtenus précédemment, et une ligne verte pointillée à :code:`max_angle`: + +.. raw:: html + +
    + Expand this for the plotting code (it's nothing new) + +.. code-block:: python + + # Calcul du modèle de faisceau + w = w.squeeze() + N_fft = 2048 + w_padded = np.concatenate((w, np.zeros(N_fft - Nr))) # zero padding à N_fft élémentspour améliorer la résolution de la FFT + w_fft_dB = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(w_padded)))**2) # amplitude of fft in dB + w_fft_dB -= np.max(w_fft_dB) # normalisation du maximum à 0 dB + theta_bins = np.arcsin(np.linspace(-1, 1, N_fft)) # Conversion des échantillons de la FFT en angles en radians + + # Tracer le diagramme de rayonnement et les résultats de la direction d'arrivée + plt.plot(theta_bins * 180 / np.pi, w_fft_dB) # ASSUREZ-VOUS D'UTILISER LE RADIAN POUR LES REPRESENTATIONS POLAIRES + plt.plot(theta_scan * 180 / np.pi, results, 'r') + plt.vlines(ymax=np.max(results), ymin=np.min(results) , x=max_angle*180/np.pi, color='g', linestyle='--') + plt.xlabel("Angle [deg]") + plt.ylabel("Amplitude [dB]") + plt.title("Diagramme de faisceau et résultats de DOA, sans formation") + plt.grid() + plt.show() + +.. raw:: html + +
    + +.. image:: ../_images/DOA_without_training_pattern.svg + :align: center + :target: ../_images/DOA_without_training_pattern.svg + :alt: DOA sans données d'entraînement, DOA et diagramme de faisceau MVDR + +Nous avons réussi à créer des zéros aux points A et B. Au point C (ligne pointillée verte), nous n'observons pas de zéro, ni de lobe principal apparent ; il s'agit plutôt d'un lobe réduit. Ceci est dû en partie à l'absence quasi totale d'énergie provenant des directions autres que A, B et C. Par conséquent, même si certains lobes sont visibles (par exemple autour de -70, 25 et 40 degrés), ils sont négligeables car aucun signal ne provient de cette direction. Une autre raison de la faible intensité du lobe en C est que le lobe principal est en quelque sorte en conflit avec les zéros qui auraient été créés par le MVDR si nous n'avions pas été pointés précisément dans cette direction. Cela étant dit, il serait souhaitable d'avoir un lobe principal marqué à notre position :code:`max_angle`, et pour ce faire, nous devrons utiliser des **données d'entraînement**. + +Nous allons maintenant charger l'enregistrement des points A et B uniquement, afin de créer les données d'entraînement. Dans une situation radar, cela équivaut à calculer :code:`R` avant de transmettre une impulsion radar (idéalement, très peu de temps avant). + +.. code-block:: python + + # Load "training data" which is just A and B, then calc Rinv + filename = '3p3G_A_B.npy' + X_A_B = np.load(filename) + R_training = X_A_B @ X_A_B.conj().T # Calc covariance matrix + Rinv_training = np.linalg.pinv(R_training) + + +Cette fois, la principale différence réside dans l'utilisation de :code:`Rinv_training` pour le calcul des poids MVDR. Nous réutiliserons :code:`max_angle`, valeur déjà déterminée. Ainsi, nous orientons le signal vers C sans pour autant l'intégrer au signal reçu utilisé pour le calcul de :code:`R` et :code:`R_inv`. + +.. code-block:: python + + # Calcul des poids MVDR en utilisant Rinv_training + s = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(max_angle)) # Vecteur de direction dans la direction souhaitée θ + s = s.reshape(-1,1) # Conversion en vecteur colonne (taille 3x1) + w = (Rinv_training @ s)/(s.conj().T @ Rinv_training @ s) # équation MVDR/Capon + +En utilisant la même méthode de représentation graphique, on obtient : + +.. image:: ../_images/DOA_with_training.svg + :align: center + :target: ../_images/DOA_with_training.svg + :alt: DOA avec données d'entraînement, DOA et diagramme de faisceau MVDR + +Notez que nous obtenons toujours des zéros provenant de A et B (le zéro de B est plus faible, mais B correspond également à un signal plus faible), mais cette fois-ci, un lobe principal important est dirigé vers notre angle d'intérêt, C. C'est là toute la puissance des données d'apprentissage, et pourquoi elles sont si importantes dans les applications radar. + +******************************* +Simulation d'interférences à large bande +******************************* + +La méthode que nous avons utilisée tout au long de ce chapitre pour simuler les signaux atteignant notre réseau depuis un certain angle d'arrivée (en multipliant le vecteur de direction par le signal émis) repose sur une hypothèse de bande étroite : le signal est supposé avoir une seule fréquence, et le vecteur de direction est calculé à cette fréquence. Cette approximation est acceptable pour de nombreux signaux, mais elle ne convient pas aux signaux à large bande, par exemple ceux dont la bande passante est supérieure à environ 5 % de la fréquence centrale. Nous aborderons brièvement une astuce permettant de simuler du **bruit** à large bande provenant d'une direction donnée (par exemple, un brouillage par barrage provenant d'un seul angle d'arrivée). + +Cette méthode fonctionne en construisant une matrice de covariance :code:`R` obtenue en sommant les contributions de chaque source de bruit à large bande. La matrice racine carrée :code:`A` est ensuite calculée, et l'ensemble d'échantillons :code:`X` est généré en « colorant » un bruit gaussien complexe standard avec :code:`A`. Un paramètre clé est :code:`fractional_bw`, qui correspond à la bande passante du signal de bruit divisée par sa fréquence centrale. Lorsque :code:`fractional_bw` = 0, le code suivant devrait reproduire le même résultat que la méthode traditionnelle de simulation des signaux reçus. Le code Python ci-dessous peut être intégré aux exemples précédents pour simuler le signal reçu :code:`X`. + +.. code-block:: python + + N = 10 # Nombre d'éléments dans le réseau linéaire uniforme (ULA) + num_samples = 10000 + d = 0.5 + num_jammers = 3 + jammer_pow_dB = np.array([30, 30, 30]) # Puissances des brouilleurs en dB + jammer_aoa_deg = np.array([-70, -20, 40]) # Angles des brouilleurs en degrés + jammer_aoa = np.sin(np.deg2rad(jammer_aoa_deg)) * np.pi + element_gain_dB = np.zeros(N) # Gains en dB pour les éléments du réseau (tous à 0 dB dans notre cas) + element_gain_linear = 10.0 ** (element_gain_dB / 10) # Conversion des gains du réseau en valeurs linéaires + fractional_bw = 0.1 # si ceci Si la valeur est 0, la méthode correspond à la méthode traditionnelle utilisant le facteur de réseau pour simuler les signaux reçus. + # Construction de la matrice de covariance NxN du brouilleur R + R = np.zeros((N, N), dtype=complex) + for m in range(N): + for n in range(N): + for j in range(num_jammers): + total_element_gain = np.sqrt(element_gain_linear[m] * element_gain_linear[n]) + sinc_term = np.sinc(0.5 * fractional_bw * (m - n) * jammer_aoa[j] / np.pi) + exp_term = np.exp(1j * (m - n) * jammer_aoa[j]) + R[m, n] += 10.0 ** (jammer_pow_dB[j] / 10) * total_element_gain * sinc_term * exp_term + R = np.eye(N, dtype=complex) + R + + # Générer les échantillons reçus + A = fractional_matrix_power(R, 0.5) # Calculer la racine carrée de la matrice (factorisation de Cholesky effective) + A = A / np.sqrt(2) + X = np.zeros((N, num_samples), dtype=complex) + for k in range(num_samples): + noise_vec = np.random.randn(N) + 1j * np.random.randn(N) # bruit complexe + X[:, k] = A.conj().T @ noise_vec + +Dans les graphiques ci-dessous, les pondérations MVDR sont calculées pour une visée à 20 degrés et affichées en noir, tandis que le formateur de faisceau conventionnel pour 20 degrés est représenté en bleu pointillé. Les trois sources de bruit sont indiquées en rouge. Dans ce premier graphique, une bande passante fractionnelle de 0 est utilisée, ce qui signifie que ces pondérations MVDR devraient correspondre aux scénarios précédents utilisant l'hypothèse de bande étroite. D'après le graphique, tout semble fonctionner correctement. Cependant, si le bruit réel s'avère être à large bande passante (et que votre SOI l'est également, ce qui signifie qu'un simple filtrage du bruit est impossible), la simulation ne correspondra pas à la réalité. + +.. image:: ../_images/doa_covariance_method_1.svg + :align: center + :target: ../_images/doa_covariance_method_1.svg + :alt: Méthode de covariance DOA avec une bande passante fractionnelle de 0 + +Nous appliquons maintenant une bande passante fractionnelle de 0,1, ce qui répartit les sources de bruit sur une large bande passante et entraîne la création de zones d'annulation beaucoup plus larges par MVDR. Dans de nombreux scénarios réels, cela représente une simulation plus réaliste. + +.. image:: ../_images/doa_covariance_method_2.svg + :align: center + :target: ../_images/doa_covariance_method_2.svg + :alt: Méthode de covariance DOA avec une bande passante fractionnelle de 0,1 + + + +******************* +Réseaux circulaires +******************* + +Nous aborderons brièvement le réseau circulaire uniforme (UCA), une géométrie de réseau couramment utilisée pour la détection d'arrivée (DOA) car elle résout le problème d'ambiguïté à 180 degrés des réseaux circulaires uniformes (ULA). Le KrakenSDR, par exemple, est un réseau à 5 éléments, généralement disposés en cercle avec un espacement régulier. En théorie, trois éléments suffisent pour former un UCA, tout comme deux éléments suffisent pour un ULA. + +Tout le code étudié jusqu'à présent s'applique aux UCA ; il suffit de remplacer l'équation du vecteur de direction par une équation spécifique aux UCA : + +.. code-block:: python + + radius = 0.05 # normalisé par la longueur d'onde ! + d = np.sqrt(2 * rayon**2 * (1 - np.cos(2*np.pi/Nr))) + sf = 1.0 / (np.sqrt(2.0) * np.sqrt(1.0 - np.cos(2*np.pi/Nr))) # Facteur d'échelle basé sur la géométrie, par exemple 1.0 pour un hexagone + x = d * sf * np.cos(2 * np.pi / Nr * np.arange(Nr)) + y = -1 * d * sf * np.sin(2 * np.pi / Nr * np.arange(Nr)) + s = np.exp(1j * 2 * np.pi * (x * np.cos(theta) + y * np.sin(theta))) + s = s.reshape(-1, 1) # Nrx1 + +Enfin, il est conseillé de balayer de 0 à 360 degrés, et non seulement de -90 à +90 degrés comme avec un réseau linéaire uniforme (ULA). + +Pour les réseaux 2D (par exemple, rectangulaires), consultez le chapitre :ref:`2d-beamforming-chapter`. + +************************* +Conclusion et références +************************* + +L'ensemble du code Python, y compris celui utilisé pour générer les figures et les animations, est disponible `sur la page GitHub du manuel : `_. + +* Implémentation DOA dans GNU Radio - https://github.com/EttusResearch/gr-doa +* Implémentation DOA utilisée par KrakenSDR - https://github.com/krakenrf/krakensdr_doa/blob/main/_signal_processing/krakenSDR_signal_processor.py + +[1] Mailloux, Robert J. Phased Array Antenna Handbook. Deuxième édition, Artech House, 2005 + +[2] Van Trees, Harry L. Optimum Array Processing: Part IV of Detection, Estimation, and Modulation Theory. Wiley, 2002. + +.. |br| raw:: html + +
    diff --git a/content-fr/frequency_domain.rst b/content-fr/frequency_domain.rst index c2817b9f..68adc9aa 100644 --- a/content-fr/frequency_domain.rst +++ b/content-fr/frequency_domain.rst @@ -140,8 +140,6 @@ Ce n'est pas grave si aucune de ces équations ne vous intéresse. En fait, nous Propriétés temps-fréquence *************************** -Earlier we examined examples of how signals appear in the time domain and the frequency domain. Now, we will cover five important "Fourier properties". These are properties that tell us if we do ____ to our time domain signal, then ____ happens to our frequency domain signal. It will give us an important insight into the type of Digital Signal Processing (DSP) we will perform on time domain signals in practice. - Nous avons examiné précédemment des exemples de la manière dont les signaux apparaissent dans le domaine temporel et dans le domaine fréquentiel. Nous allons maintenant aborder cinq importantes "propriétés de Fourier". Il s'agit de propriétés qui nous disent que si nous appliquons ____ à notre signal dans le domaine temporel, alors ____ s'appliquera à notre signal dans le domaine fréquentiel. Cela nous donnera un aperçu important du type de traitement numérique du signal (DSP) que nous effectuerons sur les signaux du domaine temporel dans la pratique. 1. Propriété de linéarité: diff --git a/content-fr/hackrf.rst b/content-fr/hackrf.rst new file mode 100644 index 00000000..7d804f09 --- /dev/null +++ b/content-fr/hackrf.rst @@ -0,0 +1,280 @@ +.. _hackrf-chapter: + +#################### +HackRF One en Python +#################### + +Le `HackRF One `_ de Great Scott Gadgets est un SDR USB 2.0 qui peut émettre ou recevoir de 1 MHz à 6 GHz et possède une fréquence d'échantillonnage de 2 à 20 MHz. Lancé en 2014, il a bénéficié de plusieurs améliorations mineures au fil des ans. C'est l'un des rares SDR économiques capables d'émettre jusqu'à 1 MHz, ce qui le rend idéal pour les applications HF (par exemple, la radioamateur) et les applications à plus haute fréquence. Sa puissance d'émission maximale de 15 dBm est également supérieure à celle de la plupart des autres SDR, pour plus de détails sur la puissance d'émissionallez allez voir `cette page `_ . Il utilise un fonctionnement half-duplex, ce qui signifie qu'il est soit en mode émission, soit en mode réception à tout moment, et il utilise un convertisseur analogique-numérique/numérique-analogique 8 bits. + +.. image:: ../_images/hackrf1.jpeg + :scale: 60 % + :align: center + :alt: HackRF One + +******************************** +HackRF Architecture +******************************** + +Le HackRF est basé sur la puce Analog Devices MAX2839, un émetteur-récepteur de 2,3 GHz à 2,7 GHz. Conçue initialement pour le WiMAX, elle est associée à une puce frontale RF MAX5864 (qui intègre essentiellement le CAN et le CNA) et à un synthétiseur/VCO large bande RFFC5072 (utilisé pour la conversion de fréquence du signal). Cela contraste avec la plupart des autres SDR économiques qui utilisent une seule puce appelée RFIC. Hormis le réglage de la fréquence générée par le RFFC5072, tous les autres paramètres que nous ajusterons, tels que l'atténuation et le filtrage analogique, seront gérés par le MAX2839. Au lieu d'utiliser un FPGA ou un système sur puce (SoC) comme de nombreux SDR, le HackRF utilise un circuit logique programmable complexe (CPLD) qui sert de simple logique d'interface, et un microcontrôleur, le LPC4320 basé sur ARM, qui gère tout le traitement numérique du signal (DSP) embarqué et l'interface USB avec l'hôte (transfert d'échantillons IQ dans les deux sens et contrôle des paramètres du SDR). Le magnifique schéma fonctionnel suivant, tiré de Great Scott Gadgets, illustre l'architecture de la dernière version du HackRF One : + +.. image:: ../_images/hackrf_block_diagram.webp + :align: center + :alt: Schéma fonctionnel du HackRF One + :target: ../_images/hackrf_block_diagram.webp + +Le HackRF One est hautement extensible et personnalisable. À l'intérieur du boîtier en plastique se trouvent quatre connecteurs (P9, P20, P22, and P28). Les détails sont `disponibles ici `_. Notez que 8 broches GPIO et 4 entrées ADC sont sur le connecteur P20, tandis que les interfaces SPI, I2C, et UART sont sur le connecteur P22. Le connecteur P28 peut être utilisé pour déclencher/synchroniser les opérations avec un autre appareil (par exemple un commutateur TR, un amplificateur externe ou un autre HackRF), via l'entrée et la sortie de déclenchement, avec un déali inférieur à une période d'échantillonnage. + +.. image:: ../_images/hackrf2.jpeg + :scale: 50 % + :align: center + :alt: Circuit imprimé du HackRF One + +L'horloge utilisée pour l'oscillateur local (LO) et le convertisseur analogique-numérique (ADC/DAC) provient soit de l'oscillateur intégré de 25 MHz, soit d'une référence externe de 10 MHz fournie via un connecteur SMA. Quelle que soit l'horloge utilisée, le HackRF génère un signal d'horloge de 10 MHz sur CLKOUT ; un signal carré standard de 3,3 V et 10 MHz conçu pour une charge à haute impédance. Le port CLKIN est conçu pour recevoir un signal carré similaire de 10 MHz et 3,3 V, et le HackRF utilisera l'horloge d'entrée au lieu du cristal interne lorsqu'un signal d'horloge est détecté (notez que la transition vers ou depuis CLKIN n'a lieu qu'au début d'une opération d'émission ou de réception). + +******************************** +Configuration matérielle et logicielle +******************************** + +Le processus d'installation du logiciel comporte deux étapes : nous installerons d'abord la bibliothèque principale HackRF de Great Scott Gadgets, puis l'API Python. + +Installation de la bibliothèque du HackRF +############################# + +Le code suivant a été testé et fonctionne sous Ubuntu 22.04 (avec le hachage de commit 17f3943 de mars 2025) : + +.. code-block:: bash + + git clone https://github.com/greatscottgadgets/hackrf.git + cd hackrf + git checkout 17f3943 + cd host + mkdir build + cd build + cmake .. + make + sudo make install + sudo ldconfig + sudo cp /usr/local/bin/hackrf* /usr/bin/. + +Après avoir installé :code:`hackrf` vous pourrez exécuter les utilitaires suivants : +* :code:`hackrf_info` - Lire les informations du périphérique HackRF, telles que le numéro de série et la version du firmware. +* :code:`hackrf_transfer` - Envoyer et recevoir des signaux via HackRF. Les fichiers d'entrée/sortie sont des échantillons en quadrature de signaux 8 bits. +* :code:`hackrf_sweep` - Analyseur de spectre en ligne de commande. +* :code:`hackrf_clock` - Lire et écrire la configuration d'entrée et de sortie d'horloge. +* :code:`hackrf_operacake` - Configurer le commutateur d'antenne Opera Cake connecté à HackRF. +* :code:`hackrf_spiflash` - Outil permettant d'écrire un nouveau firmware sur HackRF. Voir : Mise à jour du firmware. +* :code:`hackrf_debug` - Lire et écrire les registres et autres paramètres de configuration bas niveau pour le débogage. + + Si vous utilisez Ubuntu via WSL, côté Windows, vous devrez transférer le périphérique USB HackRF vers WSL. Pour cela, commencez par installer la dernière version de l'`utilitaire usbipd (fichier msi `_) (ce guide suppose que vous disposez de usbipd-win 4.0.0 ou version ultérieure), puis ouvrez PowerShell en mode administrateur et exécutez : + +.. code-block:: bash + + usbipd list + + usbipd bind --busid 1-10 + usbipd attach --wsl --busid 1-10 + +Du côté WSL, vous devriez pouvoir exécuter :code:`lsusb` et voir un nouvel élément nommé :code:`Great Scott Gadgets HackRF One`. Notez que vous pouvez ajouter l'option :code:`--auto-attach` à la commande :code:`usbipd attach` si vous souhaitez une reconnexion automatique. + +Enfin, vous devez ajouter les règles udev à l'aide de la commande suivante : + +.. code-block:: bash + + echo 'ATTR{idVendor}=="1d50", ATTR{idProduct}=="6089", SYMLINK+="hackrf-one-%k", MODE="660", TAG+="uaccess"' | sudo tee /etc/udev/rules.d/53-hackrf.rules + sudo udevadm trigger + +Débranchez puis rebranchez votre HackRF One (et réexécutez la commande :code:`usbipd attach`). Notez que j'ai rencontré des problèmes d'autorisations avec l'étape suivante jusqu'à ce que j'utilise `WSL USB Manager `_ côté Windows, pour gérer le transfert vers WSL, qui gère apparemment aussi les règles udev. + + +Que vous soyez sous Linux natif ou WSL, vous devriez maintenant pouvoir exécuter :code:`hackrf_info` et voir quelque chose comme : + +.. code-block:: bash + + hackrf_info version: git-17f39433 + libhackrf version: git-17f39433 (0.9) + Found HackRF + Index: 0 + Serial number: 00000000000000007687865765a765 + Board ID Number: 2 (HackRF One) + Firmware Version: 2024.02.1 (API:1.08) + Part ID Number: 0xa000cb3c 0x004f4762 + Hardware Revision: r10 + Hardware appears to have been manufactured by Great Scott Gadgets. + Hardware supported by installed firmware: HackRF One + +Effectuons également un enregistrement IQ de la bande FM, d'une largeur de 10 MHz centrée sur 100 MHz, et nous enregistrerons 1 million d'échantillons : + +.. code-block:: bash + + hackrf_transfer -r out.iq -f 100000000 -s 10000000 -n 1000000 -a 0 -l 30 -g 50 + +Cet utilitaire produit un fichier binaire IQ d'échantillons int8 (2 octets par échantillon IQ), qui devrait peser 2 Mo dans notre cas. Si vous êtes curieux, vous pouvez lire l'enregistrement du signal en Python à l'aide du code suivant : + +.. code-block:: python + + import numpy as np + samples = np.fromfile('out.iq', dtype=np.int8) + samples = samples[::2] + 1j * samples[1::2] + print(len(samples)) + print(samples[0:10]) + print(np.max(samples)) + +Si votre valeur maximale est de 127 (ce qui signifie que vous avez saturé le CAN), alors abaissez les deux valeurs de gain à la fin de la commande. + + +Installation de l'API Python +######################### + +Enfin, nous devons installer les `bindings Python HackRF One `_, maintenues par `GvozdevLeonid `_. Elles ont été testées et fonctionnent correctement sous Ubuntu 22.04 le 11/04/2024 avec la dernière version de la branche principale. + +.. code-block:: bash + + sudo apt install libusb-1.0-0-dev + pip install python_hackrf==1.2.7 + +Nous pouvons tester l'installation ci-dessus en exécutant le code suivant. S'il n'y a pas d'erreurs (il n'y aura donc aucune sortie), tout devrait fonctionner correctement ! + +.. code-block:: python + + from python_hackrf import pyhackrf # type: ignore + pyhackrf.pyhackrf_init() + sdr = pyhackrf.pyhackrf_open() + sdr.pyhackrf_set_sample_rate(10e6) + sdr.pyhackrf_set_antenna_enable(False) + sdr.pyhackrf_set_freq(100e6) + sdr.pyhackrf_set_amp_enable(False) + sdr.pyhackrf_set_lna_gain(30) # LNA gain - 0 dB à 40 dB par pas de 8 dB + sdr.pyhackrf_set_vga_gain(50) # VGA gain - 0 dB à 62 dB par pas de 2 dB + sdr.pyhackrf_close() + +Pour un test concret de réception d'échantillons, consultez l'exemple de code ci-dessous. + +******************************** +Gain Tx et Rx +******************************** + +Côté réception +############ + +Le HackRF One possède côté réception, 3 étages de gain différents : + +* RF (:code:`amp`, soit 0 dB soit 11 dB) +* IF (:code:`lna`, de 0 dB à 40 dB par pas de 8 dB) +* baseband (:code:`vga`, de 0 dB à 62 dB par pas de 2 dB) + +Pour la réception de la plupart des signaux, il est recommandé de désactiver l’amplificateur RF (0 dB), sauf si le signal est extrêmement faible et qu’aucun signal fort n’est présent à proximité. Le gain FI (LNA) est l’étage de gain le plus important à régler pour optimiser le rapport signal/bruit tout en évitant la saturation du CAN ; c’est le premier bouton à ajuster. Le gain de bande de base peut être laissé à une valeur relativement élevée, par exemple, nous le laisserons à 50 dB. + +Côté transmission +############# + +Côté émission, on trouve deux étages de gain : + +* RF [soit 0 dB soit 11 dB] +* IF [de 0 dB à 47 dB par pas de 1 dB] + +Vous souhaiterez probablement activer l'amplificateur RF, puis vous pourrez ajuster le gain IF en fonction de vos besoins. + +************************************************** +Réception d'échantillons IQ en Python avec le HackRF +************************************************** + +Actuellement, le package Python :code:`python_hackrf` ne comprend aucune fonction pratique pour la réception d'échantillons. Il s'agit simplement d'un ensemble de liaisons Python qui correspondent à l'API C++ du HackRF. Pour recevoir facilement des données IQ, nous devons utiliser une quantité de code non négligeable. Le package Python est configuré pour utiliser une fonction de rappel afin de recevoir davantage d'échantillons. Cette fonction doit être initialisée, mais elle sera automatiquement appelée dès que de nouveaux échantillons seront disponibles en provenance du HackRF. +Cette fonction de rappel doit toujours prendre trois arguments spécifiques et doit renvoyer :code:`0` si nous souhaitons recevoir un autre ensemble d'échantillons. Dans le code ci-dessous, à chaque appel de notre fonction de rappel, nous convertissons les échantillons au type complexe de NumPy, les mettons à l'échelle de -1 à +1, puis les stockons, dans un tableau :code:`samples` plus grand. + +Après l'exécution du code ci-dessous, si sur votre graphique temporel, les échantillons atteignent les limites de l'ADC (-1 et +1), réduisez alors :code:`lna_gain` de 3 dB jusqu'à ce que les limites ne soient clairement plus atteintes. + +.. code-block:: python + + from python_hackrf import pyhackrf # type: ignore + import matplotlib.pyplot as plt + import numpy as np + import time + + # These settings should match the hackrf_transfer example used in the textbook, and the resulting waterfall should look about the same + recording_time = 1 # seconds + center_freq = 100e6 # Hz + sample_rate = 10e6 + baseband_filter = 7.5e6 + lna_gain = 30 # 0 to 40 dB in 8 dB steps + vga_gain = 50 # 0 to 62 dB in 2 dB steps + + pyhackrf.pyhackrf_init() + sdr = pyhackrf.pyhackrf_open() + + allowed_baseband_filter = pyhackrf.pyhackrf_compute_baseband_filter_bw_round_down_lt(baseband_filter) # calculate the supported bandwidth relative to the desired one + + sdr.pyhackrf_set_sample_rate(sample_rate) + sdr.pyhackrf_set_baseband_filter_bandwidth(allowed_baseband_filter) + sdr.pyhackrf_set_antenna_enable(False) # It seems this setting enables or disables power supply to the antenna port. False by default. the firmware auto-disables this after returning to IDLE mode + + sdr.pyhackrf_set_freq(center_freq) + sdr.pyhackrf_set_amp_enable(False) # False by default + sdr.pyhackrf_set_lna_gain(lna_gain) # LNA gain - 0 to 40 dB in 8 dB steps + sdr.pyhackrf_set_vga_gain(vga_gain) # VGA gain - 0 to 62 dB in 2 dB steps + + print(f'center_freq: {center_freq} sample_rate: {sample_rate} baseband_filter: {allowed_baseband_filter}') + + num_samples = int(recording_time * sample_rate) + samples = np.zeros(num_samples, dtype=np.complex64) + last_idx = 0 + + def rx_callback(device, buffer, buffer_length, valid_length): # this callback function always needs to have these four args + global samples, last_idx + + accepted = valid_length // 2 + accepted_samples = buffer[:valid_length].astype(np.int8) # -128 to 127 + accepted_samples = accepted_samples[0::2] + 1j * accepted_samples[1::2] # Convert to complex type (de-interleave the IQ) + accepted_samples /= 128 # -1 to +1 + samples[last_idx: last_idx + accepted] = accepted_samples + + last_idx += accepted + + return 0 + + sdr.set_rx_callback(rx_callback) + sdr.pyhackrf_start_rx() + print('is_streaming', sdr.pyhackrf_is_streaming()) + + time.sleep(recording_time) + + sdr.pyhackrf_stop_rx() + sdr.pyhackrf_close() + pyhackrf.pyhackrf_exit() + + samples = samples[100000:] # get rid of the first 100k samples just to be safe, due to transients + + fft_size = 2048 + num_rows = len(samples) // fft_size + spectrogram = np.zeros((num_rows, fft_size)) + for i in range(num_rows): + spectrogram[i, :] = 10 * np.log10(np.abs(np.fft.fftshift(np.fft.fft(samples[i * fft_size:(i+1) * fft_size]))) ** 2) + extent = [(center_freq + sample_rate / -2) / 1e6, (center_freq + sample_rate / 2) / 1e6, len(samples) / sample_rate, 0] + + plt.figure(0) + plt.imshow(spectrogram, aspect='auto', extent=extent) # type: ignore + plt.xlabel("Frequency [MHz]") + plt.ylabel("Time [s]") + + plt.figure(1) + plt.plot(np.real(samples[0:10000])) + plt.plot(np.imag(samples[0:10000])) + plt.xlabel("Samples") + plt.ylabel("Amplitude") + plt.legend(["Real", "Imaginary"]) + + plt.show() + + +Lorsque vous utilisez une antenne capable de recevoir la bande FM, vous devriez obtenir un résultat similaire à celui-ci, avec plusieurs stations FM visibles sur le graphique en cascade : + +.. image:: ../_images/hackrf_time_screenshot.png + :align: center + :scale: 50 % + :alt: Graphique temporel des échantillons prélevés sur HackRF + + +.. image:: ../_images/hackrf_freq_screenshot.png + :align: center + :scale: 50 % + :alt: Spectrogramme (frequence en fonction du temps) des échantillons extraits du HackRF + diff --git a/content-fr/iq_files.rst b/content-fr/iq_files.rst index 2b0b9c13..bf61a00a 100644 --- a/content-fr/iq_files.rst +++ b/content-fr/iq_files.rst @@ -24,7 +24,7 @@ Bien qu'il soit possible de stocker les nombres complexes dans un fichier texte :scale: 70 % :align: center -En Python, le type complexe par défaut est np.complex128, qui utilise deux flottants de 64 bits par échantillon. Mais en DSP/SDR, nous avons tendance à utiliser des flottants de 32 bits à la place, car les ADC de nos SDR n'ont pas **tant** de précision que cela pour justifier des flottants de 64 bits. En Python, nous utiliserons **np.complex64**, qui utilise deux flottants de 32 bits. Lorsque vous traitez simplement un signal en Python, cela n'a pas vraiment d'importance, mais lorsque vous allez enregistrer le tableau 1d dans un fichier, vous voulez d'abord vous assurer qu'il s'agit d'un tableau de np.complex64. +En Python, le type complexe par défaut est np.complex128, qui utilise deux flottants de 64 bits par échantillon. Mais en DSP/SDR, nous avons tendance à utiliser des flottants de 32 bits à la place, car les CAN de nos SDR n'ont pas **tant** de précision que cela pour justifier des flottants de 64 bits. En Python, nous utiliserons **np.complex64**, qui utilise deux flottants de 32 bits. Lorsque vous traitez simplement un signal en Python, cela n'a pas vraiment d'importance, mais lorsque vous allez enregistrer le tableau 1d dans un fichier, vous voulez d'abord vous assurer qu'il s'agit d'un tableau de np.complex64. ************************* Exemples Python @@ -114,7 +114,7 @@ Bien que nous ayons appris à créer notre propre tracé de spectrogramme dans l Valeurs maximales et saturation ******************************* -Lorsque vous recevez des échantillons d'un SDR, il est important de connaître la valeur maximale de l'échantillon. De nombreux SDR émettent les échantillons sous forme de flottants avec une valeur maximale de 1.0 et une valeur minimale de -1.0. D'autres SDR vous donneront des échantillons sous forme d'entiers, généralement 16 bits, auquel cas les valeurs max et min seront +32767 et -32768 (sauf indication contraire), et vous pouvez choisir de diviser par 32 768 pour les convertir en flottants de -1,0 à 1,0. La raison pour laquelle il faut connaître la valeur maximale de votre SDR est due à la saturation : lors de la réception d'un signal extrêmement fort (ou si le gain est réglé trop haut), le récepteur va "saturer" et il va tronquer les valeurs élevées à la valeur maximale de l'échantillon. Les ADCs de nos SDRs ont un nombre limité de bits. Lorsque vous créez une application SDR, il est sage de toujours vérifier la saturation, et lorsque cela se produit, vous devez l'indiquer d'une manière ou d'une autre. +Lorsque vous recevez des échantillons d'un SDR, il est important de connaître la valeur maximale de l'échantillon. De nombreux SDR émettent les échantillons sous forme de flottants avec une valeur maximale de 1.0 et une valeur minimale de -1.0. D'autres SDR vous donneront des échantillons sous forme d'entiers, généralement 16 bits, auquel cas les valeurs max et min seront +32767 et -32768 (sauf indication contraire), et vous pouvez choisir de diviser par 32 768 pour les convertir en flottants de -1,0 à 1,0. La raison pour laquelle il faut connaître la valeur maximale de votre SDR est due à la saturation : lors de la réception d'un signal extrêmement fort (ou si le gain est réglé trop haut), le récepteur va "saturer" et il va tronquer les valeurs élevées à la valeur maximale de l'échantillon. Les CANs de nos SDRs ont un nombre limité de bits. Lorsque vous créez une application SDR, il est sage de toujours vérifier la saturation, et lorsque cela se produit, vous devez l'indiquer d'une manière ou d'une autre. Un signal qui est saturé aura l'air perturbé dans le domaine temporel, comme ceci : .. image:: ../_images/saturated_time.png diff --git a/content-fr/pyqt.rst b/content-fr/pyqt.rst new file mode 100644 index 00000000..22cfb225 --- /dev/null +++ b/content-fr/pyqt.rst @@ -0,0 +1,910 @@ +.. _pyqt-chapter: + +########################## +Interfaces Homme Machine temps-réel avec PyQt +########################## + +Dans ce chapitre, nous apprenons à créer des interfaces graphiques utilisateur (GUI) en temps réel avec Python grâce à PyQt, l'interface Python pour Qt. Nous y construirons un analyseur de spectre avec affichage du temps, de la fréquence et d'un spectrogramme/diagramme en cascade, ainsi que des widgets de saisie pour ajuster les différents paramètres SDR. Cet exemple est compatible avec PlutoSDR, USRP et le mode simulation uniquement. + +**************** +Introduction +**************** + +Qt (prononcé « cute ») est un framework permettant de créer des applications GUI compatibles avec Linux, Windows, macOS et Android. Ce framework puissant, utilisé dans de nombreuses applications commerciales, est écrit en C++ pour des performances optimales. PyQt est l'interface Python de Qt, offrant la possibilité de créer des applications GUI en Python tout en bénéficiant des performances d'un framework C++ performant. Dans ce chapitre, nous apprendrons à utiliser PyQt pour créer un analyseur de spectre en temps réel, utilisable avec un SDR (ou un signal simulé). Cet analyseur affichera le temps, la fréquence et un spectrogramme/diagramme en cascade, ainsi que des widgets de saisie pour ajuster les différents paramètres du SDR. Nous utiliserons `PyQtGraph `, une bibliothèque distincte basée sur PyQt, pour la visualisation des données. Côté saisie, nous utiliserons des curseurs, des listes déroulantes et des boutons. Cet exemple est compatible avec PlutoSDR, USRP et le mode simulation uniquement. Bien que le code d'exemple utilise PyQt6, chaque ligne est identique à celle de PyQt5 (à l'exception de :code:`import`), les différences entre les deux versions étant minimes du point de vue de l'API. Ce chapitre fait naturellement la part belle au code Python, comme nous l'illustrons par des exemples. À la fin de ce chapitre, vous maîtriserez les éléments de base nécessaires à la création de votre propre application SDR +interactive personnalisée ! + + +**************** +Aperçu de Qt +**************** + +Qt est un framework très complet, et nous n'aborderons ici que quelques notions de base. Cependant, il est important de comprendre certains concepts clés pour travailler avec Qt/PyQt : + +- **Widgets** : Les widgets sont les éléments constitutifs d'une application Qt et servent à créer l'interface graphique. Il existe différents types de widgets, comme les boutons, les curseurs, les étiquettes et les graphiques. Les widgets peuvent être organisés en mises en page, qui déterminent leur position à l'écran. + +- **Mises en page** : Les mises en page permettent d'organiser les widgets dans une fenêtre. Il existe plusieurs types de mises en page, notamment horizontales, verticales, en grille et en formulaire. Les mises en page permettent de créer des interfaces graphiques complexes qui s'adaptent aux changements de taille de la fenêtre. + +- **Signaux et slots** : Les signaux et les slots permettent la communication entre les différentes parties d'une application Qt. Un signal est émis par un objet lorsqu'un événement particulier se produit et est associé à un slot, une fonction de rappel appelée lors de l'émission du signal. Les signaux et les slots permettent de créer une structure événementielle dans une application Qt et de garantir la réactivité de l'interface graphique. + +- **Feuilles de style** : Les feuilles de style servent à personnaliser l'apparence des widgets dans une application Qt. Écrites dans un langage similaire à CSS, elles permettent de modifier la couleur, la police et la taille des widgets. + +- **Graphismes** : Qt dispose d'un puissant framework graphique permettant de créer des graphismes personnalisés dans une application Qt. Ce framework inclut des classes pour dessiner des lignes, des rectangles, des ellipses et du texte, ainsi que des classes pour gérer les événements de la souris et du clavier. + +- **Multithreading** : Qt prend en charge nativement le multithreading et fournit des classes pour créer des threads de travail s'exécutant en arrière-plan. Le multithreading permet d'exécuter des opérations longues dans une application Qt sans bloquer le thread principal de l'interface graphique. + +- **OpenGL** : Qt intègre la prise en charge d’OpenGL et fournit des classes pour la création de graphismes 3D dans une application Qt. OpenGL est utilisé pour créer des applications exigeant des performances graphiques 3D élevées. Dans ce chapitre, nous nous concentrerons uniquement sur les applications 2D. + + +************************* +Structure de base d'une application +************************* + +Avant d'explorer les différents widgets Qt, examinons la structure d'une application Qt typique. Une application Qt se compose d'une fenêtre principale contenant un widget central, lequel contient le contenu principal de l'application. Avec PyQt, nous pouvons créer une application Qt minimale, ne contenant qu'un seul QPushButton, comme suit : + + +.. code-block:: python + + from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton + + # Sous-classe QMainWindow pour paramétrer la fenêtre principale de + l'application + class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + + # Example de composant IHM + example_button = QPushButton('Push Me') + def on_button_click(): + print("beep") + example_button.clicked.connect(on_button_click) + + self.setCentralWidget(example_button) + + app = QApplication([]) + window = MainWindow() + window.show() # les fenêtres sont cachées par défaut + app.exec() # Démarrage de la boucle d'événements + +Essayez d'exécuter le code vous-même ; vous devrez probablement installer PyQt6 avec :code:`pip install PyQt6`. Notez que la dernière ligne est bloquante : tout ce que vous ajouterez après ne s'exécutera pas tant que vous n'aurez pas fermé la fenêtre. Le bouton QPushButton que nous créons a son signal :code:`clicked` connecté à une fonction de rappel qui affiche « beep » dans la console. + + +******************************* +Application avec thread de worker +******************************* + +L'exemple minimal présenté ci-dessus pose problème : il ne laisse aucune place pour le code SDR/DSP. La méthode :code:`__init__` de la classe :code:`MainWindow` est configurée et les fonctions de rappel sont définies, mais il est absolument impératif de ne pas y ajouter d'autre code (SDR ou DSP, par exemple). En effet, l'interface graphique étant monothread, bloquer ce thread avec du code long entraînerait des blocages ou des saccades, or nous recherchons une interface aussi fluide que possible. Pour contourner ce problème, nous pouvons utiliser un thread de travail pour exécuter le code SDR/DSP en arrière-plan. + +L'exemple ci-dessous étend l'exemple minimal précédent en incluant un thread de worker qui exécute du code (dans la fonction :code:`run`) en continu. Nous n'utilisons pas de boucle :code:`while True`, car le fonctionnement interne de PyQt exige que la fonction :code:`run` se termine et redémarre périodiquement. Pour ce faire, le signal :code:`end_of_run` du thread de worker (que nous détaillerons dans la section suivante) est associé à une fonction de rappel qui relance la fonction :code:`run` de ce même thread. Il est également nécessaire d'initialiser le thread de worker dans le code de :code:`MainWindow`, ce qui implique la création d'un nouveau :code:`QThread` et l'affectation de notre thread de worker personnalisé. Ce code peut paraître complexe, mais il s'agit d'une pratique courante dans les applications PyQt. L'essentiel à retenir +est que le code orienté interface graphique se trouve dans :code:`MainWindow`, tandis que le code orienté SDR/DSP se trouve dans la fonction :code:`run` du thread de travail. + +.. code-block:: python + + from PyQt6.QtCore import QThread, pyqtSignal, QObject, QTimer + from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton + import time + + # opérations Non-IHM (notamment SDR) néccessitant d'être lancées dans un thread spéaré. + class SDRWorker(QObject): + end_of_run = pyqtSignal() + + # Boucle principale + def run(self): + print("Starting run()") + time.sleep(1) + self.end_of_run.emit() # let MainWindow know we're done + + # Sous-classe QMainWindow pour personnaliser la fenêtre principale de votre application + class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + + # Initialisation du worker et du thread + self.sdr_thread = QThread() + worker = SDRWorker() + worker.moveToThread(self.sdr_thread) + + # Exemple de composant IHM + example_button = QPushButton('Push Me') + def on_button_click(): + print("beep") + example_button.clicked.connect(on_button_click) + self.setCentralWidget(example_button) + + # C'est ce qui permet à la fonction run() de se répéter en continu + def end_of_run_callback(): + QTimer.singleShot(0, worker.run) # Run worker again immediately + worker.end_of_run.connect(end_of_run_callback) + + self.sdr_thread.started.connect(worker.run) # kicks off the first run() when the thread starts + self.sdr_thread.start() # start thread + + app = QApplication([]) + window = MainWindow() + window.show() # Les fenêtres sont cachées par défaut + app.exec() # Démarrer l'évenèment boucle + +Essayez d'exécuter le code ci-dessus ; vous devriez voir « Starting run()» s'afficher dans la console toutes les secondes, et le bouton-poussoir devrait toujours fonctionner (sans délai). Dans le thread de travail, nous effectuons pour l'instant uniquement un affichage et une pause, mais nous y ajouterons prochainement la gestion du signal SDR et le code de traitement du signal numérique. + +************************* +Signaux et slots +************************* + +Dans l'exemple précédent, nous avons utilisé le signal :code:`end_of_run` pour la communication entre le thread de travail et le thread d'interface graphique. Ce modèle, courant dans les applications PyQt, est connu sous le nom de mécanisme « signaux et emplacements ». Un signal est émis par un objet (ici, le thread de travail) et est associé à un slot (/NDLR : emplacement en français/) (ici, la fonction de rappel :code:`end_of_run_callback` du thread d'interface graphique). Un signal peut être associé à plusieurs slots, et un slot peut être associé à plusieurs signaux. Le signal peut également transporter des arguments, qui sont transmis à l'emplacement lors de son émission. Notez que l'opération est réversible : le thread d'interface graphique peut envoyer un signal à l'emplacement du thread de travail. Le mécanisme de signaux/emplacements est un moyen puissant de communiquer entre les différentes parties d'une application PyQt, créant une structure événementielle. Il est largement utilisé dans l'exemple de code suivant. Retenez simplement qu'un slot est une fonction de rappel, et qu'un signal est un moyen de signaler cette fonction de rappel. + + +************************* +PyQtGraph +************************* + +PyQtGraph est une bibliothèque basée sur PyQt et NumPy qui offre des capacités de traçage rapides et efficaces, PyQt étant trop généraliste pour intégrer des fonctionnalités de traçage. Conçue pour les applications temps réel, elle est optimisée pour la vitesse. Elle est similaire à Matplotlib à bien des égards, mais destinée aux applications temps réel plutôt qu'aux graphiques individuels. L'exemple simple ci-dessous permet de comparer les performances de PyQtGraph et de Matplotlib : il suffit de remplacer :code:`if True` par :code:`False`. Sur un processeur Intel Core i9-10900K à 3,70 GHz, le code PyQtGraph s'est mis à jour à plus de 1 000 images par seconde, tandis que le code Matplotlib s'est mis à jour à 40 images par seconde. Cela étant dit, si vous constatez que l'utilisation de Matplotlib vous est utile (par exemple, pour gagner du temps de développement ou parce que vous souhaitez une fonctionnalité spécifique que PyQtGraph ne prend pas en charge), vous pouvez intégrer des graphiques Matplotlib dans une application PyQt, en utilisant le code ci-dessous comme point de départ. + +.. raw:: html + +
    + Développez pour afficher le code + +.. code-block:: python + + import numpy as np + import time + import matplotlib + matplotlib.use('Qt5Agg') + from PyQt6 import QtCore, QtWidgets + from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas + from matplotlib.figure import Figure + import pyqtgraph as pg # tested with pyqtgraph==0.13.7 + + n_data = 1024 + + if True: + class MplCanvas(FigureCanvas): + def __init__(self): + fig = Figure(figsize=(13, 8), dpi=100) + self.axes = fig.add_subplot(111) + super(MplCanvas, self).__init__(fig) + + + class MainWindow(QtWidgets.QMainWindow): + def __init__(self): + super(MainWindow, self).__init__() + + self.canvas = MplCanvas() + self._plot_ref = self.canvas.axes.plot(np.arange(n_data), '.-r')[0] + self.canvas.axes.set_xlim(0, n_data) + self.canvas.axes.set_ylim(-5, 5) + self.canvas.axes.grid(True) + self.setCentralWidget(self.canvas) + + # Configurez une minuterie pour déclencher le redessin en appelant update_plot + self.timer = QtCore.QTimer() + self.timer.setInterval(0) # provoque le démarrage immédiat du minuteur + self.timer.timeout.connect(self.update_plot) # provoque le redémarrage automatique du minuteur + self.timer.start() + self.start_t = time.time() # utilisé pour l'analyse comparative + + self.show() + + def update_plot(self): + self._plot_ref.set_ydata(np.random.randn(n_data)) + self.canvas.draw() # Déclenchez la mise à jour et le redessin du canevas. + print('FPS:', 1/(time.time()-self.start_t)) # on a obtenu environ 42 FPS sur un i9-10900K + self.start_t = time.time() + + else: + class MainWindow(QtWidgets.QMainWindow): + def __init__(self): + super(MainWindow, self).__init__() + + self.time_plot = pg.PlotWidget() + self.time_plot.setYRange(-5, 5) + self.time_plot_curve = self.time_plot.plot([]) + self.setCentralWidget(self.time_plot) + + # Configurez une minuterie pour déclencher le redessin en appelant update_plot. + self.timer = QtCore.QTimer() + self.timer.setInterval(0) # provoque le démarrage immédiat du timer + self.timer.timeout.connect(self.update_plot) # provoque le redémarrage automatique du minuteur + self.timer.start() + self.start_t = time.time() # utilisé pour l'évaluation des performances. + + self.show() + + def update_plot(self): + self.time_plot_curve.setData(np.random.randn(n_data)) + print('FPS:', 1/(time.time()-self.start_t)) # on a obtenu environ 42 FPS sur un i9-10900K + self.start_t = time.time() + + app = QtWidgets.QApplication([]) + w = MainWindow() + app.exec() + +.. raw:: html + +
    + +Pour ce qui est d'utiliser PyQtGraph, nous l'importons avec :code:`import pyqtgraph as pg` et nous pouvons ensuite créer un widget Qt qui représente un graphique 1D comme suit (ce code va dans la méthode :code:`__init__` de :code:`MainWindow`). + +.. code-block:: python + + # Exemple de graphique PyQtGraph + time_plot = pg.PlotWidget(labels={'left': 'Amplitude', 'bottom': 'Time'}) + time_plot_curve = time_plot.plot(np.arange(1000), + np.random.randn(1000)) # x et y + time_plot.setYRange(-5, 5) + + self.setCentralWidget(time_plot) + +.. image:: ../_images/pyqtgraph_example.png + :scale: 80 % + :align: center + :alt: PyQtGraph exemple + + +Vous pouvez constater qu'il est relativement simple de configurer un graphique, et le résultat est simplement un widget supplémentaire à ajouter à votre interface graphique. Outre les graphiques 1D, PyQtGraph possède également un équivalent de la fonction :code:`imshow()` de Matplotlib, qui permet de tracer des graphiques 2D à l'aide d'une palette de couleurs, que nous utiliserons pour notre spectrogramme/waterfall en temps réel. L'un des avantages de PyQtGraph est que les graphiques qu'il crée sont de simples widgets Qt, et que nous ajoutons d'autres éléments Qt (par exemple, un rectangle d'une certaine taille à une certaine coordonnée) en utilisant uniquement PyQt. En effet, PyQtGraph utilise la classe :code:`QGraphicsScene` de PyQt, qui fournit une interface pour gérer un grand nombre d'éléments graphiques 2D. Rien ne nous empêche donc d'ajouter des lignes, des rectangles, du texte, des ellipses, des polygones et des bitmaps, directement en utilisant PyQt. + +******* +Dispositions +******* + +Dans les exemples précédents, nous avons utilisé :code:`self.setCentralWidget()` pour définir le widget principal de la fenêtre. Cette méthode simple ne permet pas de créer des dispositions plus complexes. Pour cela, nous pouvons utiliser des dispositions, qui permettent d'organiser les widgets dans une fenêtre. Il existe plusieurs types de dispositions, notamment :code:`QHBoxLayout`, :code:`QVBoxLayout`, :code:`QGridLayout` et :code:`QFormLayout`. :code:`QHBoxLayout` et :code:`QVBoxLayout` disposent les widgets horizontalement et verticalement, respectivement. :code:`QGridLayout` les dispose sous forme de grille, et :code:`QFormLayout` les dispose sur deux colonnes : la première colonne contient les étiquettes et la seconde, les champs de saisie. + +Pour créer une nouvelle mise en page et y ajouter des widgets, essayez d'ajouter ce qui suit dans la méthode :code:`__init__` de votre :code:`MainWindow` : + +.. code-block:: python + + layout = QHBoxLayout() + layout.addWidget(QPushButton("Left-Most")) + layout.addWidget(QPushButton("Center"), 1) + layout.addWidget(QPushButton("Right-Most"), 2) + self.setLayout(layout) + + +Dans cet exemple, les widgets sont empilés horizontalement. Cependant, en remplaçant :code:`QHBoxLayout` par :code:`QVBoxLayout`, il est possible de les empiler verticalement. La fonction :code:`addWidget` permet d'ajouter des widgets à la mise en page. Son deuxième argument, optionnel, est un facteur d'étirement qui détermine l'espace occupé par le widget par rapport aux autres. + +:code:`QGridLayout` possède des paramètres supplémentaires : il est nécessaire de spécifier la ligne et la colonne du widget, ainsi que le nombre de lignes et de colonnes qu'il doit occuper (par défaut : 1 et 1). Voici un exemple de :code:`QGridLayout` : + +.. code-block:: python + + layout = QGridLayout() + layout.addWidget(QPushButton("Button at (0, 0)"), 0, 0) + layout.addWidget(QPushButton("Button at (0, 1)"), 0, 1) + layout.addWidget(QPushButton("Button at (0, 2)"), 0, 2) + layout.addWidget(QPushButton("Button at (1, 0)"), 1, 0) + layout.addWidget(QPushButton("Button at (1, 1)"), 1, 1) + layout.addWidget(QPushButton("Button at (1, 2)"), 1, 2) + layout.addWidget(QPushButton("Button at (2, 0) spanning 2 columns"), 2, 0, 1, 2) + self.setLayout(layout) + +.. image:: ../_images/qt_layouts.svg + :align: center + :target: ../_images/qt_layouts.svg + :alt: Agencements Qt illustrant des exemples de QHBoxLayout, QVBoxLayout et QGridLayout + +Pour notre analyseur de spectre, nous utiliserons :code:`QGridLayout` pour la mise en page générale, mais nous ajouterons également :code:`QHBoxLayout` pour empiler les widgets horizontalement dans un espace de la grille. Vous pouvez imbriquer des mises en page simplement en créant une nouvelle mise en page et en l'ajoutant à la mise en page de niveau supérieur (ou parente), par exemple : + +.. code-block:: python + + layout = QGridLayout() + self.setLayout(layout) + inner_layout = QHBoxLayout() + layout.addLayout(inner_layout) + + +******************* +:code:`QPushButton` +******************* + +Le premier widget que nous allons aborder est le :code:`QPushButton`, un simple bouton cliquable. Nous avons déjà vu comment créer un :code:`QPushButton` et associer son signal :code:`clicked` à une fonction de rappel. Le :code:`QPushButton` possède d'autres signaux, notamment :code:`pressed`, :code:`released` et :code:`toggled`. Le signal :code:`toggled` est émis lorsque le bouton est activé ou désactivé, et est utile pour créer des boutons à bascule. Le :code:`QPushButton` possède également plusieurs propriétés, dont :code:`text`, :code:`icon` et :code:`checkable`. Enfin, le :code:`QPushButton` possède une méthode appelée :code:`click()` qui simule un clic sur le bouton. Pour notre application d'analyseur de spectre SDR, nous utiliserons des boutons pour déclencher un réglage automatique de la plage des graphiques, en utilisant les données actuelles pour calculer les limites de l'axe des y. Comme nous avons déjà utilisé le composant :code:`QPushButton`, nous n'entrerons pas dans les détails ici. Vous trouverez plus d'informations dans la `documentation de QPushButton : `_. + + +*************** +:code:`QSlider` +*************** +Le :code:`QSlider` est un widget qui permet à l'utilisateur de sélectionner une valeur dans une plage de valeurs. Le :code:`QSlider` possède plusieurs propriétés, notamment :code:`minimum`, :code:`maximum`, :code:`value` et :code:`orientation`. Le composant :code:`QSlider` possède également plusieurs signaux, notamment :code:`valueChanged`, :code:`sliderPressed` et :code:`sliderReleased`. Il dispose aussi d'une méthode :code:`setValue()` qui permet de définir la valeur du curseur ; nous l'utiliserons fréquemment. La documentation de :code:`QSlider` est disponible ici : ``_. + + +Pour notre application d'analyseur de spectre, nous utiliserons des curseurs QSlider pour ajuster la fréquence centrale et le gain du récepteur SDR. Voici un extrait du code final de l'application qui crée le curseur de gain : + +.. code-block:: python + + # Slider de gain avec étiquette + gain_slider = QSlider(Qt.Orientation.Horizontal) + gain_slider.setRange(0, 73) # min et max inclus. L'intervalle est toujours de 1 + gain_slider.setValue(50) # valeur initiale + gain_slider.setTickPosition(QSlider.TickPosition.TicksBelow) + gain_slider.setTickInterval(2) # à des fins visuelles uniquement + gain_slider.sliderMoved.connect(worker.update_gain) + gain_label = QLabel() + def update_gain_label(val): + gain_label.setText("Gain: " + str(val)) + gain_slider.sliderMoved.connect(update_gain_label) + update_gain_label(gain_slider.value()) # initialisation du label + layout.addWidget(gain_slider, 5, 0) + layout.addWidget(gain_label, 5, 1) + + +Il est très important de savoir que :code:`QSlider` utilise des entiers. En définissant la plage de 0 à 73, on permet au curseur de choisir des valeurs entières comprises entre ces nombres (début et fin inclus). La fonction :code:`setTickInterval(2)` est purement visuelle. C'est pourquoi nous utiliserons le kHz comme unité pour le curseur de fréquence, afin d'obtenir une granularité jusqu'à 1 kHz. + +Au milieu du code ci-dessus, vous remarquerez la création d'un :code:`QLabel`, une simple étiquette de texte. Pour afficher la valeur actuelle du curseur, nous devons créer un slot (c'est-à-dire une fonction de rappel) qui met à jour l'étiquette. Nous connectons cette fonction de rappel au signal :code:`sliderMoved`, émis automatiquement à chaque déplacement du curseur. Nous appelons également cette fonction une première fois pour initialiser l'étiquette avec la valeur actuelle du curseur (50 dans notre cas). Il faut également connecter le signal :code:`sliderMoved` à un slot situé dans le thread de travail, qui mettra à jour le gain du SDR (rappelons que nous préférons ne pas gérer le SDR ni effectuer de traitement du signal numérique dans le thread principal de l'interface graphique). La fonction de rappel définissant ce slot sera abordée ultérieurement. + + +***************** +:code:`QComboBox` +***************** +Le :code:`QComboBox` est un widget de type liste déroulante permettant à l'utilisateur de sélectionner un élément dans une liste. Il possède plusieurs propriétés, notamment :code:`currentText`, :code:`currentIndex` et :code:`count`. Il dispose également de signaux tels que :code:`currentTextChanged`, :code:`currentIndexChanged` et :code:`activated`. Enfin, il possède une méthode :code:`addItem()` pour ajouter un élément à la liste et une méthode :code:`insertItem()` pour insérer un élément à un index spécifique, bien que nous ne les utilisions pas dans notre exemple d'analyseur de spectre. La documentation de :code:`QComboBox` est disponible ici : ``_. + +Pour notre application d'analyseur de spectre, nous utiliserons un :code:`QComboBox` afin de sélectionner la fréquence d'échantillonnage dans une liste prédéfinie. Au début de notre code, nous définissons les fréquences d'échantillonnage possibles avec :code:`sample_rates = [56, 40, 20, 10, 5, 2, 1, 0.5]`. Dans la méthode :code:`__init__` de la fenêtre principale, nous créons le :code:`QComboBox` comme suit : + +.. code-block:: python + + # Liste déroulante de fréquence d'échantillonnage utilisant QComboBox + sample_rate_combobox = QComboBox() + sample_rate_combobox.addItems([str(x) + ' MHz' for x in sample_rates]) + sample_rate_combobox.setCurrentIndex(0) # Il faut lui fournir l'index, et non une chaîne de caractères. + sample_rate_combobox.currentIndexChanged.connect(worker.update_sample_rate) + sample_rate_label = QLabel() + def update_sample_rate_label(val): + sample_rate_label.setText("Sample Rate: " + str(sample_rates[val]) + " MHz") + sample_rate_combobox.currentIndexChanged.connect(update_sample_rate_label) + update_sample_rate_label(sample_rate_combobox.currentIndex()) # initialisation du label + layout.addWidget(sample_rate_combobox, 6, 0) + layout.addWidget(sample_rate_label, 6, 1) + + +La seule véritable différence entre ceci et le curseur est le :code:`addItems()` où vous lui donnez la liste des chaînes à utiliser comme options, et :code:`setCurrentIndex()` qui définit la valeur de départ. + + +**************** +Lonctions lambda +**************** + +Rappelez-vous dans le code ci-dessus où nous avons fait : + +.. code-block:: python + + def update_sample_rate_label(val): + sample_rate_label.setText("Sample Rate: " + str(sample_rates[val]) + " MHz") + sample_rate_combobox.currentIndexChanged.connect(update_sample_rate_label) + + +Nous créons une fonction ne contenant qu'une seule ligne de code, puis nous passons cette fonction (les fonctions sont aussi des objets !) à :code:`connect()`. Pour simplifier, réécrivons ce modèle de code en utilisant du Python de base : + +.. code-block:: python + + def my_function(x): + print(x) + y.call_that_takes_in_function_obj(my_function) + +Dans ce cas précis, nous avons une fonction ne contenant qu'une seule ligne de code, et nous n'y faisons référence qu'une seule fois : lors de la définition du rappel :code:`connect`. Dans ce genre de situation, nous pouvons utiliser une fonction lambda, qui permet de définir une fonction sur une seule ligne. Voici le code ci-dessus réécrit à l'aide d'une fonction lambda : + +.. code-block:: python + + y.call_that_takes_in_function_obj(lambda x: print(x)) + +Si vous n'avez jamais utilisé de fonction lambda, cela peut paraître étrange, et vous n'êtes d'ailleurs pas obligé de les utiliser, mais cela permet de gagner deux lignes de code et de le rendre plus concis. Le principe est le suivant : le nom de l'argument temporaire est indiqué après « lambda », et tout ce qui suit les deux-points correspond au code qui agira sur cette variable. Il est possible d'utiliser plusieurs arguments, séparés par des virgules, ou même aucun argument avec : :code:`lambda : `. À titre d'exercice, essayez de réécrire la fonction :code:`update_sample_rate_label` ci-dessus en utilisant une fonction lambda. + + +*********************** +Le widget de tracé de PyQtGraph +*********************** + +Le widget :code:`PlotWidget` de PyQtGraph permet de générer des graphiques 1D, à l'instar de :code:`plt.plot(x,y)` de Matplotlib. Nous l'utiliserons pour les graphiques dans le domaine temporel et fréquentiel (PSD), bien qu'il convienne également aux graphiques IQ (que notre analyseur de spectre ne prend pas en charge). Pour les curieux, PlotWidget est une sous-classe de `QGraphicsView `_ de PyQt, qui est un widget permettant d'afficher le contenu d'une `QGraphicsScene `_, qui est une surface permettant de gérer un grand nombre d'éléments graphiques 2D dans Qt. L'important à retenir concernant PlotWidget est qu'il s'agit simplement d'un widget contenant un unique `PlotItem `_. Du point de vue de la documentation, il est donc préférable de se référer directement à la documentation de PlotItem : ``_. Un PlotItem contient une ViewBox pour afficher les données à représenter graphiquement, ainsi que des AxisItems et des labels pour afficher les axes et le titre, comme on peut s'y attendre. + +Voici un exemple simple d'utilisation d'un PlotWidget (à ajouter dans la méthode :code:`__init__` de :code:`MainWindow`) : + + +.. code-block:: python + + import pyqtgraph as pg + plotWidget = pg.plot(title="My Title") + plotWidget.plot(x, y) + +où x et y sont généralement des tableaux NumPy, comme avec la fonction :code:`plt.plot()` de Matplotlib. Cependant, cela représente un graphique statique où les données ne changent jamais. Pour notre analyseur de spectre, nous souhaitons mettre à jour les données dans notre thread de travail. Par conséquent, lors de l'initialisation du graphique, nous n'avons même pas besoin de lui fournir de données ; il suffit de le configurer. Voici comment nous initialisons le graphique temporel dans notre application d'analyseur de spectre : + +.. code-block:: python + + # Time plot + time_plot = pg.PlotWidget(labels={'left': 'Amplitude', 'bottom': 'Time [microseconds]'}) + time_plot.setMouseEnabled(x=False, y=True) + time_plot.setYRange(-1.1, 1.1) + time_plot_curve_i = time_plot.plot([]) + time_plot_curve_q = time_plot.plot([]) + layout.addWidget(time_plot, 1, 0) + +Vous pouvez constater que nous créons deux graphiques/courbes différents, un pour I et un pour Q. Le reste du code devrait être explicite. Pour pouvoir mettre à jour le graphique, nous devons créer un emplacement (c'est-à-dire une fonction de rappel) dans la méthode :code:`__init__` de la fenêtre principale. + +.. code-block:: python + + def time_plot_callback(samples): + time_plot_curve_i.setData(samples.real) + time_plot_curve_q.setData(samples.imag) + + +Nous connecterons ce slot au signal du thread de travail émis lors de la disponibilité de nouveaux échantillons, comme indiqué plus loin. + +La dernière étape dans la méthode :code:`__init__` de :code:`MainWindow` consiste à ajouter deux boutons à droite du graphique. Ces boutons activeront un réglage automatique de la plage. L'un utilisera les valeurs minimales et maximales actuelles, tandis que l'autre définira la plage entre -1,1 et 1,1 (correspondant aux limites de conversion analogique-numérique de nombreux SDR, plus une marge de 10 %). Nous créerons une mise en page interne, plus précisément un :code:`QVBoxLayout`, pour empiler verticalement ces deux boutons. Voici le code permettant d'ajouter les boutons : + + +.. code-block:: python + + # Boutons de plage automatique du graphique temporel + time_plot_auto_range_layout = QVBoxLayout() + layout.addLayout(time_plot_auto_range_layout, 1, 1) + auto_range_button = QPushButton('Auto Range') + auto_range_button.clicked.connect(lambda : time_plot.autoRange()) # lambda signifie simplement qu'il s'agit d'une fonction sans nom + time_plot_auto_range_layout.addWidget(auto_range_button) + auto_range_button2 = QPushButton('-1 to +1\n(ADC limits)') + auto_range_button2.clicked.connect(lambda : time_plot.setYRange(-1.1, 1.1)) + time_plot_auto_range_layout.addWidget(auto_range_button2) + +Et voici à quoi cela ressemble au final : + +.. image:: ../_images/pyqt_time_plot.png + :scale: 50 % + :align: center + :alt: Graphique temporel PyQtGraph + +Nous utiliserons un modèle similaire pour le graphique du domaine fréquentiel (PSD). + + +********************* +ImageItem de PyQtGraph +********************* + +Un analyseur de spectre se doit d'afficher un spectrogramme en cascade (ou spectrogramme en temps réel). Pour cela, nous utiliserons l'objet ImageItem de PyQtGraph, qui génère des images à 1, 3 ou 4 canaux. Un canal correspond à un tableau 2D de nombres flottants ou entiers, qui utilise ensuite une table de correspondance (LUT) pour appliquer une palette de couleurs et créer l'image. On peut également utiliser les formats RGB (3 canaux) ou RGBA (4 canaux). Nous calculerons notre spectrogramme sous forme d'un tableau NumPy 2D de nombres flottants et le transmettrons directement à l'objet ImageItem. Nous choisirons une palette de couleurs et exploiterons la fonctionnalité intégrée d'affichage d'une LUT graphique permettant de visualiser la distribution des valeurs de nos données et l'application de la palette. + +L'initialisation du spectrogramme watefall est assez simple : nous utilisons un PlotWidget comme conteneur (afin de conserver l'affichage des axes x et y) et y ajoutons un ImageItem. + +.. code-block:: python + + # Waterfall plot + waterfall = pg.PlotWidget(labels={'left': 'Time [s]', 'bottom': 'Frequency [MHz]'}) + imageitem = pg.ImageItem(axisOrder='col-major') # cet argument est simplement pour la performance + waterfall.addItem(imageitem) + waterfall.setMouseEnabled(x=False, y=False) + waterfall_layout.addWidget(waterfall) + +Le slot/callback associé à la mise à jour des données en cascade, qui se trouve dans :code:`MainWindow`'s :code:`__init__`, est le suivant : + +.. code-block:: python + + def waterfall_plot_callback(spectrogram): + imageitem.setImage(spectrogram, autoLevels=False) + sigma = np.std(spectrogram) + mean = np.mean(spectrogram) + self.spectrogram_min = mean - 2*sigma # save to window state + self.spectrogram_max = mean + 2*sigma + +Le spectrogramme sera un tableau NumPy 2D de nombres flottants. Outre la définition des données de l'image, nous calculerons les valeurs minimale et maximale de la palette de couleurs, en fonction de la moyenne et de la variance des données, que nous utiliserons ultérieurement. La dernière partie du code de l'interface graphique du spectrogramme consiste à créer la barre de couleurs, qui définit également la palette de couleurs utilisée. + +.. code-block:: python + + # Colorbar for waterfall + colorbar = pg.HistogramLUTWidget() + colorbar.setImageItem(imageitem) # Connecte la barre à l'élément image du spectrogramme + colorbar.item.gradient.loadPreset('viridis') # définit la palette de couleurs, et définit également l'élément image + imageitem.setLevels((-30, 20)) # doit être placé après la création de la barre de couleur (pour une raison inconnue) + waterfall_layout.addWidget(colorbar) + +La deuxième ligne est importante ; c’est elle qui relie la barre de couleurs à l’élément ImageItem. C’est également dans ce code que l’on choisit la palette de couleurs et que l’on définit les niveaux de départ (de -30 dB à +20 dB dans notre cas). Le code du thread de travail illustre le calcul et le stockage du tableau 2D du spectrogramme. Ci-dessous, une capture d’écran de cette partie de l’interface graphique montre l’incroyable fonctionnalité intégrée de la barre de couleurs et de l’affichage de la LUT. Notez que la courbe en cloche horizontale représente la distribution des valeurs du spectrogramme, une information très utile. + +.. image:: ../_images/pyqt_spectrogram.png + :scale: 50 % + :align: center + :alt: Spectrogramme et colorbar PyQtGraph + +*********************** +Worker Thread +*********************** + +Rappelez-vous, au début de ce chapitre, nous avons appris à créer un thread séparé à l'aide d'une classe nommée SDRWorker et de sa fonction run(). C'est dans ce thread que nous placerons tout notre code SDR et DSP, à l'exception de l'initialisation du SDR, que nous effectuerons globalement pour le moment. Ce thread de travail sera également chargé de mettre à jour les trois graphiques en émettant des signaux lorsque de nouveaux échantillons sont disponibles, afin de déclencher les fonctions de rappel que nous avons déjà créées dans :code:`MainWindow`, qui mettent finalement à jour les graphiques. La classe SDRWorker se divise en trois sections : + +#. :code:`init()` - utilisée pour initialiser un état, comme le tableau 2D du spectrogramme. +#. PyQt Signals - nous devons définir les signaux personnalisés qui seront émis +#. PyQt Slots - les fonctions de rappel déclenchées par des événements d'interface graphique, comme le déplacement d'un curseur +#. :code:`run()` - la boucle principale qui s'exécute en continu + +*********************** +Signaux PyQt +*********************** + +Dans le code de l'interface graphique, nous n'avions pas besoin de définir de signaux, car ils étaient intégrés aux widgets utilisés, comme le signal :code:`valueChanged` de :code:`QSlider`. Notre classe :code:`SDRWorker` est personnalisée, et tous les signaux que nous souhaitons émettre doivent être définis avant d'appeler :code:`run()`. Voici le code de la classe :code:`SDRWorker`, qui définit quatre signaux que nous utiliserons, ainsi que leurs types de données correspondants : + +.. code-block:: python + + # Signaux PyQt + time_plot_update = pyqtSignal(np.ndarray) + freq_plot_update = pyqtSignal(np.ndarray) + waterfall_plot_update = pyqtSignal(np.ndarray) + end_of_run = pyqtSignal() # se produit plusieurs fois par seconde + +Les trois premiers signaux envoient un seul objet : un tableau NumPy. Le dernier signal n'envoie aucun objet. Il est également possible d'envoyer plusieurs objets simultanément, en séparant les types de données par des virgules, mais cela n'est pas nécessaire pour notre application. À n'importe quel endroit de la fonction :code:`run()`, nous pouvons émettre un signal vers le thread d'interface graphique en une seule ligne de code, par exemple : + +.. code-block:: python + + self.time_plot_update.emit(samples) + +Il reste une dernière étape pour établir toutes les connexions signaux/slots : dans le code de l’interface graphique (qui se trouve à la toute fin de la méthode :code:`__init__` de :code:`MainWindow`), nous devons connecter les signaux du thread de travail aux slots de l’interface graphique, par exemple : + +.. code-block:: python + + worker.time_plot_update.connect(time_plot_callback) # connection du signal à la fonction d'appel (callback) + +Rappelez-vous que :code:`worker` est l'instance de la classe :code:`SDRWorker` créée dans le code de l'interface graphique. Nous connectons ici le signal du thread de travail, :code:`time_plot_update`, à l'emplacement de l'interface graphique, :code:`time_plot_callback`, défini précédemment. Revoyez les extraits de code présentés jusqu'ici et observez leur fonctionnement. Cela vous permettra de bien comprendre la communication entre l'interface graphique et le thread de travail, un aspect fondamental de la programmation PyQt. + + +*********************** +Slots des Worker Threads +*********************** + +Les slots des worker threads sont les fonctions de rappel déclenchées par des événements d'interface graphique, comme le déplacement du curseur de gain. Leur fonctionnement est assez simple ; par exemple, cet emplacement met à jour la valeur de gain du SDR avec la nouvelle valeur sélectionnée par le curseur : + +.. code-block:: python + + def update_gain(self, val): + print("Updated gain to:", val, 'dB') + sdr.set_rx_gain(val) + +*********************** +Worker Thread Run() +*********************** + +La fonction :code:`run()` est l'endroit où se déroule toute la partie DSP intéressante ! Dans notre application, chaque fonction :code:`run()` commencera par la réception d'un ensemble d'échantillons provenant du SDR (ou par la simulation d'échantillons si vous n'avez pas de SDR). + +.. code-block:: python + + # Main loop + def run(self): + if sdr_type == "pluto": + samples = sdr.rx()/2**11 # Receive samples + elif sdr_type == "usrp": + streamer.recv(recv_buffer, metadata) + samples = recv_buffer[0] # will be np.complex64 + elif sdr_type == "sim": + tone = np.exp(2j*np.pi*self.sample_rate*0.1*np.arange(fft_size)/self.sample_rate) + noise = np.random.randn(fft_size) + 1j*np.random.randn(fft_size) + samples = self.gain*tone*0.02 + 0.1*noise + # Truncate to -1 to +1 to simulate ADC bit limits + np.clip(samples.real, -1, 1, out=samples.real) + np.clip(samples.imag, -1, 1, out=samples.imag) + + ... + +Comme vous pouvez le constater, pour l'exemple simulé, nous générons une tonalité avec du bruit blanc, puis nous tronquons les échantillons de -1 à +1. + +Passons maintenant au traitement numérique du signal (DSP) ! Nous savons qu'il nous faudra effectuer la transformée de Fourier rapide (FFT) pour obtenir le graphique dans le domaine fréquentiel et le spectrogramme. Il s'avère que nous pouvons simplement utiliser la densité spectrale de puissance (DSP) de cet ensemble d'échantillons comme une ligne du spectrogramme. Il nous suffit donc de décaler notre spectrogramme/diagramme en cascade d'une ligne vers le haut et d'ajouter cette nouvelle ligne en bas (ou en haut, peu importe). À chaque mise à jour du graphique, nous émettons le signal contenant les données mises à jour. Nous signalons également la fin de la fonction :code:`run()` afin que le thread de l'interface graphique lance immédiatement un nouvel appel à :code:`run()`. Au final, le code est plutôt court. + +.. code-block:: python + + ... + + self.time_plot_update.emit(samples[0:time_plot_samples]) + + PSD = 10.0*np.log10(np.abs(np.fft.fftshift(np.fft.fft(samples)))**2/fft_size) + self.PSD_avg = self.PSD_avg * 0.99 + PSD * 0.01 + self.freq_plot_update.emit(self.PSD_avg) + + self.spectrogram[:] = np.roll(self.spectrogram, 1, axis=1) # shifts waterfall 1 row + self.spectrogram[:,0] = PSD # fill last row with new fft results + self.waterfall_plot_update.emit(self.spectrogram) + + self.end_of_run.emit() # emit the signal to keep the loop going + # end of run() + +Notez que nous n'envoyons pas l'intégralité des échantillons au graphique temporel, car cela représenterait un nombre excessif de points. Seuls les 500 premiers échantillons sont envoyés (paramétrable en début de script, non affiché ici). Pour le graphique de la densité spectrale de puissance (DSP), nous utilisons une moyenne mobile de la DSP, obtenue en stockant la DSP précédente et en y ajoutant 1 % de la nouvelle DSP. Cette méthode simple permet de lisser le graphique de la DSP. Notez que l'ordre d'appel de la fonction :code:`emit()` pour les signaux est indifférent ; ils auraient tout aussi bien pu être tous placés à la fin de la fonction :code:`run()`. + + +*********************** +Exemple final : Code complet +*********************** + +Jusqu’à présent, nous avons examiné des extraits de code de l’application d’analyse de spectre. Nous allons maintenant étudier le code complet et l’exécuter. Il est compatible avec PlutoSDR, USRP et le mode simulation. Si vous ne possédez ni PlutoSDR ni USRP, laissez le code tel quel ; il utilisera alors le mode simulation. Sinon, modifiez :code:`sdr_type`. En mode simulation, si vous augmentez le gain au maximum, vous constaterez que le signal est tronqué dans le domaine temporel, ce qui provoque l’apparition de signaux parasites dans le domaine fréquentiel. + +N’hésitez pas à utiliser ce code comme point de départ pour votre propre application SDR en temps réel ! Vous trouverez ci-dessous une animation de l’application en action, utilisant un PlutoSDR pour analyser la bande cellulaire 750 MHz, puis la bande Wi-Fi 2,4 GHz. Une version de meilleure qualité est disponible sur YouTube ici `here `_. + +.. image:: ../_images/pyqt_animation.gif + :scale: 100 % + :align: center + :alt: gif animé montrant le fonctionnement l'application analyseur de spectre PyQt + + +Bogues connus (pour aider à les corriger, modifiez ce fichier `edit +this +`_) +: + +#. L'axe des x du spectrogramme ne se met pas à jour lorsque l'on modifie la fréquence centrale (contrairement au graphique PSD) + +Code complet : + +.. code-block:: python + + from PyQt6.QtCore import QSize, Qt, QThread, pyqtSignal, QObject, QTimer + from PyQt6.QtWidgets import QApplication, QMainWindow, QGridLayout, QWidget, QSlider, QLabel, QHBoxLayout, QVBoxLayout, QPushButton, QComboBox # tested with PyQt6==6.7.0 + import pyqtgraph as pg # tested with pyqtgraph==0.13.7 + import numpy as np + import time + import signal # lets control-C actually close the app + + # Valeurs par défaut + fft_size = 4096 # determines buffer size + num_rows = 200 + center_freq = 750e6 + sample_rates = [56, 40, 20, 10, 5, 2, 1, 0.5] # MHz + sample_rate = sample_rates[0] * 1e6 + time_plot_samples = 500 + gain = 50 # 0 to 73 dB. int + + sdr_type = "sim" # or "usrp" or "pluto" + + # Initialisation du SDR + if sdr_type == "pluto": + import adi + sdr = adi.Pluto("ip:192.168.1.10") + sdr.rx_lo = int(center_freq) + sdr.sample_rate = int(sample_rate) + sdr.rx_rf_bandwidth = int(sample_rate*0.8) # bande-passante du filtre anti-repliement + sdr.rx_buffer_size = int(fft_size) + sdr.gain_control_mode_chan0 = 'manual' + sdr.rx_hardwaregain_chan0 = gain # dB + elif sdr_type == "usrp": + import uhd + #usrp = uhd.usrp.MultiUSRP(args="addr=192.168.1.10") + usrp = uhd.usrp.MultiUSRP(args="addr=192.168.1.201") + usrp.set_rx_rate(sample_rate, 0) + usrp.set_rx_freq(uhd.libpyuhd.types.tune_request(center_freq), 0) + usrp.set_rx_gain(gain, 0) + + # Configuration du flux (stream) et du buiffer de réception + st_args = uhd.usrp.StreamArgs("fc32", "sc16") + st_args.channels = [0] + metadata = uhd.types.RXMetadata() + streamer = usrp.get_rx_stream(st_args) + recv_buffer = np.zeros((1, fft_size), dtype=np.complex64) + + # Démarrage du flux + stream_cmd = uhd.types.StreamCMD(uhd.types.StreamMode.start_cont) + stream_cmd.stream_now = True + streamer.issue_stream_cmd(stream_cmd) + + def flush_buffer(): + for _ in range(10): + streamer.recv(recv_buffer, metadata) + + class SDRWorker(QObject): + def __init__(self): + super().__init__() + self.gain = gain + self.sample_rate = sample_rate + self.freq = 0 # in kHz, to deal with QSlider being ints and with a max of 2 billion + self.spectrogram = -50*np.ones((fft_size, num_rows)) + self.PSD_avg = -50*np.ones(fft_size) + + # Signaux PyQt + time_plot_update = pyqtSignal(np.ndarray) + freq_plot_update = pyqtSignal(np.ndarray) + waterfall_plot_update = pyqtSignal(np.ndarray) + end_of_run = pyqtSignal() # happens many times a second + + # Slots PyQt + def update_freq(self, val): # TODO: WE COULD JUST MODIFY THE SDR IN THE GUI THREAD + print("Updated freq to:", val, 'kHz') + if sdr_type == "pluto": + sdr.rx_lo = int(val*1e3) + elif sdr_type == "usrp": + usrp.set_rx_freq(uhd.libpyuhd.types.tune_request(val*1e3), 0) + flush_buffer() + + def update_gain(self, val): + print("Updated gain to:", val, 'dB') + self.gain = val + if sdr_type == "pluto": + sdr.rx_hardwaregain_chan0 = val + elif sdr_type == "usrp": + usrp.set_rx_gain(val, 0) + flush_buffer() + + def update_sample_rate(self, val): + print("Updated sample rate to:", sample_rates[val], 'MHz') + if sdr_type == "pluto": + sdr.sample_rate = int(sample_rates[val] * 1e6) + sdr.rx_rf_bandwidth = int(sample_rates[val] * 1e6 * 0.8) + elif sdr_type == "usrp": + usrp.set_rx_rate(sample_rates[val] * 1e6, 0) + flush_buffer() + + # Boucle principale + def run(self): + start_t = time.time() + + if sdr_type == "pluto": + samples = sdr.rx()/2**11 # Receive samples + elif sdr_type == "usrp": + streamer.recv(recv_buffer, metadata) + samples = recv_buffer[0] # will be np.complex64 + elif sdr_type == "sim": + tone = np.exp(2j*np.pi*self.sample_rate*0.1*np.arange(fft_size)/self.sample_rate) + noise = np.random.randn(fft_size) + 1j*np.random.randn(fft_size) + samples = self.gain*tone*0.02 + 0.1*noise + # Truncate to -1 to +1 to simulate ADC bit limits + np.clip(samples.real, -1, 1, out=samples.real) + np.clip(samples.imag, -1, 1, out=samples.imag) + + self.time_plot_update.emit(samples[0:time_plot_samples]) + + PSD = 10.0*np.log10(np.abs(np.fft.fftshift(np.fft.fft(samples)))**2/fft_size) + self.PSD_avg = self.PSD_avg * 0.99 + PSD * 0.01 + self.freq_plot_update.emit(self.PSD_avg) + + self.spectrogram[:] = np.roll(self.spectrogram, 1, axis=1) # shifts waterfall 1 row + self.spectrogram[:,0] = PSD # fill last row with new fft results + self.waterfall_plot_update.emit(self.spectrogram) + + print("Frames per second:", 1/(time.time() - start_t)) + self.end_of_run.emit() # emit the signal to keep the loop going + + + # Sous-classe QMainWindow pour configurer la fenêtre principale de + la fenêtre application + class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + + self.setWindowTitle("The PySDR Spectrum Analyzer") + self.setFixedSize(QSize(1500, 1000)) # window size, starting size should fit on 1920 x 1080 + + self.spectrogram_min = 0 + self.spectrogram_max = 0 + + layout = QGridLayout() # overall layout + + # Initialisation du worker et du thread + self.sdr_thread = QThread() + self.sdr_thread.setObjectName('SDR_Thread') # so we can see it in htop, note you have to hit F2 -> Display options -> Show custom thread names + worker = SDRWorker() + worker.moveToThread(self.sdr_thread) + + # Affichage temporel + time_plot = pg.PlotWidget(labels={'left': 'Amplitude', 'bottom': 'Time [microseconds]'}) + time_plot.setMouseEnabled(x=False, y=True) + time_plot.setYRange(-1.1, 1.1) + time_plot_curve_i = time_plot.plot([]) + time_plot_curve_q = time_plot.plot([]) + layout.addWidget(time_plot, 1, 0) + + # Boutons de plage automatique du graphique temporel + time_plot_auto_range_layout = QVBoxLayout() + layout.addLayout(time_plot_auto_range_layout, 1, 1) + auto_range_button = QPushButton('Auto Range') + auto_range_button.clicked.connect(lambda : time_plot.autoRange()) # lambda just means its an unnamed function + time_plot_auto_range_layout.addWidget(auto_range_button) + auto_range_button2 = QPushButton('-1 to +1\n(ADC limits)') + auto_range_button2.clicked.connect(lambda : time_plot.setYRange(-1.1, 1.1)) + time_plot_auto_range_layout.addWidget(auto_range_button2) + + # Graohique fréquentiel + freq_plot = pg.PlotWidget(labels={'left': 'PSD', 'bottom': 'Frequency [MHz]'}) + freq_plot.setMouseEnabled(x=False, y=True) + freq_plot_curve = freq_plot.plot([]) + freq_plot.setXRange(center_freq/1e6 - sample_rate/2e6, center_freq/1e6 + sample_rate/2e6) + freq_plot.setYRange(-30, 20) + layout.addWidget(freq_plot, 2, 0) + + # Bouton de sélection automatique de la plage de fréquence + auto_range_button = QPushButton('Auto Range') + auto_range_button.clicked.connect(lambda : freq_plot.autoRange()) # lambda just means its an unnamed function + layout.addWidget(auto_range_button, 2, 1) + + # Conteneur pour les éléments liés au flux vidéo + waterfall_layout = QHBoxLayout() + layout.addLayout(waterfall_layout, 3, 0) + + # Affichage graphique du spectrogramme + waterfall = pg.PlotWidget(labels={'left': 'Time [s]', 'bottom': 'Frequency [MHz]'}) + imageitem = pg.ImageItem(axisOrder='col-major') # this arg is purely for performance + waterfall.addItem(imageitem) + waterfall.setMouseEnabled(x=False, y=False) + waterfall_layout.addWidget(waterfall) + + # Colorbar for waterfall + colorbar = pg.HistogramLUTWidget() + colorbar.setImageItem(imageitem) # connects the bar to the waterfall imageitem + colorbar.item.gradient.loadPreset('viridis') # set the color map, also sets the imageitem + imageitem.setLevels((-30, 20)) # needs to come after colorbar is created for some reason + waterfall_layout.addWidget(colorbar) + + # Waterfall auto range button + auto_range_button = QPushButton('Auto Range\n(-2σ to +2σ)') + def update_colormap(): + imageitem.setLevels((self.spectrogram_min, self.spectrogram_max)) + colorbar.setLevels(self.spectrogram_min, self.spectrogram_max) + auto_range_button.clicked.connect(update_colormap) + layout.addWidget(auto_range_button, 3, 1) + + # Freq slider with label, all units in kHz + freq_slider = QSlider(Qt.Orientation.Horizontal) + freq_slider.setRange(0, int(6e6)) + freq_slider.setValue(int(center_freq/1e3)) + freq_slider.setTickPosition(QSlider.TickPosition.TicksBelow) + freq_slider.setTickInterval(int(1e6)) + freq_slider.sliderMoved.connect(worker.update_freq) # there's also a valueChanged option + freq_label = QLabel() + def update_freq_label(val): + freq_label.setText("Frequency [MHz]: " + str(val/1e3)) + freq_plot.autoRange() + freq_slider.sliderMoved.connect(update_freq_label) + update_freq_label(freq_slider.value()) # initialize the label + layout.addWidget(freq_slider, 4, 0) + layout.addWidget(freq_label, 4, 1) + + # Gain slider with label + gain_slider = QSlider(Qt.Orientation.Horizontal) + gain_slider.setRange(0, 73) + gain_slider.setValue(gain) + gain_slider.setTickPosition(QSlider.TickPosition.TicksBelow) + gain_slider.setTickInterval(2) + gain_slider.sliderMoved.connect(worker.update_gain) + gain_label = QLabel() + def update_gain_label(val): + gain_label.setText("Gain: " + str(val)) + gain_slider.sliderMoved.connect(update_gain_label) + update_gain_label(gain_slider.value()) # initialize the label + layout.addWidget(gain_slider, 5, 0) + layout.addWidget(gain_label, 5, 1) + + # Sample rate dropdown using QComboBox + sample_rate_combobox = QComboBox() + sample_rate_combobox.addItems([str(x) + ' MHz' for x in sample_rates]) + sample_rate_combobox.setCurrentIndex(0) # should match the default at the top + sample_rate_combobox.currentIndexChanged.connect(worker.update_sample_rate) + sample_rate_label = QLabel() + def update_sample_rate_label(val): + sample_rate_label.setText("Sample Rate: " + str(sample_rates[val]) + " MHz") + sample_rate_combobox.currentIndexChanged.connect(update_sample_rate_label) + update_sample_rate_label(sample_rate_combobox.currentIndex()) # initialize the label + layout.addWidget(sample_rate_combobox, 6, 0) + layout.addWidget(sample_rate_label, 6, 1) + + central_widget = QWidget() + central_widget.setLayout(layout) + self.setCentralWidget(central_widget) + + # Signals and slots stuff + def time_plot_callback(samples): + time_plot_curve_i.setData(samples.real) + time_plot_curve_q.setData(samples.imag) + + def freq_plot_callback(PSD_avg): + # TODO figure out if there's a way to just change the visual ticks instead of the actual x vals + f = np.linspace(freq_slider.value()*1e3 - worker.sample_rate/2.0, freq_slider.value()*1e3 + worker.sample_rate/2.0, fft_size) / 1e6 + freq_plot_curve.setData(f, PSD_avg) + freq_plot.setXRange(freq_slider.value()*1e3/1e6 - worker.sample_rate/2e6, freq_slider.value()*1e3/1e6 + worker.sample_rate/2e6) + + def waterfall_plot_callback(spectrogram): + imageitem.setImage(spectrogram, autoLevels=False) + sigma = np.std(spectrogram) + mean = np.mean(spectrogram) + self.spectrogram_min = mean - 2*sigma # save to window state + self.spectrogram_max = mean + 2*sigma + + def end_of_run_callback(): + QTimer.singleShot(0, worker.run) # Run worker again immediately + + worker.time_plot_update.connect(time_plot_callback) # connect the signal to the callback + worker.freq_plot_update.connect(freq_plot_callback) + worker.waterfall_plot_update.connect(waterfall_plot_callback) + worker.end_of_run.connect(end_of_run_callback) + + self.sdr_thread.started.connect(worker.run) # kicks off the worker when the thread starts + self.sdr_thread.start() + + + app = QApplication([]) + window = MainWindow() + window.show() # Windows are hidden by default + signal.signal(signal.SIGINT, signal.SIG_DFL) # this lets control-C actually close the app + app.exec() # Start the event loop + + if sdr_type == "usrp": + stream_cmd = uhd.types.StreamCMD(uhd.types.StreamMode.stop_cont) + streamer.issue_stream_cmd(stream_cmd) diff --git a/content-fr/rtlsdr.rst b/content-fr/rtlsdr.rst new file mode 100644 index 00000000..ef44c2c7 --- /dev/null +++ b/content-fr/rtlsdr.rst @@ -0,0 +1,220 @@ +.. _rtlsdr-chapter: + +#################### +RTL-SDR en Python +#################### + +Le RTL-SDR est de loin le SDR le plus abordable, à environ 40 €, et un excellent choix pour débuter. Bien qu'il ne permette que la réception et que sa bande passante soit limitée à environ 1,75 GHz, il offre de nombreuses applications. Dans ce chapitre, nous apprendrons à configurer le logiciel RTL-SDR et à utiliser son API Python. + +.. image:: ../_images/rtlsdrs.svg + :align: center + :target: ../_images/rtlsdrs.svg + :alt: Exemples de RTL-SDR + +******************************** +Contexte du RTL-SDR +******************************** + +Le RTL-SDR a vu le jour vers 2010, lorsque certains ont découvert qu'il était possible de pirater des dongles DVB-T bon marché équipés de la puce Realtek RTL2832U. Le DVB-T est une norme de télévision numérique principalement utilisée en Europe. L'intérêt du RTL2832U résidait dans l'accès direct aux échantillons IQ bruts, permettant ainsi de concevoir un SDR (récepteur audio numérique) polyvalent. + +La puce RTL2832U intègre le convertisseur analogique-numérique (CAN) et le contrôleur USB, mais elle doit être associée à un tuner RF. Parmi les tuners les plus courants, on trouve les Rafael Micro R820T et R828D, ainsi que l'Elonics E4000. La plage de fréquences réglables dépend du tuner et se situe généralement entre 50 et 1700 MHz. La fréquence d'échantillonnage maximale, quant à elle, est déterminée par le RTL2832U et le bus USB de votre ordinateur. Elle est généralement d'environ 2,4 MHz, sans perte significative d'échantillons. Notez que ces tuners sont extrêmement bon marché et présentent une très faible sensibilité RF. L'ajout d'un amplificateur à faible bruit (LNA) et d'un filtre passe-bande est donc souvent nécessaire pour recevoir des signaux faibles. + +Le RTL2832U utilise toujours des échantillons 8 bits ; l'ordinateur hôte recevra donc deux octets par échantillon IQ. Les RTL-SDR haut de gamme sont généralement équipés d'un oscillateur à température contrôlée (TCXO) en remplacement de l'oscillateur à quartz, moins coûteux, ce qui assure une meilleure stabilité de fréquence. Une autre option est le circuit de polarisation (bias-T), un circuit intégré fournissant environ 4,5 V CC sur le connecteur SMA. Ce circuit permet d'alimenter facilement un LNA externe ou d'autres composants RF. Ce décalage CC supplémentaire se situe côté RF du SDR et n'interfère donc pas avec le fonctionnement de réception. + +Pour ceux qui s'intéressent à la direction d'arrivée (DOA) ou à d'autres applications de formation de faisceaux, le `KrakenSDR `_ est un SDR à cohérence de phase composé de cinq RTL-SDR partageant un oscillateur et une horloge d'échantillonnage. + +******************************* +Installation du logiciel +******************************* + +Ubuntu (ou Ubuntu sous WSL) +############################### + +Sur Ubuntu 20, 22 et autres systèmes basés sur Debian, vous pouvez installer le logiciel RTL-SDR avec la commande suivante. + +.. code-block:: bash + + sudo apt install rtl-sdr + +Cela va installer la bibliothèque librtlsdr , et les outils en lignes de commande suivants :code:`rtl_sdr`, :code:`rtl_tcp`, :code:`rtl_fm`, and :code:`rtl_test`. + +Ensuite, installez le wrapper Python pour librtlsdr en utilisant : + +.. code-block:: bash + + sudo pip install pyrtlsdr + +Si vous utilisez Ubuntu via WSL, téléchargez sous Windows la dernière version de `Zadig `_ et exécutez-la pour installer le pilote « WinUSB » pour le RTL-SDR (il peut y avoir deux interfaces Bulk-In ; dans ce cas, installez « WinUSB » sur les deux). Débranchez puis rebranchez le RTL-SDR une fois l'installation de Zadig terminée. + +Ensuite, vous devrez configurer WSL pour qu'il prenne en charge le périphérique USB du RTL-SDR. Pour cela, installez d'abord la dernière version de l'utilitaire usbipd (`fichier MSI `_) (ce guide suppose que vous disposez de usbipd-win 4.0.0 ou version ultérieure), puis ouvrez PowerShell en mode administrateur et exécutez la commande suivante : + +.. code-block:: bash + + # (unplug RTL-SDR) + usbipd list + # (plug in RTL-SDR) + usbipd list + # (find the new device and substitute its index in the command below) + usbipd bind --busid 1-5 + usbipd attach --wsl --busid 1-5 + +Du côté WSL, vous devriez pouvoir exécuter la commande :code:`lsusb` et voir un nouvel élément nommé RTL2838 DVB-T ou un nom similaire. + +Si vous rencontrez des problèmes d'autorisation (par exemple, le test ci-dessous ne fonctionne qu'avec :code:`sudo`), vous devrez configurer des règles udev. Commencez par exécuter :code:`lsusb` pour trouver l'ID du RTL-SDR, puis créez le fichier :code:`/etc/udev/rules.d/10-rtl-sdr.rules` avec le contenu suivant, en remplaçant :code:`idVendor` et :code:`idProduct` par ceux de votre RTL-SDR si nécessaire : + +.. code-block:: + + SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838", MODE="0666" + +Pour actualiser udev, exécutez : + +.. code-block:: bash + + sudo udevadm control --reload-rules + sudo udevadm trigger + +Si vous utilisez WSL et que le message d'erreur suivant s'affiche :code:`Failed to send reload request: No such file or directory`, cela signifie que le service udev n'est pas en cours d'exécution et que vous devrez exécuter la commande :code:`sudo nano /etc/wsl.conf` et ajouter les lignes suivantes : + +.. code-block:: bash + + [boot] + command="service udev start" + + +Redémarrez ensuite WSL à l'aide de la commande suivante dans PowerShell en tant qu'administrateur : :code:`wsl.exe --shutdown`. + +Il peut également être nécessaire de débrancher puis de rebrancher le RTL-SDR (pour WSL, vous devrez relancer la commande :code:`usbipd attach`). + + +Windows +################### + +For Windows users, see https://www.rtl-sdr.com/rtl-sdr-quick-start-guide/. + +******************************** +Test du RTL-SDR +******************************** + +Si l'installation du logiciel a fonctionné, vous devriez pouvoir exécuter le test suivant, qui réglera le RTL-SDR sur la bande radio FM et enregistrera 1 million d'échantillons dans un fichier nommé :code:`recording.iq` dans :code:`/tmp`. + +.. code-block:: bash + + rtl_sdr /tmp/recording.iq -s 2e6 -f 100e6 -n 1e6 + +Si vous obtenez le message :code:`No supported devices found`, même après avoir ajouté :code:`sudo` au début de la commande, Linux ne détecte pas le RTL-SDR. Si la détection fonctionne avec :code:`sudo`, il s'agit d'un problème de configuration udev. Essayez de redémarrer l'ordinateur après avoir suivi les instructions de configuration udev ci-dessus. Vous pouvez également utiliser :code:`sudo` pour toutes les opérations, y compris l'exécution de Python. + +Vous pouvez tester la capacité de Python à détecter le RTL-SDR à l'aide du script suivant : + +.. code-block:: python + + from rtlsdr import RtlSdr + + sdr = RtlSdr() + sdr.sample_rate = 2.048e6 # Hz + sdr.center_freq = 100e6 # Hz + sdr.freq_correction = 60 # PPM + sdr.gain = 'auto' + + print(len(sdr.read_samples(1024))) + sdr.close() + +qui devrait afficher : + +.. code-block:: bash + + Found Rafael Micro R820T tuner + [R82XX] PLL not locked! + 1024 + +******************************** +Code Python RTL-SDR +******************************** + +Le code ci-dessus constitue un exemple d'utilisation basique du RTL-SDR en Python. Les sections suivantes détaillent les différents paramètres et astuces d'utilisation. + +Prévenir les dysfonctionnements du RTL-SDR +################################################ + +À la fin de notre script, ou une fois l'acquisition des échantillons terminée, nous appellerons :code:`sdr.close()`. Cela permettra d'éviter que le RTL-SDR ne se bloque et nécessite d'être débranché/rebranché. Malgré l'utilisation de :code:`close()`, un blocage peut survenir ; vous le constaterez si le RTL-SDR se bloque pendant l'appel à :code:`read_samples()`. Dans ce cas, vous devrez débrancher et rebrancher le RTL-SDR, et éventuellement redémarrer votre ordinateur. Si vous utilisez WSL, vous devrez reconnecter le RTL-SDR à l'aide de usbipd. + +Réglage du gain +################## + +En définissant :code:`sdr.gain = 'auto'`, vous activez le contrôle automatique du gain (CAG). Le RTL-SDR ajustera alors le gain de réception en fonction des signaux reçus, afin d'optimiser la capacité du convertisseur analogique-numérique (CAN) 8 bits sans le saturer. Dans de nombreuses situations, comme la réalisation d'un analyseur de spectre, il est utile de maintenir le gain à une valeur constante, ce qui implique un réglage manuel. Le gain du RTL-SDR n'est pas réglable en continu ; vous pouvez consulter la liste des valeurs de gain valides avec :code:`print(sdr.valid_gains_db)`. Si vous définissez un gain qui ne figure pas dans cette liste, le système choisira automatiquement la valeur autorisée la plus proche. Vous pouvez vérifier le gain actuel avec :code:`print(sdr.gain)`. Dans l'exemple ci-dessous, le gain est réglé à 49,6 dB et 4 096 échantillons sont reçus, puis représentés dans le domaine temporel : + +.. code-block:: python + + from rtlsdr import RtlSdr + import numpy as np + import matplotlib.pyplot as plt + + sdr = RtlSdr() + sdr.sample_rate = 2.048e6 # Hz + sdr.center_freq = 100e6 # Hz + sdr.freq_correction = 60 # PPM + print(sdr.valid_gains_db) + sdr.gain = 49.6 + print(sdr.gain) + + x = sdr.read_samples(4096) + sdr.close() + + plt.plot(x.real) + plt.plot(x.imag) + plt.legend(["I", "Q"]) + plt.savefig("../_images/rtlsdr-gain.svg", bbox_inches='tight') + plt.show() + +.. image:: ../_images/rtlsdr-gain.svg + :align: center + :target: ../_images/rtlsdr-gain.svg + :alt: RTL-SDR manual gain example + +Il y a quelques points à noter. Les 2 000 premiers échantillons environ semblent avoir une faible puissance de signal, car ils représentent des transitoires. Il est recommandé de les ignorer à chaque exécution de script, par exemple en utilisant :code:`sdr.read_samples(2048)` et en ne traitant pas la sortie. Par ailleurs, pyrtlsdr renvoie les échantillons sous forme de nombres à virgule flottante, compris entre -1 et +1. Bien qu'il utilise un convertisseur analogique-numérique 8 bits et produise des valeurs entières, pyrtlsdr effectue une division par 127.0 pour simplifier les calculs. + + +Fréquences d'échantillonnage autorisées +############################################ + +La plupart des récepteurs RTL-SDR nécessitent une fréquence d'échantillonnage comprise entre 230 et 300 kHz, ou entre 900 et 3,2 MHz. Notez que les fréquences élevées, en particulier supérieures à 2,4 MHz, peuvent ne pas permettre d'obtenir 100 % des échantillons via la connexion USB. Si vous spécifiez une fréquence d'échantillonnage non prise en charge, l'erreur suivante s'affichera : :code:`rtlsdr.rtlsdr.LibUSBError: Error code -22: Could not set sample rate to 899000 Hz`. Lors de la configuration d'une fréquence d'échantillonnage autorisée, le message de la console affichera la fréquence exacte ; cette valeur peut également être obtenue en appelant la fonction :code:`sdr.sample_rate`. Certaines applications peuvent tirer parti d'une valeur plus précise pour leurs calculs. + +À titre d'exercice, nous allons configurer la fréquence d'échantillonnage à 2,4 MHz et créer un spectrogramme de la bande radio FM : + +.. code-block:: python + + # ... + sdr.sample_rate = 2.4e6 # Hz + # ... + + fft_size = 512 + num_rows = 500 + x = sdr.read_samples(2048) # get rid of initial empty samples + x = sdr.read_samples(fft_size*num_rows) # get all the samples we need for the spectrogram + spectrogram = np.zeros((num_rows, fft_size)) + for i in range(num_rows): + spectrogram[i,:] = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(x[i*fft_size:(i+1)*fft_size])))**2) + extent = [(sdr.center_freq + sdr.sample_rate/-2)/1e6, + (sdr.center_freq + sdr.sample_rate/2)/1e6, + len(x)/sdr.sample_rate, 0] + plt.imshow(spectrogram, aspect='auto', extent=extent) + plt.xlabel("Frequency [MHz]") + plt.ylabel("Time [s]") + plt.show() + +.. image:: ../_images/rtlsdr-waterfall.svg + :align: center + :target: ../_images/rtlsdr-waterfall.svg + :alt: RTL-SDR waterfall (aka spectrogram) example + +Réglage PPM +############## + +Pour ceux qui s'intéressent au réglage PPM, sachez que chaque récepteur RTL-SDR présente un léger décalage/erreur de fréquence, dû au faible coût des puces de tuner et à l'absence d'étalonnage. Ce décalage de fréquence est relativement linéaire (et non constant) sur l'ensemble du spectre. On peut donc le corriger en saisissant une valeur PPM (parties par million). Par exemple, si vous syntonisez sur 100 MHz et que vous réglez le PPM sur 25, le signal reçu sera décalé vers le haut de 100 x 10⁶ / (1 x 10⁶ * 25) = 2500 Hz. L'impact de l'erreur de fréquence est plus important pour les signaux plus étroits. Cela dit, de nombreux signaux modernes intègrent une étape de synchronisation de fréquence qui corrige tout décalage de fréquence sur l'émetteur, le récepteur ou dû à l'effet Doppler. + +******************************** +Pour en savoir plus +******************************** + +#. `RTL-SDR.com's About Page `_ +#. https://hackaday.com/2019/07/31/rtl-sdr-seven-years-later/ +#. https://osmocom.org/projects/rtl-sdr/wiki/Rtl-sdr diff --git a/content-fr/sampling.rst b/content-fr/sampling.rst index 6b751832..462dd6d9 100644 --- a/content-fr/sampling.rst +++ b/content-fr/sampling.rst @@ -10,7 +10,7 @@ Dans ce chapitre, nous présentons un concept appelé échantillonnage IQ, ou é Les bases de l'échantillonnage ********************************** -Avant d'aborder l'échantillonnage QI, voyons d'abord ce que signifie l'échantillonnage. Vous avez peut-être déjà rencontré l'échantillonnage sans vous en rendre compte en enregistrant des données audio avec un microphone. Le microphone est un transducteur qui convertit les ondes sonores en un signal électrique (un niveau de tension). Ce signal électrique est transformé par un convertisseur analogique-numérique (CAN), produisant une représentation numérique de l'onde sonore. Pour simplifier, le microphone capte les ondes sonores qui sont converties en électricité, et cette électricité est à son tour convertie en nombres. Le CAN fait le lien entre les domaines analogique et numérique. Les SDR sont étonnamment similaires. Au lieu d'un microphone, ils utilisent une antenne, et utilisent également des ADC. Dans les deux cas, le niveau de tension est échantillonné par un CAN. Pour les SDR, il s'agit d'ondes radio en entrée et de nombres en sortie. +Avant d'aborder l'échantillonnage QI, voyons d'abord ce que signifie l'échantillonnage. Vous avez peut-être déjà rencontré l'échantillonnage sans vous en rendre compte en enregistrant des données audio avec un microphone. Le microphone est un transducteur qui convertit les ondes sonores en un signal électrique (un niveau de tension). Ce signal électrique est transformé par un convertisseur analogique-numérique (CAN), produisant une représentation numérique de l'onde sonore. Pour simplifier, le microphone capte les ondes sonores qui sont converties en électricité, et cette électricité est à son tour convertie en nombres. Le CAN fait le lien entre les domaines analogique et numérique. Les SDR sont étonnamment similaires. Au lieu d'un microphone, ils utilisent une antenne, et utilisent également des CAN. Dans les deux cas, le niveau de tension est échantillonné par un CAN. Pour les SDR, il s'agit d'ondes radio en entrée et de nombres en sortie. Qu'il s'agisse d'audio ou de radiofréquences, nous devons échantillonner si nous voulons capturer, traiter ou enregistrer un signal numériquement. L'échantillonnage peut sembler simple, mais il est très complexe. Une façon plus technique d'envisager l'échantillonnage d'un signal est de saisir des valeurs à des moments précis et de les sauvegarder numériquement. Disons que nous avons une fonction aléatoire, :math:`S(t)`, qui peut représenter n'importe quoi, et que c'est une fonction continue que nous voulons échantillonner : @@ -64,7 +64,7 @@ Nous devons identifier la composante de fréquence la plus élevée, puis la dou :scale: 70% :align: center -Si l'échantillonnage n'est pas assez rapide, nous obtenons ce que l'on appelle le repliement ou l'alaising, dont nous parlerons plus tard, et que nous essayons d'éviter à tout prix. Ce que font nos SDR (et la plupart des récepteurs en général), c'est filtrer tout ce qui est au-dessus de Fs/2 juste avant l'échantillonnage. Si nous essayons de recevoir un signal avec une fréquence d'échantillonnage trop faible, ce filtre coupera une partie du signal. Nos récepteurs SDR se donnent beaucoup de mal pour nous fournir des échantillons exempts de repliement ainsi que d'autres imperfections. +Si l'échantillonnage n'est pas assez rapide, nous obtenons ce que l'on appelle le repliement ou l'aliasing, dont nous parlerons plus tard, et que nous essayons d'éviter à tout prix. Ce que font nos SDR (et la plupart des récepteurs en général), c'est filtrer tout ce qui est au-dessus de Fs/2 juste avant l'échantillonnage. Si nous essayons de recevoir un signal avec une fréquence d'échantillonnage trop faible, ce filtre coupera une partie du signal. Nos récepteurs SDR se donnent beaucoup de mal pour nous fournir des échantillons exempts de repliement ainsi que d'autres imperfections. ******************************* Échantillonnage en quadrature @@ -72,7 +72,7 @@ Si l'échantillonnage n'est pas assez rapide, nous obtenons ce que l'on appelle Le terme "quadrature" a de nombreuses significations, mais dans le contexte du DSP et de la SDR, il désigne deux ondes déphasées de 90 degrés. Pourquoi un déphasage de 90 degrés? Observez que deux ondes qui sont déphasées de 180 degrés sont essentiellement la même onde avec une multipliée par -1. En étant déphasées de 90 degrés, elles deviennent orthogonales, et il y a beaucoup de choses intéressantes à faire avec les fonctions orthogonales. Par souci de simplicité, nous utilisons le sinus et le cosinus comme nos deux ondes sinusoïdales déphasées de 90 degrés. -Ensuite, attribuons des variables pour représenter la **amplitude** du sinus et du cosinus. Nous utiliserons :math:`I` pour le cos() et :math:`Q` pour le sin(): +Ensuite, attribuons des variables pour représenter l' **amplitude** du sinus et du cosinus. Nous utiliserons :math:`I` pour le cos() et :math:`Q` pour le sin(): .. math:: I \cos(2\pi ft) @@ -134,7 +134,7 @@ Cette représentation d'une sinusoïde est connue sous le nom de "diagramme de p En Python, vous pouvez utiliser np.abs(x) et np.angle(x) pour la magnitude et la phase. L'entrée peut être un nombre complexe ou un tableau de nombres complexes, et la sortie sera un ou plusieurs nombres **réels** (du type float). -Vous avez peut-être déjà compris comment ce diagramme vectoriel est lié à la convention IQ: I est réel et Q est imaginaire. À partir de maintenant, lorsque nous dessinerons le plan complexe, nous l'étiquetterons avec I et Q au lieu de réel et imaginaire. Mais il s'agira toujours des mmême nombres complexes! +Vous avez peut-être déjà compris comment ce diagramme vectoriel est lié à la convention IQ: I est réel et Q est imaginaire. À partir de maintenant, lorsque nous dessinerons le plan complexe, nous l'étiquetterons avec I et Q au lieu de réel et imaginaire. Mais il s'agira toujours des même nombres complexes! .. image:: ../_images/complex_plane_3.png :scale: 70% @@ -152,13 +152,13 @@ Nous pouvons utiliser l'identité trigonométrique :math:`a \cos(x) + b \sin(x) .. math:: x(t) = 0.806 \cos(2\pi ft + 0.519) -Même si nous avons commencé avec un nombre complexe, ce que nous transmettons est réel, ce qui est une bonne chose car vous ne pouvez pas réellement transmettre quelque chose d'imaginaire avec des ondes électromagnétiques. Nous utilisons simplement des nombres imaginaires/complexes pour représenter *ce que* nous transmettons. Nous parlerons bientôt de la fonction :math:`f`. +Même si nous avons commencé avec un nombre complexe, ce que nous transmettons est réel, ce qui est une bonne chose car vous ne pouvez pas réellement transmettre quelque chose d'imaginaire avec des ondes électromagnétiques. Nous utilisons simplement des nombres imaginaires/complexes pour représenter *ce que* nous transmettons. Nous parlerons bientôt de :math:`f`. ************************************* Les nombres complexes dans les FFT ************************************* -Les nombres complexes ci-dessus ont été supposés être des échantillons du domaine temporel, mais vous rencontrerez également des nombres complexes lorsque vous effectuerez une FFT. Lorsque nous avons abordé les séries de Fourier et les FFT au chapitre précédent, nous n'avions pas encore plongé dans les nombres complexes. Lorsque vous effectuez la FFT d'une série d'échantillons, vous obtenez la représentation dans le domaine fréquentiel. Nous avons parlé de la façon dont la FFT détermine quelles fréquences existent dans cet ensemble d'échantillons (l'amplitude de la FFT indique la "puissance" de chaque fréquence). Mais la FFT détermine également le retard (décalage temporel) nécessaire à appliquer à chacune de ces fréquences, afin que l'ensemble des sinusoïdes puisse être additionné pour reconstruire le signal dans le domaine temporel. Ce retard est simplement la phase de la FFT. La sortie d'une FFT est un tableau de nombres complexes, et chaque nombre complexe vous donne la magnitude et la phase, et l'indice de ce nombre vous donne la fréquence. Si vous générez des sinusoïdes à ces fréquences/amplitudes/phases et que vous les additionnez, vous obtiendrez votre signal original dans le domaine temporel (ou quelque chose de très proche, et c'est là que le théorème d'échantillonnage de Nyquist entre en jeu). +Les nombres complexes ci-dessus ont été supposés être des échantillons du domaine temporel, mais vous rencontrerez également des nombres complexes lorsque vous effectuerez une FFT. Lorsque nous avons abordé les séries de Fourier et les FFT au chapitre précédent, nous n'avions pas encore plongé dans les nombres complexes. Lorsque vous effectuez la FFT d'une série d'échantillons, vous obtenez la représentation dans le domaine fréquentiel. Nous avons parlé de la façon dont la FFT détermine quelles fréquences existent dans cet ensemble d'échantillons (l'amplitude de la FFT indique la "puissance" de chaque fréquence). Mais la FFT détermine également le retard (décalage temporel) nécessaire à appliquer à chacune de ces fréquences, afin que l'ensemble des sinusoïdes puissent être additionnées pour reconstruire le signal dans le domaine temporel. Ce retard est simplement la phase de la FFT. La sortie d'une FFT est un tableau de nombres complexes, et chaque nombre complexe vous donne la magnitude et la phase, et l'indice de ce nombre vous donne la fréquence. Si vous générez des sinusoïdes à ces fréquences/amplitudes/phases et que vous les additionnez, vous obtiendrez votre signal original dans le domaine temporel (ou quelque chose de très proche, et c'est là que le théorème d'échantillonnage de Nyquist entre en jeu). ************************* Côté récepteur @@ -170,17 +170,17 @@ Prenons maintenant la perspective d'un récepteur radio qui essaie de recevoir u :scale: 70% :align: center -Ce qui entre est un signal réel reçu par notre antenne, et ceux-ci sont transformés en valeurs IQ. Ce que nous faisons, c'est échantillonner les branches I et Q individuellement, en utilisant deux ADC, puis nous combinons les paires et les stockons sous forme de nombres complexes. En d'autres termes, à chaque pas de temps, on échantillonne une valeur I et une valeur Q et on les combine sous la forme :math:`I + jQ` (c'est-à-dire un nombre complexe par échantillon IQ). Il y aura toujours une "fréquence d'échantillonnage", c'est-à-dire la vitesse à laquelle l'échantillonnage est effectué. Quelqu'un pourrait dire : "J'ai une radio logicielle qui fonctionne à une fréquence d'échantillonnage de 2 MHz". Ce qu'il veut dire, c'est que la radio logicielle génère deux millions d'échantillons IQ par seconde. +Ce qui entre est un signal réel reçu par notre antenne, et ceux-ci sont transformés en valeurs IQ. Ce que nous faisons, c'est échantillonner les branches I et Q individuellement, en utilisant deux CAN, puis nous combinons les paires et les stockons sous forme de nombres complexes. En d'autres termes, à chaque pas de temps, on échantillonne une valeur I et une valeur Q et on les combine sous la forme :math:`I + jQ` (c'est-à-dire un nombre complexe par échantillon IQ). Il y aura toujours une "fréquence d'échantillonnage", c'est-à-dire la vitesse à laquelle l'échantillonnage est effectué. Quelqu'un pourrait dire : "J'ai une radio logicielle qui fonctionne à une fréquence d'échantillonnage de 2 MHz". Ce qu'il veut dire, c'est que la radio logicielle génère deux millions d'échantillons IQ par seconde. Si quelqu'un vous donne un fichier d'échantillons QI, cela ressemblera à un tableau/vecteur 1D de nombres complexes. Ce point, complexe ou non, est le but de départ de tout ce chapitre, et nous l'avons finalement atteint. Tout au long de ce manuel, vous deviendrez **très** familier avec le fonctionnement des échantillons IQ, comment les recevoir et les transmettre avec un SDR, comment les traiter dans Python et comment les enregistrer dans un fichier pour une analyse ultérieure. -Une dernière remarque importante: la figure ci-dessus montre ce qui se passe **à l'intérieur** de la SDR. Nous n'avons pas besoin de générer une onde sinusoïdale, de la décaler de 90, de la multiplier ou de l'additionner - la SDR le fait pour nous. Nous indiquons à la SDR la fréquence à laquelle nous voulons échantillonner, ou la fréquence à laquelle nous voulons transmettre nos échantillons. Du côté du récepteur, le SDR nous fournira les échantillons IQ. Du côté de l'émetteur, nous devons fournir au SDR les échantillons IQ. En termes de type de données, il s'agira soit d'entiers complexes, soit de flottants. +Une dernière remarque importante: la figure ci-dessus montre ce qui se passe **à l'intérieur** de la SDR. Nous n'avons pas besoin de générer une onde sinusoïdale, de la décaler de 90, de la multiplier ou de l'additionner - la SDR le fait pour nous. Nous indiquons à la SDR la fréquence à laquelle nous voulons échantillonner, ou la fréquence à laquelle nous voulons transmettre nos échantillons. Du côté du récepteur, la SDR nous fournira les échantillons IQ. Du côté de l'émetteur, nous devons fournir à la SDR les échantillons IQ. En termes de type de données, il s'agira soit d'entiers complexes, soit de flottants. ************************************** -Porteurse et Descente en Fréquence +Porteuse et Descente en Fréquence ************************************** Jusqu'à présent, nous n'avons pas parlé de la fréquence, mais nous avons vu qu'il y avait un :math:`f` dans les équations impliquant le cos() et le sin(). Cette fréquence est la fréquence de l'onde sinusoïdale que nous envoyons réellement dans l'air (la fréquence de l'onde électromagnétique). Nous l'appelons la "porteuse" car elle transporte nos informations sur une certaine fréquence. Lorsque nous nous accordons sur une fréquence avec notre SDR et recevons des échantillons, nos informations sont stockées dans I et Q; cette porteuse n'apparaît pas dans I et Q, en supposant que nous nous sommes réglés sur la porteuse. @@ -195,19 +195,20 @@ Lorsque nous changeons rapidement nos valeurs IQ et que nous transmettons notre Pour prendre un exemple simple, disons que nous transmettons l'échantillon IQ 1+0j, puis que nous passons à la transmission de 0+1j. Nous passons de :math:`\cos(2\pi ft)` à :math:`\sin(2\pi ft)`, ce qui signifie que notre porteuse se déphase de 90 degrés lorsque nous passons d'un échantillon à un autre. -Revenons maintenant à l'échantillonnage pour une seconde. Au lieu de recevoir des échantillons en multipliant ce qui provient de l'antenne par un cos() et un sin() puis en enregistrant I et Q, que se passerait-il si nous envoyions le signal de l'antenne dans un seul CAN, comme dans l'architecture d'échantillonnage direct dont nous venons de parler? Supposons que la fréquence porteuse soit de 2.4 GHz, comme le WiFi ou le Bluetooth. Cela signifie que nous devrions échantillonner à 4.8 GHz, comme nous l'avons appris. C'est extrêmement rapide! Un CAN qui échantillonne aussi rapidement coûte des milliers de dollars. Au lieu de cela, nous "descendant en fréquence" (*downconversion* en anglais) le signal pour que le signal que nous voulons échantillonner soit centré sur le courant continu ou 0 Hz. Cette descente en fréquence a lieu avant l'échantillonnage. Nous passons de: +Revenons maintenant à l'échantillonnage pour une seconde. Au lieu de recevoir des échantillons en multipliant ce qui provient de l'antenne par un cos() et un sin() puis en enregistrant I et Q, que se passerait-il si nous envoyions le signal de l'antenne dans un seul CAN, comme dans l'architecture d'échantillonnage direct dont nous venons de parler? Supposons que la fréquence porteuse soit de 2.4 GHz, comme le WiFi ou le Bluetooth. Cela signifie que nous devrions échantillonner à 4.8 GHz, comme nous l'avons appris. C'est extrêmement rapide! Un CAN qui échantillonne aussi rapidement coûte des milliers de dollars. Au lieu de cela, nous "descendons en fréquence" (*downconversion* en anglais) le signal pour que le signal que nous voulons échantillonner soit centré sur le courant continu ou 0 Hz. Cette descente en fréquence a lieu avant l'échantillonnage. Nous passons de: .. math:: - I \cos(2\pi ft) - - Q \sin(2\pi ft) - + + I \underbrace{\cos(2\pi ft)}_{porteuse} \ + \ \ Q \underbrace{\sin(2\pi ft)}_{porteuse} + à juste I et Q. Visualisons la conversion de fréquence dans le domaine des fréquences: + .. image:: ../_images/downconversion.png :scale: 60% :align: center + :alt: La descente en fréquences où un signal est décalé de RF à 0Hz ou à la fréquence de base Lorsque nous sommes centrés autour de 0 Hz, la fréquence maximale n'est plus de 2,4 GHz mais est basée sur les caractéristiques du signal car nous avons supprimé la porteuse. La plupart des signaux ont une largeur de bande d'environ 100 kHz à 40 MHz, de sorte que, grâce à la conversion de fréquence, nous pouvons échantillonner à un taux *beaucoup* plus faible. Les USRP B2X0 et PlutoSDR contiennent un circuit intégré RF (RFIC) qui peut échantillonner jusqu'à 56 MHz, ce qui est suffisamment élevé pour la plupart des signaux que nous rencontrerons dans la vie de tous les jours. @@ -218,7 +219,7 @@ Enfin, vous êtes peut-être curieux de savoir à quelle vitesse les signaux se .. math:: f = \frac{c}{\lambda} -où :math:`c` est la vitesse de la lumière, généralement fixée à 3e8 lorsque :math:`f` est en Hz et :math:``lambda` en mètre. Dans le domaine des communications sans fil, cette relation devient importante lorsqu'il s'agit d'antennes, car pour recevoir un signal à une certaine fréquence porteuse, :math:`f`, vous avez besoin d'une antenne qui correspond à sa longueur d'onde, :math:`\lambda`, généralement l'antenne a une longueur de :math:`\lambda/2` ou :math:`\lambda/4`. Cependant, quelle que soit la fréquence/longueur d'onde, l'information transportée par ce signal se déplace toujours à la vitesse de la lumière, de l'émetteur au récepteur. Pour calculer ce délai dans l'air, une règle empirique est que la lumière parcourt environ un 30 cm en une nanoseconde. Autre règle empirique : un signal se rendant à un satellite en orbite géostationnaire et en revenant prendra environ 0.25 seconde pour l'ensemble du trajet. +où :math:`c` est la vitesse de la lumière, généralement fixée à 3e8 lorsque :math:`f` est en Hz et :math:`\lambda` en mètre. Dans le domaine des communications sans fil, cette relation devient importante lorsqu'il s'agit d'antennes, car pour recevoir un signal à une certaine fréquence porteuse, :math:`f`, vous avez besoin d'une antenne qui correspond à sa longueur d'onde, :math:`\lambda`, généralement l'antenne a une longueur de :math:`\lambda/2` ou :math:`\lambda/4`. Cependant, quelle que soit la fréquence/longueur d'onde, l'information transportée par ce signal se déplace toujours à la vitesse de la lumière, de l'émetteur au récepteur. Pour calculer ce délai dans l'air, une règle empirique est que la lumière parcourt environ 30 cm en une nanoseconde. Autre règle empirique : un signal se rendant à un satellite en orbite géostationnaire et en revenant prendra environ 0.25 seconde pour l'ensemble du trajet. ***************************** Architectures des récepteurs @@ -246,10 +247,10 @@ Nous avons tendance à créer, enregistrer ou analyser des signaux en bande de b Dans la section précédente où nous avons joué avec le point complexe 0.7-0.4j, il s'agissait essentiellement d'un échantillon dans un signal en bande de base. La plupart du temps, lorsque vous voyez des échantillons complexes (échantillons IQ), vous êtes en bande de base. Les signaux sont rarement représentés ou stockés numériquement en RF, en raison de la quantité de données que cela prendrait, et du fait que nous ne sommes généralement intéressés que par une petite partie du spectre RF. *************************** -Le Pic DC et le décalage DC +Le Pic DC et le Décalage DC *************************** -Lorsque vous commencez à travailler avec les SDR, vous trouvez souvent un pic important au centre de la FFT. On l'appelle "offset DC" ou "pic DC" ou parfois "fuite LO", où LO signifie *Local oscilator* pour *oscillateur local* en français. +Lorsque vous commencez à travailler avec les SDR, vous trouvez souvent un pic important au centre de la FFT. On l'appelle "offset DC" ou "pic DC" ou parfois "fuite LO", où LO signifie *Local oscillator* pour *oscillateur local* en français. Voici un exemple d'un pic de courant continu: @@ -257,7 +258,7 @@ Voici un exemple d'un pic de courant continu: :scale: 50% :align: center -Because the SDR tunes to a center frequency, the 0 Hz portion of the FFT corresponds to the center frequency. Ceci étant dit, un pic de courant continu ne signifie pas nécessairement qu'il y a de l'énergie à la fréquence centrale. S'il n'y a qu'un pic de courant continu et que le reste de la FFT ressemble à du bruit, il est fort probable qu'il n'y a pas de signal présent à l'endroit où elle vous le montre. +Parceque la SDR s'accorde sur une fréquence centrale, la composante à 0hz de la FFT correspond à la fréquence centrale. Ceci étant dit, un pic de courant continu ne signifie pas nécessairement qu'il y a de l'énergie à la fréquence centrale. S'il n'y a qu'un pic de courant continu et que le reste de la FFT ressemble à du bruit, il est fort probable qu'il n'y a pas de signal présent à l'endroit où elle vous le montre. Un décalage DC est un artefact commun dans les récepteurs à conversion directe, qui est l'architecture utilisée pour les SDRs comme le PlutoSDR, RTL-SDR, LimeSDR, et de nombreux USRPs Ettus. Dans les récepteurs à conversion directe, un oscillateur local convertit le signal de sa fréquence réelle en bande de base. Par conséquent, les fuites de cet oscillateur apparaissent au centre de la bande passante observée. La fuite du LO est une énergie supplémentaire créée à cause de la combinaison des fréquences. L'élimination de ce bruit supplémentaire est difficile car il est proche du signal de sortie souhaité. De nombreux circuits intégrés RF (RFIC) intègrent une fonction automatique d'élimination du décalage continu, mais elle nécessite généralement la présence d'un signal pour fonctionner. C'est pourquoi le pic de courant continu est très apparent lorsqu'aucun signal n'est présent. diff --git a/content-fr/usrp.rst b/content-fr/usrp.rst index f43d3539..7804ff44 100644 --- a/content-fr/usrp.rst +++ b/content-fr/usrp.rst @@ -165,7 +165,7 @@ Pour spécifier le gain, vous pouvez utiliser la fonction normale set_rx_gain() Contrôle automatique du gain ###################################### -Certains USRP, y compris les séries B200 et E310, prennent en charge la commande automatique de gain (AGC pour *automatic gain controller* en anglais) qui ajuste automatiquement le gain de réception en fonction du niveau du signal reçu, afin d'essayer de "remplir" au mieux les bits de l'ADC. L'AGC peut être activé en utilisant : +Certains USRP, y compris les séries B200 et E310, prennent en charge la commande automatique de gain (AGC pour *automatic gain controller* en anglais) qui ajuste automatiquement le gain de réception en fonction du niveau du signal reçu, afin d'essayer de "remplir" au mieux les bits du CAN. L'AGC peut être activé en utilisant : .. code-block:: python @@ -194,7 +194,7 @@ Dans l'exemple complet ci-dessus, vous verrez la ligne :code:`st_args = uhd.usrp Vous pouvez voir d'autres options dans la documentation de l'API UHD C++, mais elles n'ont jamais été implémentées dans l'API Python, du moins au moment de la rédaction de ce document. -Le deuxième argument est le format de données "over-the-wire", c'est-à-dire le type de données lorsque les échantillons sont envoyés à l'hôte via USB/Ethernet/SFP. Pour l'API Python, les options sont : "sc16", "sc12" et "sc8", l'option 12 bits n'étant prise en charge que par certains USRP. Ce choix est important car la connexion entre l'USRP et l'ordinateur hôte est souvent le goulot d'étranglement, donc en passant de 16 bits à 8 bits, vous pouvez obtenir un taux plus élevé. Rappelez-vous également que de nombreux USRP ont des ADC limités à 12 ou 14 bits, utiliser "sc16" ne signifie pas que l'ADC est de 16 bits. +Le deuxième argument est le format de données "over-the-wire", c'est-à-dire le type de données lorsque les échantillons sont envoyés à l'hôte via USB/Ethernet/SFP. Pour l'API Python, les options sont : "sc16", "sc12" et "sc8", l'option 12 bits n'étant prise en charge que par certains USRP. Ce choix est important car la connexion entre l'USRP et l'ordinateur hôte est souvent le goulot d'étranglement, donc en passant de 16 bits à 8 bits, vous pouvez obtenir un taux plus élevé. Rappelez-vous également que de nombreux USRP ont des CAN limités à 12 ou 14 bits, utiliser "sc16" ne signifie pas que le CAN est de 16 bits. Pour la partie canal du :code:`st_args`, voir la sous-section Sous-dispositif and Channels ci-dessous. diff --git a/content-nl/2d_beamforming.rst b/content-nl/2d_beamforming.rst new file mode 100644 index 00000000..f49560ab --- /dev/null +++ b/content-nl/2d_beamforming.rst @@ -0,0 +1,565 @@ +.. _2d-beamforming-chapter: + +################# +2D-bundelvorming +################# + +Dit hoofdstuk breidt het 1D-hoofdstuk over bundelvorming/DOA uit naar 2D-arrays. We starten met een eenvoudige rechthoekige array en leiden de stuurvectorvergelijking en MVDR-bundelvormer af, daarna werken we met echte data van een 3x5-array. Tot slot gebruiken we de interactieve tool om de effecten van verschillende arraygeometrieen en elementafstand te verkennen. + +**************************************** +Rechthoekige Arrays en 2D-bundelvorming +**************************************** + +Rechthoekige arrays (ook wel planaire arrays) bestaan uit een 2D-array van elementen. Met een extra dimensie komt wat extra complexiteit, maar dezelfde basisprincipes blijven gelden, en het lastigste deel is het visualiseren van de resultaten (geen eenvoudige polaire grafieken meer, maar 3D-oppervlakteplots). Ook al is onze array nu 2D, dat betekent niet dat we aan elke datastructuur een extra dimensie moeten toevoegen. Zo houden we de gewichten gewoon als een 1D-array van complexe getallen. Wel moeten we de posities van onze elementen in 2D representeren. We blijven :code:`theta` gebruiken voor de azimuthoek, maar introduceren nu ook :code:`phi`, de elevatiehoek. Er bestaan meerdere conventies voor bolcoordinaten, maar wij gebruiken de volgende: + +.. image:: ../_images/Spherical_Coordinates.svg + :align: center + :target: ../_images/Spherical_Coordinates.svg + :alt: Bolcoordinatenstelsel met theta en phi + +Dat komt overeen met: + +.. math:: + + x = \sin(\theta) \cos(\phi) + + y = \cos(\theta) \cos(\phi) + + z = \sin(\phi) + +We stappen ook over op een gegeneraliseerde stuurvectorvergelijking, die niet aan een specifieke arraygeometrie is gebonden: + +.. math:: + + s = e^{2j \pi \boldsymbol{p} u / \lambda} + +waarbij :math:`\boldsymbol{p}` de verzameling x/y/z-posities van de elementen in meter is (grootte :code:`Nr` x 3) en :math:`u` de richting is waar we naartoe willen wijzen als een eenheidsvector in x/y/z (grootte 3x1). In Python ziet dat er zo uit: + +.. code-block:: python + + def steering_vector(pos, dir): + # Nrx3 3x1 + return np.exp(2j * np.pi * pos @ dir / wavelength) # outputs Nr x 1 (column vector) + +Laten we deze gegeneraliseerde stuurvectorvergelijking toepassen op een eenvoudige ULA met 4 elementen, zodat de koppeling met eerdere stof duidelijk blijft. We drukken :code:`d` nu uit in meters in plaats van relatief ten opzichte van de golflengte. We plaatsen de elementen langs de y-as: + +.. code-block:: python + + Nr = 4 + fc = 5e9 + wavelength = 3e8 / fc + d = 0.5 * wavelength # in meters + + # We will store our element positions in a list of (x,y,z)'s, even though it's just a ULA along the y-axis + pos = np.zeros((Nr, 3)) # Element positions, as a list of x,y,z coordinates in meters + for i in range(Nr): + pos[i,0] = 0 # x position + pos[i,1] = d * i # y position + pos[i,2] = 0 # z position + +De onderstaande afbeelding toont een bovenaanzicht van de ULA, met als voorbeeld een theta van 20 graden. + +.. image:: ../_images/2d_beamforming_ula.svg + :align: center + :target: ../_images/2d_beamforming_ula.svg + :alt: ULA met theta van 20 graden + +Het enige dat nog rest is het koppelen van onze oude :code:`theta` aan deze nieuwe aanpak met eenheidsvectoren. We kunnen :code:`dir` eenvoudig uit :code:`theta` berekenen: de x- en z-component van de eenheidsvector zijn 0 omdat we nog in 1D werken, en volgens onze bolcoordinatenconventie is de y-component :code:`np.cos(theta)`, dus de volledige code is :code:`dir = np.asmatrix([0, np.cos(theta_i), 0]).T`. Op dit punt kun je de gegeneraliseerde stuurvectorvergelijking koppelen aan de ULA-stuurvectorvergelijking die we al gebruikten. Probeer deze nieuwe code uit, kies een :code:`theta` tussen 0 en 360 graden (vergeet niet om naar radialen om te rekenen!), en de stuurvector moet een 4x1-array zijn. + +Laten we nu naar het 2D-geval gaan. We plaatsen onze array in het X-Z-vlak, met kijkrichting horizontaal gericht naar de positieve y-as (:math:`\theta = 0`, :math:`\phi = 0`). We gebruiken dezelfde elementafstand als eerder, maar nu hebben we in totaal 16 elementen: + +.. code-block:: python + + # Now let's switch to 2D, using a 4x4 array with half wavelength spacing, so 16 elements total + Nr = 16 + + # Element positions, still as a list of x,y,z coordinates in meters, we'll place the array in the X-Z plane + pos = np.zeros((Nr,3)) + for i in range(Nr): + pos[i,0] = d * (i % 4) # x position + pos[i,1] = 0 # y position + pos[i,2] = d * (i // 4) # z position + +Bovenaanzicht van onze rechthoekige 4x4-array: + +.. image:: ../_images/2d_beamforming_element_pos.svg + :align: center + :target: ../_images/2d_beamforming_element_pos.svg + :alt: Elementposities van rechthoekige array + +Om naar een bepaalde theta en phi te wijzen, moeten we die hoeken omzetten naar een eenheidsvector. We gebruiken dezelfde gegeneraliseerde stuurvectorvergelijking als eerder, maar nu berekenen we de eenheidsvector op basis van zowel theta als phi, met de vergelijkingen uit het begin van dit hoofdstuk: + +.. code-block:: python + + # Let's point towards an arbitrary direction + theta = np.deg2rad(60) # azimith angle + phi = np.deg2rad(30) # elevation angle + + # Using our spherical coordinate convention, we can calculate the unit vector: + def get_unit_vector(theta, phi): # angles are in radians + return np.asmatrix([np.sin(theta) * np.cos(phi), # x component + np.cos(theta) * np.cos(phi), # y component + np.sin(phi)]).T # z component + + dir = get_unit_vector(theta, phi) + # dir is a 3x1 + # [[0.75 ] + # [0.4330127] + # [0.5 ]] + +Laten we nu onze gegeneraliseerde stuurvectorfunctie gebruiken om de stuurvector te berekenen: + +.. code-block:: python + + s = steering_vector(pos, dir) + + # Use the conventional beamformer, which is simply the weights equal to the steering vector, plot the beam pattern + w = s # 16x1 vector of weights + +Het is belangrijk om op te merken dat we bij de stap van 1D naar 2D de dimensies van de datastructuren niet echt hebben aangepast: we hebben nu alleen niet-nul x/y/z-componenten. De stuurvectorvergelijking blijft hetzelfde en de gewichten blijven een 1D-array. Het kan verleidelijk zijn om gewichten als 2D-array op te slaan zodat dit visueel bij de arraygeometrie past, maar dat is niet nodig en 1D is doorgaans beter. Voor elk element bestaat er een corresponderend gewicht, en de volgorde van de gewichten is dezelfde als die van de elementposities. + +Het bundelpatroon dat bij deze gewichten hoort visualiseren is wat complexer, omdat we een 3D-plot of een 2D-heatmap nodig hebben. We scannen :code:`theta` en :code:`phi` om een 2D-array met vermogensniveaus te krijgen, en plotten die vervolgens met :code:`imshow()`. De code hieronder doet precies dat, en het resultaat staat in de figuur eronder, inclusief een punt op de eerder gekozen hoek: + +.. code-block:: python + + resolution = 100 # number of points in each direction + theta_scan = np.linspace(-np.pi/2, np.pi/2, resolution) # azimuth angles + phi_scan = np.linspace(-np.pi/4, np.pi/4, resolution) # elevation angles + results = np.zeros((resolution, resolution)) # 2D array to store results + for i, theta_i in enumerate(theta_scan): + for j, phi_i in enumerate(phi_scan): + a = steering_vector(pos, get_unit_vector(theta_i, phi_i)) # array factor + results[i, j] = np.abs(w.conj().T @ a)[0,0] # power in signal, looks better as linear + plt.imshow(results.T, extent=(theta_scan[0]*180/np.pi, theta_scan[-1]*180/np.pi, phi_scan[0]*180/np.pi, phi_scan[-1]*180/np.pi), origin='lower', aspect='auto', cmap='viridis') + plt.colorbar(label='Power [linear]') + plt.scatter(theta*180/np.pi, phi*180/np.pi, color='red', s=50) # Add a dot at the correct theta/phi + plt.xlabel('Azimuth angle [degrees]') + plt.ylabel('Elevation angle [degrees]') + plt.show() + +.. image:: ../_images/2d_beamforming_2dplot.svg + :align: center + :target: ../_images/2d_beamforming_2dplot.svg + :alt: 3D-plot van het bundelpatroon + +Laten we nu echte samples simuleren; we voegen twee toon-stoorzenders toe die uit verschillende richtingen aankomen: + +.. code-block:: python + + N = 10000 # number of samples to simulate + + jammer1_theta = np.deg2rad(-30) + jammer1_phi = np.deg2rad(10) + jammer1_dir = get_unit_vector(jammer1_theta, jammer1_phi) + jammer1_s = steering_vector(pos, jammer1_dir) # Nr x 1 + jammer1_tone = np.exp(2j*np.pi*0.1*np.arange(N)).reshape(1,-1) # make a row vector + + jammer2_theta = np.deg2rad(10) + jammer2_phi = np.deg2rad(50) + jammer2_dir = get_unit_vector(jammer2_theta, jammer2_phi) + jammer2_s = steering_vector(pos, jammer2_dir) + jammer2_tone = np.exp(2j*np.pi*0.2*np.arange(N)).reshape(1,-1) # make a row vector + + noise = np.random.normal(0, 1, (Nr, N)) + 1j * np.random.normal(0, 1, (Nr, N)) # complex Gaussian noise + r = jammer1_s @ jammer1_tone + jammer2_s @ jammer2_tone + noise # produces 16 x 10000 matrix of samples + +Voor de volledigheid berekenen we nu de MVDR-bundelvormergewichten richting de theta en phi die we eerder gebruikten (een eenheidsvector in die richting staat nog steeds in :code:`dir`): + +.. code-block:: python + + s = steering_vector(pos, dir) # 16 x 1 + R = np.cov(r) # Covariance matrix, 16 x 16 + Rinv = np.linalg.pinv(R) + w = (Rinv @ s)/(s.conj().T @ Rinv @ s) # MVDR/Capon equation + +In plaats van naar een matige 3D-plot van het bundelpatroon te kijken, gebruiken we een alternatieve methode om te controleren of deze gewichten logisch zijn: we evalueren de respons van de gewichten voor verschillende richtingen en berekenen het vermogen in dB. We beginnen met de richting waarnaar we wijzen: + +.. code-block:: python + + # Power in the direction we are pointing (theta=60, phi=30, which is still saved as dir): + a = steering_vector(pos, dir) # array factor + resp = w.conj().T @ a # scalar + print("Power in direction we are pointing:", 10*np.log10(np.abs(resp)[0,0]), 'dB') + +Dit geeft 0 dB, wat we verwachten omdat het doel van MVDR is om eenheidsvermogen in de gewenste richting te realiseren. Laten we nu ook het vermogen controleren in de richtingen van de twee jammers, plus een willekeurige richting en een richting die een graad afwijkt van de gewenste richting (dezelfde code, alleen :code:`dir` wijzigen). De resultaten staan in de tabel hieronder: + +.. list-table:: + :widths: 70 30 + :header-rows: 1 + + * - Direction Pointed + - Gain + * - :code:`dir` (direction used to find MVDR weights) + - 0 dB + * - Jammer 1 + - -17.488 dB + * - Jammer 2 + - -18.551 dB + * - 1 degree off from :code:`dir` in both :math:`\theta` and :math:`\phi` + - -0.00683 dB + * - Een willekeurige richting + - -10.591 dB + +Je resultaten kunnen verschillen door de willekeurige ruis die wordt gebruikt om de ontvangen samples te berekenen, waarmee vervolgens :code:`R` wordt bepaald. De hoofdboodschap is echter dat de jammers in een null terechtkomen met zeer laag vermogen, de richting die 1 graad afwijkt van :code:`dir` net onder 0 dB zit maar nog in de hoofdlob, en dat een willekeurige richting meestal lager is dan 0 dB maar hoger dan de jammers, en sterk kan variëren per simulatie-run. Let op dat MVDR een versterking van 0 dB in de hoofdlob geeft; bij de conventionele bundelvormer krijg je :math:`10 \log_{10}(Nr)`, dus ongeveer 12 dB voor onze 16-element-array. Dat laat een van de afwegingen van MVDR zien. + +De code voor dit onderdeel staat `hier `_. + +********************************************** +Signalen Verwerken van een Echte 2D-array +********************************************** + +In dit onderdeel werken we met echte data die is opgenomen met een 3x5-array gebouwd op een `QUAD-MxFE `_-platform van Analog Devices, dat tot 16 zend- en ontvangstkanalen ondersteunt (wij gebruikten er 15, alleen in ontvangstmodus). Er zijn twee opnames beschikbaar: de eerste bevat een enkele zender op kijkrichting van de array, die we voor calibratie gebruiken. De tweede opname bevat twee zenders uit verschillende richtingen, die we voor bundelvorming en DOA-testen gebruiken. + +- `IQ-opname van alleen C `_ (gebruikt voor calibratie, omdat C op kijkrichting staat) +- `IQ-opname van B en D `_ (gebruikt voor bundelvorming/DOA-testen) + +De QUAD-MxFE was afgestemd op 2,8 GHz en alle zenders gebruikten een eenvoudige toon binnen de observatiebandbreedte. Interessant aan deze DSP is dat de sample rate hier niet doorslaggevend is: geen van de arrayverwerkingstechnieken die we gebruiken hangt ervan af, zolang het signaal maar ergens in de basisband zit. De DSP hangt wel af van de centerfrequentie, omdat de faseverschuiving tussen elementen afhangt van frequentie en aankomstrichting. Dat is het omgekeerde van veel andere signaalverwerking, waar sample rate cruciaal is en centerfrequentie meestal niet. + +We kunnen deze opnames in Python laden met de volgende code: + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + + r = np.load("DandB_capture1.npy")[0:15] # 16th element is not connected but was still recorded + r_cal = np.load("C_only_capture1.npy")[0:15] # only the calibration signal (at kijkrichting) on + +De afstand tussen de antennes was 0,051 meter. We representeren de elementposities als een lijst met x,y,z-coordinaten in meter. We plaatsen de array in het X-Z-vlak, omdat de array verticaal gemonteerd was (met kijkrichting horizontaal gericht). + +.. code-block:: python + + fc = 2.8e9 # center frequency in Hz + d = 0.051 # spacing between antennas in meters + wavelength = 3e8 / fc + Nr = 15 + rows = 3 + cols = 5 + + # Element positions, as a list of x,y,z coordinates in meters + pos = np.zeros((Nr, 3)) + for i in range(Nr): + pos[i,0] = d * (i % cols) # x position + pos[i,1] = 0 # y position + pos[i,2] = d * (i // cols) # z position + + # Plot and label positions of elements + fig = plt.figure() + ax = fig.add_subplot(projection='3d') + ax.scatter(pos[:,0], pos[:,1], pos[:,2], 'o') + # Label indices + for i in range(Nr): + ax.text(pos[i,0], pos[i,1], pos[i,2], str(i), fontsize=10) + plt.xlabel("X Position [m]") + plt.ylabel("Y Position [m]") + ax.set_zlabel("Z Position [m]") + plt.grid() + plt.show() + +De plot labelt elk element met zijn index, overeenkomend met de volgorde van de elementen in de opgenomen :code:`r`- en :code:`r_cal`-IQ-samples. + +.. image:: ../_images/2d_array_element_positions.svg + :align: center + :target: ../_images/2d_array_element_positions.svg + :alt: Elementposities van 2D-array + +Calibratie gebeurt met alleen de :code:`r_cal`-samples, die zijn opgenomen terwijl enkel de zender op kijkrichting actief was. Het doel is om voor elk element de fase- en amplitude-offset te vinden. Bij perfecte calibratie, en als de zender exact op kijkrichting staat, zouden alle afzonderlijke ontvangstkanalen hetzelfde signaal moeten ontvangen: onderling in fase en met gelijke amplitude. Door onvolkomenheden in array/kabels/antennes heeft elk element echter een andere fase- en amplitude-offset. In het calibratieproces bepalen we deze offsets, die we later op de :code:`r`-samples toepassen voordat we arrayverwerking uitvoeren. + +Er zijn veel manieren om te calibreren, maar wij gebruiken een methode op basis van eigenwaardedecompositie van de covariantiematrix. De covariantiematrix is een vierkante matrix met grootte :code:`Nr x Nr`, waarbij :code:`Nr` het aantal ontvangstkanalen is. De eigenvector die hoort bij de grootste eigenwaarde representeert idealiter het ontvangen signaal; die gebruiken we om fase-offsets te bepalen door van elk element in de eigenvector de fase te nemen en te normaliseren op het eerste element, dat als referentie dient. De amplitudecalibratie gebruikt de eigenvector niet, maar de gemiddelde amplitude van het ontvangen signaal per element. + +.. code-block:: python + + # Calc covariance matrix, it's Nr x Nr + R_cal = r_cal @ r_cal.conj().T + + # eigenvalue decomposition, v[:,i] is the eigenvector corresponding to the eigenvalue w[i] + w, v = np.linalg.eig(R_cal) + + # Plot eigenvalues to make sure we have just one large one + w_dB = 10*np.log10(np.abs(w)) + w_dB -= np.max(w_dB) # normalize + fig, (ax1) = plt.subplots(1, 1, figsize=(7, 3)) + ax1.plot(w_dB, '.-') + ax1.set_xlabel('Index') + ax1.set_ylabel('Eigenvalue [dB]') + plt.show() + + # Use max eigenvector to calibrate + v_max = v[:, np.argmax(np.abs(w))] + mags = np.mean(np.abs(r_cal), axis=1) + mags = mags[0] / mags # normalize to first element + phases = np.angle(v_max) + phases = phases[0] - phases # normalize to first element + cal_table = mags * np.exp(1j * phases) + print("cal_table", cal_table) + +Hieronder staat de plot van de eigenwaardeverdeling. We willen zien dat er slechts een grote waarde is en de rest klein, wat overeenkomt met een enkel ontvangen signaal. Eventuele interferers of multipad verslechteren het calibratieproces. + +.. image:: ../_images/2d_array_eigenvalues.svg + :align: center + :target: ../_images/2d_array_eigenvalues.svg + :alt: Eigenwaardeverdeling van 2D-array + +De calibratietabel is een lijst met complexe getallen, een per element, die de fase- en amplitude-offsets representeren (rechthoekige notatie is hier praktischer dan polaire notatie). Het eerste element is het referentie-element en is altijd 1.0 + 0.j. De overige elementen zijn de offsets per element in dezelfde volgorde als in :code:`pos`. + +.. code-block:: python + + [1. +0.j 0.99526771+0.76149029j -0.91754588-0.66825262j + -0.96840297+0.37251012j 0.87866849+0.40446665j 0.56040169+1.50499875j + -0.80109196-1.29299264j -1.28464742-0.31133052j 1.26622038+0.46047599j + 2.01855809+9.77121302j -0.29249322-1.09413205j -1.0372309 -0.17983522j + -0.70614339+0.78682873j -0.75612972+5.67234809j 1.00032754-0.60824109j] + + +We kunnen deze offsets op elke sample-set van de array toepassen door elk samplekanaal te vermenigvuldigen met het corresponderende element uit de calibratietabel: + +.. code-block:: python + + # Apply cal offsets to r + for i in range(Nr): + r[i, :] *= cal_table[i] + +Terzijde: daarom berekenden we de offsets met :code:`mags[0] / mags` en :code:`phases[0] - phases`. Met de omgekeerde volgorde zouden we bij toepassing moeten delen in plaats van vermenigvuldigen, en vermenigvuldigen is hier handiger. + +Vervolgens voeren we DOA-schatting uit met het MUSIC-algoritme. We gebruiken de functies :code:`steering_vector()` en :code:`get_unit_vector()` die we eerder definieerden om voor elk array-element de stuurvector te berekenen, en gebruiken daarna MUSIC om de DOA van de twee zenders in de :code:`r`-samples te schatten. Het MUSIC-algoritme is in het vorige hoofdstuk behandeld. + +.. code-block:: python + + # DOA using MUSIC + resolution = 400 # number of points in each direction + theta_scan = np.linspace(-np.pi/2, np.pi/2, resolution) # azimuth angles + phi_scan = np.linspace(-np.pi/4, np.pi/4, resolution) # elevation angles + results = np.zeros((resolution, resolution)) # 2D array to store results + R = np.cov(r) # Covariance matrix, 15 x 15 + Rinv = np.linalg.pinv(R) + expected_num_signals = 4 + w, v = np.linalg.eig(R) # eigenvalue decomposition, v[:,i] is the eigenvector corresponding to the eigenvalue w[i] + eig_val_order = np.argsort(np.abs(w)) + v = v[:, eig_val_order] # sort eigenvectors using this order + V = np.zeros((Nr, Nr - expected_num_signals), dtype=np.complex64) # Noise subspace is the rest of the eigenvalues + for i in range(Nr - expected_num_signals): + V[:, i] = v[:, i] + for i, theta_i in enumerate(theta_scan): + for j, phi_i in enumerate(phi_scan): + dir_i = get_unit_vector(-1*theta_i, phi_i) # TODO figure out why -1* was needed to match reality + s = steering_vector(pos, dir_i) # 15 x 1 + music_metric = 1 / (s.conj().T @ V @ V.conj().T @ s) + music_metric = np.abs(music_metric).squeeze() + music_metric = np.clip(music_metric, 0, 2) # Useful for ABCD one + results[i, j] = music_metric + +Onze resultaten zijn 2D, omdat de array 2D is, dus we moeten een 3D-plot of een 2D-heatmap gebruiken. We doen beide. Eerst een 3D-plot met elevatie op de ene as en azimuth op de andere: + +.. code-block:: python + + # 3D az-el DOA results + results = 10*np.log10(results) # convert to dB + results[results < -20] = -20 # crop the z axis to some level of dB + fig, ax = plt.subplots(subplot_kw={"projection": "3d", "computed_zorder": False}) + surf = ax.plot_surface(np.rad2deg(theta_scan[:,None]), # type: ignore + np.rad2deg(phi_scan[None,:]), + results, + cmap='viridis') + #ax.set_zlim(-10, results[max_idx]) + ax.set_xlabel('Azimuth (theta)') + ax.set_ylabel('Elevation (phi)') + ax.set_zlabel('Power [dB]') # type: ignore + fig.savefig('../_images/2d_array_3d_doa_plot.svg', bbox_inches='tight') + plt.show() + +.. image:: ../_images/2d_array_3d_doa_plot.png + :align: center + :scale: 30% + :target: ../_images/2d_array_3d_doa_plot.png + :alt: 3D-DOA-plot + +Afhankelijk van de situatie kan het lastig zijn om waarden uit een 3D-plot af te lezen, dus we kunnen ook een 2D-heatmap met :code:`imshow()` maken: + +.. code-block:: python + + # 2D, az-el heatmap (same as above, but 2D) + extent=(np.min(theta_scan)*180/np.pi, + np.max(theta_scan)*180/np.pi, + np.min(phi_scan)*180/np.pi, + np.max(phi_scan)*180/np.pi) + plt.imshow(results.T, extent=extent, origin='lower', aspect='auto', cmap='viridis') # type: ignore + plt.colorbar(label='Power [linear]') + plt.xlabel('Theta (azimuth, degrees)') + plt.ylabel('Phi (elevation, degrees)') + plt.savefig('../_images/2d_array_2d_doa_plot.svg', bbox_inches='tight') + plt.show() + +.. image:: ../_images/2d_array_2d_doa_plot.svg + :align: center + :target: ../_images/2d_array_2d_doa_plot.svg + :alt: 2D-DOA-plot + +Met deze 2D-plot kunnen we de geschatte azimuth en elevatie van de twee zenders eenvoudig aflezen (en zien dat het er inderdaad twee zijn). Op basis van de testopstelling die voor deze opname is gebruikt, komen deze resultaten overeen met de werkelijkheid. De *exacte* azimuth en elevatie zijn nooit gemeten, omdat daarvoor zeer specialistische apparatuur nodig is. + +Als oefening kun je zowel de conventionele bundelvormer als MVDR proberen en de resultaten vergelijken met MUSIC. + +De volledige code van dit onderdeel staat `hier `_. + +************************ +Interactieve Ontwerptool +************************ + +De onderstaande interactieve tool is gemaakt door `Jason Durbin `_, een freelance phased-array-engineer, die toestemming gaf om de tool in PySDR op te nemen. Bekijk gerust het `volledige project `_ of zijn `adviesbureau `_. Met deze tool kun je de geometrie van een phased array aanpassen, elementafstanden wijzigen, de stuurpositie veranderen, sidelobe-tapering toevoegen en meer. + +Enkele details over deze tool: antenne-elementen worden als isotroop aangenomen. De directiviteitsberekening gaat echter uit van straling over een halve hemisfeer (dus zonder achterlobben). Daardoor is de berekende directiviteit 3 dBi hoger dan bij volledig isotroop (de individuele elementgain is dus +3,0 dBi). De mesh kan fijner worden gemaakt door theta/phi-, u/v- of azimuth/elevatiepunten te verhogen. Door in de fase-/attenuatieplots op elementen te klikken (of lang te drukken) kun je fase/attenuatie handmatig instellen (let op: kies dan "enable override"). In de attenuatie-popup kun je elementen ook uitschakelen. Door met de muis over de 2D far-field- of geometrieplots te bewegen (of aan te raken) zie je de plotwaarde onder de cursor. + +.. raw:: html + + + +
    +
    +
    +

    Geometry

    +
    +
    +

    Steering

    + +
    + + +
    +
    + + +
    +
    +
    +

    Taper(s)

    +
    + + +
    +
    +
    +
    +
    +

    Quantization

    +
    + + +
    +
    + + +
    +
    + + +
    +
    + 0 bits would be no quantization. +
    +
    +
    +
    +
    + +
    Loading...
    +
    +
    +
    +
    +

    Element
    Phase

     
    +
    + +
    + +
    +
    +

    Element Attenuation

     
    +
    + +
    + +
    +
    +

    2-D Radiation Pattern

     
    +
    + +
    + +
    +
    +
    +
    +

    1-D Pattern Cuts

    +
    + +
    + +
    +
    +
    +
    +

    Taper

    +
    + +
    + +
    +
    diff --git a/content-nl/about_author.rst b/content-nl/about_author.rst index 7e1ef167..12bec106 100644 --- a/content-nl/about_author.rst +++ b/content-nl/about_author.rst @@ -4,11 +4,11 @@ Over de auteur ################## -Dr. Marc Lichtman is een onderzoeker in draadloze communicatie die is gespecialiseerd in SDR, machine learning, LTE/5G-NR en spectrum sensing. Hij is een Adjunct-Professor op de Universiteit van Maryland. Hier heeft hij een cursus gemaakt en onderwezen wat als basis heeft gediend voor dit boek. Zijn cursus was een keuzevak als basis voor studenten die zich willen gaan specialiseren in SDR/DSP. Het heeft hem geholpen om de immens zware stof toegankelijk en activerend te maken voor studenten die konden programmeren, maar weinig-tot-niets wisten over de fysieke (PHY) laag. Het was niet ongewoon om een klas te starten met een mini-hackathon waar studenten een (door Marc verzonden) verborgen signaal moesten vinden of decoderen op basis van wat ze zojuist hadden geleerd. +Dr. Marc Lichtman is een onderzoeker in draadloze communicatie die is gespecialiseerd in SDR, machine learning, LTE/5G-NR en spectrum sensing. Hij is een Adjunct-Professor op de Universiteit van Maryland. Hier heeft hij een cursus gemaakt en onderwezen wat als basis heeft gediend voor dit boek. Zijn cursus was een keuzevak als basis voor studenten die zich willen gaan specialiseren in SDR/DSP. Het heeft hem geholpen om de immens zware stof toegankelijk en activerend te maken voor studenten die konden programmeren, maar weinig-tot-niets wisten over draadloze communicatie. Het was niet ongewoon om een klas te starten met een mini-hackathon waar studenten een (door Marc verzonden) verborgen signaal moesten vinden of decoderen op basis van wat ze zojuist hadden geleerd. -Marc is ook een van de hoofdpersonen van het `GNU Radio project `_, een open source SDR framework wat veel gebruikt wordt in de Academische wereld en defensie-gerelateerd onderzoek. Terwijl Python geweldig is om te leren, snel dingen uit te proberen en te ontwikkelen, leent het zich niet goed voor grote en complexe applicaties. GNU Radio kan gebruikt worden om complexere DSP-applicaties te implementeren. Daarnaast is een GNU Radio applicatie of een enkel blok erg gemakkelijk te delen met anderen. +Marc is ook een van de hoofdpersonen van het `GNU Radio project `_, een open source SDR framework wat veel gebruikt wordt in de Academische wereld en defensie-gerelateerd onderzoek. GNU Radio kan gebruikt worden om complexere DSP-applicaties te implementeren. Daarnaast is een GNU Radio applicatie of een enkel blok erg gemakkelijk te delen met anderen. -Marc leeft momenteel in de Washington DC omgeving met zijn vrouw Lindsey en hun vele katten en honden. Zijn hobby’s zijn houtbewerking, lasersnijden, de klarinet/saxofoon spelen, zeilen, tuinieren, drones bouwen/vliegen, elektrische skateboards bouwen/rijden en geavanceerd jojoën. +Marc leeft momenteel in de Washington DC omgeving met zijn vrouw Lindsey en hun vele katten en honden. Zijn hobby’s zijn houtbewerking, lasersnijden, de klarinet/saxofoon, zeilen, tuinieren en pinbal spelen. Email: marc@pysdr.org diff --git a/content-nl/cyclostationary.rst b/content-nl/cyclostationary.rst new file mode 100644 index 00000000..4b0befb8 --- /dev/null +++ b/content-nl/cyclostationary.rst @@ -0,0 +1,975 @@ +.. _freq-domain-chapter: + +################################### +Cyclostationaire Signaalverwerking +################################### + +.. raw:: html + + Mede-auteur: Sam Brown + +In dit hoofdstuk maken we cyclostationaire signaalverwerking (CSP) inzichtelijker. Dit is een relatief nichegebied binnen RF-signaalverwerking dat wordt gebruikt om signalen met cyclostationaire eigenschappen te analyseren of te detecteren (vaak bij zeer lage SNR), zoals de meeste moderne digitale modulatieschema's. We behandelen de Cyclic Autocorrelation Function (CAF), Spectral Correlation Function (SCF), Spectral Coherence Function (COH), de geconjugeerde varianten ervan, en hoe je ze toepast. Het hoofdstuk bevat meerdere volledige Python-implementaties met voorbeelden voor BPSK, QPSK, OFDM en combinaties van meerdere signalen. + +**************** +Introductie +**************** + +Cyclostationaire signaalverwerking (CSP) is een verzameling technieken die de cyclostationaire eigenschap van veel echte communicatiesignalen benut. Denk aan gemoduleerde signalen zoals AM/FM/TV-uitzendingen, cellulair verkeer, WiFi, radarsignalen en andere signalen waarvan statistische eigenschappen periodiek veranderen. Veel traditionele signaalverwerking gaat uit van stationariteit: gemiddelde, variantie en hogere orde momenten veranderen dan niet in de tijd. In de praktijk zijn veel RF-signalen echter cyclostationair: hun statistiek verandert *periodiek* in de tijd. CSP benut dit en kan worden gebruikt om signalen in ruis te detecteren, modulatie te herkennen en signalen te scheiden die zowel in tijd als in frequentie overlappen. + +Als je na dit hoofdstuk en wat experimenteren in Python dieper in CSP wilt duiken, bekijk dan William Gardner's leerboek uit 1994 `Cyclostationarity in Communications and Signal Processing `_, zijn boek uit 1987 `Statistical Spectral Analysis `_, of Chad Spooner's `verzameling blogposts `_. + +Een bron die je hier vindt en vrijwel nergens anders: aan het einde van het SCF-deel staat een interactieve JavaScript-app waarmee je in je browser met de SCF van een voorbeeldsignaal kunt spelen en direct ziet hoe de SCF verandert bij andere signaal- en SCF-parameters. Deze interactieve demo's zijn gratis voor iedereen en worden in belangrijke mate mogelijk gemaakt door de steun van PySDR's `Patreon `_-leden. + +***************************** +Herhaling van Autocorrelatie +***************************** + +Zelfs als je de autocorrelatiefunctie al kent, is een korte herhaling nuttig omdat dit de basis van CSP is. De autocorrelatiefunctie meet de overeenkomst (correlatie) tussen een signaal en een in de tijd verschoven versie van zichzelf. Intuitief geeft ze aan in welke mate een signaal repetitief gedrag vertoont. De autocorrelatie van :math:`x(t)` is: + +.. math:: + R_x(\tau) = E[x(t)x^*(t-\tau)] + +waar :math:`E` de verwachtingsoperator is, :math:`\tau` de tijdsvertraging, en :math:`*` het complex geconjugeerde teken. In discrete tijd met een eindig aantal samples (ons praktische geval) wordt dit: + +.. math:: + R_x(\tau) = \frac{1}{N} \sum_{n=-N/2}^{N/2} x\left[ n+\frac{\tau}{2} \right] x^*\left[ n-\frac{\tau}{2} \right] + +waar :math:`N` het aantal samples in het signaal is. + +Als een signaal op een bepaalde manier periodiek is, zoals de herhalende symboolvorm van een QPSK-signaal, dan zal de autocorrelatie over een bereik van tau ook periodiek zijn. Als een QPSK-signaal bijvoorbeeld 8 samples per symbool heeft, dan is bij tau als geheel veelvoud van 8 de overeenkomst veel sterker dan bij andere tau-waarden. Deze periodiciteit in de autocorrelatie is precies wat we met CSP-technieken willen detecteren. + +************************************************ +De Cyclic Autocorrelation Function (CAF) +************************************************ + +Zoals in de vorige sectie besproken, willen we bepalen wanneer periodiciteit in de autocorrelatie aanwezig is. Herinner de Fouriertransformatie: als we willen testen hoe sterk een frequentie :math:`f` in een willekeurig signaal :math:`x(t)` aanwezig is, gebruiken we: + +.. math:: + X(f) = \int x(t) e^{-j2\pi ft} dt + +Als we periodiciteit in de autocorrelatie willen vinden, berekenen we dus: + +.. math:: + R_x(\tau, \alpha) = \lim_{T\rightarrow\infty} \frac{1}{T} \int_{-T/2}^{T/2} x(t + \tau/2)x^*(t - \tau/2)e^{-j2\pi \alpha t}dt. + +of in discrete tijd: + +.. math:: + R_x(\tau, \alpha) = \frac{1}{N} \sum_{n=-N/2}^{N/2} x\left[ n+\frac{\tau}{2} \right] x^*\left[ n-\frac{\tau}{2} \right] e^{-j2\pi \alpha n} + +waarmee we testen hoe sterk frequentie :math:`\alpha` aanwezig is. Deze vergelijking noemen we de Cyclic Autocorrelation Function (CAF). Je kunt de CAF ook zien als een set Fourier-reekscoefficienten die de periodiciteit beschrijven. Met andere woorden: de CAF bevat amplitude en fase van harmonischen in de autocorrelatie van een signaal. We noemen signalen "cyclostationair" wanneer ze een periodieke of bijna periodieke autocorrelatie hebben. De CAF is daarmee een uitbreiding van de klassieke autocorrelatie voor cyclostationaire signalen. + +De CAF is een functie van twee variabelen: vertraging :math:`\tau` (tau) en cyclische frequentie :math:`\alpha`. Cyclische frequenties in CSP representeren de snelheid waarmee signaalstatistiek verandert, in het geval van de CAF vooral het tweede-ordemoment/variantiegedrag. Daarom corresponderen cyclische frequenties vaak met duidelijke periodiciteit zoals gemoduleerde symbolen in communicatiesignalen. We gaan zien hoe de symboolsnelheid van een BPSK-signaal en de gehele veelvouden daarvan (harmonischen) zichtbaar worden als cyclische frequenties in de CAF. + +In Python kan de CAF van basisbandsignaal :code:`samples` voor gegeven :code:`alpha` en :code:`tau` zo worden berekend (de omliggende code vullen we zo aan): + +.. code-block:: python + + CAF = (np.exp(1j * np.pi * alpha * tau) * + np.sum(samples * np.conj(np.roll(samples, tau)) * + np.exp(-2j * np.pi * alpha * np.arange(N)))) + +We gebruiken :code:`np.roll()` om een van de sample-sets met tau te verschuiven, omdat verschuiving in gehele aantallen samples moet gebeuren. Als we beide sets tegengesteld zouden verschuiven, slaan we om-en-om verschuivingen over. Daarnaast voegen we een frequentieverschuiving toe, omdat we telkens 1 sample verschuiven en slechts aan een kant (in plaats van een halve sample aan beide kanten zoals in de basis-CAF). De frequentie van die correctie is :code:`alpha/2`. + +Om met de CAF in Python te spelen, simuleren we eerst een voorbeeldsignaal. We gebruiken een rechthoekig BPSK-signaal (dus zonder pulse shaping) met 20 samples per symbool, plus witte Gaussische ruis (AWGN). We voegen een frequentie-offset toe aan het BPSK-signaal, zodat we later laten zien hoe cyclostationaire verwerking zowel frequentie-offset als cyclische frequentie kan schatten. Deze offset is vergelijkbaar met een radio die een signaal ontvangt zonder precies op de middenfrequentie afgestemd te zijn. + +De volgende code simuleert de IQ-samples die we in de volgende twee secties gebruiken: + +.. code-block:: python + + N = 100000 # number of samples to simulate + f_offset = 0.2 # Hz normalized + sps = 20 # cyclic freq (alpha) will be 1/sps or 0.05 Hz normalized + + symbols = np.random.randint(0, 2, int(np.ceil(N/sps))) * 2 - 1 # random 1's and -1's + bpsk = np.repeat(symbols, sps) # repeat each symbol sps times to make rectangular BPSK + bpsk = bpsk[:N] # clip off the extra samples + bpsk = bpsk * np.exp(2j * np.pi * f_offset * np.arange(N)) # Freq shift up the BPSK, this is also what makes it complex + noise = np.random.randn(N) + 1j*np.random.randn(N) # complex white Gaussian noise + samples = bpsk + 0.1*noise # add noise to the signal + +Omdat absolute sample rate en symboolsnelheid in dit hoofdstuk niet doorslaggevend zijn, gebruiken we genormaliseerde frequentie. Dat komt neer op sample rate = 1 Hz. Het signaal moet dan tussen -0.5 en +0.5 Hz liggen. Daarom zul je de variabele :code:`sample_rate` bewust niet in de code-snippets zien; we werken met samples per symbool (:code:`sps`). + +Ter illustratie kijken we eerst naar de power spectral density (FFT) van het signaal zelf, *voordat* CSP wordt toegepast: + +.. image:: ../_images/psd_of_bpsk_used_for_caf.svg + :align: center + :target: ../_images/psd_of_bpsk_used_for_caf.svg + :alt: PSD van BPSK gebruikt voor CAF + +Je ziet de toegepaste frequentieverschuiving van 0.2 Hz. Door 20 samples per symbool is het signaal relatief smal, maar zonder pulse shaping valt het in frequentie langzaam af. + +Nu berekenen we de CAF bij de juiste alpha en over een bereik aan tau-waarden (als start nemen we tau van -50 tot +50). De juiste alpha is hier simpelweg de inverse van samples per symbool: 1/20 = 0.05 Hz. In Python genereren we de CAF door over tau te itereren: + +.. code-block:: python + + # CAF only at the correct alpha + alpha_of_interest = 1/sps # equates to 0.05 Hz + taus = np.arange(-50, 51) + CAF = np.zeros(len(taus), dtype=complex) + for i in range(len(taus)): + CAF[i] = (np.exp(1j * np.pi * alpha_of_interest * taus[i]) * # This term is to make up for the fact we're shifting by 1 sample at a time, and only on one side + np.sum(samples * np.conj(np.roll(samples, taus[i])) * + np.exp(-2j * np.pi * alpha_of_interest * np.arange(N)))) + +Laten we het reele deel van :code:`CAF` plotten met :code:`plt.plot(taus, np.real(CAF))`: + +.. image:: ../_images/caf_at_correct_alpha.svg + :align: center + :target: ../_images/caf_at_correct_alpha.svg + :alt: CAF bij correcte alpha + +Dit ziet er misschien wat vreemd uit, maar onthoud dat tau het tijddomein representeert. Het belangrijkste is dat er veel energie in de CAF zit bij deze alpha, omdat deze alpha overeenkomt met een cyclische frequentie in ons signaal. Ter vergelijking bekijken we de CAF bij een onjuiste alpha, bijvoorbeeld 0.08 Hz: + +.. image:: ../_images/caf_at_incorrect_alpha.svg + :align: center + :target: ../_images/caf_at_incorrect_alpha.svg + :alt: CAF bij onjuiste alpha + +Let op de y-as: er zit nu veel minder energie in de CAF. De precieze patronen zijn op dit moment minder belangrijk en worden duidelijker na de SCF in de volgende sectie. + +Wat we ook kunnen doen is de CAF over een bereik van alpha's berekenen en per alpha het vermogen in de CAF bepalen via de magnitude en vervolgens som of gemiddelde (in dit geval maakt dat weinig uit). Als we deze vermogens over alpha plotten, verwachten we pieken op de cyclische frequenties in het signaal. De volgende code voegt een :code:`for`-loop toe en gebruikt een alpha-stap van 0.005 Hz (dit kan lang duren): + +.. code-block:: python + + alphas = np.arange(0, 0.5, 0.005) + CAF = np.zeros((len(alphas), len(taus)), dtype=complex) + for j in range(len(alphas)): + for i in range(len(taus)): + CAF[j, i] = (np.exp(1j * np.pi * alphas[j] * taus[i]) * + np.sum(samples * np.conj(np.roll(samples, taus[i])) * + np.exp(-2j * np.pi * alphas[j] * np.arange(N)))) + CAF_magnitudes = np.average(np.abs(CAF), axis=1) # at each alpha, calc power in the CAF + plt.plot(alphas, CAF_magnitudes) + plt.xlabel('Alpha') + plt.ylabel('CAF Power') + +.. image:: ../_images/caf_avg_over_alpha.svg + :align: center + :target: ../_images/caf_avg_over_alpha.svg + :alt: Gemiddelde CAF over alpha + +We zien niet alleen de verwachte piek op 0.05 Hz, maar ook pieken op gehele veelvouden daarvan. Dat komt doordat de CAF een Fourier-reeks is en harmonischen van de grondfrequentie zichtbaar zijn, zeker bij PSK/QAM zonder pulse shaping. De energie bij alpha = 0 is het totale vermogen in de PSD. Meestal nullen we die component uit omdat 1) we de PSD vaak al apart plotten en 2) deze anders het dynamisch bereik van de colormap verstoort bij 2D-plots. + +Hoewel de CAF interessant is, willen we vaak cyclische frequentie *als functie van RF-frequentie* bekijken, in plaats van alleen cyclische frequentie op zichzelf. Dat brengt ons bij de Spectral Correlation Function (SCF). + +************************************************ +De Spectral Correlation Function (SCF) +************************************************ + +Net zoals de CAF periodiciteit in de autocorrelatie laat zien, laat de SCF periodiciteit in de PSD zien. Autocorrelatie en PSD vormen een Fouriertransformatie-paar; daarom is het logisch dat CAF en SCF dat ook doen. Dit heet de *Cyclic Wiener Relationship*. Dit wordt nog duidelijker als je bedenkt dat CAF en SCF bij :math:`\alpha=0` respectievelijk de gewone autocorrelatie en PSD zijn. + +Je kunt de SCF verkrijgen door de Fouriertransformatie van de CAF te nemen. Voor ons BPSK-signaal met 20 samples per symbool bekijken we de SCF bij de juiste alpha (0.05 Hz). Dat vereist alleen de FFT van de CAF en een magnitudeplot. De volgende code sluit aan op de eerdere CAF-code met een enkele alpha: + +.. code-block:: python + + f = np.linspace(-0.5, 0.5, len(taus)) + SCF = np.fft.fftshift(np.fft.fft(CAF)) + plt.plot(f, np.abs(SCF)) + plt.xlabel('Frequency') + plt.ylabel('SCF') + +.. image:: ../_images/fft_of_caf.svg + :align: center + :target: ../_images/fft_of_caf.svg + :alt: FFT van CAF + +Let op dat we de toegepaste 0.2 Hz frequentie-offset terugzien van de BPSK-simulatie (dit staat los van cyclische frequentie en samples per symbool). Daarom zag de CAF er sinusvormig uit in het tau-domein: dat werd vooral bepaald door de relatief hoge RF-frequentie in dit voorbeeld. + +Helaas is dit voor duizenden of miljoenen alpha's extreem rekenintensief. Een tweede nadeel van direct FFT op de CAF is dat er geen averaging plaatsvindt. Efficiënte/praktische SCF-berekening gebruikt meestal een vorm van averaging, op tijd- of frequentiebasis, zoals in de volgende twee secties. + +Hieronder staat een interactieve JavaScript-app met SCF-implementatie, zodat je met verschillende signaal- en SCF-parameters intuïtie kunt opbouwen. De signaalfrequentie is een vrij directe regelaar en laat zien hoe goed de SCF RF-frequentie identificeert. Probeer pulse shaping door de optie Rectangular Pulse uit te zetten en varieer de roll-off. Let op: met de standaard alpha-stap geeft niet elke samples-per-symbool-waarde een zichtbare SCF-piek. Een kleinere alpha-stap helpt vaak, maar kost meer rekentijd. + +.. raw:: html + +
    + + +
    + + + 0.2 +
    + + + 20 +
    + + + + +
    + + +
    + + +
    + + +
    + + +
    + +
    +
    + +
    + + + + + +******************************** +Frequentie-smoothingmethode (FSM) +******************************** + +Nu we conceptueel begrijpen wat de SCF doet, kijken we naar een efficiente berekeningsmethode. We starten met het periodogram, de gekwadrateerde magnitude van de Fouriertransformatie van een signaal: + +.. math:: + + I(u,f) = \frac{1}{N}\left|X(u,f)\right|^2 + +Het cyclische periodogram krijgen we uit het product van twee in frequentie verschoven Fouriertransformaties: + +.. math:: + + I(u,f,\alpha) = \frac{1}{N}X(u,f + \alpha/2) X^*(u,f - \alpha/2) + +Beide zijn schattingen van PSD en SCF, maar voor een betrouwbare SCF moet je middelen over tijd of frequentie. Middelen over tijd heet de Time Smoothing Method (TSM): + +.. math:: + S_X(f, \alpha) = \lim_{T\rightarrow\infty} \frac{1}{T} \lim_{U\rightarrow\infty} \frac{1}{U} \int_{-U/2}^{U/2} X(t,f + \alpha/2) X^*(t,f - \alpha/2) dt + +middelen over frequentie heet de Frequency Smoothing Method (FSM): + +.. math:: + S_X(f, \alpha) = \lim_{\Delta\rightarrow 0} \lim_{T\rightarrow \infty} \frac{1}{T} g_{\Delta}(f) \otimes \left[X(t,f + \alpha/2) X^*(t,f - \alpha/2)\right] + +waar de functie :math:`g_{\Delta}(f)` een frequentiesmoothingfunctie is die over een klein frequentiebereik middelt. + +Hieronder staat een minimale Python-implementatie van FSM, een op frequentiemiddeling gebaseerde methode om de SCF van een signaal te berekenen. Eerst wordt het cyclische periodogram berekend door twee verschoven FFT-versies te vermenigvuldigen, daarna wordt elke slice gefilterd met een vensterfunctie waarvan de lengte de resolutie van de SCF-schatting bepaalt. Langere vensters geven gladdere resultaten met lagere resolutie; kortere vensters doen het omgekeerde. + +.. code-block:: python + + alphas = np.arange(0, 0.3, 0.001) + Nw = 256 # window length + N = len(samples) # signal length + window = np.hanning(Nw) + + X = np.fft.fftshift(np.fft.fft(samples)) # FFT of entire signal + + num_freqs = int(np.ceil(N/Nw)) # freq resolution after decimation + SCF = np.zeros((len(alphas), num_freqs), dtype=complex) + for i in range(len(alphas)): + shift = int(alphas[i] * N/2) + SCF_slice = np.roll(X, -shift) * np.conj(np.roll(X, shift)) + SCF[i, :] = np.convolve(SCF_slice, window, mode='same')[::Nw] # apply window and decimate by Nw + SCF = np.abs(SCF) + SCF[0, :] = 0 # null out alpha=0 which is just the PSD of the signal, it throws off the dynamic range + + extent = (-0.5, 0.5, float(np.max(alphas)), float(np.min(alphas))) + plt.imshow(SCF, aspect='auto', extent=extent, vmax=np.max(SCF)/2) + plt.xlabel('Frequency [Normalized Hz]') + plt.ylabel('Cyclic Frequency [Normalized Hz]') + plt.show() + +Let op dat door de manier waarop de verschuiving als geheel aantal samples wordt berekend en afgerond, het helpt om minstens :code:`2 / alpha_resolution` samples tegelijk te verwerken. + +Laten we de SCF berekenen voor het rechthoekige BPSK-signaal van eerder, met 20 samples per symbool en cyclische frequenties van 0 tot 0.3 met stapgrootte 0.001: + +.. image:: ../_images/scf_freq_smoothing.svg + :align: center + :target: ../_images/scf_freq_smoothing.svg + :alt: SCF met de Frequency Smoothing Method (FSM), cyclostationaire verwerking + +Deze methode heeft als voordeel dat maar een grote FFT nodig is, maar als nadeel dat voor smoothing veel convoluties nodig zijn. Let op de decimatie na de convolve via :code:`[::Nw]`; dit is optioneel maar sterk aanbevolen om het aantal weer te geven pixels te beperken, en door de opbouw van de SCF gooi je hiermee in de praktijk geen bruikbare informatie weg. + +*************************** +Tijd-smoothingmethode (TSM) +*************************** + +Nu bekijken we een TSM-implementatie in Python. De code hieronder splitst het signaal in *num_windows* blokken, elk van lengte *Nw* met overlap *Noverlap*. Overlap is niet verplicht, maar geeft vaak een netter resultaat. Daarna wordt per blok een vensterfunctie toegepast (hier Hanning, maar andere vensters kunnen ook) en een FFT genomen. De SCF ontstaat vervolgens door over blokken te middelen. De vensterlengte bepaalt, net als bij FSM, de afweging tussen resolutie en gladheid. + + +.. code-block:: python + + alphas = np.arange(0, 0.3, 0.001) + Nw = 256 # window length + N = len(samples) # signal length + Noverlap = int(2/3*Nw) # block overlap + num_windows = int((N - Noverlap) / (Nw - Noverlap)) # Number of windows + window = np.hanning(Nw) + + SCF = np.zeros((len(alphas), Nw), dtype=complex) + for ii in range(len(alphas)): # Loop over cyclic frequencies + neg = samples * np.exp(-1j*np.pi*alphas[ii]*np.arange(N)) + pos = samples * np.exp( 1j*np.pi*alphas[ii]*np.arange(N)) + for i in range(num_windows): + pos_slice = window * pos[i*(Nw-Noverlap):i*(Nw-Noverlap)+Nw] + neg_slice = window * neg[i*(Nw-Noverlap):i*(Nw-Noverlap)+Nw] + SCF[ii, :] += np.fft.fft(neg_slice) * np.conj(np.fft.fft(pos_slice)) # Cross Cyclic Power Spectrum + SCF = np.fft.fftshift(SCF, axes=1) # shift the RF freq axis + SCF = np.abs(SCF) + SCF[0, :] = 0 # null out alpha=0 which is just the PSD of the signal, it throws off the dynamic range + + extent = (-0.5, 0.5, float(np.max(alphas)), float(np.min(alphas))) + plt.imshow(SCF, aspect='auto', extent=extent, vmax=np.max(SCF)/2) + plt.xlabel('Frequency [Normalized Hz]') + plt.ylabel('Cyclic Frequency [Normalized Hz]') + plt.show() + +.. image:: ../_images/scf_time_smoothing.svg + :align: center + :target: ../_images/scf_time_smoothing.svg + :alt: SCF met de Time Smoothing Method (TSM), cyclostationaire verwerking + +Ziet er grofweg hetzelfde uit als FSM. + +***************** +Pulse-shaped BPSK +***************** + +Tot nu toe onderzochten we CSP alleen voor een *rechthoekig* BPSK-signaal. In echte RF-systemen zien we echter bijna nooit rechthoekige pulsen; een uitzondering is de BPSK-chippingsequentie in direct-sequence spread spectrum (DSSS), die vaak ongeveer rechthoekig is. + +Laten we nu kijken naar een BPSK-signaal met raised-cosine (RC) pulse shaping, een veelgebruikte vorm in digitale communicatie om de bezette bandbreedte te verkleinen ten opzichte van rechthoekig BPSK. Zoals besproken in :ref:`pulse-shaping-chapter` is de RC-pulsvorm in het tijddomein: + +.. math:: + h(t) = \mathrm{sinc}\left( \frac{t}{T} \right) \frac{\cos\left(\frac{\pi\beta t}{T}\right)}{1 - \left( \frac{2 \beta t}{T} \right)^2} + +De parameter :math:`\beta` bepaalt hoe snel het filter in het tijddomein afvalt, wat omgekeerd samenhangt met het afvallen in frequentie: + +.. image:: ../_images/raised_cosine_freq.svg + :align: center + :target: ../_images/raised_cosine_freq.svg + :alt: Raised-cosinefilter in het frequentiedomein met verschillende roll-offwaarden + +Let op dat :math:`\beta=0` overeenkomt met een oneindig lange pulsvorm en dus niet praktisch is. Ook geldt dat :math:`\beta=1` *niet* overeenkomt met een rechthoekige pulsvorm. In de praktijk ligt roll-off vaak tussen 0.2 en 0.4. + +We kunnen een BPSK-signaal met raised-cosine pulse shaping simuleren met onderstaande code; de eerste 5 en laatste 4 regels zijn gelijk aan rechthoekig BPSK: + +.. code-block:: python + + N = 100000 # number of samples to simulate + f_offset = 0.2 # Hz normalized + sps = 20 # cyclic freq (alpha) will be 1/sps or 0.05 Hz normalized + num_symbols = int(np.ceil(N/sps)) + symbols = np.random.randint(0, 2, num_symbols) * 2 - 1 # random 1's and -1's + + pulse_train = np.zeros(num_symbols * sps) + pulse_train[::sps] = symbols # easier explained by looking at an example output + print(pulse_train[0:96].astype(int)) + + # Raised-Cosine Filter for Pulse Shaping + beta = 0.3 # roll-off parameter (avoid exactly 0.2, 0.25, 0.5, and 1.0) + num_taps = 101 # somewhat arbitrary + t = np.arange(num_taps) - (num_taps-1)//2 + h = np.sinc(t/sps) * np.cos(np.pi*beta*t/sps) / (1 - (2*beta*t/sps)**2) # RC equation + bpsk = np.convolve(pulse_train, h, 'same') # apply the pulse shaping + + bpsk = bpsk[:N] # clip off the extra samples + bpsk = bpsk * np.exp(2j * np.pi * f_offset * np.arange(N)) # Freq shift up the BPSK, this is also what makes it complex + noise = np.random.randn(N) + 1j*np.random.randn(N) # complex white Gaussian noise + samples = bpsk + 0.1*noise # add noise to the signal + +Let op dat :code:`pulse_train` simpelweg onze symbolen zijn met :code:`sps - 1` nullen na elk symbool, dus in volgorde bijvoorbeeld: + +.. code-block:: bash + + [ 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0... + +De onderstaande plot toont het pulse-shaped BPSK-signaal in het tijddomein, nog zonder ruis en zonder frequentieverschuiving: + +.. image:: ../_images/pulse_shaped_BSPK.svg + :align: center + :target: ../_images/pulse_shaped_BSPK.svg + :alt: Pulse-shaped BPSK-signaal met raised-cosine pulsvorm + +Laten we nu de SCF van dit pulse-shaped BPSK-signaal berekenen met roll-off 0.3, 0.6 en 0.9. We gebruiken dezelfde frequentieverschuiving van 0.2 Hz, dezelfde FSM-implementatie, FSM-parameters en symboollengte als in het rechthoekige BPSK-voorbeeld voor een eerlijke vergelijking: + +:code:`beta = 0.3`: + +.. image:: ../_images/scf_freq_smoothing_pulse_shaped_bpsk.svg + :align: center + :target: ../_images/scf_freq_smoothing_pulse_shaped_bpsk.svg + :alt: SCF van pulse-shaped BPSK met de Frequency Smoothing Method (FSM), beta 0.3 + +:code:`beta = 0.6`: + +.. image:: ../_images/scf_freq_smoothing_pulse_shaped_bpsk2.svg + :align: center + :target: ../_images/scf_freq_smoothing_pulse_shaped_bpsk2.svg + :alt: SCF van pulse-shaped BPSK met de Frequency Smoothing Method (FSM), beta 0.6 + +:code:`beta = 0.9`: + +.. image:: ../_images/scf_freq_smoothing_pulse_shaped_bpsk3.svg + :align: center + :target: ../_images/scf_freq_smoothing_pulse_shaped_bpsk3.svg + :alt: SCF van pulse-shaped BPSK met de Frequency Smoothing Method (FSM), beta 0.9 + +In alle drie gevallen verdwijnen de sterke sidelobes op de frequentie-as, en op de cyclische frequentie-as zien we niet dezelfde krachtige harmonischen van de grondfrequentie. Dat komt doordat raised-cosine pulse shaping de energie spectraal veel beter begrenst dan rechthoekige pulsenvormen. Hierdoor hebben pulse-shaped signalen doorgaans een "schonere" SCF dan rechthoekige signalen, vaak als een dominante piek met smeer erboven. Dit geldt voor alle enkelvoudige draaggolfsignalen met digitale modulatie, niet alleen BPSK. Bij grotere beta wordt de piek op de frequentie-as breder doordat het signaal meer bandbreedte gebruikt. + +******************************** +SNR en Aantal Symbolen +******************************** + +Komt binnenkort. We behandelen dan waarom boven een bepaald punt hogere SNR niet meer helpt, maar meer symbolen wel, en hoe packet-gebaseerde golfvormen leiden tot een beperkt aantal symbolen per transmissie. + +******************************** +QPSK en Hogere-orde Modulatie +******************************** + +Komt binnenkort. Dit deel zal QPSK, hogere orde PSK, QAM en een korte introductie tot hogere-orde cyclische momenten en cumulanten bevatten. + +******************************** +Meerdere Overlappende Signalen +******************************** + +Tot nu toe keken we naar een signaal tegelijk. Maar wat als het ontvangen signaal meerdere individuele signalen bevat die in frequentie, tijd en zelfs cyclische frequentie overlappen (dus hetzelfde aantal samples per symbool hebben)? Als signalen niet in frequentie overlappen, kun je ze met simpele filtering scheiden en met een PSD detecteren, mits boven de ruisvloer. Overlappen ze niet in de tijd, dan kun je stijg- en daalflanken per transmissie detecteren en met time-gating per signaal verwerken. In CSP richten we ons vaak op detectie van signalen met verschillende cyclische frequenties die in zowel tijd als frequentie overlappen. + +Laten we drie signalen simuleren met verschillende eigenschappen: + +* Signaal 1: rechthoekig BPSK met 20 samples per symbool en 0.2 Hz frequentie-offset +* Signaal 2: pulse-shaped BPSK met 20 samples per symbool, -0.1 Hz frequentie-offset en 0.35 roll-off +* Signaal 3: pulse-shaped QPSK met 4 samples per symbool, 0.2 Hz frequentie-offset en 0.21 roll-off + +Zoals je ziet hebben twee signalen dezelfde cyclische frequentie en twee dezelfde RF-frequentie. Daarmee kunnen we met verschillende graden van parameteroverlap experimenteren. + +Op elk signaal passen we een fractional-delay-filter toe met een willekeurige (niet-gehele) vertraging, zodat geen artefacten ontstaan doordat gesimuleerde samples exact uitgelijnd zijn (meer hierover in :ref:`sync-chapter`). Het rechthoekige BPSK-signaal verlagen we in vermogen ten opzichte van de andere twee, omdat rechthoekige pulsen zeer sterke cyclostationaire eigenschappen hebben en anders de SCF domineren. + +.. raw:: html + +
    + Klap open voor Python-code die de drie signalen simuleert + +.. code-block:: python + + N = 1000000 # number of samples to simulate + + def fractional_delay(x, delay): + N = 21 # number of taps + n = np.arange(-N//2, N//2) # ...-3,-2,-1,0,1,2,3... + h = np.sinc(n - delay) # calc filter taps + h *= np.hamming(N) # window the filter to make sure it decays to 0 on both sides + h /= np.sum(h) # normalize to get unity gain, we don't want to change the amplitude/power + return np.convolve(x, h, 'same') # apply filter + + # Signal 1, Rect BPSK + sps = 20 + f_offset = 0.2 + signal1 = np.repeat(np.random.randint(0, 2, int(np.ceil(N/sps))) * 2 - 1, sps) + signal1 = signal1[:N] * np.exp(2j * np.pi * f_offset * np.arange(N)) + signal1 = fractional_delay(signal1, 0.12345) + + # Signal 2, Pulse-shaped BPSK + sps = 20 + f_offset = -0.1 + beta = 0.35 + symbols = np.random.randint(0, 2, int(np.ceil(N/sps))) * 2 - 1 + pulse_train = np.zeros(int(np.ceil(N/sps)) * sps) + pulse_train[::sps] = symbols + t = np.arange(101) - (101-1)//2 + h = np.sinc(t/sps) * np.cos(np.pi*beta*t/sps) / (1 - (2*beta*t/sps)**2) + signal2 = np.convolve(pulse_train, h, 'same') + signal2 = signal2[:N] * np.exp(2j * np.pi * f_offset * np.arange(N)) + signal2 = fractional_delay(signal2, 0.52634) + + # Signal 3, Pulse-shaped QPSK + sps = 4 + f_offset = 0.2 + beta = 0.21 + data = x_int = np.random.randint(0, 4, int(np.ceil(N/sps))) # 0 to 3 + data_degrees = data*360/4.0 + 45 # 45, 135, 225, 315 degrees + symbols = np.cos(data_degrees*np.pi/180.0) + 1j*np.sin(data_degrees*np.pi/180.0) + pulse_train = np.zeros(int(np.ceil(N/sps)) * sps, dtype=complex) + pulse_train[::sps] = symbols + t = np.arange(101) - (101-1)//2 + h = np.sinc(t/sps) * np.cos(np.pi*beta*t/sps) / (1 - (2*beta*t/sps)**2) + signal3 = np.convolve(pulse_train, h, 'same') + signal3 = signal3[:N] * np.exp(2j * np.pi * f_offset * np.arange(N)) + signal3 = fractional_delay(signal3, 0.3526) + + # Add noise + noise = np.random.randn(N) + 1j*np.random.randn(N) + samples = 0.5*signal1 + signal2 + 1.5*signal3 + 0.1*noise + +.. raw:: html + +
    + +Voordat we in de CSP-resultaten duiken, bekijken we eerst de PSD van dit signaal: + +.. image:: ../_images/psd_of_multiple_signals.svg + :align: center + :target: ../_images/psd_of_multiple_signals.svg + :alt: PSD van drie verschillende signalen + +Signalen 1 en 3, die aan de positieve kant van de PSD liggen, overlappen, en je ziet signaal 1 (smaller) maar net uitsteken. Je krijgt hier ook een indruk van het ruisniveau. + +We gebruiken nu FSM om de SCF van deze gecombineerde signalen te berekenen: + +.. image:: ../_images/scf_freq_smoothing_pulse_multiple_signals.svg + :align: center + :target: ../_images/scf_freq_smoothing_pulse_multiple_signals.svg + :alt: SCF van drie verschillende signalen met de Frequency Smoothing Method (FSM) + +Let op dat signaal 1, ondanks de rechthoekige pulsvorm, zijn harmonischen grotendeels verborgen ziet onder de "kegel" boven signaal 3. In de PSD zagen we al dat signaal 1 als het ware achter signaal 3 zat. Met CSP kunnen we toch detecteren dat signaal 1 aanwezig is en de cyclische frequentie redelijk nauwkeurig benaderen, wat vervolgens voor synchronisatie bruikbaar is. Dat is precies de kracht van cyclostationaire signaalverwerking. + +************************ +Alternatieve CSP-kenmerken +************************ + +SCF is niet de enige manier om cyclostationariteit te detecteren, zeker niet als je cyclische frequentie niet per se over RF-frequentie hoeft te bekijken. Een eenvoudige methode (zowel conceptueel als qua rekentijd) is de **FFT van de magnitude** van het signaal te nemen en op pieken te zoeken. In Python is dat erg simpel: + +.. code-block:: python + + samples_mag = np.abs(samples) + #samples_mag = samples * np.conj(samples) # pretty much the same as line above + magnitude_metric = np.abs(np.fft.fft(samples_mag)) + +Let op dat deze methode in essentie gelijk is aan het signaal vermenigvuldigen met zijn complex geconjugeerde en daarna een FFT nemen. + +Voordat we de metric plotten, nullen we de DC-component uit omdat die veel energie bevat en het dynamisch bereik verstoort. We halen ook de helft van de FFT-output weg, omdat de FFT-invoer reeel is en de output dus symmetrisch is. Daarna kunnen we de metric plotten en pieken zien: + +.. code-block:: python + + magnitude_metric = magnitude_metric[:len(magnitude_metric)//2] # only need half because input is real + magnitude_metric[0] = 0 # null out the DC component + f = np.linspace(-0.5, 0.5, len(samples)) + plt.plot(f, magnitude_metric) + +Daarna kun je een piekzoekalgoritme gebruiken, zoals SciPy's :code:`signal.find_peaks()`. Hieronder plotten we :code:`magnitude_metric` voor elk van de drie signalen uit de sectie met overlappende signalen, eerst apart en daarna gecombineerd: + +.. image:: ../_images/non_csp_metric.svg + :align: center + :target: ../_images/non_csp_metric.svg + :alt: Metric voor detectie van cyclostationariteit zonder CAF of SCF + +De harmonischen van rechthoekig BPSK overlappen helaas met cyclische frequenties van de andere signalen. Dit toont meteen een nadeel van deze alternatieve aanpak: je kunt cyclische frequentie niet over RF-frequentie bekijken zoals bij SCF. + +Hoewel deze methode cyclostationariteit benut, wordt ze meestal niet als volwaardige "CSP-techniek" gezien, mogelijk door haar eenvoud. + +Voor het vinden van de RF-frequentie (carrier frequency offset) bestaat een vergelijkbare truc. Voor BPSK neem je de FFT van het signaal in het kwadraat (complexe FFT-invoer); je krijgt dan een piek op tweemaal de carrier-offset. Voor QPSK neem je de FFT van het signaal tot de vierde macht; dan krijg je een piek op viermaal de carrier-offset. + +.. code-block:: python + + samples_squared = samples**2 + squared_metric = np.abs(np.fft.fftshift(np.fft.fft(samples_squared)))/len(samples) + squared_metric[len(squared_metric)//2] = 0 # null out the DC component + + samples_quartic = samples**4 + quartic_metric = np.abs(np.fft.fftshift(np.fft.fft(samples_quartic)))/len(samples) + quartic_metric[len(quartic_metric)//2] = 0 # null out the DC component + +Probeer deze methode gerust op eigen gesimuleerde of opgenomen signalen; ook buiten CSP is dit erg bruikbaar. + +********************************* +Spectral Coherence Function (COH) +********************************* + +*TLDR: de spectral coherence function is een genormaliseerde versie van de SCF die in sommige situaties beter werkt dan de gewone SCF.* + +Een andere maat voor cyclostationariteit, die vaak informatiever is dan ruwe SCF, is de Spectral Coherence Function (COH). COH normaliseert de SCF zodat de uitkomst tussen -1 en 1 ligt (voor magnitude bekijken we 0 tot 1). Dit is nuttig omdat informatie over cyclostationariteit wordt gescheiden van informatie over het vermogensspectrum, die in ruwe SCF door elkaar zitten. Door normalisatie blijft vooral het effect van cyclische correlatie over. + +Om COH beter te begrijpen helpt het om het statistische concept van de `correlatiecoefficient `_ te herhalen. De correlatiecoefficient :math:`\rho_{X,Y}` kwantificeert hoe sterk twee toevalsvariabelen :math:`X` en :math:`Y` samenhangen op schaal -1 tot 1. Definitie: + +.. math:: + \rho_{X,Y} = \frac{E[(X-\mu_X)(Y-\mu_Y)]}{\sigma_X \sigma_Y} + +COH breidt dit concept uit naar spectrale correlatie: het meet hoe sterk de PSD van een signaal op de ene frequentie samenhangt met de PSD van datzelfde signaal op een andere frequentie. Deze twee frequenties zijn de verschuivingen die we bij SCF-berekening toepassen. Voor COH berekenen we eerst de SCF zoals eerder, :math:`S_X(f,\alpha)`, en normaliseren vervolgens met het product van twee verschoven PSD-termen, analoog aan normaliseren met standaarddeviaties: + +.. math:: + \rho = C_x(f, \alpha) = \frac{S_X(f,\alpha)}{\sqrt{C_x^0(f + \alpha/2) C_x^0(f - \alpha/2)}} + +De noemer is het belangrijkste nieuwe onderdeel: de termen :math:`C_x^0(f + \alpha/2)` en :math:`C_x^0(f - \alpha/2)` zijn simpelweg de PSD verschoven met :math:`\alpha/2` en :math:`-\alpha/2`. Anders gezegd: de SCF is een cross-spectral density (vermogensspectrum met twee ingangen), terwijl de normalisatietermen autospectrale dichtheden zijn (een ingang). + +We passen dit nu toe in Python, specifiek op SCF met FSM. Omdat FSM in het frequentiedomein middelt, hebben we :math:`C_x^0(f + \alpha/2)` en :math:`C_x^0(f - \alpha/2)` al beschikbaar; in code zijn dat :code:`np.roll(X, -shift)` en :code:`np.roll(X, shift)`, omdat :code:`X` het signaal na FFT is. We vermenigvuldigen die, nemen de wortel en delen de SCF-slice door dat resultaat (binnen de for-loop over alpha): + +.. code-block:: python + + COH_slice = SCF_slice / np.sqrt(np.roll(X, -shift) * np.roll(X, shift)) + +Tot slot herhalen we dezelfde convolve- en decimatiestap als bij de uiteindelijke SCF-slice. + +.. code-block:: python + + COH[i, :] = np.convolve(COH_slice, window, mode='same')[::Nw] + +.. raw:: html + +
    + Klap open voor volledige code om zowel SCF als COH te genereren en te plotten + +.. code-block:: python + + alphas = np.arange(0, 0.3, 0.001) + Nw = 256 # window length + N = len(samples) # signal length + window = np.hanning(Nw) + + X = np.fft.fftshift(np.fft.fft(samples)) # FFT of entire signal + + num_freqs = int(np.ceil(N/Nw)) # freq resolution after decimation + SCF = np.zeros((len(alphas), num_freqs), dtype=complex) + COH = np.zeros((len(alphas), num_freqs), dtype=complex) + for i in range(len(alphas)): + shift = int(alphas[i] * N/2) + SCF_slice = np.roll(X, -shift) * np.conj(np.roll(X, shift)) + SCF[i, :] = np.convolve(SCF_slice, window, mode='same')[::Nw] # apply window and decimate by Nw + COH_slice = SCF_slice / np.sqrt(np.roll(X, -shift) * np.roll(X, shift)) + COH[i, :] = np.convolve(COH_slice, window, mode='same')[::Nw] # apply the same windowing + decimation + SCF = np.abs(SCF) + COH = np.abs(COH) + + # null out alpha=0 for both so that it doesnt hurt our dynamic range and ability to see the non-zero alphas + SCF[np.argmin(np.abs(alphas)), :] = 0 + COH[np.argmin(np.abs(alphas)), :] = 0 + + extent = (-0.5, 0.5, float(np.max(alphas)), float(np.min(alphas))) + fig, [ax0, ax1] = plt.subplots(1, 2, figsize=(10, 5)) + ax0.imshow(SCF, aspect='auto', extent=extent, vmax=np.max(SCF)/2) + ax0.set_xlabel('Frequency [Normalized Hz]') + ax0.set_ylabel('Cyclic Frequency [Normalized Hz]') + ax0.set_title('Regular SCF') + ax1.imshow(COH, aspect='auto', extent=extent, vmax=np.max(COH)/2) + ax1.set_xlabel('Frequency [Normalized Hz]') + ax1.set_title('Spectral Coherence Function (COH)') + plt.show() + +.. raw:: html + +
    + +Laten we nu COH (en gewone SCF) berekenen voor een rechthoekig BPSK-signaal met 20 samples per symbool en 0.2 Hz frequentie-offset: + +.. image:: ../_images/scf_coherence.svg + :align: center + :target: ../_images/scf_coherence.svg + :alt: SCF en COH van een rechthoekig BPSK-signaal met 20 samples per symbool en 0.2 Hz frequentie-offset + +Zoals je ziet zijn hogere alpha's in COH veel duidelijker dan in SCF. Draaien we dezelfde code op pulse-shaped BPSK, dan is het verschil kleiner: + +.. image:: ../_images/scf_coherence_pulse_shaped.svg + :align: center + :target: ../_images/scf_coherence_pulse_shaped.svg + :alt: SCF en COH van een pulse-shaped BPSK-signaal met 20 samples per symbool en 0.2 Hz frequentie-offset + +Probeer voor je eigen toepassing zowel SCF als COH te genereren om te zien welke het beste werkt. + +********** +Conjugates +********** + +Tot nu toe gebruikten we voor CAF en SCF formules waarin in de tweede term het complex geconjugeerde (:math:`*`) van het signaal staat: + +.. math:: + R_x(\tau,\alpha) = \lim_{T\rightarrow\infty} \frac{1}{T} \int_{-T/2}^{T/2} x(t + \tau/2)x^*(t - \tau/2)e^{-j2\pi \alpha t}dt \\ + S_X(f,\alpha) = \lim_{T\rightarrow\infty} \frac{1}{T} \lim_{U\rightarrow\infty} \frac{1}{U} \int_{-U/2}^{U/2} X(t,f + \alpha/2) X^*(t,f - \alpha/2) dt + +Er bestaat echter ook een alternatieve vorm van CAF en SCF zonder geconjugeerde term. Deze heten respectievelijk *conjugate CAF* en *conjugate SCF*. De naamgeving is wat verwarrend; onthoud vooral dat er een "normale" en een geconjugeerde variant is. De geconjugeerde versie kan extra informatie opleveren, maar is niet altijd nodig. + +.. math:: + R_{x^*}(\tau,\alpha) = \lim_{T\rightarrow\infty} \frac{1}{T} \int_{-T/2}^{T/2} x(t + \tau/2)x(t - \tau/2)e^{-j2\pi \alpha t}dt \\ + S_{x^*}(f,\alpha) = \lim_{T\rightarrow\infty} \frac{1}{T} \lim_{U\rightarrow\infty} \frac{1}{U} \int_{-U/2}^{U/2} X(t,f + \alpha/2) X(t,f - \alpha/2) dt + +Dit is dezelfde structuur als de oorspronkelijke CAF/SCF, maar zonder geconjugeerde term. Ook in discrete tijd geldt hetzelfde verschil. + +Om de betekenis van de geconjugeerde vormen goed te begrijpen, bekijken we de kwadratuurrepresentatie van een reeel bandpass-signaal: + +.. math:: + y(t) = x_I(t) \cos(2\pi f_c t + \phi) + x_Q(t) \sin(2\pi f_c t + \phi) + +:math:`x_I(t)` en :math:`x_Q(t)` zijn respectievelijk de in-phase (I) en quadratuur (Q)-component van het signaal, en het zijn deze IQ-samples die we uiteindelijk met CSP in baseband verwerken. + +Met de formule van Euler, :math:`e^{jx} = \cos(x) + j \sin(x)`, kunnen we de vergelijking hierboven herschrijven met complexe exponenten: + +.. math:: + y(t) = \frac{x_I(t) - j x_Q(t)}{2} e^{j 2\pi f_c t + j \phi} + \frac{x_I(t) + j x_Q(t)}{2} e^{-j 2\pi f_c t - j \phi} + +We kunnen de complexe envelop, die we :math:`z(t)` noemen, gebruiken om het reele signaal :math:`y(t)` te representeren, onder de aanname dat de signaalbandbreedte veel kleiner is dan de draaggolffrequentie :math:`f_c`, wat typisch zo is in RF-toepassingen: + +.. math:: + y(t) = z(t) e^{j 2 \pi f_c t + j \phi} + z^*(t) e^{-j 2 \pi f_c t - j \phi} + +Dit staat bekend als de complex-basebandrepresentatie. + +Terug naar de CAF: laten we het deel berekenen dat bekend staat als het "lag product", oftewel :math:`x(t + \tau/2) x(t - \tau/2)`. + +.. math:: + \left(z(t + \tau/2) e^{j 2 \pi f_c (t + \tau/2) + j \phi} + z^*(t + \tau/2) e^{-j 2 \pi f_c (t + \tau/2) - j \phi}\right) \times \\ \left(z(t - \tau/2) e^{j 2 \pi f_c (t - \tau/2) + j \phi} + z^*(t - \tau/2) e^{-j 2 \pi f_c (t - \tau/2) - j \phi}\right) + +Hoewel het niet meteen zichtbaar is, bevat dit resultaat vier termen die overeenkomen met de vier combinaties van geconjugeerde en niet-geconjugeerde :math:`z(t)`: + +.. math:: + z(t + \tau/2) z(t - \tau/2) e^{(\ldots)} \\ + z(t + \tau/2) z^*(t - \tau/2) e^{(\ldots)} \\ + z^*(t + \tau/2) z(t - \tau/2) e^{(\ldots)} \\ + z^*(t + \tau/2) z^*(t - \tau/2) e^{(\ldots)} + +Het blijkt dat de 1e en 4e term qua informatie-inhoud effectief hetzelfde zijn, net als de 2e en 3e. In de praktijk blijven dus twee relevante gevallen over: het geconjugeerde en het niet-geconjugeerde geval. Samengevat: om alle statistische informatie uit :math:`y(t)` te halen, moeten beide combinaties worden meegenomen. + +Om de geconjugeerde SCF met de frequentie-smoothingmethode te implementeren, is er naast het verwijderen van :code:`conj()` nog een extra stap nodig, omdat we een grote FFT doen en daarna in het frequentiedomein middelen. Een eigenschap van de Fouriertransformatie is dat complex geconjugeerd in het tijddomein overeenkomt met omklappen en conjugeren in het frequentiedomein: + +.. math:: + x^*(t) \leftrightarrow X^*(-f) + +Omdat we in de normale SCF de tweede term al complex conjugeren (met :code:`SCF_slice = np.roll(X, -shift) * np.conj(np.roll(X, shift))`), valt die extra conjugatie weg. Dan blijft het volgende over: + +.. code-block:: python + + SCF_slice = np.roll(X, -shift) * np.flip(np.roll(X, -shift - 1)) + +Let op de toegevoegde :code:`np.flip()`, en dat :code:`roll()` in omgekeerde richting moet gebeuren. De volledige FSM-implementatie van de geconjugeerde SCF is: + +.. code-block:: python + + alphas = np.arange(-1, 1, 0.01) # Conj SCF should be calculated from -1 to +1 + Nw = 256 # window length + N = len(samples) # signal length + window = np.hanning(Nw) + + X = np.fft.fftshift(np.fft.fft(samples)) # FFT of entire signal + + num_freqs = int(np.ceil(N/Nw)) # freq resolution after decimation + SCF = np.zeros((len(alphas), num_freqs), dtype=complex) + for i in range(len(alphas)): + shift = int(np.round(alphas[i] * N/2)) + SCF_slice = np.roll(X, -shift) * np.flip(np.roll(X, -shift - 1)) # THIS LINE IS THE ONLY DIFFERENCE + SCF[i, :] = np.convolve(SCF_slice, window, mode='same')[::Nw] + SCF = np.abs(SCF) + + extent = (-0.5, 0.5, float(np.min(alphas)), float(np.max(alphas))) + plt.imshow(SCF, aspect='auto', extent=extent, vmax=np.max(SCF)/2, origin='lower') + plt.xlabel('Frequency [Normalized Hz]') + plt.ylabel('Cyclic Frequency [Normalized Hz]') + plt.show() + +Een andere grote wijziging is dat we voor geconjugeerde SCF alpha's tussen -1 en +1 willen berekenen, terwijl we bij normale SCF door symmetrie vaak 0.0 tot 0.5 gebruikten. Zodra we voorbeeldsignalen bekijken, wordt duidelijk waarom. + +Waarom is de geconjugeerde SCF belangrijk? Om dat te laten zien bekijken we de geconjugeerde SCF van ons basisvoorbeeld: rechthoekig BPSK met 20 samples per symbool (cyclische frequentie 0.05 Hz) en 0.2 Hz frequentie-offset: + +.. image:: ../_images/scf_conj_rect_bpsk.svg + :align: center + :target: ../_images/scf_conj_rect_bpsk.svg + :alt: Geconjugeerde SCF van rechthoekig BPSK met de Frequency Smoothing Method (FSM) + +De kern uit deze sectie: in de geconjugeerde SCF krijg je pieken op de cyclische frequentie +/- **tweemaal** de carrier-frequency-offset, die we :math:`f_c` noemen. Op de frequentie-as liggen ze rond 0 Hz in plaats van rond :math:`f_c`. Met onze offset van 0.2 Hz krijg je dus pieken op 0.4 Hz +/- de cyclische frequentie van 0.05 Hz. Onthoud vooral dat je in de geconjugeerde SCF pieken verwacht op: + +.. math:: + 2f_c \pm \alpha + +Laten we nu naar pulse-shaped BPSK kijken met dezelfde 0.2 Hz offset, 20 samples per symbool en 0.3 roll-off: + +.. image:: ../_images/scf_conj_pulseshaped_bpsk.svg + :align: center + :target: ../_images/scf_conj_pulseshaped_bpsk.svg + :alt: Geconjugeerde SCF van raised-cosine pulse-shaped BPSK met de Frequency Smoothing Method (FSM) + +Dit is logisch gezien het normale SCF-patroon dat we voor BPSK zagen. + +Nu het interessante deel: de geconjugeerde SCF van rechthoekig QPSK met dezelfde 0.2 Hz en 20 samples per symbool: + +.. image:: ../_images/scf_conj_rect_qpsk.svg + :align: center + :target: ../_images/scf_conj_rect_qpsk.svg + :alt: Geconjugeerde SCF van rechthoekig QPSK met de Frequency Smoothing Method (FSM) + +Op het eerste gezicht lijkt dit misschien op een bug in de code, maar kijk naar de colorbar: die geeft aan welke waarden bij welke kleuren horen. Bij :code:`plt.imshow()` met automatische schaal worden kleuren (hier paars tot geel) altijd geschaald van minimum tot maximum van de 2D-array. Bij de geconjugeerde SCF van QPSK is de volledige output relatief laag, omdat *er bij QPSK geen duidelijke pieken in de geconjugeerde SCF zitten*. Hieronder dezelfde QPSK-output met schaalinstelling zoals in de eerdere BPSK-voorbeelden: + +.. image:: ../_images/scf_conj_rect_qpsk_scaled.svg + :align: center + :target: ../_images/scf_conj_rect_qpsk_scaled.svg + :alt: Geconjugeerde SCF van rechthoekig QPSK met de Frequency Smoothing Method (FSM), met schaalinstelling + +Let op het bereik van de colorbar. + +De geconjugeerde SCF voor QPSK, en ook voor hogere-orde PSK en QAM, is in essentie nul/ruis. Dat betekent dat we de geconjugeerde SCF kunnen gebruiken om de aanwezigheid van BPSK te detecteren (bijvoorbeeld de chipping-sequentie in DSSS), zelfs als er veel overlappende QPSK/QAM-signalen aanwezig zijn. Dit is een zeer krachtig hulpmiddel in de CSP-gereedschapskist. + +Laten we de geconjugeerde SCF draaien op het drie-signalen-scenario dat we eerder meerdere keren gebruikten, met de volgende signalen: + +* Signaal 1: rechthoekig BPSK met 20 samples per symbool en 0.2 Hz frequentie-offset +* Signaal 2: pulse-shaped BPSK met 20 samples per symbool, -0.1 Hz frequentie-offset en 0.35 roll-off +* Signaal 3: pulse-shaped QPSK met 4 samples per symbool, 0.2 Hz frequentie-offset en 0.21 roll-off + +.. image:: ../_images/scf_conj_multiple_signals.svg + :align: center + :target: ../_images/scf_conj_multiple_signals.svg + :alt: Geconjugeerde SCF van drie verschillende signalen met de Frequency Smoothing Method (FSM) + +Merk op dat we de twee BPSK-signalen zien, terwijl het QPSK-signaal niet zichtbaar is; anders zouden we een piek op alpha = 0.65 en 0.15 Hz zien. Zonder inzoomen is dat soms lastig, maar er zijn pieken op 0.4 +/- 0.05 Hz en -0.2 +/- 0.05 Hz. + +******************************** +FFT-accumulatiemethode (FAM) +******************************** + +De eerder besproken FSM- en TSM-technieken werken uitstekend, vooral als je een specifieke set cyclische frequenties wilt berekenen (beide implementaties hebben een buitenste lus over cyclische frequentie). Er is echter een nog efficientere SCF-implementatie: de FFT Accumulation Method (FAM), die direct de volledige set cyclische frequenties berekent (dus de frequenties die horen bij alle gehele verschuivingen van het signaal; het aantal hangt af van de signaallengte). Een vergelijkbare techniek is de `Strip Spectral Correlation Analyzer (SSCA) `_, die ook alle cyclische frequenties tegelijk berekent, maar om herhaling te vermijden hier niet wordt behandeld. Deze klasse technieken wordt soms "blind estimators" genoemd, omdat ze vaak worden gebruikt wanneer vooraf geen kennis van cyclische frequenties beschikbaar is. De FAM is een tijd-smoothingmethode (zie het als geavanceerde TSM), terwijl SSCA te vergelijken is met geavanceerde FSM. + +De minimale Python-code voor FAM is eigenlijk vrij compact, al is de koppeling met de wiskunde minder direct omdat we niet meer over alpha itereren. Net als bij TSM splitsen we het signaal op in tijdvensters met overlap. Op elk sampleblok passen we een Hanning-venster toe. In het FAM-algoritme zitten twee FFT-stappen; de eerste gebeurt op een 2D-array, dus veel FFT's worden in een regel uitgevoerd. Na een frequentieverschuiving voeren we een tweede FFT uit om de SCF op te bouwen (daarna nemen we de magnitude in het kwadraat). Voor meer detail zie de externe bronnen onderaan deze sectie. + +.. mermaid:: + + flowchart TD + A[Input samples] --> B[Opsplitsen in overlappende vensters] + B --> C[Hanning venster toepassen] + C --> D[Eerste FFT over elk venster] + D --> E[Frequentieverschuiving] + E --> F[Tweede FFT] + F --> G[Magnitude in het kwadraat nemen] + G --> H[SCF benadering] + + +.. code-block:: python + + N = 2**14 + x = samples[0:N] + Np = 512 # Number of input channels, should be power of 2 + L = Np//4 # Offset between points in the same column at consecutive rows in the same channelization matrix. It should be chosen to be less than or equal to Np/4 + num_windows = (len(x) - Np) // L + 1 + Pe = int(np.floor(int(np.log(num_windows)/np.log(2)))) + P = 2**Pe + N = L*P + + # channelization + xs = np.zeros((num_windows, Np), dtype=complex) + for i in range(num_windows): + xs[i,:] = x[i*L:i*L+Np] + xs2 = xs[0:P,:] + + # windowing + xw = xs2 * np.tile(np.hanning(Np), (P,1)) + + # first FFT + XF1 = np.fft.fftshift(np.fft.fft(xw)) + + # freq shift down + f = np.arange(Np)/float(Np) - 0.5 + f = np.tile(f, (P, 1)) + t = np.arange(P)*L + t = t.reshape(-1,1) # make it a column vector + t = np.tile(t, (1, Np)) + XD = XF1 * np.exp(-2j*np.pi*f*t) + + # main calcs + SCF = np.zeros((2*N, Np)) + Mp = N//Np//2 + for k in range(Np): + for l in range(Np): + XF2 = np.fft.fftshift(np.fft.fft(XD[:,k]*np.conj(XD[:,l]))) # second FFT + i = (k + l) // 2 + a = int(((k - l) / Np + 1) * N) + SCF[a-Mp:a+Mp, i] = np.abs(XF2[(P//2-Mp):(P//2+Mp)])**2 + +.. image:: ../_images/scf_fam.svg + :align: center + :target: ../_images/scf_fam.svg + :alt: SCF met de FFT-accumulatiemethode (FAM), cyclostationaire signaalverwerking + +Laten we inzoomen op het interessante gebied rond 0.2 Hz en lage cyclische frequenties voor meer detail: + +.. image:: ../_images/scf_fam_zoomedin.svg + :align: center + :target: ../_images/scf_fam_zoomedin.svg + :alt: Ingezoomde SCF met de FFT-accumulatiemethode (FAM), cyclostationaire signaalverwerking + +Er is een duidelijke hotspot op 0.05 Hz en een zwakkere op 0.1 Hz die met deze kleurenschaal lastig te zien kan zijn. + +We kunnen de RF-frequentie-as ook samendrukken en de SCF in 1D plotten om makkelijker te zien welke cyclische frequenties aanwezig zijn: + +.. image:: ../_images/scf_fam_1d.svg + :align: center + :target: ../_images/scf_fam_1d.svg + :alt: Plot van cyclische frequentie met de FFT-accumulatiemethode (FAM), cyclostationaire signaalverwerking + +Een belangrijke valkuil van FAM is dat het, afhankelijk van je signaallengte, een enorm aantal pixels kan opleveren. Als slechts een of twee rijen in :code:`imshow()` de energie bevatten, kunnen die door de schaalinstelling op je scherm deels gemaskeerd worden. Let daarom op de afmeting van de 2D-SCF-matrix. Wil je minder pixels op de cyclische-frequentie-as, gebruik dan max pooling of mean pooling. Zet onderstaande code na de SCF-berekening en voor het plotten (mogelijk moet je :code:`pip install scikit-image` uitvoeren): + +.. code-block:: python + + # Max pooling in cyclic domain + import skimage.measure + print("Old shape of SCF:", SCF.shape) + SCF = skimage.measure.block_reduce(SCF, block_size=(16, 1), func=np.max) # type: ignore + print("New shape of SCF:", SCF.shape) + +Externe bronnen over FAM: + +* R.S. Roberts, W. A. Brown, and H. H. Loomis, Jr., "Computationally Efficient Algorithms for Cyclic Spectral Analysis," IEEE Signal Processing Magazine, April 1991, pp. 38-49. `Hier beschikbaar `_ +* Da Costa, Evandro Luiz. Detection and identification of cyclostationary signals. Diss. Naval Postgraduate School, 1996. `Hier beschikbaar `_ +* Chad's blog post on FAM: https://cyclostationary.blog/2018/06/01/csp-estimators-the-fft-accumulation-method/ + +******************************** +OFDM +******************************** + +Cyclostationariteit is extra sterk in OFDM-signalen door het gebruik van een cyclic prefix (CP), waarbij de laatste samples van elk OFDM-symbool worden gekopieerd en vooraan toegevoegd. Dat levert een sterke cyclische frequentie op die hoort bij de OFDM-symboollengte (de inverse van de subcarrier spacing plus de CP-duur). + +Laten we met een OFDM-signaal experimenteren. Hieronder staat een simulatie van OFDM met CP, 64 subcarriers, 25% CP en QPSK-modulatie op elke subcarrier. We interpoleren 2x om een realistische sample rate te simuleren, waardoor de OFDM-symboollengte in samples (64 + (64*0.25)) * 2 = 160 wordt. Dan verwachten we pieken op alpha's die gehele veelvouden van 1/160 zijn: 0.00625, 0.0125, 0.01875, enzovoort. We simuleren 200k samples, wat overeenkomt met 1250 OFDM-symbolen (elk OFDM-symbool is relatief lang). + +.. code-block:: python + + from scipy.signal import resample + N = 200000 # number of samples to simulate + num_subcarriers = 64 + cp_len = num_subcarriers // 4 # length of the cyclic prefix in symbols, in this case 25% of the starting OFDM symbol + print("CP length in samples", cp_len*2) # remember there is 2x interpolation at the end + print("OFDM symbol length in samples", (num_subcarriers+cp_len)*2) # remember there is 2x interpolation at the end + num_symbols = int(np.floor(N/(num_subcarriers+cp_len))) // 2 # remember the interpolate by 2 + print("Number of OFDM symbols:", num_symbols) + + qpsk_mapping = { + (0,0) : 1+1j, + (0,1) : 1-1j, + (1,0) : -1+1j, + (1,1) : -1-1j, + } + bits_per_symbol = 2 + + samples = np.empty(0, dtype=np.complex64) + for _ in range(num_symbols): + data = np.random.binomial(1, 0.5, num_subcarriers*bits_per_symbol) # 1's and 0's + data = data.reshape((num_subcarriers, bits_per_symbol)) # group into subcarriers + symbol_freq = np.array([qpsk_mapping[tuple(b)] for b in data]) # remember we start in the freq domain with OFDM + symbol_time = np.fft.ifft(symbol_freq) + symbol_time = np.hstack([symbol_time[-cp_len:], symbol_time]) # take the last CP samples and stick them at the start of the symbol + samples = np.concatenate((samples, symbol_time)) # add symbol to samples buffer + + samples = resample(samples, len(samples)*2) # interpolate by 2x + samples = samples[:N] # clip off the few extra samples + + # Add noise + SNR_dB = 5 + n = np.sqrt(np.var(samples) * 10**(-SNR_dB/10) / 2) * (np.random.randn(N) + 1j*np.random.randn(N)) + samples = samples + n + +Omdat we pieken verwachten op 0.00625, 0.0125 en 0.01875, gebruiken we een cyclische-frequentieresolutie van 1e-5 zodat dit op nette veelvouden uitkomt. Als zo'n fijne resolutie onpraktisch is of cyclische frequenties onbekend zijn, kun je oversampling gebruiken (bijvoorbeeld meer samples per symbool; hier factor 2). Binnen de FSM-aanpak verwerken we dan minstens :code:`2 / alpha_resolution` samples, dus 200k samples. Hieronder staan resultaten met :code:`alphas = np.arange(0, 0.02, 1e-5)` en max pooling actief: + +.. image:: ../_images/scf_freq_smoothing_ofdm_zoomed_in.svg + :align: center + :target: ../_images/scf_freq_smoothing_ofdm_zoomed_in.svg + :alt: SCF van OFDM met de Frequency Smoothing Method (FSM) + +Let op de drie pieken; die worden nog duidelijker als je de RF-frequentie-as comprimeert en cyclische frequentie in 1D plot. + +Externe bronnen over OFDM binnen CSP: + +#. Sutton, Paul D., Keith E. Nolan, and Linda E. Doyle. "Cyclostationary signatures in practical cognitive radio applications." IEEE Journal on selected areas in Communications 26.1 (2008): 13-24. `Hier beschikbaar `_ + +******************************************** +Signaaldetectie met Bekende Cyclische Frequentie +******************************************** + +In sommige toepassingen wil je CSP gebruiken om een al bekend signaal of golfvorm te detecteren, zoals varianten van 802.11, LTE of 5G. Als je de cyclische frequentie van het signaal kent en je sample rate bekend is, hoef je in principe maar een enkele alpha en tau te berekenen. Een voorbeeld van dit type probleem met een RF-opname van WiFi volgt binnenkort. diff --git a/content-nl/detection.rst b/content-nl/detection.rst new file mode 100644 index 00000000..c92f3c84 --- /dev/null +++ b/content-nl/detection.rst @@ -0,0 +1,1107 @@ +.. _detection-chapter: + +##################################################### +Detectie met Correlatie +##################################################### + +.. raw:: html + + Mede-auteur: Sam Brown + +In dit hoofdstuk leren we hoe we de aanwezigheid van signalen kunnen detecteren en hun timing terug kunnen vinden door ontvangen samples kruis te correleren met een voor ons bekend deel van het signaal, zoals de preamble van een pakket. Deze methode leidt van nature tot een eenvoudige vorm van classificatie met een rij correlators. We introduceren de basisconcepten van signaaldetectie, met focus op de beslissing of een specifiek signaal wel of niet aanwezig is in een ruisachtige omgeving. Daarbij behandelen we zowel de theoretische basis als praktische technieken om onder onzekerheid zo goed mogelijk te beslissen. + +**************************************************** +Basis van Signaaldetectie en Correlators +**************************************************** + +Signaaldetectie is de taak waarbij wordt besloten of een waargenomen energiepiek een betekenisvol signaal is of alleen achtergrondruis. + +De Uitdaging: In systemen zoals radar of sonar is ruis overal aanwezig. Als de detector te gevoelig is, krijg je "valse alarmen". Is hij niet gevoelig genoeg, dan "mist" hij het echte doel. + +De oplossing begint met de Neyman-Pearson-detector, die een wiskundige "sweet spot" geeft: maximale kans op detectie bij een strikt begrensde kans op vals alarm. CFAR-detectors (CFAR: Constant False Alarm Rate) bouwen hierop voort door adaptief te reageren op veranderingen in het ruisniveau. Meer specifiek worden CFAR-detectors gebruikt wanneer de ruisstatistiek niet stationair is, dus wanneer ruisvloer en ruisverdeling veranderen door interferentie en veranderende kanaalomstandigheden. Het doel is om de detectiedrempel automatisch mee te laten bewegen met de achtergrondruis, zodat een gewenste vals-alarmkans behouden blijft. Dat vereist een continue schatting van de ruisvloer. + +Zodra een systeem weet dat er iets aanwezig is, moet het precies bepalen waar de data start. Digitale pakketten in LTE, 5G en wifi beginnen met een "preamble": een bekend en herhaald patroon. Een preamble-correlator werkt als een "slot-en-sleutel"-mechanisme, waarbij de sleutel een symboolreeks is die de ontvanger kent en die uniek is voor het te herstellen signaal. Door een kopie van die preamble over het inkomende signaal te schuiven en op elke vertraging een inwendig product te nemen, meet de ontvanger de overeenkomst tussen sjabloon en ontvangen reeks. Als beide bijna perfect uitlijnen, ontstaat een scherpe piek die exact aangeeft waar de data begint. Geavanceerde varianten houden ook rekening met frequentie-offset door afstemverschillen of Doppler-verschuiving. + +Wanneer een bekend signaal (de preamble) over een kanaal met alleen Additive White Gaussian Noise (AWGN) wordt verzonden, is de taak simpel: beslissen of het signaal aanwezig is. Dit is het eenvoudigste, maar ook meest fundamentele detectieprobleem. + +De Kruiscorrelatiefunctie +############################### + +Een correlator in de eenvoudigste vorm is gewoon een kruiscorrelatie tussen een ontvangen signaal en een sjabloon van wat je zoekt. Kruiscorrelatie is een inwendig product tussen twee vectoren terwijl één vector over de andere schuift. Als je convolutie kent: het is bijna hetzelfde, behalve dat je de tweede vector niet omkeert, dus net iets eenvoudiger. Voor complexe signalen, waar we hier mee werken, neem je ook de complex geconjugeerde van één ingang. In Python kan dat zo: + +.. code-block:: python + + def correlate(a, v): + n = len(a) + m = len(v) + result = [] + for i in range(n - m + 1): + s = 0 + for j in range(m): + s += a[i + j] * v[j].conjugate() + result.append(s) + return result + + # Voorbeeldgebruik: + a = [1+2j, 2+1j, 3+0j, 4-1j, 5-2j] + v = [0+1j, 1+0j, 0.5-0.5j] + correlate(a, v) + +Let op hoe :code:`a` schuift en :code:`v` complex geconjugeerd wordt, en hoe de loop met :code:`j` en :code:`s` in feite gewoon een inwendig vector-product is. Gelukkig hoeven we kruiscorrelatie niet zelf van nul te implementeren: in Python kunnen we NumPy's :code:`correlate` gebruiken (er is ook een SciPy-variant). + +Python-voorbeeld van een Kruiscorrelatie +######################################################## + +Om een basisvoorbeeld van een correlator in Python te maken, bouwen we eerst een voorbeeldsignaal met een bekende preamble in ruis. We gebruiken een Zadoff-Chu-sequentie als bekende preamble vanwege de uitstekende autocorrelatie-eigenschappen en het veelvuldige gebruik in communicatiesystemen. We negeren hier de rest van de payload-data, al volgt in echte systemen na de preamble meestal onbekende data. Een Zadoff-Chu-sequentie genereren we zo: + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + N = 839 # Length of Zadoff-Chu sequence + u = 25 # Root of ZC sequence + t = np.arange(N) + zadoff_chu = np.exp(-1j * np.pi * u * t * (t + 1) / N) + +De resulterende sequentie *is* een signaal: de IQ-samples van :code:`zadoff_chu` vormen een complex basisbandsignaal zoals we vaak in dit boek zien, alleen encodeert het hier geen bits. We kunnen een realistischer scenario nabootsen door dit Zadoff-Chu-signaal op een willekeurige offset in een langere AWGN-stroom te plaatsen: + +.. code-block:: python + + signal_length = 10 * N # overall simulated signal length + offset = np.random.randint(N, signal_length - N) + print(f"True offset: {offset}") + snr_db = -15 + noise_power = 1 / (2 * (10**(snr_db / 10))) + signal = np.sqrt(noise_power/2) * (np.random.randn(signal_length) + 1j * np.random.randn(signal_length)) + signal[offset:offset+N] += zadoff_chu # place our ZC signal at the random offset + +Let op dat we hier een *zeer* lage SNR gebruiken. Die is zo laag dat je de Zadoff-Chu-sequentie in het tijdsdomein helemaal niet terugziet. De sequentie is 839 samples lang op ongeveer 8000 gesimuleerde samples, en zit zo diep in de ruis dat je zelfs geen kleine toename in signaalamplitude ziet. + +.. image:: ../_images/detection_basic_1.svg + :align: center + :target: ../_images/detection_basic_1.svg + :alt: Time Domain Signal with Zadoff-Chu Sequence + +Nu kunnen we de correlator implementeren door een kruiscorrelatie uit te voeren tussen het ontvangen signaal en onze bekende Zadoff-Chu-sequentie met :code:`np.correlate()`. Dit veronderstelt dat de ontvanger de exacte preamble kent. :code:`zadoff_chu` werd eerst gebruikt om het scenario te simuleren, maar fungeert nu ook als sjabloon dat de ontvanger in de correlator gebruikt. In Python kan dit in één regel: + +.. code-block:: python + + correlation = np.correlate(signal, zadoff_chu, mode='valid') + +De :code:`valid`-modus lichten we zo toe. We normaliseren de uitgang ook met de sequentielengte en nemen de magnitude in het kwadraat om vermogen te krijgen. Je kunt ook alleen de magnitude nemen; dat werkt meestal ook. Het belangrijkste blijft de :code:`np.correlate()`-operatie. + +.. code-block:: python + + correlation = np.abs(correlation / N)**2 # normalize by N, and take magnitude squared + +Hieronder plotten we de magnitude in het kwadraat en markeren we de echte startpositie van de sequentie om te zien of de correlator die vindt: + +.. image:: ../_images/detection_basic_2.svg + :align: center + :target: ../_images/detection_basic_2.svg + :alt: Correlator Output + +Ondanks de zeer lage SNR zien we een duidelijke piek in de correlator-uitgang precies waar de Zadoff-Chu-sequentie is geplaatst. Dat is de *start* van de sequentie: de 839 samples vanaf die piek bevatten het patroon. Dit laat de kracht van correlatiegebaseerde detectie zien, zeker in combinatie met een lange preamble. We hebben nog geen expliciete drempel ingesteld om te beslissen of de piek een echt signaal of ruis is; we inspecteren nu visueel. Voor automatische detectie is een drempel nodig. De rest van dit hoofdstuk gaat grotendeels over hoe je die drempel goed kiest, vooral wanneer ruisvloer en interferentie continu veranderen. + +Modi: Valid, Same en Full +####################################### + +Je hebt misschien gezien dat :code:`np.correlate()` en :code:`np.convolve()` drie modi hebben: :code:`valid`, :code:`same` en :code:`full`. Die bepalen de lengte van de output-array ten opzichte van de inputs. In ons geval gebruikten we :code:`valid`, wat betekent dat alleen punten worden teruggegeven waar beide arrays volledig overlappen. De outputlengte wordt dan :code:`len(signal) - len(zadoff_chu) + 1`. Met :code:`same` krijg je een output met dezelfde lengte als het (langste) ingangssignaal. Met :code:`full` krijg je de volledige lineaire discrete convolutie, met een iets langere output van lengte :code:`max(M, N) - min(M, N) + 1`, waarbij :code:`M` en :code:`N` de lengtes van beide arrays zijn. In veel RF-signaalbewerking gebruiken we convolutie om een FIR-filter toe te passen, en dan is :code:`same` handig omdat input en output even lang blijven. Voor correlatiegebaseerde detectie willen we meestal :code:`valid`, omdat vooral de posities interessant zijn waar de preamble volledig overlapt met het ontvangen signaal. + +De Neyman-Pearson-detector +############################ + +De gouden standaard voor het kiezen van een goede drempel voor correlatoruitgang is de Neyman-Pearson-detector. Deze theorie helpt een optimale beslissing nemen onder een specifieke randvoorwaarde: maximaliseer de detectiekans, :math:`P_{D}`, bij een vaste en acceptabele vals-alarmkans, :math:`P_{FA}`. Simpel gezegd: jij kiest hoeveel valse detecties je maximaal accepteert (bijvoorbeeld één per uur), en Neyman-Pearson geeft de beste drempel om zoveel mogelijk echte signalen te vinden. Voor detectie van een bekende preamble in AWGN is de aanpak eenvoudig: bereken een correlatiewaarde tussen het ontvangen signaal en een bekend preamble-patroon. Overschrijdt die waarde de drempel :math:`\tau`, dan verklaar je het signaal aanwezig; anders ga je ervan uit dat er alleen ruis is. + +De prestatie van deze detector, gemeten met :math:`P_{D}` en :math:`P_{FA}`, hangt af van de drempel :math:`\tau`, de SNR en de preamblelengte :math:`L`. De vals-alarmkans is een functie van de drempel en ruisvariantie :math:`\sigma_n^2`: + +:math:`P_{FA} = Q\left(\frac{\tau}{\sigma_n}\right)` + +De detectiekans is een functie van drempel, ruisvariantie en preamble-energie (:math:`E_s = L \cdot S`, met :math:`S` als gemiddeld symboolvermogen): + +:math:`P_{D} = Q\left(\frac{\tau - \sqrt{E_s}}{\sigma_n}\right) = Q\left(\frac{\tau - \sqrt{L \cdot S}}{\sigma_n}\right)` + +Hier is :math:`Q(x)` de Q-functie (staartkans van de standaardnormale verdeling), oftewel de kans dat een standaardnormale variabele groter is dan :math:`x`. + +Prestatie-analyse: ROC-curves en Pd-vs-SNR-curves +################################################################# + +Om te kwantificeren hoe goed een correlatie-detector presteert in ruis, gebruiken engineers twee hoofdvisualisaties: de Receiver Operating Characteristic (ROC)-curve en de Probability of Detection (:math:`P_{d}`)-tegen-SNR-curve. + +De ROC-curve zet :math:`P_{d}` uit tegen :math:`P_{fa}` bij vaste SNR. Door de detectiedrempel op de correlatoruitgang te variëren kies je een punt op deze curve; het blijft een afweging. Een lagere drempel verhoogt :math:`P_{d}` (meer signalen gevonden), maar ook :math:`P_{fa}` (meer ruis-triggers). Hoe sterker de curve naar linksboven buigt, hoe beter de detector. Een perfecte detector zit linksboven (100% :math:`P_{d}`, 0% :math:`P_{fa}`), terwijl een diagonaal overeenkomt met gokken. + +.. image:: ../_images/detection_pd_vs_snr.svg + :align: center + :target: ../_images/detection_pd_vs_snr.svg + :alt: Pd vs SNR Curve and ROC curve + +Uit de vergelijkingen (en intuïtie) volgt dat preamblelengte :math:`L` een cruciale ontwerpparameter is, omdat die direct de processing gain en daarmee de detectieprestatie bepaalt. Bij vaste drempel en SNR groeit :math:`P_{D}` met :math:`L`. Een langere preamble verzamelt meer signaalenergie, waardoor scheiding tussen signaal en achtergrondruis eenvoudiger wordt. Deze prestatieverbetering heet "processing gain" en wordt vaak in dB uitgedrukt als :math:`10\log_{10}(L)`. Dit is essentieel voor zwakke signalen die anders gemist worden. Door energie over meer samples te integreren kun je signalen detecteren die onder de ruisvloer liggen. + + +***************************************************** +Voorbeeld: GPS-signalen detecteren onder de ruisvloer +***************************************************** + +Korte introductie tot GPS-signalen +################################## + +In maart 2026 waren er 31 operationele satellieten in de Amerikaanse GPS-constellatie. Ze vliegen in medium Earth orbit (MEO) rond de aarde en doen ongeveer twee omwentelingen per dag. Alle satellieten zenden een signaal uit rond 1575.42 MHz (L1); dit signaal staat continu aan en gebruikt voor alle satellieten dezelfde draagfrequentie. Tegen de tijd dat het signaal het aardoppervlak bereikt is het extreem zwak, ruim onder de ruisvloer. Orthogonaliteit tussen satellieten wordt bereikt doordat elke satelliet een unieke PRN-code (pseudo-random noise) van 1023 chips krijgt, de C/A-code. Daarom zie je dit signaal ook vaak als "L1 C/A". Deze C/A-codes zijn Gold-codes en zo ontworpen dat twee verschillende codes vrijwel orthogonaal zijn; correleer je twee verschillende satellietcodes met elkaar, dan krijg je bijna nul. De C/A-code loopt op 1.023 miljoen chips per seconde en is 1023 chips lang, dus herhaalt exact elke 1 ms. Boven op die herhalende code moduleert elke satelliet langzaam navigatiedata (baaninformatie, klokcorrecties, enz.) met slechts 50 bits/s, waardoor een databit 20 volledige coderepetities beslaat. Dit principe van een andere code per zender heet CDMA (Code Division Multiple Access), hetzelfde idee als achter 3G. + +Aan de ontvangerkant gebruikt de ontvanger, om een van de 31 satellieten te vinden, de code van die satelliet en genereert lokaal een kopie van de PRN-sequentie. Vervolgens gebruikt hij een correlator om het begin van de sequentie te vinden, vergelijkbaar met het begin van een pakket/frame, al zendt GPS in de praktijk continu uit. De exacte correlatiepiek wordt ook gebruikt om te bepalen hoe ver het signaal heeft afgelegd voor het de ontvanger bereikt. Als je dit voor 4 of meer satellieten doet, kan de ontvanger via trilateratie zijn positie op aarde bepalen. Omdat satellieten zo snel bewegen (ongeveer 4 km/s relatief), is er bovendien aanzienlijke Dopplerverschuiving. Daarom moet de ontvanger ook over een raster van mogelijke frequentie-offsets zoeken naar de beste correlatiepiek, feitelijk een 2D-zoekprobleem. De maximale Dopplerverschuiving is ongeveer +/-20 kHz (:code:`4e3 / 3e8 * 1.575e9`). Dit proces herhaalt elke 1 ms, al houdt de ontvanger de tijdsverschillen en Dopplerverschuiving daarna bij zodat niet telkens een volledige zoekactie nodig is. Het eerste vinden van een satelliet heet "acquisition", en het daarna volgen van het signaal heet "tracking". Acquisition is rekenintensiever en kan minuten duren bij een "cold start", wanneer de ontvanger nog geen informatie heeft over zichtbare satellieten, hun Doppler of de eigen locatie. + +Correlatie-aanpak +################# + +We kruiscorreleren het binnenkomende signaal (hier: een L1-opname) met een lokaal gegenereerde replica van de code van elke satelliet. Een grote correlatiepiek betekent dat die satelliet zichtbaar is en geeft de start van de 1 ms codeperiode. Om ook over frequentie te zoeken en Doppler mee te nemen, gebruiken we een FFT en voeren we de correlatie uit in het frequentiedomein. Daardoor kunnen we efficient meerdere frequentie-offsets testen door de FFT-bins van de lokale codereplica te verschuiven. Tot slot accumuleren we vermogen (correlatiemagnitude in het kwadraat) over meerdere 1 ms-blokken om de SNR te verbeteren. Dat heet non-coherente integratie en helpt om GPS-signalen onder de ruisvloer te detecteren. In het tijddomein zoeken we de pieken in de correlatie-uitgang gedeeld door het gemiddelde correlatievermogen over alle delays, als normalisatie. + +Voorbeeldopname +############### + +We gebruiken een voorbeeldopname van GPS van Daniel Estevez, die je `hier kunt downloaden `_. Het bestand is complex float32 met 4 MHz samplerate en gecentreerd op 1575.42 MHz. + +Hieronder zie je het spectrogram van de opname; er is niet veel zichtbaar. De verticale lijn is niet het GPS-signaal zelf, maar waarschijnlijk smalbandige interferentie. De werkelijke GPS L1-signalen gebruiken een chiprate van 1.023 MHz met daarbovenop een signaal met zeer lag datarate, waardoor de totale signaalbandbreedte ongeveer 2 MHz is. Dat zie je hier nauwelijks terug in het spectrogram. Dit is een goed voorbeeld van hoe GPS-signalen ruim onder de ruisvloer binnenkomen en waarom correlatiegebaseerde detectie noodzakelijk is. + +.. image:: ../_images/detection_gps_spectrogram.svg + :align: center + :target: ../_images/detection_gps_spectrogram.svg + :alt: Spectrogram van GPS L1-opname + +Voor wie verder wil kijken: deze opname is een klein deel van een veel groter bestand op `IQEngine `_, onder :code:`estevez/GPS and other GNSS`, met opname :code:`GPS-L1-2022-03-27`. Op IQEngine staat die als int16 in SigMF-formaat. + +Python-voorbeeld +################ + +Pas :code:`filename` aan naar de locatie waar je het IQ-bestand hebt opgeslagen. Let op dat :code:`num_integrations` bepaalt hoeveel van de IQ-opname wordt ingelezen en verwerkt: die waarde maal 1 ms (bij deze korte opname is 10 de maximale waarde). + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + + filename = "GPS_L1_recording_10ms_4MHz_cf32.iq" + sample_rate = 4e6 + chip_rate = 1023000 # chips / sec (part of the GPS spec) + num_chips = 1023 # chips per C/A code period + samples_per_code = int(round(sample_rate / chip_rate * num_chips)) # Exact number of samples in one 1 ms code period at 4 MHz + doppler_min_hz = -5e3 # GPS Doppler ≈ ±4 kHz for stationary receiver + doppler_max_hz = 5e3 + doppler_step_hz = 500 # good enough for a coarse search + num_integrations = 10 # non-coherent power integrations (so 10 ms total), determines how much of the IQ recording we read in and process! + detection_thresh_dB = 14.0 # Peak-to-mean ratio (PMR) threshold in dB to declare a detection, GPS C/A signals are typically 14–20 dB PMR above threshold with 10ms of integration + gps_svs = list(range(1, 33)) # 1–32 + + ##### C/A Code Generation ##### + # The GPS C/A code is a Gold code formed by XOR-ing two 10-stage maximal-length + # shift registers (G1 and G2). G2 is effectively delayed by a satellite- + # specific number of chips before the XOR + # Reference: IS-GPS-200, Table 3-Ia + G2_DELAY = [ # G2 phase delay (chips) for gps_svs 1–32 + 5, 6, 7, 8, 17, 18, 139, 140, # 1– 8 + 141, 251, 252, 254, 255, 256, 257, 258, # 9–16 + 469, 470, 471, 472, 473, 474, 509, 512, # 17–24 + 513, 514, 515, 516, 859, 860, 861, 862, # 25–32 + ] + + """G1 LFSR: polynomial x^10 + x^3 + 1, all-ones init, output at stage 10.""" + reg = np.ones(10, dtype=np.int8) + G1 = np.empty(num_chips, dtype=np.int8) + for i in range(num_chips): + G1[i] = reg[9] + fb = reg[2] ^ reg[9] # stages 3 and 10 (0-indexed: 2 and 9) + reg = np.roll(reg, 1) + reg[0] = fb + + """G2 LFSR: polynomial x^10+x^9+x^8+x^6+x^3+x^2+1, all-ones init.""" + reg = np.ones(10, dtype=np.int8) + G2 = np.empty(num_chips, dtype=np.int8) + for i in range(num_chips): + G2[i] = reg[9] + fb = reg[1]^reg[2]^reg[5]^reg[7]^reg[8]^reg[9] # taps 2,3,6,8,9,10 + reg = np.roll(reg, 1) + reg[0] = fb + + # 1023-chip C/A PRN code for SV sv (1-32) as float32, 1's and -1's, so BPSK + def make_prn(sv: int) -> np.ndarray: + g2_delayed = np.roll(G2, G2_DELAY[sv - 1]) + bits = G1 ^ g2_delayed # {0, 1} + return (1 - 2 * bits).astype(np.float32) # BPSK: {+1, −1} + + def upsample_prn(sv: int) -> np.ndarray: + """Nearest-neighbour upsample 1023-chip C/A code → samples_per_code samples.""" + code = make_prn(sv) + idx = (np.arange(samples_per_code) * num_chips / samples_per_code).astype(int) + return code[idx] + + # Pre-compute template signals - conjugate FFTs of all upsampled PRN codes + template_signals = {sv: np.conj(np.fft.fft(upsample_prn(sv))) for sv in gps_svs} + + # Read in IQ file + n_needed = samples_per_code * num_integrations + iq = np.fromfile(filename, dtype=np.complex64, count=n_needed) + # For the full version from IQEngine use the following instead + #iq = np.fromfile(filename, dtype=np.int16, count=n_needed * 2) + #iq = (iq[0::2] + 1j * iq[1::2]).astype(np.complex64) + + # Loop through satellites performing acquisition + results = [] + detected = [] + print(f" {'SV':>3} {'Doppler (Hz)':>13} {'Phase (chips)':>14}" + f" {'Phase (samp)':>13} {'Delay (µs)':>11} {'PMR (dB)':>9}") + doppler_bins = np.arange(doppler_min_hz, doppler_max_hz + doppler_step_hz, doppler_step_hz) + for sv in gps_svs: + corr_map = np.zeros((len(doppler_bins), samples_per_code)) + n_total = samples_per_code * num_integrations + for di, f_d in enumerate(doppler_bins): + t = np.arange(n_total) / sample_rate # time vector + mixed = iq[:n_total] * np.exp(-2j*np.pi*float(f_d)*t) # freq shift + + # Non-coherent integration: accumulate squared correlation magnitude + for k in range(num_integrations): + blk = mixed[k * samples_per_code:(k + 1) * samples_per_code] + sig_fft = np.fft.fft(blk) + corr = np.fft.ifft(sig_fft * template_signals[sv]) # cross-correlation in freq domain + corr_map[di] += np.abs(corr)**2 + + # Normalize by mean and convert to dB + peak_val = float(np.max(corr_map)) + mean_val = float(np.mean(corr_map)) + pmr_db = 10.0 * np.log10(peak_val / mean_val) + + peak_idx = np.unravel_index(np.argmax(corr_map), corr_map.shape) + best_doppler_hz = float(doppler_bins[peak_idx[0]]) + best_phase_samp = int(peak_idx[1]) + best_phase_chips = best_phase_samp * num_chips / samples_per_code + + r = { + "sv": sv, + "detected": pmr_db >= detection_thresh_dB, + "doppler_hz": best_doppler_hz, + "code_phase_samp": best_phase_samp, # sample offset = "start of packet" + "code_phase_chip": best_phase_chips, + "pmr_db": pmr_db, + "corr_map": corr_map, + "doppler_bins": doppler_bins, + } + results.append(r) + + # Print row + delay_us = r['code_phase_samp'] / sample_rate * 1e6 + flag = " ← DETECTED" if r['detected'] else "" + print(f" {sv:>3} {r['doppler_hz']:>+13.0f} {r['code_phase_chip']:>14.2f}" + f" {r['code_phase_samp']:>13d} {delay_us:>11.3f} {r['pmr_db']:>9.1f}{flag}") + +Dit zou de volgende uitvoer moeten geven: + +.. code-block:: + + SV Doppler (Hz) Phase (chips) Phase (samp) Delay (µs) PMR (dB) + 1 -3000 757.79 2963 740.750 5.6 + 2 +1500 264.19 1033 258.250 9.1 + 3 -2000 316.62 1238 309.500 5.8 + 4 +5000 577.48 2258 564.500 5.0 + 5 +1000 64.96 254 63.500 5.3 + 6 +1500 511.76 2001 500.250 5.0 + 7 -4000 763.41 2985 746.250 5.0 + 8 +3500 961.62 3760 940.000 5.4 + 9 +3500 118.67 464 116.000 4.9 + 10 +0 890.52 3482 870.500 5.4 + 11 +2500 837.33 3274 818.500 14.6 ← GEDETECTEERD + 12 -500 871.60 3408 852.000 16.4 ← GEDETECTEERD + 13 +1000 137.85 539 134.750 5.9 + 14 +2500 287.72 1125 281.250 5.0 + 15 -5000 908.68 3553 888.250 5.3 + 16 +1500 292.58 1144 286.000 5.9 + 17 +500 994.61 3889 972.250 5.3 + 18 +4500 1005.61 3932 983.000 5.4 + 19 +5000 588.48 2301 575.250 5.0 + 20 +0 768.53 3005 751.250 5.4 + 21 -3000 749.60 2931 732.750 5.0 + 22 +2500 558.05 2182 545.500 14.4 ← GEDETECTEERD + 23 -5000 390.02 1525 381.250 5.3 + 24 +2500 955.48 3736 934.000 5.9 + 25 +1500 597.94 2338 584.500 15.5 ← GEDETECTEERD + 26 -1500 239.89 938 234.500 6.2 + 27 -2500 488.74 1911 477.750 4.7 + 28 +3000 858.81 3358 839.500 5.2 + 29 -4000 998.70 3905 976.250 5.2 + 30 -2000 937.58 3666 916.500 5.2 + 31 +5000 463.42 1812 453.000 15.9 ← GEDETECTEERD + 32 +1000 342.45 1339 334.750 16.2 ← GEDETECTEERD + +Zoals je ziet detecteren we 6 satellieten. Hoewel onze drempel op 14.0 staat, kun je uit de lijst vrij duidelijk afleiden dat de meeste andere satellieten niet zichtbaar waren, met mogelijk uitzondering van SV-2, die waarschijnlijk net onder de drempel bleef. Voor wie dit wil verifiëren: de opname is gemaakt op 2022-03-27T11:32:04 ergens in Spanje. + +Plotten +####### + +Laten we de resultaten van satelliet 11, de eerste die we detecteerden, plotten. De eerste plot is de 2D-correlatiekaart over Doppler en tijd/delay. De tweede plot is een doorsnede van die correlatiekaart bij de beste Doppler-bin, en toont correlatievermogen over de tijd zoals in de vorige sectie. + +.. code-block:: python + + # Plotting + sv = 11 # we detected 11, 12, 22, 25, 31, 32 although try looking at one we didnt find as well! + r = results[sv - 1] # print the dict of results for this SV to see what we got + cmap = r['corr_map'] # 2-D array of correlation power vs Doppler and code phase + d_bins = r['doppler_bins'] # Doppler bins corresponding + chips_axis = np.arange(samples_per_code) * num_chips / samples_per_code + + # 2-D Doppler × code-phase map + plt.figure(0, figsize=(10, 6)) + im = plt.pcolormesh(chips_axis, d_bins, cmap, shading='auto', cmap='viridis') + plt.xlabel("Code Phase (chips)") + plt.ylabel("Doppler (Hz)") + plt.title(f"SV {sv} — 2-D Acquisition Map (PMR = {r['pmr_db']:.1f} dB)") + plt.legend(fontsize=8, loc='upper right') + plt.colorbar(im, label="Correlation Power") + + # code-phase slice at best Doppler + best_di = int(np.argmin(np.abs(d_bins - r['doppler_hz']))) + plt.figure(1, figsize=(10, 6)) + plt.plot(chips_axis, cmap[best_di], lw=1, color='steelblue') + plt.xlabel("Code Phase (chips)") + plt.ylabel("Correlation Power") + plt.title(f"SV {sv} — Code-Phase Slice (Doppler = {r['doppler_hz']:+.0f} Hz)") + plt.legend(fontsize=8) + plt.grid(True, alpha=0.3) + + plt.show() + +.. image:: ../_images/detection_gps_2d_map.png + :align: center + :width: 700px + :alt: 2D-acquisitiekaart + +.. image:: ../_images/detection_gps_code_phase_slice.svg + :align: center + :target: ../_images/detection_gps_code_phase_slice.svg + :alt: Doorsnede van codefase + +We gaan hier niet dieper in op het trilateratieproces, maar juist de exacte positie van die piek maakt het mogelijk om de afstand tot de satelliet te bepalen. Combineer je die informatie van 4 of meer satellieten, dan kan de ontvanger zijn positie op aarde berekenen. + + +**************************************************** +CFAR-detectors: Robuust in Veranderende Omgevingen +**************************************************** + +Hoewel de Neyman-Pearson-detector optimaal is bij een vaste ruisvloer, zijn praktijkomstandigheden zelden zo stabiel. In een dynamische omgeving, zoals radar door regen of een draadloze ontvanger in een drukke stad, schommelen achtergrondruis en interferentie voortdurend. Hier wordt een Constant False Alarm Rate (CFAR)-detector essentieel. + +CFAR-detectors zijn de werkpaarden van systemen waar een onvoorspelbare achtergrond een vaste drempel onbruikbaar maakt: + +- Radar en sonar detecteren doelen (vliegtuigen, onderzeeers) tegen "clutter": reflecties van golven, regen of land die veranderen terwijl de sensor beweegt. +- Draadloze communicatie, zoals cognitieve radio en LTE/5G-systemen, gebruikt CFAR om beschikbaar spectrum te vinden of inkomende pakketten te detecteren bij grillige interferentie van andere apparaten. +- Medische beeldvorming gebruikt CFAR in automatische analyse van echo- of MRI-data om echte weefselstructuren te onderscheiden van variërende elektronische ruis. + +De "C" in CFAR staat voor Constant, omdat het doel is om de vals-alarmkans (:math:`P_{FA}`) op een stabiel, voorspelbaar niveau te houden. + +Om een drempelwaarde te kiezen, moet je een statistisch ruismodel aannemen (de ruisverdeling). In eenvoudige AWGN is dat een Gauss-verdeling. In radarclutter kan het bijvoorbeeld een Rayleigh- of Weibull-verdeling zijn. Als je model niet klopt, gaat :math:`P_{FA}` "driften", waardoor het systeem óf blind wordt óf overspoeld raakt door valse triggers. + +In plaats van een vaste waarde schat een CFAR-detector het ruisvermogen in de lokale "omgeving" van het signaal en vermenigvuldigt die schatting met een schaalfactor (:math:`T`) afgeleid van de gewenste :math:`P_{FA}`. Daardoor stijgt de drempel automatisch mee als de ruisvloer stijgt. + +Per-lag versus Systeemniveau Vals-alarmkans +#################################################### + +Dit is een cruciaal onderscheid dat beginners vaak missen. Bij preamble-zoekacties voer je meestal een schuivende correlatie uit, waarbij je de drempel op duizenden tijdsverschuivingen ("lags") per seconde controleert. + +Per-lag :math:`P_{FA}`: de kans dat één specifieke correlatietoets een vals alarm oplevert. Stel je :math:`P_{FA}` op 0,001, dan heeft elke losse lag 1 op 1000 kans op een "spooksignaal". + +Systeemniveau (globaal) :math:`P_{FA}`: de kans dat het systeem minstens één vals alarm geeft in een volledig zoekvenster (bijv. over 2048 lags). + +Wiskundig geldt: als je per-lag :math:`P_{FA}` gelijk is aan :math:`p`, dan is de kans op minstens één vals alarm over :math:`N` lags ongeveer :math:`1-(1-p)^{N}`. + +Gevolg: bij 1000 lags en per-lag :math:`P_{FA}` van 0,001 rapporteert het systeem in bijna 63% van de zoekacties minstens één vals alarm. Om de systeemniveau-kans laag te houden moet per-lag :math:`P_{FA}` dus extreem klein zijn. + +Python-voorbeeld +################# + +Om zelf met een CFAR-detector te experimenteren, simuleren we eerst een scenario met herhaalde QPSK-pakketten met bekende preamble over een kanaal met tijdsvariërende ruisvloer. Daarna implementeren we een eenvoudige Cell-Averaging CFAR (CA-CFAR)-detector om preambles in het ontvangen signaal te vinden. De volgende Python-code genereert het ontvangen signaal: + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + from scipy.signal import correlate + + def generate_qpsk_packets(num_packets, sps, preamble): + """Generates repeating QPSK packets with gaps and varying noise.""" + qpsk_map = np.array([1+1j, -1+1j, -1-1j, 1-1j]) / np.sqrt(2) + data_len = 200 + gap_len = 100 + full_signal = [] + + # Pre-calculate preamble upsampled for correlation + upsampled_preamble = np.repeat(preamble, sps) + + for _ in range(num_packets): + data = qpsk_map[np.random.randint(0, 4, data_len)] + packet = np.concatenate([preamble, data]) + full_signal.extend(np.repeat(packet, sps)) + full_signal.extend(np.zeros(gap_len * sps)) + + return np.array(full_signal), upsampled_preamble + + # Setup Parameters + sps = 4 + preamble_syms = np.array([1+1j, 1+1j, -1-1j, -1-1j, 1-1j, -1+1j]) / np.sqrt(2) + tx_signal, ref_preamble = generate_qpsk_packets(5, sps, preamble_syms) + + # Channel: Time-Varying Noise Floor + t = np.arange(len(tx_signal)) + noise_env = 0.05 + 0.3 * np.sin(2 * np.pi * 0.0003 * t)**2 + noise = (np.random.randn(len(tx_signal)) + 1j*np.random.randn(len(tx_signal))) * noise_env + rx_signal = tx_signal + noise + +De eerste stap is één correlatie van het ontvangen signaal met de bekende preamble. In de praktijk gebeurt dit vaak in batches, maar hier doen we het in één batch: + +.. code-block:: python + + # Preamble-correlatie, een correlatiepiek ontstaat wanneer referentie en ontvangen segment matchen + corr_out = correlate(rx_signal, ref_preamble, mode='same') + corr_power = np.abs(corr_out)**2 + +TODO: kijk naar de ruwe output van alleen deze stap + +Nu implementeren we de CFAR-detector, passen die toe op de correlatoruitgang en visualiseren de resultaten: + +.. code-block:: python + + # CFAR Detection on Correlator Output + def ca_cfar_adaptive(data, num_train, num_guard, pfa): + num_cells = len(data) + thresholds = np.zeros(num_cells) + alpha = num_train * (pfa**(-1/num_train) - 1) # Scaling factor + half_window = (num_train + num_guard) // 2 + guard_half = num_guard // 2 + for i in range(half_window, num_cells - half_window): + # Extract training cells (excluding guard cells and CUT) + lagging_win = data[i - half_window : i - guard_half] + leading_win = data[i + guard_half + 1 : i + half_window + 1] + noise_floor_est = np.mean(np.concatenate([lagging_win, leading_win])) + thresholds[i] = alpha * noise_floor_est + return thresholds + + # Detect on correlator power + cfar_thresholds = ca_cfar_adaptive(corr_power, num_train=60, num_guard=20, pfa=1e-5) + detections = np.where(corr_power > cfar_thresholds)[0] + # Filter detections to only include those where threshold is non-zero (avoid edges) + detections = detections[cfar_thresholds[detections] > 0] + + # Subplot 1: Received Signal and Raw Power + plt.figure(figsize=(14, 8)) + plt.subplot(2, 1, 1) + plt.plot(np.abs(rx_signal)**2, color='gray', alpha=0.4, label='Rx Signal Power ($|r(t)|^2$)') + plt.title("Time-Domain Received Signal") + plt.ylabel("Power") + plt.legend() + plt.grid(True, alpha=0.3) + + # Subplot 2: Correlator Output vs Adaptive Threshold + plt.subplot(2, 1, 2) + plt.plot(corr_power, label='Correlator Output $|r(t) * p^*(-t)|^2$', color='blue') + plt.plot(cfar_thresholds, label='CFAR Adaptive Threshold', color='red', linestyle='--', linewidth=1.5) + if len(detections) > 0: # Overlay detections + plt.scatter(detections, corr_power[detections], color='lime', edgecolors='black', label='Detections (Preamble Found)', zorder=5) + plt.title("Preamble Correlator Output with Adaptive CFAR Threshold") + plt.xlabel("Sample Index") + plt.ylabel("Correlation Power") + plt.legend() + plt.grid(True, alpha=0.3) + plt.show() + +.. image:: ../_images/detection_cfar.svg + :align: center + :target: ../_images/detection_cfar.svg + :alt: CFAR Detector Output Example + + + +Frequentie-offset-robuuste Preamble-correlators +#################################################### + +Het detecteren van een preamble wordt een meerdimensionaal zoekprobleem wanneer de middenfrequentie onbekend is. In een perfect gesynchroniseerd systeem werkt een coherente correlator als matched filter en maximaliseert die de SNR. Frequentie-offset introduceert echter een tijdsafhankelijke faserotatie die het signaal loskoppelt van het lokale sjabloon, met potentieel dramatisch verlies van detectiegevoeligheid als gevolg. + +De impact van frequentie-offset :math:`\Delta f` hangt af van de grootte ervan ten opzichte van de preambleduur (:math:`T_{p}`): + +Licht verschoven (Doppler/clock drift): meestal veroorzaakt door ppm-onnauwkeurigheid van de lokale oscillator (LO) of beweging met lage snelheid. Hier geldt :math:`\Delta f \cdot T_{p} \ll 1`. De correlatiepiek verzwakt iets, maar de timing is nog steeds terug te winnen. + +In gevallen waar de frequentie-offset volledig onbekend is, zoals bij "cold start"-satellietacquisitie of sterk dynamische UAV-links, kan de coherente som zelfs naar nul uitdoven als de fase over de preamble meer dan :math:`180^{\circ}` roteert (:math:`\Delta f > 1/(2T_{p})`). Detectie wordt dan praktisch onmogelijk, ongeacht de SNR. + +Het verlies in correlatiemagnitude door frequentie-offset wordt beschreven door de Dirichlet-kern (de periodieke sinc-functie). Naarmate de frequentie-offset toeneemt, volgt de coherente som van geroteerde vectoren deze sinc-achtige afrol. + +Het verlies in dB door frequentie-offset kan benaderd worden met: + +:math:`L_{dB}(\Delta f) = 20 \log_{10} \left| \frac{\sin(\pi \Delta f N T_{s})}{N \sin(\pi \Delta f T_{s})} \right|` + +Waarbij: + + - :math:`N`: aantal symbolen in de preamble. + - :math:`T_{s}`: symboolperiode. + - :math:`\Delta f`: frequentie-offset in Hz. + +Als :math:`\Delta f` toeneemt, oscilleert de teller terwijl de noemer groeit, waardoor "nullen" in de gevoeligheid ontstaan. Voor een standaard correlator ligt de eerste nul bij :math:`\Delta f = 1/(N T_{s})`. Zit je offset op een halve binbreedte, dan verlies je ongeveer 3,9 dB, wat je effectieve SNR en :math:`P_{d}` merkbaar verslechtert. + +Methoden voor Robuustheid tegen Frequentie-offset +################################################# + +A. Coherente Gesegmenteerde Correlator + +De preamble met lengte :math:`N` wordt opgesplitst in :math:`M` segmenten van lengte :math:`L = N/M`. Elk segment wordt coherent gecorreleerd, waarna de resultaten worden gecombineerd met compensatie voor de fasedrift tussen segmenten. + +:math:`Y_{coh} = \sum_{m=0}^{M-1} \left( \sum_{k=0}^{L-1} r[k+mL] \cdot p^{*}[k] \right) e^{-j \hat{\phi}_m}` + +Hierbij is :math:`\hat{\phi}_m` een schatting van de faserotatie voor dat segment. Dit behoudt de SNR-gain van een preamble over volledige lengte, maar vraagt een nauwkeurige frequentieschatting om fasen goed uit te lijnen. + +B. Niet-coherente Gesegmenteerde Correlator + +Segmenten worden coherent gecorreleerd, maar de magnitudes worden opgeteld, waarbij fase-informatie wordt weggegooid. + +:math:`Y_{non-coh} = \sum_{m=0}^{M-1} \left| \sum_{k=0}^{L-1} r[k+mL] \cdot p^{*}[k] \right|^{2}` + +Deze aanpak is zeer robuust tegen frequentie-offset (tot ongeveer :math:`1/(L T_{s})`). Nadeel is Non-Coherent Integration Loss. Door magnitudes op te tellen in plaats van complexe waarden stapelt ruis sneller op dan signaal, wat de "post-detection" SNR effectief verlaagt. + +C. Brute-force Frequentiezoektocht + +De ontvanger draait meerdere parallelle correlators, elk verschoven met een discrete frequentie :math:`\Delta f_{i}`. + +Deze methode biedt de beste SNR-prestatie (volledige coherente gain), maar is ook het meest rekentechnisch kostbaar. De "bin spacing" moet klein genoeg zijn (volgens de Dirichlet-formule) zodat het worst-case verlies tussen bins acceptabel blijft (bijv. < 1 dB). + +Bij time-domain tapping worden samples geconvolueerd met een vaste set gewichten. Voor een frequentiezoekactie heb je dan een aparte FIR-bank per frequentiebin nodig. Dat is efficiënt voor korte preambles op FPGA's met Xilinx DSP48-slices. +Frequentiedomeinverwerking (FFT): voor een zoekactie neem je de FFT van het inkomende signaal en de preamble. Vermenigvuldiging in het frequentiedomein is equivalent aan correlatie. +De "frequency shift trick": om verschillende frequentie-offsets te testen heb je geen meerdere FFT's nodig. Je kunt de FFT-bins van de preamble circulair verschuiven ten opzichte van het signaal vóór puntsgewijze vermenigvuldiging en IFFT. +Voor continue stromen gebruik je chunkmethoden zoals Overlap-Save of Overlap-Add, zodat correlatiepieken aan de randen van FFT-vensters niet verloren gaan. + +Robuustheid tegen frequentie-offset is een afruil tussen processing gain en rekentechnische complexiteit. Niet-coherente gesegmenteerde correlatie is het meest robuust in omgevingen met veel onzekerheid, maar vraagt een hogere linkmarge. Coherente segmentmethoden en brute-force FFT-zoekacties bieden betere gevoeligheid, maar vereisen aanzienlijk meer hardwarebronnen. Begrijpen hoe het Dirichlet-verlies werkt is cruciaal om de benodigde "bin density" van een frequentiezoekende ontvanger te bepalen. + +TODO: Licht deze figuur toe en voeg een relevant stuk Python toe aan deze sectie + +.. image:: ../_images/detection_freq_offset.svg + :align: center + :target: ../_images/detection_freq_offset.svg + :alt: Invloed van frequentie-offset op correlatie + +***************************************************************** +DSSS-signalen (Direct Sequence Spread Spectrum) Detecteren +***************************************************************** + +In een DSSS-systeem is de correlator-detector de vitale schakel die een bruikbaar signaal uit schijnbaar willekeurige ruis haalt. Met een chipsequentie op hoge snelheid ("chipping code") spreidt het systeem de signaalenergie over een veel bredere band dan de oorspronkelijke data nodig heeft. Omdat het totale vermogen gelijk blijft, daalt de vermogensspectrale dichtheid (PSD) sterk. Dit "spectraal verdunnen" kan het signaal onder de thermische ruisvloer brengen, waardoor het voor klassieke smalbandontvangers bijna onzichtbaar wordt. Voor buitenstaanders lijkt het op achtergrondruis, maar de bedoelde ontvanger gebruikt dezelfde chipsequentie om te "ontspreiden", waardoor de energie terug samenkomt in de oorspronkelijke smalle band en smalbandinterferentie juist uitgesmeerd wordt. Dat maakt betrouwbare detectie mogelijk, zelfs in zeer ruisrijke omstandigheden. + +De Rol van Autocorrelatie-eigenschappen +######################################## + +De juiste sequentie kiezen is cruciaal voor synchronisatie en multipad-onderdrukking. Idealiter heeft een sequentie perfecte autocorrelatie: een hoge piek bij perfecte uitlijning en bijna nul op alle andere tijdsverschuivingen. Scherpe autocorrelatiepieken laten de ontvanger locken met sub-chip timingnauwkeurigheid. Als een signaal via een reflectie later binnenkomt, zorgt goede autocorrelatie dat de ontvanger die vertraagde kopie als ongecorreleerde ruis behandelt in plaats van destructieve interferentie. + + +Veelgebruikte Spreidingssequenties +#################################### + +Verschillende toepassingen vragen verschillende wiskundige eigenschappen van hun sequenties. Voorbeelden zijn: + +- Barker-codes, bekend om de best mogelijke autocorrelatie bij korte lengtes (tot 13), en klassiek gebruikt in 802.11b-wifi. +- M-sequenties (maximale lengte), opgewekt met linear-feedback shift registers (LFSR's), bieden uitstekende pseudo-willekeurigheid en autocorrelatie over lange periodes. +- Gold-codes, afgeleid van paren m-sequenties, leveren een grote set sequenties met gecontroleerde kruiscorrelatie, en zijn daarom standaard in GPS en CDMA met meerdere gelijktijdige signalen. +- Zadoff-Chu (ZC)-sequenties, complexwaardig met constante amplitude en nul autocorrelatie voor alle niet-nul shifts, zijn nu een hoeksteen van LTE en 5G-synchronisatie. +- Kasami-codes, vergelijkbaar met Gold-codes maar vaak met nog lagere kruiscorrelatie bij gegeven lengte, nuttig in hoge-dichtheidsomgevingen. + +Chip-timing-synchronisatie in DSSS +#################################################### + +In een DSSS-systeem hangt het kunnen terughalen van data volledig af van synchronisatie met de inkomende chipsequentie. Omdat chips veel korter zijn dan databits kan zelfs een kleine fractionele timingfout, waarbij de ontvanger "tussen" chips samplet, de correlatiepiek sterk verlagen. We verkennen dit effect met een simpele DSSS-simulatie en plotten de correlatie-output terwijl we de timing-offset variëren van 0 tot 1 chip. Let op: we doen hier geen volledige correlatie, maar een dotproduct bij lag 0, omdat we weten dat daar de piek hoort te zitten. + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + + # Barker 11 sequence: +1, -1, +1, +1, -1, +1, +1, +1, -1, -1, -1 + barker11 = np.array([1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1]) + samples_per_chip = 100 + + # Upsample the sequence to simulate continuous-ish time + sig = np.repeat(barker11, samples_per_chip) + + offsets = np.linspace(-1.5, 1.5, 500) # Fractional chip offsets + peaks = [] + + for offset in offsets: + # Shift the signal by a fractional number of chips (converted to samples) + shift_samples = int(offset * samples_per_chip) + if shift_samples > 0: + shifted_sig = np.pad(sig, (shift_samples, 0))[:len(sig)] + elif shift_samples < 0: + shifted_sig = np.pad(sig, (0, abs(shift_samples)))[abs(shift_samples):] + else: + shifted_sig = sig + + # Compute normalized correlation at zero lag for this specific offset + correlation = np.vdot(sig, shifted_sig) / np.vdot(sig, sig) + peaks.append(np.abs(correlation)) + + plt.figure(figsize=(10, 5)) + plt.plot(offsets, peaks, label='Normalized Correlation', color='blue', linewidth=2) + plt.axvline(0, color='red', linestyle='--', alpha=0.5, label='Perfect Alignment') + plt.title('DSSS Correlation Peak vs. Fractional Chip Timing Offset') + plt.xlabel('Offset (Fraction of a Chip)') + plt.ylabel('Normalized Correlation Peak Magnitude') + plt.grid(True, which='both', linestyle='--', alpha=0.6) + plt.legend() + plt.savefig('../_images/detection_dsss.svg', bbox_inches='tight') + plt.show() + +.. image:: ../_images/detection_dsss.svg + :align: center + :target: ../_images/detection_dsss.svg + :alt: DSSS + +De piek ligt zoals verwacht bij offset nul en daalt ongeveer lineair; bij een halve chip-offset zit je rond de helft van de piekwaarde. Na meer dan één chip-offset kan het lijken alsof de correlatie weer stijgt, maar de echte piek blijft laag omdat de uitlijning met de sequentie dan weg is. + +**************************************************** +Realtime Pakketdetectie in Continue IQ-stromen +**************************************************** + +Tot nu toe hebben we de theoretische basis van signaaldetectie verkend, van correlators via CFAR-detectors tot spread-spectrumsystemen. Nu brengen we alles samen voor een veelvoorkomend praktijkprobleem: **pakketten detecteren in een continue stroom IQ-samples van een SDR**. Stel je dit scenario voor: een modem of IoT-apparaat verstuurt eens per seconde (of onregelmatig) een datapakket. Je SDR ontvangt continu samples, bijvoorbeeld op 1 MHz. Pakketten komen op onvoorspelbare momenten binnen, verborgen in ruis en interferentie. Je moet: + +1. Detecteren wanneer een pakket aankomt +2. De exacte sample-index bepalen waar het start +3. Het pakket uitknippen voor verdere verwerking (demodulatie, decodering, enz.) +4. Dit realtime doen zonder pakketten te missen + +Dit is fundamenteel anders dan een vooraf opgenomen IQ-bestand verwerken, waarbij je het hele signaal in één keer kunt analyseren. Hier komen samples continu binnen en moet je met beperkte rekenmiddelen realtime beslissingen nemen. We combineren hiervoor meerdere technieken uit dit hoofdstuk: + +1. **Kruiscorrelatie**: om het bekende preamblepatroon te vinden +2. **CFAR-detectie**: om drempels adaptief te zetten bij variërende ruis +3. **Bufferbeheer**: om continue streamdata af te handelen +4. **Piekdetectie**: om precieze pakkettiming te bepalen + +Om realtime te kunnen werken verzamelen we samples in **buffers** (bijvoorbeeld chunks van 100.000 samples), draaien de detector op elke buffer en houden toestand bij over buffergrenzen heen, zodat pakketten die twee buffers overspannen niet gemist worden. + +Implementatie +############## + +Onze detector volgt deze workflow: + +.. mermaid:: + + flowchart TD + A("Continue IQ-stroom van SDR
    (1 MHz sample rate)") + B("Buffer-opbouw
    (bijv. 100k samples = 0,1 s)") + C("Kruiscorrelatie met bekende preamble") + D("CFAR-drempelberekening") + E("Piekdetectie
    (correlatie > drempel)") + F("Pakketextractie & validatie") + A --> B --> C --> D --> E --> F + +Om pakketten die over buffergrenzen gaan niet te missen gebruiken we een **overlap-save**-aanpak, waarbij elke buffer de laatste ``N_preamble`` samples van de vorige buffer bevat. Zo zit elk pakket dat aan het einde van buffer ``i`` start volledig in buffer ``i+1``. Dat kost iets extra rekentijd, maar voorkomt gemiste pakketten op buffergrenzen. + +Laten we stap voor stap een complete pakketdetector in Python bouwen. We gebruiken een Zadoff-Chu-preamble zoals eerder, maar korter, en implementeren een adaptieve CFAR-detector. + +Stap 1: Definieer de Preamble en Parameters +******************************************* + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + from scipy.signal import correlate + + # Preamble: Zadoff-Chu sequence (excellent correlation properties) + N_zc = 63 # ZC sequence length (typically prime or power of 2 - 1) + u = 5 # ZC root + t = np.arange(N_zc) + preamble = np.exp(-1j * np.pi * u * t * (t + 1) / N_zc) + + # System parameters + sample_rate = 1e6 + buffer_size = 100000 + overlap_size = len(preamble) # Overlap to catch boundary packets + + # CFAR parameters + cfar_guard = 10 + cfar_train = 50 + pfa_target = 1e-6 + + # Packet parameters (for simulation) + packet_length = 500 # Total packet length in samples (preamble + data) + snr_db = -5 + +Stap 2: CFAR-detectorfunctie +******************************* + +We gebruiken de Cell-Averaging CFAR (CA-CFAR) van eerder, licht geoptimaliseerd: + +.. code-block:: python + + def ca_cfar_1d(signal, num_train, num_guard, pfa): + """ + 1D Cell-Averaging CFAR detector. + + Args: + signal: Input signal (typically correlation magnitude) + num_train: Number of training cells (on each side) + num_guard: Number of guard cells (on each side) + pfa: Target probability of false alarm + + Returns: + threshold: Adaptive threshold array + """ + n = len(signal) + threshold = np.zeros(n) + alpha = num_train * (pfa**(-1/num_train) - 1) + + for i in range(n): + # Define training window indices + train_start_left = max(0, i - num_guard - num_train) + train_end_left = max(0, i - num_guard) + train_start_right = min(n, i + num_guard + 1) + train_end_right = min(n, i + num_guard + num_train + 1) + + # Collect training cells (avoid guard cells and CUT) + train_cells = np.concatenate([ + signal[train_start_left:train_end_left], + signal[train_start_right:train_end_right] + ]) + + if len(train_cells) > 0: + noise_est = np.mean(train_cells) + threshold[i] = alpha * noise_est + + return threshold + +Stap 3: Pakketdetectiefunctie +********************************** + +.. code-block:: python + + def detect_packets(buffer, preamble, cfar_guard, cfar_train, pfa, + min_spacing=None): + """ + Detect packets in a buffer of IQ samples. + + Args: + buffer: Complex IQ samples + preamble: Known preamble sequence + cfar_guard: CFAR guard cells + cfar_train: CFAR training cells + pfa: Target false alarm probability + min_spacing: Minimum samples between detections (prevents duplicates) + + Returns: + detections: List of sample indices where packets start + """ + # Correlate buffer with preamble + corr = correlate(buffer, preamble, mode='same') + corr_power = np.abs(corr)**2 + + # Compute adaptive threshold + threshold = ca_cfar_1d(corr_power, cfar_train, cfar_guard, pfa) + + # Find peaks above threshold + detections_raw = np.where(corr_power > threshold)[0] + + # Compensate for correlation offset (peak occurs at len(preamble)//2 after true start) + half_preamble = len(preamble) // 2 + detections_raw = detections_raw - half_preamble + + # Remove edge detections (unreliable) + half_preamble = len(preamble) // 2 + detections_raw = detections_raw[ + (detections_raw > half_preamble) & + (detections_raw < len(buffer) - half_preamble) + ] + + # Remove duplicate detections (peaks close together) + if min_spacing is None: + min_spacing = len(preamble) + + detections = [] + if len(detections_raw) > 0: + detections.append(detections_raw[0]) + for det in detections_raw[1:]: + if det - detections[-1] > min_spacing: + detections.append(det) + + return detections, corr_power, threshold + +Stap 4: Simulatie - Genereer Testsignaal +****************************************** + +.. code-block:: python + + def generate_packet_stream(preamble, packet_length, num_packets, + sample_rate, snr_db): + """ + Generate a simulated IQ stream with intermittent packets. + + Returns: + signal: Complex IQ samples + true_starts: Ground truth packet start indices + """ + # Calculate noise power from SNR + signal_power = 1.0 # Normalized preamble power + noise_power = signal_power / (10**(snr_db/10)) + noise_std = np.sqrt(noise_power / 2) # Complex noise + + # Generate QPSK data (random payload after preamble) + qpsk_map = np.array([1+1j, -1+1j, -1-1j, 1-1j]) / np.sqrt(2) + + # Time between packets (1 second +/- 20% jitter) + packets_per_sec = 1 + avg_gap = int(sample_rate / packets_per_sec) + + signal = [] + true_starts = [] + + for i in range(num_packets): + # Add gap (noise only) + if i == 0: + gap_length = np.random.randint(avg_gap//2, avg_gap) + else: + gap_length = np.random.randint(int(avg_gap*0.8), int(avg_gap*1.2)) + + noise = noise_std * (np.random.randn(gap_length) + + 1j*np.random.randn(gap_length)) + signal.extend(noise) + + # Record true packet start + true_starts.append(len(signal)) + + # Add packet (preamble + data) + data_length = packet_length - len(preamble) + data = qpsk_map[np.random.randint(0, 4, data_length)] + packet = np.concatenate([preamble, data]) + + # Add noise to packet + packet_noisy = packet + noise_std * (np.random.randn(len(packet)) + + 1j*np.random.randn(len(packet))) + signal.extend(packet_noisy) + + # Add final gap + gap_length = np.random.randint(avg_gap//2, avg_gap) + noise = noise_std * (np.random.randn(gap_length) + + 1j*np.random.randn(gap_length)) + signal.extend(noise) + + return np.array(signal), true_starts + + # Generate 5 seconds of signal with ~5 packets + signal, true_starts = generate_packet_stream( + preamble, packet_length, num_packets=5, + sample_rate=sample_rate, snr_db=snr_db + ) + + print(f"Generated {len(signal)} samples ({len(signal)/sample_rate:.1f} sec)") + print(f"True packet starts: {true_starts}") + +Stap 5: Detectie in Streaming-modus +**************************************** + +Nu verwerken we het signaal in stukken en simuleren daarmee realtime streaming: + +.. code-block:: python + + def process_stream(signal, preamble, buffer_size, overlap_size, + cfar_guard, cfar_train, pfa): + """ + Process continuous IQ stream in buffers (simulates real-time). + + Returns: + all_detections: List of detected packet starts (global indices) + """ + all_detections = [] + n_samples = len(signal) + current_pos = 0 + + while current_pos < n_samples: + # Define buffer with overlap + buffer_start = max(0, current_pos - overlap_size) + buffer_end = min(n_samples, current_pos + buffer_size) + buffer = signal[buffer_start:buffer_end] + + # Detect packets in this buffer + detections, corr_power, threshold = detect_packets( + buffer, preamble, cfar_guard, cfar_train, pfa + ) + + # Convert buffer-relative indices to global indices + for det in detections: + global_idx = buffer_start + det + + # Avoid duplicate detections from overlap region + if len(all_detections) == 0 or \ + global_idx - all_detections[-1] > len(preamble): + all_detections.append(global_idx) + + current_pos += buffer_size + + return all_detections + + + detected_starts = process_stream( + signal, preamble, buffer_size, overlap_size, + cfar_guard, cfar_train, pfa_target + ) + + print(f"\nDetection Results:") + print(f"True packets: {len(true_starts)}") + print(f"Detected packets: {len(detected_starts)}") + print(f"Detected starts: {detected_starts}") + +Stap 6: Evalueer Prestaties +***************************** + +.. code-block:: python + + # Calculate detection statistics + tolerance = len(preamble) + + matched_detections = [] + false_alarms = [] + + for det in detected_starts: + # Check if detection matches any true packet + matched = False + for true_start in true_starts: + if abs(det - true_start) <= tolerance: + matched_detections.append(det) + matched = True + break + if not matched: + false_alarms.append(det) + + missed_packets = len(true_starts) - len(matched_detections) + + print(f"\nPerformance Metrics:") + print(f" Correct detections: {len(matched_detections)}/{len(true_starts)}") + print(f" Missed packets: {missed_packets}") + print(f" False alarms: {len(false_alarms)}") + + # Calculate timing errors + timing_errors = [] + for det in matched_detections: + errors = [abs(det - ts) for ts in true_starts] + timing_errors.append(min(errors)) + + if len(timing_errors) > 0: + print(f" Timing error (avg): {np.mean(timing_errors):.1f} samples") + print(f" Timing error (max): {np.max(timing_errors):.1f} samples") + +Stap 7: Visualiseer Resultaten +******************************* + +.. code-block:: python + + # Process one buffer for detailed visualization + buffer_start = max(0, true_starts[0] - 5000) + buffer_end = min(len(signal), true_starts[0] + 20000) + viz_buffer = signal[buffer_start:buffer_end] + + detections_viz, corr_viz, thresh_viz = detect_packets( + viz_buffer, preamble, cfar_guard, cfar_train, pfa_target + ) + + # Convert to global indices for plotting + detections_viz_global = [d + buffer_start for d in detections_viz] + + # Create visualization + fig, axes = plt.subplots(3, 1, figsize=(14, 10)) + time_axis = (np.arange(len(viz_buffer)) + buffer_start) / sample_rate * 1000 # ms + + # Subplot 1: Received signal power + axes[0].plot(time_axis, np.abs(viz_buffer)**2, 'gray', alpha=0.6, linewidth=0.5) + axes[0].set_ylabel('Power') + axes[0].set_title('Received IQ Signal Power') + axes[0].grid(True, alpha=0.3) + + # Mark true packet locations + for ts in true_starts: + if buffer_start <= ts <= buffer_end: + t_ms = ts / sample_rate * 1000 + axes[0].axvline(t_ms, color='green', linestyle='--', alpha=0.7, + label='True Packet' if ts == true_starts[0] else '') + axes[0].legend() + + # Subplot 2: Correlation output + axes[1].plot(time_axis, corr_viz, 'blue', linewidth=1, label='Correlation') + axes[1].plot(time_axis, thresh_viz, 'red', linestyle='--', linewidth=1.5, + label='CFAR Threshold') + axes[1].set_ylabel('Correlation Power') + axes[1].set_title('Preamble Correlation with Adaptive CFAR Threshold') + axes[1].grid(True, alpha=0.3) + axes[1].legend() + + # Subplot 3: Detections + detection_mask = np.zeros(len(viz_buffer)) + for det in detections_viz: + detection_mask[det] = corr_viz[det] + + axes[2].plot(time_axis, corr_viz, 'blue', alpha=0.4, linewidth=0.8) + axes[2].scatter(time_axis[detection_mask > 0], detection_mask[detection_mask > 0], + color='lime', edgecolors='black', s=100, zorder=5, + label='Detected Packets') + axes[2].set_xlabel('Time (ms)') + axes[2].set_ylabel('Correlation Power') + axes[2].set_title('Detected Packet Locations') + axes[2].grid(True, alpha=0.3) + axes[2].legend() + + plt.tight_layout() + + plt.show() + +De visualisatie zou het volgende moeten laten zien: + +1. **Bovenste plot**: ruwe signaalpower met gemarkeerde echte pakketlocaties +2. **Middelste plot**: correlatie-output met adaptieve CFAR-drempel die de ruisvloer volgt +3. **Onderste plot**: gedetecteerde pakketten gemarkeerd als pieken boven de drempel + +.. image:: ../_images/detection_realtime.png + :align: center + :scale: 50 % + :alt: Real-time packet detection results + +Praktische Overwegingen en Tuning +#################################### + +Afweging op basis van buffergrootte +************************************ + +**Grotere buffers (bijv. 1M samples):** + +- ✅ Betere CFAR-ruisschatting (meer trainingscellen) +- ✅ Lagere rekentechnische overhead (minder functie-aanroepen) +- ❌ Hogere latency (buffer moet eerst gevuld worden) +- ❌ Meer geheugen nodig + +**Kleinere buffers (bijv. 10k samples):** + +- ✅ Lagere latency (snellere respons) +- ✅ Minder geheugengebruik +- ❌ CFAR-prestatie verslechtert (minder trainingscellen) +- ❌ Hoger CPU-gebruik (vaker verwerken) + +**Aanbeveling**: begin met buffergrootte = 10× tot 100× je preamblelengte. Voor een preamble van 63 samples bij 1 Msps kun je 10k-100k samples proberen. + +CFAR-parametertuning +********************** + +De drie CFAR-parameters bepalen het detectorgedrag: + +**num_guard** (guard-cellen): + +- Doel: voorkomt dat signaalenergie in de ruisschatting lekt +- Te klein: signaal lekt in trainingsregio → hogere drempel → gemiste detecties +- Te groot: minder trainingscellen → slechtere ruisschatting +- **Vuistregel**: zet op ongeveer 0,5 tot 1,0× de preamblelengte + +**num_train** (training-cellen): + +- Doel: schat de lokale ruisvloer +- Te klein: ruisachtige drempel → valse alarmen of gemiste detecties +- Te groot: drempel past zich te traag aan ruisveranderingen aan +- **Vuistregel**: zet op ongeveer 3 tot 5× de preamblelengte + +**pfa** (kans op vals alarm): + +- Doel: regelt de detectiegevoeligheid +- Te hoog (bijv. 1e-2): veel valse alarmen +- Te laag (bijv. 1e-10): zwakke pakketten worden gemist +- **Vuistregel**: start met 1e-5 voor per-lag PFA en stuur bij op basis van vals-alarmkans op systeemniveau + +Onthoud de relatie tussen per-lag en systeemniveau vals-alarmkansen uit het eerdere deel van dit hoofdstuk. diff --git a/content-nl/digital_modulation.rst b/content-nl/digital_modulation.rst index 9316fe00..a438b40f 100644 --- a/content-nl/digital_modulation.rst +++ b/content-nl/digital_modulation.rst @@ -84,7 +84,7 @@ Amplitude Shift Keying (ASK) (Nederlands: amplitudeverschuivingsmodulatie) is he Let op hoe de gemiddelde waarde nul is; dit heeft altijd onze voorkeur. -We kunnen meer dan twee niveaus gebruiken om meer bits per symbool te versturen. Hieronder een voorbeeld van 4-ASK. In dit geval bevat elk symbool 2 bits aan informatie. +We kunnen meer dan twee niveaus gebruiken om meer bits per symbool te versturen. Hieronder een voorbeeld van 4-ASK (waarvan 0 ook een van de vier niveaus is). In dit geval bevat elk symbool 2 bits aan informatie. .. image:: ../_images/ask2.svg :align: center @@ -114,7 +114,7 @@ Dit moduleert ons signaal op de draaggolf (de sinusoïde is die draaggolf). Het :alt: Samples per symbol depiction using 2-ASK in the time domain, with 10 samples per symbol (sps) Het bovenste figuur laat de discrete samples zien als rode punten, dus ons digitale signaal. Het onderste figuur laat zien hoe het resulterende gemoduleerde signaal eruitziet, dit zou door de lucht verzonden kunnen worden. -In echte systemen is de frequentie van de draaggolf veel hoger dan de snelheid waarmee de symbolen afwisselen. In ons voorbeeld zijn er maar 3 perioden van de draaggolf per symbool, maar in de praktijk zouden er duizenden kunnen zijn, afhankelijk van hoe hoog in het spectrum het verzonden wordt. +In echte systemen is de frequentie van de draaggolf veel hoger dan de snelheid waarmee de symbolen afwisselen. In ons voorbeeld zijn er maar 2.5 perioden van de draaggolf per symbool, maar in de praktijk zouden er duizenden kunnen zijn, afhankelijk van hoe hoog in het spectrum het verzonden wordt. We raden deze links aan voor meer info over ASK `` ************************ Phase Shift Keying (PSK) @@ -208,7 +208,7 @@ We willen niet een 0 ontvangen als een 1. -Even terug naar ASK. Net als PSK kun je ASK ook laten zien in het IQ-diagram. Hier is het IQ-diagram van 2-ASK, 4-ASK, en 8-ASK, in bipolaire vorm, en ook 2-ASK en 4-ASK in de unipolaire vorm. +Even terug naar ASK. Net als PSK kun je ASK ook laten zien in het IQ-diagram. Hier is het IQ-diagram van 2-ASK, 4-ASK, en 8-ASK, in bipolaire vorm, en ook 2-ASK en 4-ASK in de unipolaire vorm. Bipolair betekent in deze context dat het signaal zowel positieve als negatieve waarden kan aannemen. Unipolair gebruikt daarentegen alleen positieve waarden. .. image:: ../_images/ask_set.png :scale: 50 % @@ -269,7 +269,8 @@ FSK is niet moeilijk te vatten -- we schuiven tussen N frequenties waarbij elke 4. 1.1990 GHz Dit zou dan om 4-FSK met twee bits per symbool gaan. -In het frequentiedomein zou 4-FSK er zo uit kunnen zien: +De afstand tussen de frequenties is 200 kHz, dus het totale signaal zou dan net iets meer dan 600 kHz in beslag nemen. +Wanneer we de FFT nemen van veel symbolen in een 4-FSK signaal, zou het spectrum in de basisband er zou uit kunnen zien: .. image:: ../_images/fsk.svg :align: center @@ -278,7 +279,7 @@ In het frequentiedomein zou 4-FSK er zo uit kunnen zien: Een belangrijke vraag die je jezelf moet stellen is: Welke afstand moet ik tussen de frequenties aanhouden? Deze afstand wordt vaak aangegeven als :math:`\Delta f` in Hz. Om er voor te zorgen dat de ontvanger symbolen aan frequenties kan koppelen, willen we vermijden dat signalen in het frequentiedomein overlappen, dus :math:`\Delta f` moet groot genoeg zijn. -De bandbreedte van elke draaggolf is een functie van de symboolsnelheid. +De bandbreedte van elke draaggolf is een functie van de symboolsnelheid en het toegepaste pulsvormingsfilter. Meer symbolen per seconde geeft kortere symbolen en dus een grotere bandbreedte (denk aan de inverse relatie tussen tijd en frequentie). Hoe sneller we symbolen gaan oversturen, hoe breder elke draaggolf wordt en dus hoe groter we :math:`\Delta f` moeten maken om te voorkomen dat de draaggolven elkaar overlappen. @@ -293,9 +294,9 @@ Dit is een analoge versie van FSK. In plaats van het springen tussen discrete frequenties, gebruikt de FM-zender een continu audiosignaal waarmee het de frequentie van de draaggolf moduleert. Hieronder is een voorbeeld te zien van FM- en AM-modulatie, waarbij het "signaal" waarmee gemoduleerd wordt, in het bovenste figuur te zien is. -.. image:: ../_images/Carrier_Mod_AM_FM.webp +.. image:: ../_images/am_fm_animation.gif :align: center - :target: ../_images/Carrier_Mod_AM_FM.webp + :target: ../_images/am_fm_animation.gif :alt: Animation of a carrier, amplitude modulation (AM), and frequency modulation (FM) in the time domain In dit boek maken we ons vooral druk over de digitale vormen van modulatie. diff --git a/content-nl/doa.rst b/content-nl/doa.rst index 4a0cc16d..a5295a41 100644 --- a/content-nl/doa.rst +++ b/content-nl/doa.rst @@ -1,55 +1,73 @@ .. _doa-chapter: #################################### -DOA & Beamforming +DOA en Bundelvorming #################################### -We zullen in dit hoofdstuk het gaan hebben over de concepten van bundelvorming (eng: beamforming), direction-of-arrival (DOA) (Nederlands: aankomstrichting) en phased arrays. Met behulp van Python simulatievoorbeelden worden Technieken zoals Capon en MUSIC besproken. We behandelen beamforming vs. DOA en twee verschillende soorten phased arrays (passief en actief). +In dit hoofdstuk behandelen we bundelvorming, direction-of-arrival (DOA, aankomstrichting) en phased arrays in het algemeen. We vergelijken verschillende arraytypen en geometrieen, en laten zien waarom elementafstand een cruciale rol speelt. Technieken zoals MVDR/Capon en MUSIC worden geintroduceerd en gedemonstreerd met Python-simulaties. **N.B. Dit hoofdstuk wordt momenteel vertaald en kan nog fouten bevatten.** +*********************** +Bundelvorming Overzicht +*********************** + +Een phased array, ook wel elektronisch gestuurde array genoemd, is een verzameling antennes die je aan zend- en ontvangstzijde kunt gebruiken in communicatie- en radarsystemen. Je ziet phased arrays op de grond, in de lucht en op satellieten. De antennes in de array noemen we meestal elementen, en soms wordt de volledige array ook een sensor genoemd. Deze elementen zijn vaak omnidirectionele antennes, gelijkmatig verdeeld in een lijn of over twee dimensies. + +Bundelvorming is een signaalverwerkingstechniek voor antenne-arrays waarmee je een *ruimtelijk* filter maakt: signalen uit ongewenste richtingen worden onderdrukt en gewenste richtingen versterkt. Je kunt bundelvorming gebruiken om de SNR van gewenste signalen te verhogen, stoorzenders te nullen, bundelpatronen te vormen, of zelfs meerdere datastromen op dezelfde tijd en frequentie te verzenden/ontvangen. Hiervoor gebruiken we gewichten (coefficienten) per array-element, digitaal of analoog. Door deze gewichten te sturen vorm je bundels en nullen, vandaar de naam bundelvorming. Dat sturen gaat extreem snel; veel sneller dan mechanisch gimbal-antennes, die je als alternatief kunt zien. In dit hoofdstuk behandelen we bundelvorming vooral vanuit communicatielinks, waar de ontvanger een of meer signalen met zo hoog mogelijke SNR wil ontvangen. In radar speelt bundelvorming eveneens een grote rol, met als doel detectie en tracking van doelen. + +.. image:: ../_images/doa_complex_scenario.svg + :align: center + :target: ../_images/doa_complex_scenario.svg + :alt: Diagram van een complex scenario met meerdere signalen die op een array invallen + +Bundelvormingstechnieken kun je grofweg in drie categorieen indelen: conventioneel, adaptief en blind. Conventionele bundelvorming is vooral nuttig wanneer je de aankomstrichting van het gewenste signaal al kent; je kiest gewichten die de arraygain in die richting maximaliseren. Dat kan aan zend- en ontvangstzijde. Adaptieve bundelvorming past de gewichten aan op basis van de invoer van de bundelvormer om een criterium te optimaliseren (bijvoorbeeld een stoorzender nullen of meerdere hoofdbundels vormen). Door de gesloten lus wordt adaptieve bundelvorming meestal aan ontvangstzijde gebruikt, waarbij de invoer van de bundelvormer simpelweg het ontvangen signaal is, en de gewichten op statistiek van die ontvangen data worden bijgewerkt. + +De onderstaande taxonomie probeert de verschillende deelgebieden binnen bundelvorming te ordenen en tegelijk voorbeeldtechnieken te tonen: + +.. image:: ../_images/beamforming_taxonomy.svg + :align: center + :target: ../_images/beamforming_taxonomy.svg + :alt: Taxonomie van bundelvorming met conventionele, adaptieve en blinde methoden en de plaats van DOA-schatting + ************************ -Overzicht en termen +DOA Overzicht ************************ -Een phased array, ook wel een elektronisch gestuurd array genoemd, is een array van antennes die aan de zend- of ontvangstkant kan worden gebruikt om (elektronische) bundels op een bepaalde richting op te focussen. -Deze techniek wordt gebruikt in communicatie- en radartoepassingen. +Direction-of-Arrival (DOA) in DSP/SDR is het proces waarbij je met een antenne-array de aankomstrichtingen van een of meer ontvangen signalen detecteert en schat. Dat verschilt van bundelvorming, waar de nadruk ligt op het ontvangen van een signaal terwijl ruis en interferentie zo veel mogelijk worden onderdrukt. Hoewel DOA duidelijk onder het bundelvormingsdomein valt, raken de termen in de praktijk snel door elkaar. Sommige technieken, zoals conventionele en MVDR-bundelvorming, kun je zowel voor bundelvorming als DOA gebruiken. Voor DOA sweep je dan over hoeken, voer je per hoek de bundelvormingsstap uit, en zoek je pieken in het resultaat. Elke piek betekent dat er een signaal is, maar niet direct of dit het gewenste signaal, een stoorzender of een multipadreflectie is. Je kunt deze DOA-methoden zien als een omhulsel rond een specifieke bundelvormer. Andere bundelvormers laten zich niet eenvoudig in een DOA-routine verpakken, bijvoorbeeld door extra invoer die je binnen DOA niet beschikbaar hebt. Daarnaast zijn er DOA-methoden zoals MUSIC en ESPRIT die strikt voor DOA bedoeld zijn en geen bundelvormer zijn. Omdat veel bundelvormingsmethoden aannemen dat je de aankomstrichting van het gewenste signaal kent, moet je bij beweging van doel of array continu DOA blijven doen als tussenstap, zelfs als je hoofddoel demodulatie van het gewenste signaal is. -Phased arrays kun je grofweg in drie categorieën indelen: +Phased arrays en bundelvorming/DOA worden breed toegepast, maar je ziet ze vooral terug in radarsystemen, nieuwere wifi-standaarden, mmWave binnen 5G, satellietcommunicatie en stoorzenders. Algemeen geldt: toepassingen die een hoge antennegain vereisen, of een snel stuurbare hoge-gain antenne, zijn goede kandidaten voor phased arrays. -1. **Passive electronically scanned array (PESA)**, beter bekend als een analoge of traditionele phased array. Hierbij worden analoge faseverschuivers gebruikt om de bundelrichting aan te passen. - Bij de ontvanger worden alle elementen na een faseverschuiving (en eventueel versterking) opgeteld en met een mixer naar de basisband geschoven om te verwerken. - Bij de zender gebeurt het tegenovergestelde; een enkel digitaal signaal wordt analoog gemaakt waarna meerdere faseverschuivers en versterkers worden gebruikt om het signaal voor elke antenne te produceren. -2. **Active electronically scanned array (AESA)**, beter bekend als een volledig digitale array. Hier heeft elk element zijn eigen RF-componenten en het richten van de bundel gebeurt dan volledig digitaal. Vanwege de RF-componenten is dit de duurste aanpak, maar het geeft flexibiliteit en maakt hogere snelheden mogelijk. Digitale arrays zijn ideaal voor SDR's alhoewel het aantal kanalen van de SDR de grootte van de array beperkt. Wanneer er digitale faseverschuivers worden toegepast, dan hebben deze een bepaalde amplitude- en faseresolutie. -3. **Hybride array**, Nu worden meer PESA subarrays gebruikt, waarbij elke subarray zijn eigen RF voorkant heeft net als bij AESA's. Deze aanpak geeft het beste van beide werelden enwordt het meest toegepast in moderne arrays. +****************** +Typen Arrays +****************** + +Phased arrays vallen grofweg in drie typen uiteen: + +1. **Analoog**, ook wel passive electronically scanned array (PESA) of traditionele phased array. Hier sturen analoge faseverschuivers de bundel. Aan ontvangstzijde tel je alle elementen op na faseverschuiving (en eventueel regelbare versterking), waarna je naar een enkel kanaal omlaag converteert en ontvangt. Aan zendzijde gebeurt het omgekeerde: een enkel digitaal signaal gaat de analoge keten in, waarna faseverschuivers en gain-trappen het signaal per antenne-element vormen. Digitale faseverschuivers hebben een eindige bitresolutie en besturingslatentie. Een belangrijk voordeel van analoge bundelvorming is dat sterke stoorzenders al voor de ADC kunnen worden genuld, zodat de ontvanger niet verzadigt. +2. **Digitaal**, ook wel active electronically scanned array (AESA), waarbij elk element een eigen RF-front-end heeft en de bundelvorming volledig digitaal plaatsvindt. Dit is doorgaans de duurste aanpak omdat RF-componenten kostbaar zijn, maar je krijgt er veel flexibiliteit en snelheid voor terug, plus toegang tot adaptieve technieken die we later behandelen. Digitale arrays passen goed bij SDR's, al begrenst het aantal SDR-kanalen het aantal elementen. +3. **Hybride**, waarbij de array uit meerdere subarrays bestaat die afzonderlijk op analoge arrays lijken, terwijl elke subarray wel een eigen RF-front-end heeft zoals bij digitale arrays. Dit is in moderne systemen vaak de meest gebruikte aanpak omdat het een goede balans biedt. Hybride arrays kunnen adaptieve technieken gebruiken en tegelijk sterke interferentie al in het analoge domein onderdrukken voor de ADC, wat vooral in radar en in vijandige RF-omgevingen belangrijk is. + +Let op: de termen PESA en AESA worden vooral in radarcontext gebruikt en de precieze afbakening is niet altijd scherp. Daarom zijn de termen analoog/digitaal/hybride vaak duidelijker en breder toepasbaar. Hieronder vind je een voorbeeld van de drie typen: .. image:: ../_images/beamforming_examples.svg :align: center :target: ../_images/beamforming_examples.svg - :alt: Example of phased arrays including Passive electronically scanned array (PESA), Active electronically scanned array (AESA), Hybrid array, showing Raytheon's MIM-104 Patriot Radar, ELM-2084 Israeli Multi-Mission Radar, Starlink User Terminal, aka Dishy - -We zullen in dit hoofdstuk voornamelijk focussen op de signaalbewerking voor volledig digitale arrays, omdat deze beter geschikt zijn voor simulatie en DSP toepassingen. In het volgende hoofdstuk gaan we aan de slag met de "Phaser" array en SDR van Analog Devices die 8 analoge faseverschuivers heeft aangesloten op een Pluto. - -We zullen de antennes die de array vormen meestal elementen noemen, en soms wordt de array ook wel een "sensor" genoemd. Deze array-elementen zijn meestal omnidirectionele antennes, die gelijkmatig verdeeld zijn in een lijn of over twee dimensies. - -Een bundelvormer is in wezen een ruimtelijk filter; het filtert signalen uit alle richtingen behalve de gewenste richting(en). Net als bij normale filters, gebruiken we gewichten (coefficienten) op elk element van een array. We manipuleren dan de gewichten om de bundel(s) van de array te vormen, vandaar de naam bundelvormer! We kunnen deze bundels (en nullen) extreem snel sturen; veel sneller dan mechanisch gestuurde antennes (een mogelijk alternatief). Een enkele array kan, zolang het maar genoeg elementen heeft, tegelijkertijd meerdere signalen elektronisch volgen terwijl het interferentie onderdrukt. We zullen bundelvorming meestal bespreken in de context van een communicatieverbinding, waarbij de ontvanger probeert een of meerdere signalen met een zo hoog mogelijke SNR te ontvangen. + :alt: Voorbeeld van phased arrays: PESA, AESA en hybride, met o.a. Patriot-radar, ELM-2084 en Starlink-terminal -Bundelvormingstechnieken worden meestal onderverdeeld in conventionele en adaptieve technieken. Bij conventionele bundelvorming ga je er vanuit dat je al weet waar het signaal vandaan komt. De bundelvormer kiest dan gewichten om de versterking in die richting te maximaliseren. Dit kan zowel aan de ontvangende als aan de zendende kant van een communicatiesysteem worden gebruikt. Bij adaptieve bundelvorming daarentegen worden, om een bepaald criterium te optimaliseren, de gewichten voortdurend aangepast op basis van de uitgang van de bundelvormer. Vaak is het doel een interferentiebron te onderdrukken. Vanwege de gesloten lus en adaptieve aard wordt adaptieve bundelvorming typisch alleen aan de ontvangende kant gebruikt, dus de "uitgang van de bundelvormer" is gewoon je ontvangen signaal. Adaptieve bundelvorming houdt dus in dat je de gewichten aanpast op basis van de statistieken van de ontvangen gegevens. +Naast deze drie typen is ook de geometrie belangrijk. De eenvoudigste vorm is de uniforme lineaire array (ULA), waarbij antennes op een rechte lijn met gelijke afstand staan (1D). ULA's hebben een 180-gradenambiguiteit, waar we later op terugkomen. Een oplossing is antennes in een cirkel plaatsen: de uniforme cirkelarray (UCA). Voor 2D-bundels gebruiken we meestal een uniforme rechthoekige array (URA), met een rasterpatroon. -Direction-of-Arrival (DOA) binnen DSP/SDR verwijst naar de manier waarop een array van antennes wordt gebruikt om de aankomstrichtingen van een of meerdere signalen in te schatten (in tegenstelling tot bundelvorming, dat zich richt op het ontvangen van een signaal terwijl zoveel mogelijk ruis en interferentie wordt onderdrukt). Omdat DOA zeker onder het onderwerp bundelvorming valt, kunnen de termen verwarrend zijn. -Dezelfde technieken die bij bundelvorming worden gebruikt, zijn ook toepasbaar bij DOA. Het vinden van de richting gebeurt op dezelfde manieren. -De meeste bundelvormingstechnieken gaan er van uit dat de aankomstrichting van het signaal bekend is. Wanneer de zender of ontvanger zich verplaatsten zal het alsnog continu DOA moeten uitvoeren, zelfs als het primaire doel is om het signaal te ontvangen en demoduleren. - -Phased arrays en bundelvorming/DOA worden gebruikt in allerlei toepassingen. Je kunt ze onder andere vinden in verschillende vormen van radar, mmWave-communicatie binnen 5G, satellietcommunicatie en voor het storen van verbindingen. Elke toepassing die een antenne met een hoge versterking vereist, of een snel bewegende antenne met een hoge versterking, zijn goede kandidaten voor phased arrays. +In dit hoofdstuk focussen we op digitale arrays, omdat die beter aansluiten op simulatie en DSP. De concepten gelden echter ook voor analoge en hybride arrays. In het volgende hoofdstuk werken we praktisch met de "Phaser"-SDR van Analog Devices, met een 10 GHz 8-element analoge array met fase- en gain-shifters, gekoppeld aan een Pluto en Raspberry Pi. We focussen hier vooral op ULA-geometrie omdat die de eenvoudigste wiskunde en code geeft, maar de kernideeen gelden ook voor andere geometrieen; aan het einde raken we UCA kort aan. ******************* Eisen SDR ******************* -Zoals besproken bestaat een analoge phased array uit een faseverschuiver (en versterker) per kanaal. Dit betekent dat er analoge hardware nodig is naast de SDR. Aan de andere kant kan elke SDR met meer dan één kanaal, waarbij alle kanelen fasegekoppeld zijn en dezelfde klok gebruiken, als een digitale array worden gebruikt. Dit is meestal het geval bij SDR's met meerdere kanalen. -Er zijn veel SDR's die **twee** ontvangstkanalen bevatten, zoals de Ettus USRP B210 en de Analog Devices Pluto (het 2e kanaal wordt blootgesteld met een uFL-connector op het bord zelf). Helaas, als je verder gaat dan twee kanalen, kom je in het segment van SDR's van $10k+ terecht, althans in 2023, zoals de USRP N310. Het grootste probleem is dat goedkope SDR's meestal niet aan elkaar kunnen worden "gekoppeld" om het aantal kanalen te vermeerderen. De uitzondering is de KerberosSDR (4 kanalen) en KrakenSDR (5 kanalen) die meerdere RTL-SDR's gebruiken die een LO delen met een gedeelde LO om een goedkope digitale array te vormen; het nadeel is de zeer beperkte bemonsteringsfrequentie (tot 2,56 MHz) en afstemmingsbereik (tot 1766 MHz). De KrakenSDR-kaart en een antenneconfiguratievoorbeeld wordt hieronder getoond. +Analoge phased arrays gebruiken per kanaal/element een faseverschuiver (en vaak ook een regelbare gain-trap) in analoge RF-hardware. Dat betekent dat een analoge phased array meestal gespecialiseerde hardware is naast je SDR, of speciaal voor een toepassing wordt ontworpen. Aan de andere kant kan elke SDR met meer dan een kanaal als digitale array werken zonder extra hardware, mits de kanalen fasecoherent zijn en dezelfde klok gebruiken; dat is doorgaans zo bij SDR's met meerdere ontvangstkanalen op dezelfde print. + + Er zijn veel SDR's met **twee** ontvangstkanalen, zoals de Ettus USRP B210 en Analog Devices Pluto (waar het tweede kanaal via een uFL-connector op het bord beschikbaar is). Boven twee kanalen kom je helaas vaak in het $10k+-segment terecht (stand 2023), zoals de Ettus USRP N310 of Analog Devices QuadMXFE (16 kanalen). Een belangrijk probleem is dat goedkope SDR's meestal niet eenvoudig te koppelen zijn om op te schalen in kanaalaantal. Een uitzondering is de KerberosSDR (4 kanalen) en KrakenSDR (5 kanalen), die meerdere RTL-SDR's met gedeelde LO combineren tot een betaalbare digitale array. Nadeel is de beperkte samplerate (tot 2,56 MHz) en het beperkte afstembereik (tot 1766 MHz). De KrakenSDR-print en een voorbeeld van een antenne-opstelling staan hieronder. .. image:: ../_images/krakensdr.jpg @@ -57,7 +75,7 @@ Er zijn veel SDR's die **twee** ontvangstkanalen bevatten, zoals de Ettus USRP B :alt: The KrakenSDR :target: ../_images/krakensdr.jpg -In dit hoofdstuk zullen we geen specifieke SDR's gebruiken; in plaats daarvan simuleren we het ontvangen van signalen met Python, en gaan we door de benodigde bewerkingen voor bundelvorming/DOA. +In dit hoofdstuk gebruiken we geen specifieke SDR-hardware; in plaats daarvan simuleren we ontvangen signalen in Python en doorlopen we de DSP-stappen voor bundelvorming/DOA bij digitale arrays. ******************************************** @@ -129,18 +147,18 @@ Hier zijn enkele veelvoorkomende bewerkingen in zowel MATLAB als Python, als een - :code:`[A A]` - :code:`np.concatenate((A,A))` -******************* -Basiswiskunde -******************* +********************* +Stuurvector +********************* -Voordat we met de leuke dingen beginnen zullen we eerst een beetje wiskunde moeten behandelen. Het volgende deel is wel zo geschreven dat de wiskunde extreem simpel is met figuren erbij. Alleen de meest basale goniometrische en exponentiële eigenschappen worden gebruikt. Deze basiswiskude is belangrijk om later de pythoncode te begrijpen waarmee we DOA uitvoeren. +Voor we naar de leuke stukken gaan moeten we eerst een beetje wiskunde doen, maar dit deel is zo opgezet dat het relatief rechttoe rechtaan blijft en met figuren wordt ondersteund. We gebruiken alleen basale goniometrische en exponentiele eigenschappen. Deze basis is belangrijk om later de Python-code voor DOA goed te begrijpen. We hebben een 1 dimensionale array van antennes die uniform zijn uitgespreid: .. image:: ../_images/doa.svg :align: center :target: ../_images/doa.svg - :alt: Diagram showing direction of arrival (DOA) of a signal impinging on a uniformly spaced antenna array, showing boresight angle and distance between elements or apertures + :alt: Diagram showing direction of arrival (DOA) of a signal impinging on a uniformly spaced antenna array, showing kijkrichting angle and distance between elements or apertures In dit voorbeeld komt het signaal van rechts dus het raakt het meest rechtste element als eerste. Laten we de vertraging berekenen tussen wanneer het signaal het eerste element raakt en wanneer het het volgende element bereikt. We kunnen dit doen door het volgende trigonometrische probleem te vormen, probeer te begrijpen hoe deze driehoek is gevormd vanuit het bovenstaande figuur. Het rode segment vertegenwoordigt de afstand die het signaal moet afleggen *nadat* het het eerste element heeft bereikt en voordat het het volgende element raakt. @@ -156,62 +174,93 @@ Als je SOS CAS TOA nog kent, zijn we in dit geval geinteresseerd in de "aanligge De aanliggende vertelt ons hoe ver het signaal moet reizen tussen het raken van het eerste en het raken van het volgende element, dus het wordt aanliggende :math:`= d \cos(90 - \theta)`. Nu is er een goniometrische identiteit die ons in staat stelt dit om te zetten in aanliggende :math:`= d \sin(\theta)`. Dit is slechts een afstand, we moeten dit omzetten in een tijd met behulp van de lichtsnelheid: verstreken tijd :math:`= d \sin(\theta) / c` [seconden]. Deze vergelijking geldt tussen elk aangrenzend element van onze array, hoewel we het hele ding met een geheel getal kunnen vermenigvuldigen om de niet-aangrenzende elementen te berekenen, omdat ze gelijkmatig verdeeld zijn (dit zullen we later doen). -Nu zullen we deze formules koppelen aan de DSP-wereld. Laten we ons signaal op de basisband :math:`s(t)` noemen en het verzenden op een bepaalde frequentie, :math:`f_c`, dus het verzonden signaal is :math:`s(t) e^{2j \pi f_c t}`. Laten we zeggen dat dit signaal het eerste element op tijd :math:`t = 0` raakt, wat betekent dat het volgende element na :math:`d \sin(\theta) / c` [seconden] wordt geraakt, zoals we hierboven hebben berekend. Het tweede element ontvangt dan: +Nu zullen we deze gonio en lichtsnelheid formules koppelen aan de DSP-wereld. Laten we ons signaal op de basisband :math:`x(t)` noemen en het verzenden op een bepaalde frequentie, :math:`f_c`, dus het verzonden signaal is :math:`x(t) e^{2j \pi f_c t}`. We gebruiken :math:`d_m` om de afstand in meters tussen de elementen aan te geven. Laten we zeggen dat dit signaal het eerste element op tijd :math:`t = 0` raakt, wat betekent dat het volgende element na :math:`d_m \sin(\theta) / c` [seconden] wordt geraakt, zoals we hierboven hebben berekend. Het tweede element ontvangt dan: .. math:: - s(t - \Delta t) e^{2j \pi f_c (t - \Delta t)} + x(t - \Delta t) e^{2j \pi f_c (t - \Delta t)} .. math:: - \mathrm{waar} \quad \Delta t = d \sin(\theta) / c + \mathrm{waar} \quad \Delta t = d_m \sin(\theta) / c tijdverschuivingen worden afgetrokken van het tijdsargument. -De ontvanger of SDR vermenigvuldigt effectief het signaal met de draaggolf, maar in omgekeerde richting. Na de verschuiving naar de basisband ziet de ontvanger: +De ontvanger of SDR vermenigvuldigt het signaal met de draaggolf, maar in omgekeerde richting. Na de verschuiving naar de basisband ziet de ontvanger: .. math:: - s(t - \Delta t) e^{2j \pi f_c (t - \Delta t)} e^{-2j \pi f_c t} + x(t - \Delta t) e^{2j \pi f_c (t - \Delta t)} e^{-2j \pi f_c t} .. math:: - = s(t - \Delta t) e^{-2j \pi f_c \Delta t} + = x(t - \Delta t) e^{-2j \pi f_c \Delta t} -Met een kleine truc is dit nog verder te vereenvoudigen. Bedenk dat wanneer we een signaal samplen, we dit kunnen modelleren door :math:`t` te vervangen door :math:`nT` waar :math:`T` de sampleperiodetijd is en :math:`n` gewoon 0, 1, 2, 3... . Door dit in te vullen krijgen we :math:`s(nT - \Delta t) e^{-2j \pi f_c \Delta t}`. Welnu, :math:`nT` is zoveel groter dan :math:`\Delta t` dat we het eerste :math:`\Delta t`-termijn kunnen weglaten en we :math:`s(nT) e^{-2j \pi f_c \Delta t}` overhouden. Als de samplefrequentie ooit snel genoeg wordt om de snelheid van het licht over een kleine afstand te benaderen, kunnen we dit opnieuw bekijken, maar onthoud dat onze samplefrequentie slechts een beetje hoger moet zijn dan de bandbreedte van het signaal van belang. +Met een kleine truc is dit nog verder te vereenvoudigen. Wanneer we een signaal samplen, kunnen we :math:`t` vervangen door :math:`nT`, waarbij :math:`T` de sampleperiode is en :math:`n` gelijk is aan 0, 1, 2, 3... . Dan krijgen we :math:`x(nT - \Delta t) e^{-2j \pi f_c \Delta t}`. Voor een smalbandig signaal verandert de envelop langzaam genoeg over de propagatievertraging :math:`\Delta t`, zodat we :math:`x(nT - \Delta t) \approx x(nT)` mogen aannemen. Dan blijft over: :math:`x(nT) e^{-2j \pi f_c \Delta t}`. Als de samplerate ooit hoog genoeg wordt om de lichtsnelheid over zeer kleine afstanden te benaderen, moeten we deze aanname opnieuw beoordelen. In de praktijk is de samplerate echter slechts iets hoger dan de bandbreedte van het signaal van interesse. Laten we doorgaan met deze wiskunde maar dingen in discrete termen gaan vertegenwoordigen zodat het meer op onze Python-code lijkt. De laatste vergelijking kan als volgt worden voorgesteld, laten we :math:`\Delta t` weer invullen: .. math:: - s[n] e^{-2j \pi f_c \Delta t} + x[n] e^{-2j \pi f_c \Delta t} .. math:: - = s[n] e^{-2j \pi f_c d \sin(\theta) / c} + = x[n] e^{-2j \pi f_c d_m \sin(\theta) / c} We zijn bijna klaar. Gelukkig is er nog een vereenvoudiging die we kunnen maken. Herinner je de relatie tussen middenfrequentie en golflengte: :math:`\lambda = \frac{c}{f_c}` of de vorm die we zullen gebruiken: :math:`f_c = \frac{c}{\lambda}`. Als we dit invullen krijgen we: .. math:: - s[n] e^{-2j \pi \frac{c}{\lambda} d \sin(\theta) / c} + = x[n] e^{-2j \pi d \sin(\theta) / \lambda} + +Wat we normaal willen doen met DOA is de afstand tussen twee elementen uit te drukken als een fractie van de golflengte in plaats van meters. De meest gekozen waarde tijdens het ontwerpen van een array is om voor :math:`d` een halve golflengte te gebruiken. Ongeacht wat :math:`d` is, vanaf dit punt gaan we :math:`d` uitdrukken als een fractie van de golflengte in plaats van meters, waardoor de vergelijking en al onze code eenvoudiger wordt. Dus, :math:`d` (zonder subscript :math:`m`) is de genormaliseerde afstand, gelijk aan :math:`d = d_m / \lambda`. Dan kunnen we de vergelijking nog verder vereenvoudigen tot: .. math:: - = s[n] e^{-2j \pi d \sin(\theta) / \lambda} + x[n] e^{-2j \pi d \sin(\theta)} -Wat we normaal willen doen met DOA si de afstand tussen twee elementen uit te drukken als een fractie van de golflengte. De meest gekozen waarde tijdens het ontwerpen van een array is om voor :math:`d` een halve golflengte te gebruiken. Ongeacht wat :math:`d` is, vanaf dit punt gaan we :math:`d` uitdrukken als een fractie van de golflengte in plaats van meters, waardoor de vergelijking en al onze code eenvoudiger wordt: +Dit is voor aangrenzende elementen, voor het :math:`k`'de element moeten we gewoon :math:`d` keer :math:`k` vermenigvuldigen: .. math:: - s[n] e^{-2j \pi d \sin(\theta)} + x[n] e^{-2j \pi d k \sin(\theta)} -Dit is voor aangrenzende elementen, voor het :math:`k`'de element moeten we gewoon :math:`d` keer :math:`k` vermenigvuldigen: +Nu moeten we afspreken welke conventies we willen gebruiken voor het coordinatenstelsel. In dit boek gaan we ervan uit dat 0 graden de raaklijn is van de plaatsing van de array (d.w.z. de lijn waarop de elementen zich bevinden), zoals te zien is in het bovenstaande diagram, en dat theta met de klok mee toeneemt. We zullen ook het meest linker element als het referentie-element beschouwen, en elk extra element ligt dan :math:`d_m` verder naar rechts. Dit is het tegenovergestelde van ons diagram hierboven, dus we moeten de richting van de faseverschuiving omkeren, wat betekent dat we het negatieve teken moeten verwijderen: + +.. math:: + x[n] e^{2j \pi d k \sin(\theta)} + +Dit kunnen we in matrixformaat gieten door k op te laten lopen voor alle :code:`Nr`elementen in de array, van :math:`k = 0, 1, ... , N-1`: .. math:: - s[n] e^{-2j \pi d k \sin(\theta)} -Nu zijn we klaar! De bovenstaande vergelijking zul je in alle DOA artikelen en implementaties tegenkomen! We noemen die exponentiële term de "array factor" (vaak aangeduid als :math:`a`) en stellen het voor als een array, een 1D array voor een 1D antenne array, enz. In Python is :math:`a`: + x + \begin{bmatrix} + e^{2j \pi d (0) \sin(\theta)} \\ + e^{2j \pi d (1) \sin(\theta)} \\ + e^{2j \pi d (2) \sin(\theta)} \\ + \vdots \\ + e^{2j \pi d (N_r - 1) \sin(\theta)} \\ + \end{bmatrix} + +Hierbij is :math:`x` de 1D rij-vector van het te verzenden signaal, en noemen we de getoonde kolom-vector de "stuurvector" (vaak aangeduid als :math:`s` en in code :code:`s`) en stellen we deze voor als een array, een 1D array voor een 1D antenne array, enz. Omdat :math:`e^{0} = 1`, is het eerste element van de stuurvector altijd 1, en de rest zijn faseverschuivingen ten opzichte van het eerste element: + +.. math:: + + s = + \begin{bmatrix} + 1 \\ + e^{2j \pi d (1) \sin(\theta)} \\ + e^{2j \pi d (2) \sin(\theta)} \\ + \vdots \\ + e^{2j \pi d (N_r - 1) \sin(\theta)} \\ + \end{bmatrix} + + +Nu zijn we klaar! De bovenstaande vergelijking zul je in alle DOA artikelen en ULA implementaties tegenkomen! Je kunt ook tegenkomen dat :math:`2\pi\sin(\theta)` als :math:`\psi` wordt uitgedrukt, waardoor de stuurvector gelijk wordt aan :math:`e^{jd\psi}`, de meer algemene vorm (die we dus niet gebruiken). In python is :code:`s`: .. code-block:: python - a = [np.exp(-2j*np.pi*d*0*np.sin(theta)), np.exp(-2j*np.pi*d*1*np.sin(theta)), np.exp(-2j*np.pi*d*2*np.sin(theta)), ...] # let op de oplopende k + s = [np.exp(2j*np.pi*d*0*np.sin(theta)), np.exp(2j*np.pi*d*1*np.sin(theta)), np.exp(2j*np.pi*d*2*np.sin(theta)), ...] # k wordt hier dus opgehoogd # of - a = np.exp(-2j * np.pi * d * np.arange(Nr) * np.sin(theta)) # Nr is het aantal elementen in de array + s = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta)) # met Nr het aaantal ontvangstantennes -Merk op dat het eerste element in een 1+0j resulteert (omdat :math:`e^{0}=1`); dit is logisch omdat alles hierboven relatief is aan dat eerste element, dus het ontvangt het signaal zoals het is zonder enige relatieve faseverschuivingen. Dit is puur hoe dat resulteert uit de wiskunde. In werkelijkheid kan elk element als referentie worden beschouwd, maar zoals je later in onze wiskunde/code zult zien, is het verschil in fase/amplitude dat tussen elementen wordt ontvangen wat telt. Het is allemaal relatief. +Merk op dat het eerste element in een 1+0j resulteert (omdat :math:`e^{0}=1`); dit is logisch omdat alles hierboven relatief is aan dat eerste element, dus het ontvangt het signaal zoals het is zonder enige relatieve faseverschuivingen. Dit is puur hoe dat resulteert uit de wiskunde. In werkelijkheid kan elk element als referentie worden gebruikt, maar zoals je later in onze wiskunde/code zult zien, is het verschil in fase/amplitude dat tussen elementen wordt ontvangen wat telt. Het is allemaal relatief. + +Vergeet niet dat :code:`d` is uitgedrukt in golflengte als eenheid en niet in meters! ********************** Een signaal ontvangen @@ -241,23 +290,23 @@ Nu gaan we een antenne simuleren, met drie omnidirectionele antennes op een rij, Nr = 3 theta_degrees = 20 # aankomstrichting in graden theta = theta_degrees / 180 * np.pi # naar radialen - a = np.exp(-2j * np.pi * d * np.arange(Nr) * np.sin(theta)) # array factor van hierboven - print(a) # 3 complexe elementen, de eerste is 1+0j + s = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta)) # de stuurvector + print(s) # 3 complexe elementen, de eerste is 1+0j -Nu gaan we het signaal ontvangen. Om de array factor toe te passen moeten we een matrixvermenigvuldiging van :code:`a` en :code:`tx` uitvoeren, dus laten we beide omzetten naar 2D met de metode die we eerder hebben besproken toen we de matrixwiskunde in Python doornamen. Eerst zetten we het om naar rijvectoren met :code:`x.reshape(-1,1)`. Vervolgens voeren we de matrixvermenigvuldiging uit, aangegeven door het :code:`@`-symbool. Ook moeten we met een transpositie-operatie :code:`tx` omzetten van een rijvector naar een kolomvector (zie het als een rotatie van 90 graden), zodat de matrixvermenigvuldiging gelijke binnenste dimensies heeft. +Om de array factor toe te passen moeten we een matrixvermenigvuldiging doen van :code:`s` en :code:`tx`, dus laten we beide omzetten naar 2D met de methode die we eerder hebben besproken toen we de matrixwiskunde in Python doornamen. Eerst zetten we het om naar rijvectoren met :code:`onzearray.reshape(-1,1)`. Vervolgens voeren we de matrixvermenigvuldiging uit, aangegeven door het :code:`@`-symbool. Ook moeten we met een transpositie-operatie :code:`tx` omzetten van een rijvector naar een kolomvector (zie het als een rotatie van 90 graden), zodat de matrixvermenigvuldiging gelijke binnenste dimensies heeft. .. code-block:: python - a = a.reshape(-1,1) - print(a.shape) # 3x1 - tx = tx.reshape(-1,1) - print(tx.shape) # 10000x1 + s = s.reshape(-1,1) # omzetten naar een kolomvector + print(s.shape) # 3x1 + tx = tx.reshape(1,-1) # meteen transponeren naar een rijvector + print(tx.shape) # 1x10000x # matrixvermenigvuldiging - r = a @ tx.T # laat je niet afleiden door het transponeren, het belangrijkste is dat we de het tx signaal vermenigvuldigen met de a-factor - print(r.shape) # 3x10000. r is nu tweedimensionaal: tijd en afstand + X = s @ tx # We simuleren het ontvangen signaal X met een matrixvermenigvuldiging + print(X.shape) # 3x10000. X is nu tweedimensionaal: tijd en afstand -Op dit moment is :code:`r` een 2D array van 3 x 10000 elementen. Dit is omdat we drie array-elementen en 10000 gesimuleerde samples hebben. We kunnen elk individueel signaal eruit halen en de eerste 200 samples laten zien. Hieronder zullen we alleen de reële delen weergeven, maar net als bij elk basisbandsignaal is er ook een imaginair deel. Een vervelend onderdeel van matrixwiskunde in Python is dat we :code:`.squeeze()` moeten toevoegen oom de extra dimensies met lengte 1 te verwijderen, zodat we naar een normale 1D NumPy-array gaan die we verder kunnen gebruiken. +Op dit moment is :code:`X` een 2D array van 3 x 10000 elementen. Dit is omdat we drie array-elementen en 10000 gesimuleerde samples hebben. We gebruiken de hoofdletter :code:`X` om duidelijk aan tegeven dat het om meerdere ontvangen, opgestapelde signalen gaat. We kunnen elk individueel signaal eruit halen en de eerste 200 samples laten zien. Hieronder zullen we alleen de reële delen weergeven, maar net als bij elk basisbandsignaal is er ook een imaginair deel. Een vervelend onderdeel van matrixwiskunde in Python is dat we :code:`.squeeze()` moeten toevoegen oom de extra dimensies met lengte 1 te verwijderen, zodat we naar een normale 1D NumPy-array gaan die we verder kunnen gebruiken. .. code-block:: python @@ -269,56 +318,58 @@ Op dit moment is :code:`r` een 2D array van 3 x 10000 elementen. Dit is omdat we .. image:: ../_images/doa_time_domain.svg :align: center :target: ../_images/doa_time_domain.svg + +Het faseverschil tussen de element is zoals we hadden verwacht (tenzij het signaal haaks aankomt, en dan alle element op het zelfde moment bereikt, en er dus geen verschuiving is, zet theta op 0 om dit te zien). Probeer de hoek aan te passen en kijk wat er gebeurt. -Note the phase shifts between elements like we expect to happen (unless the signal arrives at boresight in which case it will reach all elements at the same time and there wont be a shift, set theta to 0 to see). Element 0 appears to arrive first, with the others slightly delayed. Try adjusting the angle and see what happens. +Laten we als laatste nog wat ruis toevoegen aan dit ontvangen signaal, want elk signaal dat we zullen behandelen heeft een bepaalde hoeveelheid ruis. We willen de ruis toepassen nadat de stuurvector is toegepast, omdat elk element een onafhankelijk ruisignaal ervaart (we kunnen dit doen omdat AWG-ruis na een faseverschuiving nog steeds AWG-ruis is): -As one final step, let's add noise to this received signal, as every signal we will deal with has some amount of noise. We want to apply the noise after the array factor is applied, because each element experiences an independent noise signal (we can do this because AWGN with a phase shift applied is still AWGN): .. code-block:: python n = np.random.randn(Nr, N) + 1j*np.random.randn(Nr, N) - r = r + 0.5*n # r and n are both 3x10000 + X = X + 0.1*n # X en n zijn allebij 3x10000 .. image:: ../_images/doa_time_domain_with_noise.svg :align: center :target: ../_images/doa_time_domain_with_noise.svg -******************* -Conventional DOA -******************* +*********************************** +Conventionele Bundelvorming en DOA +*********************************** -We will now process these samples :code:`r`, pretending we don't know the angle of arrival, and perform DOA, which involves estimating the angle of arrival(s) with DSP and some Python code! As discussed earlier in this chapter, the act of beamforming and performing DOA are very similar and are often built off the same techniques. Throughout the rest of this chapter we will investigate different "beamformers", and for each one we will start with the beamformer math/code that calculates the weights, :math:`w`. These weights can be "applied" to the incoming signal :code:`r` through the simple equation :math:`w^H r`, or in Python :code:`w.conj().T @ r`. In the example above, :code:`r` is a :code:`3x10000` matrix, but after we apply the weights we are left with :code:`1x10000`, as if our receiver only had one antenna, and we can use normal RF DSP to process the signal. After developing the beamformer, we will apply that beamformer to the DOA problem. +We gaan deze samples :code:`X` nu verwerken alsof we de aankomstrichting niet kennen, en vervolgens DOA uitvoeren. Daarbij schatten we de aankomstrichting(en) met DSP en Python-code. Zoals eerder in dit hoofdstuk besproken zijn bundelvorming en DOA sterk aan elkaar verwant en vaak gebaseerd op dezelfde technieken. In de rest van dit hoofdstuk bekijken we verschillende bundelvormers. Voor elke techniek starten we met de wiskunde/code om de gewichten, :math:`w`, te berekenen. Deze gewichten kunnen we vervolgens op het inkomende signaal :code:`X` "toepassen" met de eenvoudige vergelijking :math:`w^H X`, of in Python :code:`w.conj().T @ X`. In het voorbeeld hierboven is :code:`X` een :code:`3x10000`-matrix, maar na het toepassen van de gewichten houden we :code:`1x10000` over, alsof onze ontvanger maar één antenne heeft. Daarna kunnen we normale RF signaalbewerking toepassen op het signaal. Zodra we de bundelvormer hebben opgebouwd, passen we die toe op het DOA-probleem. -We'll start with the "conventional" beamforming approach, a.k.a. delay-and-sum beamforming. Our weights vector :code:`w` needs to be a 1D array for a uniform linear array, in our example of three elements, :code:`w` is a :code:`3x1` array of complex weights. With conventional beamforming we leave the magnitude of the weights at 1, and adjust the phases so that the signal constructively adds up in the direction of our desired signal, which we will refer to as :math:`\theta`. It turns out that this is the exact same math we did above! +We beginnen met de "conventionele" bundelvormingsaanpak, ook wel delay-and-sum genoemd. Onze gewichtenvector :code:`w` moet voor een uniforme lineaire array een 1D-array zijn. In ons voorbeeld met drie elementen is :code:`w` een :code:`3x1`-array met complexe gewichten. Bij conventionele bundelvorming laten we de amplitudes van de gewichten op 1 staan en passen we alleen de fases aan, zodat het signaal constructief in de richting van het gewenste signaal optelt, aangeduid met :math:`\theta`. Dit blijkt exact dezelfde wiskunde te zijn als hierboven; onze gewichten zijn dus gewoon onze stuurvector. .. math:: - w_{conventional} = e^{-2j \pi d k \sin(\theta)} + w_{conv} = e^{2j \pi d k \sin(\theta)} -or in Python: +of in Python: .. code-block:: python - w = np.exp(-2j * np.pi * d * np.arange(Nr) * np.sin(theta)) # Conventional, aka delay-and-sum, beamformer - r = w.conj().T @ r # example of applying the weights to the received signal (i.e., perform the beamforming) + w = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta)) # conventionele, oftewel delay-and-sum-beamformer + X_weighted = w.conj().T @ X # voorbeeld van gewichten toepassen op het ontvangen signaal (dus bundelvorming uitvoeren) + print(X_weighted.shape) # 1x10000 -where :code:`Nr` is the number of elements in our uniform linear array with spacing of :code:`d` fractions of wavelength (most often ~0.5). As you can see, the weights don't depend on anything other than the array geometry and the angle of interest. If our array involved calibrating the phase, we would include those calibration values too. +waar :code:`Nr` het aantal elementen is in onze uniforme lineaire array met een onderlinge afstand van :code:`d` golflengtefracties (meestal ~0,5). Zoals je ziet hangen de gewichten alleen af van de arraygeometrie en de gewenste hoek. Als onze array fasekalibratie nodig heeft, nemen we die kalibratiewaarden ook mee. Je ziet in de vergelijking voor :code:`w` ook dat de gewichten complex zijn en allemaal een amplitude van één (unity) hebben. -But how do we know the angle of interest :code:`theta`? We must start by performing DOA, which involves scanning through (sampling) all directions of arrival from -π to +π (-180 to +180 degrees), e.g., in 1 degree increments. At each direction we calculate the weights using a beamformer; we will start by using the conventional beamformer. Applying the weights to our signal :code:`r` will give us a 1D array of samples, as if we received it with 1 directional antenna. We can then calculate the power in the signal by taking the variance with :code:`np.var()`, and repeat for every angle in our scan. We will plot the results and look at it with our human eyes/brain, but what most RF DSP does is find the angle of maximum power (with a peak-finding algorithm) and call it the DOA estimate. +Maar hoe kennen we de gewenste hoek :code:`theta`? We moeten eerst DOA uitvoeren, waarbij we alle aankomstrichtingen van -π tot +π (-180 tot +180 graden) scannen (samplen), bijvoorbeeld in stappen van 1 graad. Voor elke richting berekenen we de gewichten met een bundelvormer; we beginnen met de conventionele bundelvormer. Als we de gewichten op :code:`X` toepassen, krijgen we een 1D-array met samples, alsof we met één richtantenne ontvangen. Daarna kunnen we het signaalvermogen bepalen via de variantie met :code:`np.var()`, en dit herhalen voor elke hoek in de scan. We plotten de resultaten en beoordelen ze visueel, maar in de praktijk zoekt RF-DSP meestal de hoek met het maximale vermogen (via een piekzoekalgoritme) en noemt die de DOA-schatting. .. code-block:: python - theta_scan = np.linspace(-1*np.pi, np.pi, 1000) # 1000 different thetas between -180 and +180 degrees + theta_scan = np.linspace(-1*np.pi, np.pi, 1000) # 1000 verschillende theta-waarden tussen -180 en +180 graden results = [] for theta_i in theta_scan: - w = np.exp(-2j * np.pi * d * np.arange(Nr) * np.sin(theta_i)) # Conventional, aka delay-and-sum, beamformer - r_weighted = w.conj().T @ r # apply our weights. remember r is 3x10000 - results.append(10*np.log10(np.var(r_weighted))) # power in signal, in dB so its easier to see small and large lobes at the same time - results -= np.max(results) # normalize + w = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta_i)) # conventionele, oftewel delay-and-sum-beamformer + X_weighted = w.conj().T @ X # pas de gewichten toe; onthoud dat X 3x10000 is + results.append(10*np.log10(np.var(X_weighted))) # signaalvermogen in dB, zodat kleine en grote lobben tegelijk zichtbaar zijn + results -= np.max(results) # normalize (optional) - # print angle that gave us the max value + # print de hoek die de maximale waarde geeft print(theta_scan[np.argmax(results)] * 180 / np.pi) # 19.99999999999998 - plt.plot(theta_scan*180/np.pi, results) # lets plot angle in degrees + plt.plot(theta_scan*180/np.pi, results) # plot de hoek in graden plt.xlabel("Theta [Degrees]") plt.ylabel("DOA Metric") plt.grid() @@ -328,249 +379,762 @@ But how do we know the angle of interest :code:`theta`? We must start by perfor :align: center :target: ../_images/doa_conventional_beamformer.svg -We found our signal! You're probably starting to realize where the term electrically steered array comes in. Try increasing the amount of noise to push it to its limit, you might need to simulate more samples being received for low SNRs. Also try changing the direction of arrival. +We hebben ons signaal gevonden. Je ziet nu waarschijnlijk ook waar de term "elektronisch gestuurde array" vandaan komt. Probeer de hoeveelheid ruis te verhogen om de limiet op te zoeken; bij lage SNR heb je mogelijk meer gesimuleerde samples nodig. Probeer ook de aankomstrichting te veranderen. -If you prefer viewing angle on a polar plot, use the following code: +Als je de DOA-resultaten liever in een poolplot ziet, gebruik dan de volgende code: .. code-block:: python fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}) - ax.plot(theta_scan, results) # MAKE SURE TO USE RADIAN FOR POLAR - ax.set_theta_zero_location('N') # make 0 degrees point up - ax.set_theta_direction(-1) # increase clockwise - ax.set_rlabel_position(55) # Move grid labels away from other labels + ax.plot(theta_scan, results) # GEBRUIK RADIALEN VOOR EEN POOLPLOT + ax.set_theta_zero_location('N') # maak dat 0 graden omhoog wijst + ax.set_theta_direction(-1) # laat de hoek met de klok mee toenemen + ax.set_rlabel_position(55) # verplaats rasterlabels weg van andere labels plt.show() .. image:: ../_images/doa_conventional_beamformer_polar.svg :align: center :target: ../_images/doa_conventional_beamformer_polar.svg - :alt: Example polar plot of performing direction of arrival (DOA) showing the beam pattern and 180 degree ambiguity + :alt: Example polar plot of performing direction of arrival (DOA) showing the beam pattern and 180-degree ambiguity -We will keep seeing this pattern of looping over angles, and having some method of calculating the beamforming weights, then applying them to the recieved signal. In the next beamforming method (MVDR) we will use our received signal :code:`r` as part of the weight calculations, making it an adaptive technique. But first we will investigate some interesting things that happen with phased arrays, including why we have that second peak at 160 degrees. +We blijven dit patroon terugzien: over alle hoeken, op een bepaalde manier de gewichten berekenen en die vervolgens op het ontvangen signaal toepassen. In de volgende methode (MVDR) gebruiken we het ontvangen signaal :code:`X` ook in de gewichtenberekening, waardoor het een adaptieve techniek wordt. Maar eerst bekijken we een paar interessante effecten van phased arrays, waaronder waarom er een tweede piek bij 160 graden staat. -******************** -180 Degree Ambiguity -******************** +********************* +180-gradenambiguiteit +********************* -Let's talk about why is there a second peak at 160 degrees; the DOA we simulated was 20 degrees, but it is not a coincidence that 180 - 20 = 160. Picture three omnidirectional antennas in a line placed on a table. The array's boresight is 90 degrees to the axis of the array, as labeled in the first diagram in this chapter. Now imagine the transmitter in front of the antennas, also on the (very large) table, such that its signal arrives at a +20 degree angle from boresight. Well the array sees the same effect whether the signal is arriving with respect to its front or back, the phase delay is the same, as depicted below with the array elements in red and the two possible transmitter DOA's in green. Therefore, when we perform the DOA algorithm, there will always be a 180 degree ambiguity like this, the only way around it is to have a 2D array, or a second 1D array positioned at any other angle w.r.t the first array. You may be wondering if this means we might as well only calculate -90 to +90 degrees to save compute cycles, and you would be correct! +Laten we bespreken waarom er een tweede piek op 160 graden staat. De gesimuleerde DOA was 20 graden, en het is geen toeval dat 180 - 20 = 160. Stel je drie omnidirectionele antennes in een lijn op een tafel voor. De kijkrichting van de array staat 90 graden op de as van de array, zoals in het eerste diagram van dit hoofdstuk. Denk nu aan een zender vóór de antennes, ook op die (erg grote) tafel, zodat het signaal binnenkomt onder +20 graden ten opzichte van de kijkrichting. Voor de array is het faseverschil echter hetzelfde of het signaal van voren of van achteren komt. Dat zie je hieronder, met de array-elementen in rood en de twee mogelijke DOA-posities van de zender in groen. Daarom krijg je bij het uitvoeren van een DOA-algoritme altijd dit soort 180-gradenambiguiteit. De enige oplossing is een 2D-array, of een tweede 1D-array onder een andere hoek ten opzichte van de eerste. Je vraagt je misschien af of je dan net zo goed alleen van -90 tot +90 graden kunt rekenen om rekentijd te besparen. Dat klopt. .. image:: ../_images/doa_from_behind.svg :align: center :target: ../_images/doa_from_behind.svg -*********************** -Broadside of the Array -*********************** - -To demonstrate this next concept, let's try sweeping the angle of arrival (AoA) from -90 to +90 degrees instead of keeping it constant at 20: +Laten we de aankomstrichting (Engels: Angle of Arrival, AoA) eens sweepen van -90 tot +90 graden, in plaats van hem constant op 20 te houden: .. image:: ../_images/doa_sweeping_angle_animation.gif :scale: 100 % :align: center - :alt: Animation of direction of arrival (DOA) showing the broadside of the array + :alt: Animation of direction of arrival (DOA) showing the endfire of the array -As we approach the broadside of the array (a.k.a. endfire), which is when the signal arrives at or near the axis of the array, performance drops. We see two main degradations: 1) the main lobe gets wider and 2) we get ambiguity and don't know whether the signal is coming from the left or the right. This ambiguity adds to the 180 degree ambiguity discussed earlier, where we get an extra lobe at 180 - theta, causing certain AoA to lead to three lobes of roughly equal size. This broadside ambiguity makes sense though, the phase shifts that occur between elements are identical whether the signal arrives from the left or right side w.r.t. the array axis. Just like with the 180 degree ambiguity, the solution is to use a 2D array or two 1D arrays at different angles. In general, beamforming works best when the angle is closer to the boresight. +Wanneer we de endfire-regio van de array naderen (dus wanneer het signaal op of dicht bij de array-as aankomt), daalt de prestatie. We zien twee belangrijke verslechteringen: 1) de hoofdlob wordt breder en 2) er ontstaat ambiguiteit, waardoor je niet weet of het signaal van links of rechts komt. Deze ambiguiteit komt boven op de eerder besproken 180-gradenambiguiteit, waarbij je een extra lob op 180 - theta krijgt. Daardoor kunnen bepaalde AoA's tot drie lobben van ongeveer gelijke grootte leiden. Deze endfire-ambiguiteit is logisch: de faseverschuivingen tussen elementen zijn identiek of het signaal nu van links of rechts van de array-as komt. Net als bij de 180-gradenambiguiteit is de oplossing een 2D-array of twee 1D-arrays onder verschillende hoeken. In het algemeen werkt bundelvorming het beste wanneer de hoek dichter bij de kijkrichting ligt. -******************* -When d is not λ/2 -******************* +Vanaf nu tonen we in poolplots alleen nog -90 tot +90 graden, omdat het patroon voor 1D-lineaire arrays (waar dit hoofdstuk over gaat) toch gespiegeld is rond de array-as. + +******************** +Bundelpatroon +******************** + +De grafieken die we tot nu toe hebben getoond zijn DOA-resultaten; ze geven het ontvangen vermogen per hoek na het toepassen van de bundelvormer. Ze horen bij een specifiek scenario met zenders op bepaalde hoeken. We kunnen echter ook het bundelpatroon zelf bekijken, dus vóórdat we een signaal ontvangen. Dit heet soms het rustpatroon of de arrayrespons. + +Onthoud dat onze stuurvector, die we steeds terugzien, + +.. code-block:: python + + np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta)) + +de ULA-geometrie vastlegt, en als extra parameter alleen de richting heeft waar je naartoe wilt sturen. We kunnen het rustpatroon (arrayrespons) berekenen en plotten voor een gekozen stuurhoek. Dat laat de natuurlijke respons van de array zien als we geen extra bundelvorming toepassen. Dit kan door de FFT van de complex geconjugeerde gewichten te nemen, dus zonder for-loop. Het lastige deel is zero-padding voor extra resolutie en het mappen van FFT-bins naar hoeken in radialen of graden, waarbij een arcsinus nodig is, zoals je in het voorbeeld hieronder ziet. + +.. code-block:: python + + Nr = 3 + d = 0.5 + N_fft = 512 + theta_degrees = 20 # er is geen SOI; we verwerken geen samples, dit is alleen de richting waar we op richten + theta = theta_degrees / 180 * np.pi + w = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta)) # conventionele beamformer + w_padded = np.concatenate((w, np.zeros(N_fft - Nr))) # zero-pad naar N_fft elementen voor meer FFT-resolutie + w_fft_dB = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(w_padded)))**2) # FFT-magnitude in dB + w_fft_dB -= np.max(w_fft_dB) # normalize to 0 dB at peak + + # map FFT-bins naar hoeken in radialen + theta_bins = np.arcsin(np.linspace(-1, 1, N_fft)) # in radians + + # vind het maximum zodat we het in de plot kunnen tonen + theta_max = theta_bins[np.argmax(w_fft_dB)] + + fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}) + ax.plot(theta_bins, w_fft_dB) # GEBRUIK RADIALEN VOOR EEN POOLPLOT + ax.plot([theta_max], [np.max(w_fft_dB)],'ro') + ax.text(theta_max - 0.1, np.max(w_fft_dB) - 4, np.round(theta_max * 180 / np.pi)) + ax.set_theta_zero_location('N') # laat 0 graden omhoog wijzen + ax.set_theta_direction(-1) # laat de hoek met de klok mee toenemen + ax.set_rlabel_position(55) # verplaats rasterlabels weg van andere labels + ax.set_thetamin(-90) # toon alleen de bovenste helft + ax.set_thetamax(90) + ax.set_ylim([-30, 1]) # zonder ruis hoeft de schaal maar tot -30 dB te gaan + plt.show() + +.. image:: ../_images/doa_quiescent.svg + :align: center + :target: ../_images/doa_quiescent.svg + +Dit patroon blijkt bijna exact overeen te komen met het patroon dat je krijgt bij DOA met de conventionele bundelvormer (delay-and-sum), wanneer er één toon op `theta_degrees` aanwezig is en weinig tot geen ruis. De plot kan er anders uitzien door hoe ver de y-as in dB naar beneden loopt, of door de FFT-grootte waarmee dit rustpatroon is gemaakt. Probeer :code:`theta_degrees` of het aantal elementen :code:`Nr` te variëren om te zien hoe de respons verandert. + +Voor het leuke, laat de volgende animatie het bundelpatroon van de conventionele bundelvormer zien, voor een 8-element-array die tussen -90 en +90 graden wordt gestuurd. Ook zie je de acht gewichten in het complexe vlak (reële en imaginaire as). + +.. image:: ../_images/delay_and_sum.gif + :scale: 90 % + :align: center + :alt: Beam pattern of delay and sum while viewing each weight on the complex plane + +Let erop dat alle gewichten eenheidsamplitude hebben (ze blijven op de eenheidscirkel), en dat elementen met een hoger indexnummer sneller "draaien". Als je goed kijkt, zie je dat ze bij 0 graden allemaal samenvallen; ze hebben dan allemaal 0 faseverschuiving (1+0j). + +******************** +Array Pulsbreedte +******************** + +Voor wie nieuwsgierig is: er bestaan vergelijkingen die de breedte van de hoofdlob benaderen op basis van het aantal elementen. Ze werken vooral goed bij grotere arrays (bijvoorbeeld 8 elementen of meer). De half-power beamwidth (HPBW) is de breedte op 3 dB onder de piek van de hoofdlob, en is ongeveer :math:`\frac{0.9 \lambda}{N_rd\cos(\theta)}` [1]. Voor halve-golflengteafstand vereenvoudigt dit tot: + +.. math:: + + \text{HPBW} \approx \frac{1.8}{N_r\cos(\theta)} \text{ [radians]} \qquad \text{when } d = \lambda/2 -So far we have been using a distance between elements, d, equal to one half wavelength. So for example, an array designed for 2.4 GHz WiFi with λ/2 spacing would have a spacing of 3e8/2.4e9/2 = 12.5cm or about 5 inches, meaning a 4x4 element array would be about 15" x 15" x the height of the antennas. There are times when an array may not be able to achieve exactly λ/2 spacing, such as when space is restricted, or when the same array has to work on a variety of carrier frequencies. +De first-null beamwidth (FNBW), dus de hoofdlobbreedte van nul tot nul, is ongeveer :math:`\frac{2\lambda}{N_rd}` [1]. Voor halve-golflengteafstand vereenvoudigt dit tot: + +.. math:: + + \text{FNBW} \approx \frac{4}{N_r} \text{ [radians]} \qquad \text{when } d = \lambda/2 + +Laten we de vorige code gebruiken maar :code:`Nr` verhogen naar 16 elementen. Met de vergelijkingen hierboven zou de HPBW, gericht op 20 graden (0,35 radialen), ongeveer 0,12 radialen of **6,8 graden** moeten zijn. De FNBW zou ongeveer 0,25 radialen of **14,3 graden** moeten zijn. Laten we simuleren hoe dicht we daarbij in de buurt komen. Voor het bekijken van bundelbreedtes gebruiken we meestal rechthoekige plots in plaats van poolplots. Hieronder staan de resultaten, met HPBW in groen en FNBW in rood. + +.. image:: ../_images/doa_quiescent_beamwidth.svg + :align: center + :target: ../_images/doa_quiescent_beamwidth.svg -Let's examine when the spacing is greater than λ/2, i.e., too much spacing, by varying d between λ/2 and 4λ. We will remove the bottom half of the polar plot since it's a mirror of the top anyway. +In de plot is het misschien lastig te zien, maar als je ver inzoomt blijkt de HPBW ongeveer 6,8 graden en de FNBW ongeveer 15,4 graden te zijn. Dat ligt dus behoorlijk dicht bij de berekening, zeker voor HPBW. + +********************* +Wanneer d niet λ/2 is +********************* + +Tot nu toe hebben we de elementafstand :math:`d` gelijk genomen aan een halve golflengte. Een array voor 2,4 GHz wifi met λ/2-afstand heeft bijvoorbeeld een elementafstand van 3e8/2.4e9/2 = 12,5 cm (ongeveer 5 inch). Een 4x4-array komt dan uit op ongeveer 15" x 15" x de hoogte van de antennes. Soms kun je echter geen exacte λ/2-afstand halen, bijvoorbeeld door ruimtegebrek, of omdat dezelfde array op meerdere draaggolffrequenties moet werken. + +Laten we bekijken wat er gebeurt als de afstand groter is dan λ/2, dus te groot, door :math:`d` te variëren tussen λ/2 en 4λ. We laten de onderste helft van de poolplot weg, omdat die toch een spiegeling van de bovenkant is. .. image:: ../_images/doa_d_is_large_animation.gif :scale: 100 % :align: center :alt: Animation of direction of arrival (DOA) showing what happens when distance d is much more than half-wavelength -As you can see, in addition to the 180 degree ambiguity we discussed earlier, we now have additional ambiguity, and it gets worse as d gets higher (extra/incorrect lobes form). These extra lobes are known as grating lobes, and they are a result of "spatial aliasing". As we learned in the :ref:`sampling-chapter` chapter, when we don't sample fast enough we get aliasing. The same thing happens in the spatial domain; if our elements are not spaced close enough together w.r.t. the carrier frequency of the signal being observed, we get garbage results in our analysis. You can think of spacing out antennas as sampling space! In this example we can see that the grating lobes don't get too problematic until d > λ, but they will occur as soon as you go above λ/2 spacing. +Zoals je ziet krijgen we, naast de eerder besproken 180-gradenambiguiteit, extra ambiguiteit. Die wordt erger naarmate :math:`d` groter wordt (extra/foute lobben ontstaan). Deze extra lobben heten grating lobes en zijn het gevolg van "spatial aliasing". Zoals we in het :ref:`sampling-chapter`-hoofdstuk hebben gezien: als je niet snel genoeg samplet, krijg je aliasing. Hetzelfde gebeurt in het ruimtelijke domein. Als elementen niet dicht genoeg op elkaar staan ten opzichte van de draaggolffrequentie van het waargenomen signaal, krijg je slechte analyseresultaten. Je kunt antenneafstand zien als het samplen van ruimte. In dit voorbeeld worden grating lobes pas echt problematisch bij :math:`d > \lambda`, maar ze ontstaan al zodra je boven λ/2 gaat. Dat komt doordat Nyquist zegt dat we minstens twee keer zo snel moeten samplen als het waargenomen signaal, dus twee samples per cyclus. Onze ruimtelijke samplefrequentie meten we in samples per meter. Omdat de equivalente radiaalfrequentie in de ruimte :math:`2\pi/\lambda` radialen per meter is, en één cyclus :math:`2\pi` radialen (360 graden) bevat, moeten we de ruimte minstens samplen met: + +.. math:: + + \text{spatial sampling rate} \geq 2 \text{ [samples/cycle]} \cdot \frac{2\pi/\lambda \text{ [radians/meter]}}{2\pi \text{ [radians/cycle]}} + + \text{spatial sampling rate} \geq 2/\lambda \text{ [samples/meter]} + +of, uitgedrukt in elementafstand :math:`d` (in feite meter per ruimtelijke sample): + +.. math:: + + d \leq \lambda/2 + +Zolang :math:`d \leq \lambda/2` krijgen we geen grating lobes. -Now what happens when d is less than λ/2, such as when we need to fit the array in a small space? Let's repeat the same simulation: +Wat gebeurt er dan als :math:`d` kleiner is dan λ/2, bijvoorbeeld wanneer de array in een kleine ruimte moet passen? We weten dat we dan geen grating lobes krijgen, maar er gebeurt wel iets anders. Laten we dezelfde simulatie herhalen, startend bij 0,5λ en dan :math:`d` verlagen: .. image:: ../_images/doa_d_is_small_animation.gif :scale: 100 % :align: center :alt: Animation of direction of arrival (DOA) showing what happens when distance d is much less than half-wavelength -While the main lobe gets wider as d gets lower, it still has a maximum at 20 degrees, and there are no grating lobes, so in theory this would still work (at least at high SNR). To better understand what breaks as d gets too small, let's repeat the experiment but with an additional signal arriving from -40 degrees: +Terwijl de hoofdlob breder wordt als :math:`d` kleiner wordt, blijft het maximum wel op 20 graden liggen en ontstaan er geen grating lobes. In theorie werkt dit dus nog steeds (tenminste bij hoge SNR en zolang onderlinge koppeling geen groot probleem wordt). Om beter te begrijpen wat er misgaat bij te kleine :math:`d`, herhalen we het experiment met een extra signaal dat binnenkomt op -40 graden: .. image:: ../_images/doa_d_is_small_animation2.gif :scale: 100 % :align: center :alt: Animation of direction of arrival (DOA) showing what happens when distance d is much less than half-wavelength and there are two signals present -Once we get lower than λ/4 there is no distinguishing between the two different paths, and the array performs poorly. As we will see later in this chapter, there are beamforming techniques that provide more precise beams than conventional beamforming, but keeping d as close to λ/2 as possible will continue to be a theme. +Zodra we onder λ/4 komen, is er nauwelijks nog onderscheid te maken tussen de twee verschillende paden en presteert de array slecht. Zoals we later in dit hoofdstuk zullen zien, zijn er bundelvormingstechnieken met scherpere bundels dan conventionele bundelvorming. Toch blijft het een belangrijk uitgangspunt om :math:`d` zo dicht mogelijk bij λ/2 te houden. + +.. + UITGECOMMENTARIEERD OMDAT NIET DUIDELIJK IS WAT DEZE SECTIE TOEVOEGT VOOR DE LEZER, BEHALVE EEN ALTERNATIEVE VERGELIJKING EN TERM DIE VEEL COMPACTER GEPRESENTEERD KAN WORDEN + ********************** + Bartlett Beamformer + ********************** + + Nu we de basis hebben behandeld, maken we een korte zijstap naar notatie en algebraische details van wat we net deden, zodat we bundelsweeps door de ruimte compact en elegant wiskundig kunnen beschrijven. De volgende algebraische notatie leent zich goed voor vectorisatie, en is daardoor geschikt voor realtime verwerking. + + Het proces van bundels door de ruimte sweepen om DOA te schatten heeft een technische naam: "Bartlett-beamforming" (soms ook Fourier-beamforming genoemd, al kan die term ook naar een andere techniek verwijzen). Hieronder een korte samenvatting van wat we eerder hebben gedaan om DOA te berekenen, nu in Bartlett-termen: + + #. We kozen een reeks richtingen om op te richten (bijv. -90 tot +90 graden met een bepaalde stap) + #. We berekenden voor elke richting bundelvormingsgewichten om de bundel daarheen te sturen + #. De uitgangen van de array-elementen werden met hun bijbehorende gewichten vermenigvuldigd en opgeteld + #. We berekenden het signaalvermogen per richting en plotten de resultaten + #. Piekdetectie gaf aan uit welke richtingen waarschijnlijk signalen werden ontvangen + + We schrijven die stappen nu wiskundig op. Laat het door de array ontvangen signaal worden weergegeven met stuurvector :math:`\mathbf{s}`. Dit ontvangen signaal hangt af van de aankomstrichting (DOA), genoteerd als :math:`\theta`. De gewichten noteren we als :math:`\mathbf{w}`. De array-uitgang is dan het inwendig product :math:`\mathbf{w}^{H} \mathbf{s}`. Het signaalvermogen volgt uit het kwadraat van de magnitude van die uitgang: :math:`\left| \mathbf{w}^{H} \mathbf{s} \right|^{2} = \mathbf{w}^{H} \mathbf{s} \mathbf{s}^{H} \mathbf{w} = \mathbf{w} \mathbf{R_{ss}} \mathbf{w}`, waarbij :math:`\mathbf{R}` de geschatte ruimtelijke covariantiematrix is. Die covariantiematrix meet de overeenkomst tussen samples van verschillende array-elementen. Dit herhalen we voor elke te scannen richting; het enige dat per richting verandert is :math:`\mathbf{w}`. We zijn vrij in de gekozen richtingen, dus dat hoeft niet per se een sweep van -90 tot +90 graden te zijn. Alles kan desgewenst parallel met dezelfde :math:`\mathbf{R}` worden verwerkt. Dit is de essentie van Bartlett beamforming: de bundelsweep zoals eerder in Python beschreven. + + .. math:: + P = \left\| \mathbf{w} \mathbf{s}\right\|^2 + + = (\mathbf{w}^H\mathbf{s})(\mathbf{w}^H\mathbf{s})^* + + = \mathbf{s}^H\mathbf{w}\mathbf{w}^H\mathbf{s} + + = \mathbf{s}^H\mathbf{R}\mathbf{s} + + Deze wiskundige representatie is ook toepasbaar op andere DOA-technieken. ********************** -MVDR/Capon Beamformer +Ruimtelijke Tapering ********************** -We will now look at a beamformer that is slightly more complicated than the conventional/delay-and-sum technique, but tends to perform much better, called the Minimum Variance Distortionless Response (MVDR) or Capon Beamformer. Recall that variance of a signal corresponds to how much power is in the signal. The idea behind MVDR is to keep the signal at the angle of interest at a fixed gain of 1 (0 dB), while minimizing the total variance/power of the resulting beamformed signal. If our signal of interest is kept fixed then minimizing the total power means minimizing interferers and noise as much as possible. It is often refered to as a "statistically optimal" beamformer. +Ruimtelijke tapering is een techniek die je naast de conventionele bundelvormer gebruikt, waarbij je de amplitude van de gewichten aanpast om bepaalde eigenschappen te krijgen. Ook als je geen conventionele bundelvormer gebruikt, is het taperingconcept belangrijk om te begrijpen. Toen we de gewichten van de conventionele bundelvormer berekenden, waren dat complexe getallen met allemaal amplitude één (unity). Met ruimtelijke tapering vermenigvuldigen we de gewichten met scalaire factoren om die amplitude te schalen. Laten we beginnen met wat er gebeurt als we de gewichten met willekeurige waarden tussen 0 en 1 vermenigvuldigen: + +.. code-block:: python + + tapering = np.random.uniform(0, 1, Nr) # willekeurige tapering + w *= tapering + +We simuleren een signaal dat op kijkrichting (0 graden) wordt ontvangen bij hoge SNR om te zien wat er gebeurt. Merk op dat dit proces equivalent is aan het simuleren van het quiescent antenna pattern voor deze gewichten, en dus dezelfde resultaten geeft, zoals we aan het eind van dit hoofdstuk bespreken. + +.. image:: ../_images/spatial_tapering_animation.gif + :scale: 80 % + :align: center + :alt: Spatial tapering using random values to adjust the magnitude of the weights + +Probeer de breedte van de hoofdlob en de positie van de nullen te observeren. + +Het blijkt dat tapering de zijlobben kan verlagen, wat vaak gewenst is, door de amplitude van de gewichten aan de **randen** van de array te verlagen. Een Hamming-venster kan bijvoorbeeld als taperingwaarden worden gebruikt: + +.. code-block:: python + + tapering = np.hamming(Nr) # Hamming-vensterfunctie + w *= tapering + +Voor de leuk laten we de taperingfunctie geleidelijk overgaan van een rechthoekvenster (geen venster) naar een Hamming-venster: + +.. image:: ../_images/spatial_tapering_animation2.gif + :scale: 80 % + :align: center + :alt: Spatial tapering using a hamming window to adjust the magnitude of the weights + +We zien hier een paar veranderingen. Ten eerste kan de hoofdlob breder of smaller worden afhankelijk van de taperingfunctie (minder zijlobben betekent meestal een bredere hoofdlob). Een rechthoekige taper (dus geen tapering) geeft de smalste hoofdlob, maar ook de hoogste zijlobben. Ten tweede zien we dat de gain van de hoofdlob afneemt wanneer we tapering toepassen. Dat komt doordat we uiteindelijk minder signaalenergie ontvangen doordat we niet de volledige gain van alle elementen gebruiken. Bij zeer lage SNR kan dat een belangrijk nadeel zijn. + +Als je je afvraagt waarom er zoveel zijlobben zijn bij een rechthoekvenster (geen tapering): dat is dezelfde reden waarom een rechthoekvenster in het tijdsdomein tot spectrale lekkage in het frequentiedomein leidt. De Fourier-transformatie van een rechthoekvenster is een sinc-functie, :math:`sin(x)/x`, met zijlobben die oneindig doorlopen. Bij arrays samplen we in het ruimtelijke domein, en het bundelpatroon is de Fourier-transformatie van dat ruimtelijke sampleproces in combinatie met de gewichten. Daarom konden we eerder in dit hoofdstuk het bundelpatroon met een FFT plotten. In de sectie over vensterfuncties in het frequentiedomein hebben we de frequentierespons van venstertypen al vergeleken: + +.. image:: ../_images/windows.svg + :align: center + :target: ../_images/windows.svg + +****************************** +Gewichten Handmatig Aanpassen +****************************** + +De conventionele bundelvormer geeft ons een vergelijking om gewichten te berekenen voor een specifieke richting. Maar laten we nu even doen alsof we geen methode hebben en handmatig met de gewichten (zowel amplitude als fase) spelen om te zien wat er gebeurt. Hieronder staat een kleine JavaScript-app die het bundelpatroon van een 8-element-array simuleert, met sliders voor gain en fase per element. Je kunt tapering toevoegen, of minder dan 8 elementen simuleren door de amplitude van één of meer elementen op nul te zetten. + +.. raw:: html + +
    +
    + Element     Magnitude (Gain)                  Phase +
    + + + +************************ +Adaptieve Bundelvorming +************************ + +De conventionele bundelvormer die we eerder hebben besproken is een eenvoudige en effectieve manier om bundelvorming uit te voeren, maar hij heeft beperkingen. Hij werkt bijvoorbeeld minder goed wanneer meerdere signalen uit verschillende richtingen binnenkomen, of wanneer het ruisniveau hoog is. In zulke gevallen gebruiken we geavanceerdere technieken, vaak "adaptieve" bundelvorming genoemd. Het idee hierachter is dat we het ontvangen signaal gebruiken om de gewichten te berekenen, in plaats van een vaste set gewichten zoals bij conventionele bundelvorming. Daardoor kan de bundelvormer zich aanpassen aan de omgeving en beter presteren, omdat de gewichten nu op statistieken van de ontvangen data zijn gebaseerd. + +Adaptieve bundelvormingstechnieken kun je verder opdelen in reguliere en subruimte-gebaseerde methoden. Subruimtemethoden zoals MUSIC en ESPRIT zijn erg krachtig, maar vereisen dat je schat hoeveel signalen aanwezig zijn. Daarnaast hebben ze minimaal drie elementen nodig om te werken (al is minimaal vier aanbevolen). -The MVDR/Capon beamformer can be summarized in the following equation: +De eerste adaptieve bundelvormingstechniek die we bekijken is MVDR, vaak het de-facto-algoritme wanneer mensen over adaptieve bundelvorming praten. + +*********************** +MVDR/Capon-bundelvormer +*********************** + +We bekijken nu een bundelvormer die iets complexer is dan de conventionele/delay-and-sum-techniek, maar meestal veel beter presteert: de Minimum Variance Distortionless Response (MVDR), ook wel Capon-bundelvormer genoemd. Onthoud dat de variantie van een signaal overeenkomt met het vermogen in dat signaal. Het idee achter MVDR is om de versterking van het signaal in de gewenste richting 1 (0 dB) te houden, terwijl de totale variantie/het totale vermogen van het gebundelde signaal wordt geminimaliseerd. Als het gewenste signaal vast staat, betekent het minimaliseren van het totale vermogen dat interferentie en ruis zo veel mogelijk worden onderdrukt. Daarom wordt MVDR vaak een "statistisch optimale" bundelvormer genoemd. + +De MVDR/Capon-bundelvormer kan worden samengevat met de volgende vergelijking: + +.. math:: + + w_{mvdr} = \frac{R^{-1} s}{s^H R^{-1} s} + +De vector :math:`s` is de stuurvector voor de gewenste richting en is aan het begin van dit hoofdstuk besproken. :math:`R` is de geschatte ruimtelijke covariantiematrix op basis van onze ontvangen samples, te bepalen via :code:`R = np.cov(X)` of handmatig met :math:`R = X X^H`, dus :code:`X` vermenigvuldigd met zijn complex geconjugeerde getransponeerde. De ruimtelijke covariantiematrix heeft grootte :code:`Nr` x :code:`Nr` (3x3 in de voorbeelden tot nu toe) en geeft aan hoe sterk de samples van de elementen op elkaar lijken. De vergelijking kan in eerste instantie verwarrend zijn, maar de noemer dient vooral voor schaling. De teller is het belangrijkst: de inverse van de covariantiematrix vermenigvuldigd met de stuurvector. Toch moeten we de noemer wel meenemen, omdat die als normalisatieconstante werkt zodat de amplitude van de gewichten niet wegdrijft wanneer :math:`R` in de tijd verandert. + +.. raw:: html + +
    + Voor wie interesse heeft in de MVDR-afleiding: klap dit open + + +**Uitgang van de bundelvormer** - De uitgang van de bundelvormer met gewichtenvector :math:`\mathbf{w}` is: + +.. math:: + + y(t) = \mathbf{w}^H \mathbf{x}(t) + + +**Optimalisatieprobleem** - Het doel is om bundelvormingsgewichten te bepalen die het uitgangsvermogen minimaliseren, onder de voorwaarde van een distortionless respons in de gewenste richting :math:`\theta_0`. Formeel schrijven we dat als: + +.. math:: + + \min_{\mathbf{w}} \, \mathbf{w}^H \mathbf{R} \mathbf{w} \quad \text{subject to} \quad \mathbf{w}^H \mathbf{s} = 1 + +waarbij: + +* :math:`\mathbf{R} = E[\mathbf{X}\mathbf{X}^H]` de covariantiematrix van de ontvangen signalen is +* :math:`\mathbf{s}` de stuurvector in de gewenste signaalrichting :math:`\theta_0` is + +**Lagrangemethode** - Introduceer een Lagrange-multiplier :math:`\lambda` en vorm de Lagrangiaan: .. math:: - w_{mvdr} = \frac{R^{-1} a}{a^H R^{-1} a} + L(\mathbf{w}, \lambda) = \mathbf{w}^H \mathbf{R} \mathbf{w} - \lambda (\mathbf{w}^H \mathbf{s} - 1) -where :math:`R` is the covariance matrix estimate based on our recieved samples, calculated by multiplying :code:`r` with the complex conjugate transpose of itself, i.e., :math:`R = r r^H`, and the result will be a :code:`Nr` x :code:`Nr` size matrix (3x3 in the examples we have seen so far). This covariance matrix tells us how similar the samples received from the three elements are. The vector :math:`a` is the steering vector corresponding to the desired direction and was discussed at the beginning of this chapter. +**Oplossen van de optimalisatie** - Door de Lagrangiaan af te leiden naar :math:`\mathbf{w^H}` en gelijk te stellen aan nul krijgen we: -If we already know the direction of the signal of interest, and that direction does not change, we only have to calculate the weights once and simply use them to receive our signal of interest. Although even if the direction doesn't change, we benefit from recalculating these weights periodically, to account for changes in the interference/noise, which is why we refer to these non-conventional digital beamformers as "adaptive" beamforming; they use information in the signal we receive to calculate the best weights. Just as a reminder, we can *perform* beamforming using MVDR by calculating these weights and applying them to the signal with :code:`w.conj().T @ r`, just like we did in the conventional method, the only difference is how the weights are calculated. +.. math:: + + \frac{\partial L}{\partial \mathbf{w}^*} = 2\mathbf{R}\mathbf{w} - \lambda \mathbf{s} = 0 + + \mathbf{w} = \lambda \mathbf{s} \mathbf{{R^{-1}}} + + +Om :math:`\lambda` op te lossen, passen we de randvoorwaarde :math:`\mathbf{w}^H \mathbf{s} = 1` toe: + +.. math:: + + \implies (\lambda \mathbf{s^{H}}\mathbf{{R^{-1}}})s = 1 + + \implies \lambda = \frac{1}{\mathbf{s}^{H}\mathbf{R}^{-1}\mathbf{s}} + + \mathbf{R}\mathbf{w} = \lambda \mathbf{s} + + \mathbf{w_{mvdr}} = \frac{\mathbf{R}^{-1} \mathbf{s}}{\mathbf{s}^H \mathbf{R}^{-1} \mathbf{s}} + +.. raw:: html -To perform DOA using the MVDR beamformer, we simply repeat the MVDR calculation while scanning through all angles of interest. I.e., we act like our signal is coming from angle :math:`\theta`, even if it isn't. At each angle we calculate the MVDR weights, then apply them to the received signal, then calculate the power in the signal. The angle that gives us the highest power is our DOA estimate, or even better we can plot power as a function of angle to see the beam pattern, as we did above with the conventional beamformer, that way we don't need to assume how many signals are present. +
    -In Python we can implement the MVDR/Capon beamformer as follows, which will be done as a function so that it's easy to use later on: +Als we de richting van het gewenste signaal al kennen en die richting niet verandert, hoeven we de gewichten maar één keer te berekenen en kunnen we die gebruiken om het signaal te ontvangen. Toch is periodiek herberekenen vaak nuttig, zelfs bij constante richting, om veranderingen in interferentie/ruis op te vangen. Daarom noemen we dit soort niet-conventionele digitale beamformers "adaptief"; ze gebruiken informatie uit het ontvangen signaal om betere gewichten te berekenen. Ter herinnering: we *voeren* bundelvorming met MVDR uit door deze gewichten te berekenen en toe te passen met :code:`w.conj().T @ X`, net als bij de conventionele methode. Alleen de manier waarop de gewichten worden berekend verschilt. + +Om DOA met de MVDR-bundelvormer uit te voeren, herhalen we eenvoudig de MVDR-berekening terwijl we alle relevante hoeken scannen. Met andere woorden: we doen alsof het signaal uit hoek :math:`\theta` komt, ook als dat niet zo is. Per hoek berekenen we de MVDR-gewichten, passen die toe op het ontvangen signaal en berekenen vervolgens het signaalvermogen. De hoek met het hoogste vermogen is onze DOA-schatting. Nog beter is om vermogen als functie van hoek te plotten, zoals we eerder deden met de conventionele bundelvormer, zodat we niet vooraf hoeven aan te nemen hoeveel signalen aanwezig zijn. + +In Python kunnen we de MVDR/Capon-bundelvormer als volgt implementeren, hier als functie zodat hij later makkelijk te hergebruiken is: .. code-block:: python - # theta is the direction of interest, in radians, and r is our received signal - def w_mvdr(theta, r): - a = np.exp(-2j * np.pi * d * np.arange(Nr) * np.sin(theta)) # steering vector in the desired direction theta - a = a.reshape(-1,1) # make into a column vector (size 3x1) - R = r @ r.conj().T # Calc covariance matrix. gives a Nr x Nr covariance matrix of the samples - Rinv = np.linalg.pinv(R) # 3x3. pseudo-inverse tends to work better/faster than a true inverse - w = (Rinv @ a)/(a.conj().T @ Rinv @ a) # MVDR/Capon equation! numerator is 3x3 * 3x1, denominator is 1x3 * 3x3 * 3x1, resulting in a 3x1 weights vector - return w + # theta is de gewenste richting in radialen, en X is het ontvangen signaal + def w_mvdr(theta, X): + s = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta)) # stuurvector in de gewenste richting theta + s = s.reshape(-1,1) # maak er een kolomvector van (grootte 3x1) + R = (X @ X.conj().T)/X.shape[1] # bereken covariantiematrix; dit geeft een Nr x Nr-matrix van de samples + Rinv = np.linalg.pinv(R) # 3x3. pseudo-inverse werkt meestal beter/sneller dan een echte inverse + w = (Rinv @ s)/(s.conj().T @ Rinv @ s) # MVDR/Capon-vergelijking; teller is 3x3 * 3x1, noemer is 1x3 * 3x3 * 3x1, resultaat is 3x1 + return w -Using this MVDR beamformer in the context of DOA, we get the following Python example: +Als we deze MVDR-bundelvormer in DOA-context gebruiken, krijgen we het volgende Python-voorbeeld: .. code-block:: python - theta_scan = np.linspace(-1*np.pi, np.pi, 1000) # 1000 different thetas between -180 and +180 degrees + theta_scan = np.linspace(-1*np.pi, np.pi, 1000) # 1000 verschillende theta-waarden tussen -180 en +180 graden results = [] for theta_i in theta_scan: - w = w_mvdr(theta_i, r) # 3x1 - r_weighted = w.conj().T @ r # apply weights - power_dB = 10*np.log10(np.var(r_weighted)) # power in signal, in dB so its easier to see small and large lobes at the same time + w = w_mvdr(theta_i, X) # 3x1 + X_weighted = w.conj().T @ X # pas gewichten toe + power_dB = 10*np.log10(np.var(X_weighted)) # vermogen in dB, zodat kleine en grote lobben tegelijk zichtbaar zijn results.append(power_dB) results -= np.max(results) # normalize -When applied to the previous DOA example simulation, we get the following: +Toegepast op de vorige DOA-simulatie krijgen we: .. image:: ../_images/doa_capons.svg :align: center :target: ../_images/doa_capons.svg -It appears to work fine, but to really compare this to other techniques we'll have to create a more interesting problem. Let's set up a simulation with an 8-element array receiving three signals from different angles: 20, 25, and 40 degrees, with the 40 degree one received at a much lower power than the other two, as a way to spice things up. Our goal will be to detect all three signals, meaning we want to be able to see noticeable peaks (high enough for a peak-finder algorithm to extract). The code to generate this new scenario is as follows: +Dit lijkt goed te werken, maar om echt met andere technieken te vergelijken maken we een interessanter scenario. We zetten een simulatie op met een 8-element-array die drie signalen ontvangt vanuit verschillende hoeken: 20, 25 en 40 graden, waarbij het signaal op 40 graden met veel lager vermogen binnenkomt dan de andere twee. Ons doel is alle drie signalen te detecteren, dus we willen duidelijk zichtbare pieken hebben (hoog genoeg voor een piekzoekalgoritme). De code om dit scenario te genereren is: .. code-block:: python - Nr = 8 # 8 elements - theta1 = 20 / 180 * np.pi # convert to radians + Nr = 8 # 8 elementen + theta1 = 20 / 180 * np.pi # omzetten naar radialen theta2 = 25 / 180 * np.pi theta3 = -40 / 180 * np.pi - a1 = np.exp(-2j * np.pi * d * np.arange(Nr) * np.sin(theta1)).reshape(-1,1) # 8x1 - a2 = np.exp(-2j * np.pi * d * np.arange(Nr) * np.sin(theta2)).reshape(-1,1) - a3 = np.exp(-2j * np.pi * d * np.arange(Nr) * np.sin(theta3)).reshape(-1,1) - # we'll use 3 different frequencies. 1xN + s1 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta1)).reshape(-1,1) # 8x1 + s2 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta2)).reshape(-1,1) + s3 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta3)).reshape(-1,1) + # we gebruiken 3 verschillende frequenties. 1xN tone1 = np.exp(2j*np.pi*0.01e6*t).reshape(1,-1) tone2 = np.exp(2j*np.pi*0.02e6*t).reshape(1,-1) tone3 = np.exp(2j*np.pi*0.03e6*t).reshape(1,-1) - r = a1 @ tone1 + a2 @ tone2 + 0.1 * a3 @ tone3 + X = s1 @ tone1 + s2 @ tone2 + 0.1 * s3 @ tone3 # let op: de laatste heeft 1/10 van het vermogen n = np.random.randn(Nr, N) + 1j*np.random.randn(Nr, N) - r = r + 0.05*n # 8xN + X = X + 0.05*n # 8xN -You can put this code at the top of your script, since we are generating a different signal than the original example. If we run our MVDR beamformer on this new scenario we get the following results: +Je kunt deze code bovenaan je script plaatsen, omdat we hier een ander signaal genereren dan in het oorspronkelijke voorbeeld. Als we in dit scenario de MVDR-bundelvormer draaien, krijgen we: .. image:: ../_images/doa_capons2.svg :align: center :target: ../_images/doa_capons2.svg -It works pretty well, we can see the two signals received only 5 degrees apart, and we can also see the 3rd signal (at -40 or 320 degrees) that was received at one tenth the power of the others. Now let's run the conventional beamformer on this new scenario: +Dit werkt vrij goed: we zien twee signalen die slechts 5 graden uit elkaar liggen, en ook het derde signaal (op -40 of 320 graden) dat met een tiende van het vermogen van de andere binnenkomt. Laten we nu in hetzelfde scenario de conventionele bundelvormer draaien: .. image:: ../_images/doa_complex_scenario.svg :align: center :target: ../_images/doa_complex_scenario.svg -While it might be a pretty shape, it's not finding all three signals at all... By comparing these two results we can see the benefit from using a more complex and "adptive" beamformer. +Hoewel het er visueel mooi uitziet, vindt deze methode duidelijk niet alle drie de signalen. Door deze twee resultaten te vergelijken zie je het voordeel van een complexere en "adaptieve" bundelvormer. -As a quick aside for the interested reader, there is actually an optimization that can be made when performing DOA with MVDR, using a trick. Recall that we calculate the power in a signal by taking the variance, which is the mean of the magnitude squared (assuming our signals average value is zero which is almost always the case for baseband RF). We can represent taking the power in our signal after applying our weights as: +Als korte zijstap voor geïnteresseerden: er is een optimalisatie mogelijk bij DOA met MVDR. Onthoud dat we signaalvermogen berekenen via de variantie, oftewel het gemiddelde van de magnitude in het kwadraat (aangenomen dat het gemiddelde van het signaal ongeveer nul is, wat bij basisband-RF vrijwel altijd zo is). Het vermogen na toepassen van de gewichten kunnen we schrijven als: .. math:: P_{mvdr} = \frac{1}{N} \sum_{n=0}^{N-1} \left| w^H_{mvdr} r_n \right|^2 -If we plug in the equation for the MVDR weights we get: +Als we overstappen van een sommatie naar de verwachtingsoperator, en de vergelijking voor MVDR-gewichten invullen, krijgen we: .. math:: - P_{mvdr} = \frac{1}{N} \sum_{n=0}^{N-1} \left| \left( \frac{R^{-1} a}{a^H R^{-1} a} \right)^H r_n \right|^2 + P_{mvdr} = E \left( \left| w^H_{mvdr} X_n \right| ^2 \right) - = \frac{1}{N} \sum_{n=0}^{N-1} \left| \frac{a^H R^{-1}}{a^H R^{-1} a} r_n \right|^2 - - ... \mathrm{math} - - = \frac{1}{a^H R^{-1} a} + = w^H_{mvdr} E \left( X X^H \right) w_{mvdr} + + = w^H_{mvdr} R w_{mvdr} + + = \frac{s^H R^{-1} s}{s^H R^{-1} s} \cdot R \cdot \frac{R^{-1} s}{s^H R^{-1} s} + + = \frac{s^H R^{-1} s}{(s^H R^{-1} s)(s^H R^{-1} s)} + + = \frac{1}{s^H R^{-1} s} + +Dit betekent dat we de gewichten niet expliciet hoeven toe te passen; de laatste vermogensvergelijking hierboven kan direct in de DOA-scan worden gebruikt en bespaart rekenwerk: + +.. code-block:: python + + def power_mvdr(theta, X): + s = np.exp(2j * np.pi * d * np.arange(r.shape[0]) * np.sin(theta)) # stuurvector in de gewenste richting theta_i + s = s.reshape(-1,1) # maak er een kolomvector van (grootte 3x1) + R = (X @ X.conj().T)/X.shape[1] # bereken covariantiematrix; dit geeft een Nr x Nr-matrix van de samples + Rinv = np.linalg.pinv(R) # 3x3. pseudo-inverse werkt meestal beter dan een echte inverse + return 1/(s.conj().T @ Rinv @ s).squeeze() + +Om dit in de vorige simulatie te gebruiken hoef je in de for-loop alleen nog :code:`10*np.log10()` toe te passen; er zijn geen gewichten meer om toe te passen, want die berekening hebben we overgeslagen. -Meaning we don't have to apply the weights at all, this final equation above for power can be used directly in our DOA scan, saving us some computations: +Er bestaan nog veel meer beamformers, maar hierna staan we eerst kort stil bij hoe het aantal elementen invloed heeft op bundelvorming en DOA. + +********************** +Covariantiematrix +********************** + +Laten we kort de ruimtelijke covariantiematrix bespreken, een kernbegrip in *adaptieve* bundelvorming. Een covariantiematrix is een wiskundige representatie van de overeenkomst tussen paren elementen in een willekeurige vector (in ons geval de array-elementen, daarom noemen we dit de *ruimtelijke* covariantiematrix). Een covariantiematrix is altijd vierkant, en de waarden op de diagonaal zijn de covariantie van elk element met zichzelf. We berekenen in de praktijk een *schatting* van de ruimtelijke covariantiematrix, omdat we maar een beperkt aantal samples hebben. + +In het algemeen is de covariantiematrix gedefinieerd als: + +:math:`\mathrm{cov}(X) = E \left[ (X - E[X])(X - E[X])^H \right]` + +voor draadloze basisbandsignalen is :math:`E[X]` meestal nul of bijna nul, dus dit vereenvoudigt tot: + +:math:`\mathrm{cov}(X) = E[X X^H]` + +Met een beperkt aantal IQ-samples, :math:`\boldsymbol{X}`, kunnen we deze covariantie schatten. We noteren die als :math:`\hat{R}`: + +.. math:: + + \hat{R} = \frac{\boldsymbol{X} \boldsymbol{X}^H}{N} + + = \frac{1}{N} \sum^N_{n=1} X_n X_n^H + +waar :math:`N` het aantal samples is (niet het aantal elementen). In Python ziet dat er zo uit: + +:code:`R = (X @ X.conj().T)/X.shape[1]` + +Als alternatief kunnen we de ingebouwde NumPy-functie gebruiken: + +:code:`R = np.cov(X)` + +Als voorbeeld bekijken we de ruimtelijke covariantiematrix voor het scenario met één zender en drie elementen: .. code-block:: python - def power_mvdr(theta, r): - a = np.exp(-2j * np.pi * d * np.arange(r.shape[0]) * np.sin(theta)) # steering vector in the desired direction theta_i - a = a.reshape(-1,1) # make into a column vector (size 3x1) - R = r @ r.conj().T # Calc covariance matrix. gives a Nr x Nr covariance matrix of the samples - Rinv = np.linalg.pinv(R) # 3x3. pseudo-inverse tends to work better than a true inverse - return 1/(a.conj().T @ Rinv @ a).squeeze() + [[ 1.494+0.j 0.486+0.881j -0.543+0.839j] + [ 0.486-0.881j 1.517 +0.j 0.483+0.886j] + [-0.543-0.839j 0.483-0.886j 1.499+0.j ]] + +Let op dat de diagonale elementen reëel zijn en ongeveer gelijk. Dat komt doordat ze vooral het ontvangen signaalvermogen per element weergeven, en dat is vergelijkbaar omdat alle elementen dezelfde gain hebben. De off-diagonale elementen bevatten de meest relevante informatie, al zie je uit de ruwe waarden vooral dat er duidelijke correlatie tussen elementen aanwezig is. + +Als onderdeel van adaptieve bundelvorming zie je vaak dat we de inverse van de ruimtelijke correlatiematrix nemen. Die inverse vertelt hoe twee elementen zich tot elkaar verhouden nadat de invloed van de andere elementen is verwijderd. In statistiek heet dit de "precision matrix" en in radar de "whitening matrix". + +********************** +LCMV-bundelvormer +********************** + +Hoewel MVDR krachtig is, wat als we meer dan één SOI hebben? Met een kleine aanpassing op MVDR kunnen we gelukkig een schema bouwen dat meerdere SOI's aankan: de Linearly Constrained Minimum Variance (LCMV)-bundelvormer. Dit is een generalisatie van MVDR waarbij we de gewenste respons voor meerdere richtingen specificeren, een beetje als een ruimtelijke variant van SciPy's :code:`firwin2()` voor wie dat kent. De optimale gewichtenvector voor de LCMV-bundelvormer is samen te vatten als: + +.. math:: + + w_{lcmv} = R^{-1} C [C^H R^{-1} C]^{-1} f + +waar :math:`C` een matrix is met stuurvectoren van de bijbehorende SOI's en stoorzenders, en :math:`f` de gewenste responsvector is. Voor een bepaalde rij krijgt :math:`f` de waarde 0 als de bijbehorende stuurvector onderdrukt moet worden (null), en 1 als we er een bundel op willen richten. Hebben we bijvoorbeeld twee gewenste bronnen en twee interferentiebronnen, dan kunnen we :code:`f = [1,1,0,0]` kiezen. De LCMV-bundelvormer is een krachtig hulpmiddel om interferentie en ruis uit meerdere richtingen te onderdrukken en tegelijk gewenste signalen uit meerdere richtingen te versterken. De keerzijde is dat het totale aantal nullen en bundels dat je tegelijk kunt vormen beperkt is door de arraygrootte (het aantal elementen). Daarnaast moet je voor elke SOI en interferer een stuurvector opstellen, wat in de praktijk niet altijd eenvoudig beschikbaar is. Als je schattingen gebruikt, kan de prestatie van de LCMV-bundelvormer dalen. Daarom sturen we nullen liever met de ruimtelijke covariantiematrix :math:`R` (gebaseerd op statistiek van het ontvangen signaal), in plaats van nullen te "hardcoden" door de AoA van een interferer te schatten en daar een stuurvector voor te bouwen met een 0 in :math:`f`. + +LCMV uitvoeren in Python lijkt sterk op MVDR, maar we moeten :code:`C` opgeven (mogelijk samengesteld uit meerdere stuurvectoren) en :code:`f` als 1D-array met 1'en en 0'en zoals hierboven beschreven. De volgende code laat zien hoe je de LCMV-bundelvormer implementeert voor twee SOI's (15 en 60 graden). Onthoud dat MVDR maar één SOI tegelijk ondersteunt. Daarom is hier :code:`f = [1; 1]` zonder nullen, omdat we geen "hardcoded" nullen opnemen. We simuleren een scenario met vier stoorzenders op -60, -30, 0 en 30 graden. + +.. code-block:: python + + # Richt op de SOI bij 15 graden en nog een potentiële SOI op 60 graden die we niet hebben gesimuleerd + soi1_theta = 15 / 180 * np.pi # omzetten naar radialen + soi2_theta = 60 / 180 * np.pi + + # LCMV-gewichten + R_inv = np.linalg.pinv(np.cov(X)) # 8x8 + s1 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(soi1_theta)).reshape(-1,1) # 8x1 + s2 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(soi2_theta)).reshape(-1,1) # 8x1 + C = np.concatenate((s1, s2), axis=1) # 8x2 + f = np.ones(2).reshape(-1,1) # 2x1 + + # LCMV-vergelijking + # 8x8 8x2 2x8 8x8 8x2 2x1 + w = R_inv @ C @ np.linalg.pinv(C.conj().T @ R_inv @ C) @ f # output is 8x1 + +We kunnen het bundelpatroon van :code:`w` plotten met de FFT-methode van eerder: + +.. image:: ../_images/lcmv_beam_pattern.svg + :align: center + :target: ../_images/lcmv_beam_pattern.svg + :alt: Example beam pattern when using the LCMV beamformer + +Zoals je ziet hebben we bundels naar de twee gewenste richtingen en nullen op de locaties van de stoorzenders (net als bij MVDR hoeven we niet expliciet te zeggen waar de zenders zitten; dat volgt uit het ontvangen signaal). Groene en rode punten in de plot geven respectievelijk de AoA's van SOI's en stoorzenders aan. + +.. raw:: html + +
    + Klap dit open voor de volledige code + +.. code-block:: python + + # Simuleer ontvangen signaal + Nr = 8 # 8 elementen + theta1 = -60 / 180 * np.pi # omzetten naar radialen + theta2 = -30 / 180 * np.pi + theta3 = 0 / 180 * np.pi + theta4 = 30 / 180 * np.pi + s1 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta1)).reshape(-1,1) # 8x1 + s2 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta2)).reshape(-1,1) + s3 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta3)).reshape(-1,1) + s4 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta4)).reshape(-1,1) + # we gebruiken 3 verschillende frequenties. 1xN + tone1 = np.exp(2j*np.pi*0.01e6*t).reshape(1,-1) + tone2 = np.exp(2j*np.pi*0.02e6*t).reshape(1,-1) + tone3 = np.exp(2j*np.pi*0.03e6*t).reshape(1,-1) + tone4 = np.exp(2j*np.pi*0.04e6*t).reshape(1,-1) + X = s1 @ tone1 + s2 @ tone2 + s3 @ tone3 + s4 @ tone4 + n = np.random.randn(Nr, N) + 1j*np.random.randn(Nr, N) + X = X + 0.5*n # 8xN + + # Richt op de SOI bij 15 graden en nog een potentiële SOI op 60 graden die we niet hebben gesimuleerd + soi1_theta = 15 / 180 * np.pi # omzetten naar radialen + soi2_theta = 60 / 180 * np.pi + + # LCMV-gewichten + R_inv = np.linalg.pinv(np.cov(X)) # 8x8 + s1 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(soi1_theta)).reshape(-1,1) # 8x1 + s2 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(soi2_theta)).reshape(-1,1) # 8x1 + C = np.concatenate((s1, s2), axis=1) # 8x2 + f = np.ones(2).reshape(-1,1) # 2x1 + + # LCMV-vergelijking + # 8x8 8x2 2x8 8x8 8x2 2x1 + w = R_inv @ C @ np.linalg.pinv(C.conj().T @ R_inv @ C) @ f # output is 8x1 + + # Plot bundelpatroon + w = w.squeeze() # reduceer naar een 1D-array + N_fft = 1024 + w_padded = np.concatenate((w, np.zeros(N_fft - Nr))) # zero-pad naar N_fft elementen voor meer FFT-resolutie + w_fft_dB = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(w_padded)))**2) # FFT-magnitude in dB + w_fft_dB -= np.max(w_fft_dB) # normalize to 0 dB at peak + theta_bins = np.arcsin(np.linspace(-1, 1, N_fft)) # map FFT-bins naar hoeken in radialen + + fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}) + ax.plot(theta_bins, w_fft_dB) # GEBRUIK RADIALEN VOOR EEN POOLPLOT + # Voeg punten toe op de locaties van stoorzenders en SOI's + ax.plot([theta1], [0], 'or') + ax.plot([theta2], [0], 'or') + ax.plot([theta3], [0], 'or') + ax.plot([theta4], [0], 'or') + ax.plot([soi1_theta], [0], 'og') + ax.plot([soi2_theta], [0], 'og') + ax.set_theta_zero_location('N') # laat 0 graden omhoog wijzen + ax.set_theta_direction(-1) # laat de hoek met de klok mee toenemen + ax.set_thetagrids(np.arange(-90, 105, 15)) # dit is in graden + ax.set_rlabel_position(55) # verplaats rasterlabels weg van andere labels + ax.set_thetamin(-90) # toon alleen de bovenste helft + ax.set_thetamax(90) + ax.set_ylim([-30, 1]) # zonder ruis hoeven we maar tot -30 dB te gaan + plt.show() + +.. raw:: html -To use this in the previous simulation, within the for loop, the only thing left to do is take the :code:`10*np.log10()` and you're done, there are no weights to apply; we skipped calculating the weights! +
    -There are many more beamformers out there, but next we are going to take a moment to discuss how the number of elements impacts our ability to perform beamforming and DOA. +Er is een interessante toepassing van LCMV waar je misschien al aan dacht: stel dat je de hoofdbundel niet exact op 20 graden wilt richten, maar juist breder wilt maken dan conventionele bundelvorming normaal oplevert. Dat kan door de gewenste responsvector :code:`f` op 1 te zetten voor een hoekbereik (bijvoorbeeld meerdere waarden tussen 10 en 30 graden) en daarbuiten op 0. Daarmee kun je een bundelpatroon maken dat breder is dan de hoofdlob van de conventionele bundelvormer, wat handig is in praktijksituaties waar de exacte aankomstrichting niet bekend is. Je kunt dezelfde aanpak ook gebruiken om een null over een breder hoekbereik te maken. Houd er wel rekening mee dat dit meerdere vrijheidsgraden kost. Als voorbeeld simuleren we een 18-element-array, met een interessehoek van 15 tot 30 graden via 4 verschillende theta's, en een null van 45 tot 60 graden ook met 4 theta's. We simuleren hier geen echte stoorzenders. + +.. code-block:: python + + Nr = 18 + X = np.random.randn(Nr, N) + 1j*np.random.randn(Nr, N) # simuleer ontvangen signaal met alleen ruis + + # Richt op de SOI van 15 tot 30 graden met 4 verschillende theta's + soi_thetas = np.linspace(15, 30, 4) / 180 * np.pi # omzetten naar radialen + + # Maak een null van 45 tot 60 graden met 4 verschillende theta's + null_thetas = np.linspace(45, 60, 4) / 180 * np.pi # omzetten naar radialen + + # LCMV-gewichten + R_inv = np.linalg.pinv(np.cov(X)) + s = [] + for soi_theta in soi_thetas: + s.append(np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(soi_theta)).reshape(-1,1)) + for null_theta in null_thetas: + s.append(np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(null_theta)).reshape(-1,1)) + C = np.concatenate(s, axis=1) + f = np.asarray([1]*len(soi_thetas) + [0]*len(null_thetas)).reshape(-1,1) + w = R_inv @ C @ np.linalg.pinv(C.conj().T @ R_inv @ C) @ f # LCMV-vergelijking + + # Plot bundelpatroon zoals eerder... + +.. image:: ../_images/lcmv_beam_pattern_spread.svg + :align: center + :target: ../_images/lcmv_beam_pattern_spread.svg + :alt: Example beam pattern when using the LCMV beamformer with a spread beam and a spread null + +De bundel en null zijn nu uitgespreid over het gevraagde bereik. Probeer het aantal theta's voor de hoofdbundel en/of null te wijzigen, en ook het aantal elementen, om te zien of de resulterende gewichten de gewenste respons nog kunnen realiseren. ******************* -Number of Elements +Nullsturing ******************* -Coming soon! +Nu we LCMV hebben gezien, is het de moeite waard om een eenvoudigere techniek te bekijken die zowel in analoge als digitale arrays kan worden gebruikt: null steering. Zie het als een uitbreiding op de conventionele bundelvormer: naast een bundel naar de gewenste richting kun je ook nullen op specifieke hoeken plaatsen. Deze techniek past gewichten niet aan op basis van het ontvangen signaal (we berekenen bijvoorbeeld geen :code:`R`) en wordt dus niet als adaptief beschouwd. In de simulatie hieronder hoeven we zelfs geen signaal te simuleren; we construeren alleen de gewichten met null steering en visualiseren vervolgens het bundelpatroon. + +De gewichten voor null steering bereken je door te starten met de conventionele bundelvormer op de interessehoek, en daarna met de sidelobe-canceler-vergelijking de gewichten bij te werken zodat nullen worden toegevoegd, één voor één. De sidelobe-canceler-vergelijking is: + +.. math:: + + w_{\text{new}} = w_{\text{orig}} - \frac{w_{\text{null}}^H w_{\text{orig}}}{w_{\text{null}}^H w_{\text{null}}} w_{\text{null}} + +waar :math:`w_{\text{null}}` de stuurvector is in de richting van de null die we aan :math:`w_{\text{orig}}` willen toevoegen. De gewichten worden bijgewerkt door de geschaalde null-stuurvector van de huidige gewichten af te trekken. De schaalfactor volgt uit projectie van de huidige gewichten op de null-stuurvector, gedeeld door de projectie van die null-stuurvector op zichzelf. Dit herhaal je voor elke null-richting (:math:`w_{\text{orig}}` begint als conventionele bundelvormingsgewichten en wordt na elke null bijgewerkt). Het volledige proces: + +.. math:: + + \text{1:} \qquad w_{\text{orig}} = e^{2j \pi d k \sin(\theta_{SOI})} \qquad + + \text{2:} \qquad w_{\text{null}} = e^{2j \pi d k \sin(\theta_{null})} \qquad + + \text{3:} \qquad w_{\text{new}} = w_{\text{orig}} - \frac{w_{\text{null}}^H w_{\text{orig}}}{w_{\text{null}}^H w_{\text{null}}} w_{\text{null}} + + \text{4:} \qquad w_{\text{orig}} = w_{\text{new}} \qquad \qquad \qquad + + \text{5:} \qquad \text{GOTO 2 to add next null} + +Laten we een 8-element-array simuleren en vier nullen plaatsen: + +.. code-block:: python + + d = 0.5 + Nr = 8 + + theta_soi = 30 / 180 * np.pi # omzetten naar radialen + nulls_deg = [-60, -30, 0, 60] # graden + nulls_rad = np.asarray(nulls_deg) / 180 * np.pi + + # Start met een conventionele beamformer gericht op theta_soi + w = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta_soi)).reshape(-1,1) + + # Loop over de nullen + for null_rad in nulls_rad: + # gewichten gelijk aan stuurvector in de gewenste null-richting + w_null = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(null_rad)).reshape(-1,1) + + # scaling_factor (complex scalar) voor w in de genulde richting + scaling_factor = w_null.conj().T @ w / (w_null.conj().T @ w_null) + print("scaling_factor:", scaling_factor, scaling_factor.shape) + + # Werk gewichten bij om de null toe te voegen + w = w - w_null @ scaling_factor # sidelobe-canceler equation + + # Plot bundelpatroon + N_fft = 1024 + w_padded = np.concatenate((w.squeeze(), np.zeros(N_fft - Nr))) # zero-pad naar N_fft elementen voor meer FFT-resolutie + w_fft_dB = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(w_padded)))**2) # FFT-magnitude in dB + w_fft_dB -= np.max(w_fft_dB) # normalize to 0 dB at peak + theta_bins = np.arcsin(np.linspace(-1, 1, N_fft)) # map FFT-bins naar hoeken in radialen + + fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}) + ax.plot(theta_bins, w_fft_dB) + # Voeg punten toe op de locaties van nullen en SOI + for null_rad in nulls_rad: + ax.plot([null_rad], [0], 'or') + ax.plot([theta_soi], [0], 'og') + ax.set_theta_zero_location('N') # laat 0 graden omhoog wijzen + ax.set_theta_direction(-1) # laat de hoek met de klok mee toenemen + ax.set_thetagrids(np.arange(-90, 105, 15)) # dit is in graden + ax.set_rlabel_position(55) # verplaats rasterlabels weg van andere labels + ax.set_thetamin(-90) # toon alleen de bovenste helft + ax.set_thetamax(90) + ax.set_ylim([-40, 1]) # zonder ruis hoeven we maar tot -40 dB te gaan + plt.show() + +We krijgen het volgende bundelpatroon. Je ziet mogelijk nullen op posities die je niet expliciet hebt gevraagd; dat is verwacht gedrag en komt door het beperkte aantal elementen. Bij te weinig elementen kan het ook zijn dat nullen/bundel niet exact op de bedoelde plek liggen, of dat de criteria helemaal niet haalbaar zijn door een gebrek aan vrijheidsgraden (aantal elementen min 1). + +.. image:: ../_images/null_steering.svg + :align: center + :target: ../_images/null_steering.svg + :alt: Example of null steering beamforming ******************* MUSIC ******************* -We will now change gears and talk about a different kind of beamformer. All of the previous ones have fallen in the "delay-and-sum" category, but now we will dive into "sub-space" methods. These involve dividing the signal subspace and noise subspace, which means we must estimate how many signals are being received by the array, to get a good result. MUltiple SIgnal Classification (MUSIC) is a very popular sub-space method that involves calculating the eigenvectors of the covariance matrix (which is a computationally intensive operation by the way). We split the eigenvectors into two groups: signal sub-space and noise-subspace, then project steering vectors into the noise sub-space and steer for nulls. That might seem confusing at first, which is part of why MUSIC seems like black magic! +We schakelen nu over naar een ander type bundelvormer. Alle eerdere methoden vielen in de "delay-and-sum"-categorie, maar nu duiken we in subruimtemethoden. Daarbij splitsen we in een signaal-subruimte en een ruis-subruimte, wat betekent dat we eerst moeten schatten hoeveel signalen de array ontvangt. MUltiple SIgnal Classification (MUSIC) is een populaire subruimtemethode die eigenvectoren van de covariantiematrix gebruikt (een rekenintensieve operatie). We splitsen de eigenvectoren in twee groepen: signaal-subruimte en ruis-subruimte, en projecteren daarna stuurvectoren in de ruis-subruimte om nullen te sturen. Dat klinkt in het begin verwarrend, wat mede verklaart waarom MUSIC soms als zwarte magie voelt. -The core MUSIC equation is the following: +De kernvergelijking van MUSIC is: .. math:: - \hat{\theta} = \mathrm{argmax}\left(\frac{1}{a^H V_n V^H_n a}\right) + \hat{\theta} = \mathrm{argmax}\left(\frac{1}{s^H V_n V^H_n s}\right) -where :math:`V_n` is that list of noise sub-space eigenvectors we mentioned (a 2D matrix). It is found by first calculating the eigenvectors of :math:`R`, which is done simply by :code:`w, v = np.linalg.eig(R)` in Python, and then splitting up the vectors (:code:`w`) based on how many signals we think the array is receiving. There is a trick for estimating the number of signals that we'll talk about later, but it must be between 1 and :code:`Nr - 1`. I.e., if you are designing an array, when you are choosing the number of elements you must have one more than the number of anticipated signals. One thing to note about the equation above is :math:`V_n` does not depend on the array factor :math:`a`, so we can precalculate it before we start looping through theta. The full MUSIC code is as follows: +waar :math:`V_n` de lijst is met eigenvectoren van de ruis-subruimte (een 2D-matrix). Die krijg je door eerst de eigenvectoren van :math:`R` te berekenen, in Python simpel met :code:`w, v = np.linalg.eig(R)`, en daarna de vectoren te splitsen op basis van hoeveel signalen we denken dat de array ontvangt. Er is een truc om het aantal signalen te schatten, die komt later, maar het moet tussen 1 en :code:`Nr - 1` liggen. Ontwerp je een array, dan moet het aantal elementen dus minstens één hoger zijn dan het verwachte aantal signalen. Belangrijk detail: in de vergelijking hierboven hangt :math:`V_n` niet af van stuurvector :math:`s`, dus :math:`V_n` kunnen we vooraf berekenen voordat we over theta loopen. De volledige MUSIC-code: .. code-block:: python - num_expected_signals = 3 # Try changing this! + num_expected_signals = 3 # Probeer dit te veranderen! - # part that doesn't change with theta_i - R = r @ r.conj().T # Calc covariance matrix, it's Nr x Nr - w, v = np.linalg.eig(R) # eigenvalue decomposition, v[:,i] is the eigenvector corresponding to the eigenvalue w[i] - eig_val_order = np.argsort(np.abs(w)) # find order of magnitude of eigenvalues - v = v[:, eig_val_order] # sort eigenvectors using this order - # We make a new eigenvector matrix representing the "noise subspace", it's just the rest of the eigenvalues + # deel dat niet verandert met theta_i + R = np.cov(X) # bereken covariantiematrix; dit geeft een Nr x Nr-matrix + w, v = np.linalg.eig(R) # eigenwaarde-ontbinding, v[:,i] is de eigenvector bij eigenwaarde w[i] + eig_val_order = np.argsort(np.abs(w)) # bepaal volgorde op grootte van eigenwaarden + v = v[:, eig_val_order] # sorteer eigenvectoren volgens die volgorde + # maak een nieuwe eigenvectormatrix voor de "ruis-subruimte"; dit zijn de overblijvende eigenwaarden V = np.zeros((Nr, Nr - num_expected_signals), dtype=np.complex64) for i in range(Nr - num_expected_signals): V[:, i] = v[:, i] - theta_scan = np.linspace(-1*np.pi, np.pi, 1000) # -180 to +180 degrees + theta_scan = np.linspace(-1*np.pi, np.pi, 1000) # -180 tot +180 graden results = [] for theta_i in theta_scan: - a = np.exp(-2j * np.pi * d * np.arange(Nr) * np.sin(theta_i)) # array factor - a = a.reshape(-1,1) - metric = 1 / (a.conj().T @ V @ V.conj().T @ a) # The main MUSIC equation - metric = np.abs(metric.squeeze()) # take magnitude - metric = 10*np.log10(metric) # convert to dB - results.append(metric) + s = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta_i)) # stuurvector + s = s.reshape(-1,1) + metric = 1 / (s.conj().T @ V @ V.conj().T @ s) # de hoofdvergelijking van MUSIC + metric = np.abs(metric.squeeze()) # neem de magnitude + metric = 10*np.log10(metric) # converteer naar dB + results.append(metric) results /= np.max(results) # normalize -Running this algorithm on the complex scenario we have been using, we get the following very precise results, showing the power of MUSIC: +Als we dit algoritme op het complexe scenario van hierboven toepassen, krijgen we zeer precieze resultaten, wat de kracht van MUSIC laat zien: .. image:: ../_images/doa_music.svg :align: center :target: ../_images/doa_music.svg :alt: Example of direction of arrival (DOA) using MUSIC algorithm beamforming -Now what if we had no idea how many signals were present? Well there is a trick; you sort the eigenvalue magnitudes from highest to lowest, and plot them (it may help to plot them in dB): +Wat als we geen idee hebben hoeveel signalen aanwezig zijn? Daar is een truc voor: sorteer de magnitudes van de eigenwaarden van hoog naar laag en plot ze (in dB plotten helpt vaak): .. code-block:: python @@ -580,147 +1144,388 @@ Now what if we had no idea how many signals were present? Well there is a trick :align: center :target: ../_images/doa_eigenvalues.svg -The eigenvalues associated with the noise-subspace are going to be the smallest, and they will all tend around the same value, so we can treat these low values like a "noise floor", and any eigenvalue above the noise floor represents a signal. Here we can clearly see there are three signals being received, and adjust our MUSIC algorithm accordingly. If you don't have a lot of IQ samples to process or the signals are at low SNR, the number of signals might not be as obvious. Feel free to play around by adjusting :code:`num_expected_signals` between 1 and 7, you'll find that underestimating the number will lead to missing signal(s) while overestimating will only slightly hurt performance. +De eigenwaarden die bij de ruis-subruimte horen zijn het kleinst en clusteren rond ongeveer dezelfde waarde. Je kunt deze lage waarden dus als "ruisvloer" zien, en elke eigenwaarde erboven komt overeen met een signaal. Hier zien we duidelijk dat er drie signalen worden ontvangen, en kunnen we het MUSIC-algoritme daarop afstemmen. Heb je weinig IQ-samples of lage SNR, dan is het aantal signalen minder duidelijk. Speel gerust met :code:`num_expected_signals` tussen 1 en 7; onderschatting zorgt voor gemiste signalen, overschatting schaadt de prestatie meestal maar beperkt. -Another experiment worth trying with MUSIC is to see how close two signals can arrive at (in angle) while still distinguishing between them; sub-space techniques are especially good at that. The animation below shows an example, with one signal at 18 degrees and another slowly sweeping angle of arrival. +Nog een interessant experiment met MUSIC is kijken hoe dicht twee signalen qua hoek bij elkaar kunnen liggen terwijl je ze nog kunt onderscheiden; subruimtetechnieken zijn hier juist erg goed in. De animatie hieronder laat een voorbeeld zien, met één signaal op 18 graden en een tweede waarvan de aankomstrichting langzaam sweept. .. image:: ../_images/doa_music_animation.gif :scale: 100 % :align: center +********** +Root MUSIC +********** + +Alle DOA-technieken die we tot nu toe hebben behandeld, inclusief conventionele bundelvorming, MVDR en MUSIC zelf, werken door over een raster met kandidaat-hoeken te sweepen en per hoek een metric te berekenen (vaak parallel). Root MUSIC elimineert die scan volledig. In plaats van pieken in een spectrum te zoeken, bepaalt het de signaalrichtingen analytisch door de wortels van een polynoom op te lossen. Daardoor kan Root MUSIC zowel sneller als nauwkeuriger zijn dan spectrale MUSIC, omdat de piekpositie niet langer beperkt is door de hoekresolutie van je scanraster. Een beperking is dat Root MUSIC alleen direct werkt voor een ULA. Voor 2D-arrays of niet-ULA 1D-arrays bestaan varianten/uitbreidingen, maar die zijn veel complexer. Net als bij MUSIC hebben we nog steeds :code:`num_expected_signals` nodig, wat je ook als beperking kunt zien. + +Root MUSIC benut het feit dat de stuurvector van een ULA een nette Vandermonde-structuur heeft: een vector (of matrix) waarin elke rij bestaat uit opeenvolgende machten van een basiswaarde, bijvoorbeeld :code:`[1, x, x^2, x^3, ..., x^(n-1)]`. Bij halve-golflengteafstand zijn de stuurvectorelementen gewoon opeenvolgende machten van één complex getal :math:`z = e^{j\pi\sin\theta}`, zoals we aan het begin van dit hoofdstuk hebben gezien. + +Voor Root MUSIC bouwen we een polynoom op uit de projectiematrix van de ruis-subruimte. We gebruiken dezelfde MUSIC-kostfunctie als in de vorige sectie, maar nu in de vorm: + +.. math:: + P(z) = z^{N_r-1} \, s^H(z) \, V_n V_n^H \, s(z) + +waar :math:`V_n` de ruis-subruimtematrix is uit de eigenwaarde-ontbinding van de covariantiematrix :math:`R`, net als bij MUSIC. Als je dit product uitwerkt, krijg je een polynoom van graad :math:`2(N_r-1)`. Op punten waar :math:`P(z)` een wortel op de eenheidscirkel :math:`|z|=1` heeft, zou de MUSIC-kostfunctie oneindig worden; dat zijn dus signaalrichtingen. In de praktijk, met een eindig aantal samples, vallen wortels niet exact op de eenheidscirkel maar clusteren er dichtbij. Daarom kiezen we de :math:`D` wortels (waar :math:`D` het aantal verwachte signalen is) die het dichtst bij de eenheidscirkel liggen. + +De polynoomcoefficienten worden opgebouwd door de diagonalen van de projectiematrix van de ruis-subruimte :math:`D = V_n V_n^H` op te tellen: + +.. math:: + p_k = \sum_{\substack{m,n=0 \\ n-m = k-(N_r-1)}}^{N_r-1} [D]_{m,n}, \quad k = 0, 1, \ldots, 2(N_r-1) + +oftewel de som over de :math:`(k-(N_r-1))`-de diagonaal van :math:`D`. Zodra we het polynoom :math:`P(z) = p_0 + p_1 z + \cdots + p_{2(N_r-1)} z^{2(N_r-1)}` hebben, bepalen we numeriek de wortels en zetten we de signaalwortels terug om naar hoeken: + +.. math:: + \hat{\theta} = \arcsin\!\left(\frac{\angle z}{2\pi d}\right) + +De volledige Root MUSIC-code, met hetzelfde ontvangen signaal :code:`X` en dezelfde parameters als in het MUSIC-voorbeeld, is: + +.. code-block:: python + + num_expected_signals = 3 + + # Zelfde eigenwaarde-ontbinding als bij MUSIC + R = np.cov(X) + w, v = np.linalg.eig(R) + eig_val_order = np.argsort(np.abs(w)) + v = v[:, eig_val_order] + V = v[:, :Nr - num_expected_signals] # eigenvectoren van ruis-subruimte + + # Bouw het Root MUSIC-polynoom op uit diagonalen van de ruis-subruimteprojectie + D = V @ V.conj().T + p = np.zeros(2*Nr - 1, dtype=np.complex128) + for k in range(2*Nr - 1): + p[k] = np.sum(np.diag(D, k - (Nr - 1))) + + # Vind wortels, houd die binnen de eenheidscirkel, kies de num_expected_signals + # wortels die het dichtst bij de eenheidscirkel liggen + roots = np.roots(p[::-1]) # np.roots verwacht hoogste-graadscoefficient eerst + roots = roots[np.abs(roots) <= 1.0] # verwijder de conjugaat-reciproke partners die dezelfde DOA opleveren + roots = roots[np.argsort(-np.abs(roots))] # sorteer: dichtst bij eenheidscirkel eerst + doa_roots = roots[:num_expected_signals] + + # Zet wortels om naar hoeken in graden + doas_deg = np.sort(np.arcsin(np.angle(doa_roots) / (2 * np.pi * d)) * 180 / np.pi) + print("Estimated DOAs (degrees):", doas_deg) + +Het meeste rekenwerk wordt hier gedaan door NumPy's :code:`np.roots()`-functie, die de companion-matrixmethode gebruikt om de polynoomwortels te vinden. + +Als je dit op hetzelfde drie-signalen-scenario uitvoert, krijg je vrij nauwkeurige hoekschattingen, zonder sweep, resolutiestap of piekzoekalgoritme: + +.. code-block:: console + + Estimated DOAs (degrees): [-39.98674197 19.99724883 25.00387589] + True DOAs (degrees): [-40. 20. 25.] + +Vergelijk dat met spectrale MUSIC, waarvoor een theta-sweep van duizend punten nodig was om dezelfde drie pieken te vinden. De nauwkeurigheid van Root MUSIC wordt in essentie begrensd door de covariantiematrixschatting, niet door een gekozen roosterstap. De rekenwinst valt vooral op bij grote :code:`Nr`, omdat een polynoom van graad :math:`2(N_r-1)` opbouwen en oplossen veel goedkoper is dan de MUSIC-vergelijking over duizenden stuurhoeken evalueren. + +Een belangrijk punt: Root MUSIC erft dezelfde eisen als MUSIC. Je moet nog steeds het aantal signalen kennen (of schatten), en je hebt genoeg elementen nodig zodat :math:`N_r > D`. De eigenwaarde-plottruc uit de MUSIC-sectie werkt hier net zo goed om eerst het aantal signalen te schatten. + +*** +LMS +*** + +De Least Mean Squares (LMS)-bundelvormer is een bundelvormer met lage complexiteit, geïntroduceerd door Bernard Widrow. Deze verschilt op twee punten van de bundelvormers die we eerder zagen: 1) je moet de SOI kennen, of ten minste een deel ervan (bijv. synchronisatiereeks, pilots, enz.), en 2) hij is iteratief, dus de gewichten worden in meerdere iteraties aangescherpt. LMS werkt door de gemiddelde kwadratische fout te minimaliseren tussen het gewenste signaal (SOI) en de uitgang van de bundelvormer (dus gewichten toegepast op ontvangen samples). In de klassieke implementatie is elk ontvangen sample de volgende iteratiestap: pas huidige gewichten toe op één sample, bereken fout, en gebruik die fout om gewichten bij te sturen. Daarna herhaal je dit. De LMS-bundelvormer is toepasbaar in zowel analoge als digitale bundelvorming. Het LMS-algoritme: + +.. math:: + + w_{n+1} = w_n + \mu \underbrace{\left(y_n - w_{n}^H x_n\right)^*}_{error} x_n + +waar :math:`w_n` de gewichtenvector is bij iteratie/sample :math:`n`, :math:`\mu` de stapgrootte is, :math:`x_n` het ontvangen sample op :math:`n`, :math:`y_n` de verwachte waarde in die iteratie (de bekende SOI), en :math:`*` de complex geconjugeerde is. Laat :math:`w_{n}^H x_n` de vergelijking niet ingewikkelder laten lijken dan nodig: dat is simpelweg het toepassen van de huidige gewichten op het ingangssignaal, oftewel standaard bundelvorming. De stapgrootte :math:`\mu` bepaalt hoe snel de gewichten convergeren naar optimale waarden. Een kleine :math:`\mu` geeft trage convergentie (je haalt mogelijk de beste gewichten niet voordat het bekende signaal weg is), terwijl een grote :math:`\mu` instabiliteit kan veroorzaken. LMS is krachtig voor adaptieve bundelvorming, maar heeft beperkingen: je hebt een bekende SOI nodig, en tijd- en frequentiesynchronisatie maken onderdeel uit van het LMS-proces zodat je SOI-referentie is uitgelijnd met de ontvangen samples. + +In het Python-voorbeeld hieronder simuleren we een 8-element-array met een SOI die bestaat uit een herhaalde Gold-code, gemoduleerd als BPSK. Gold-codes worden gebruikt in 5G en GPS en hebben uitstekende kruiscorrelatie-eigenschappen, waardoor ze goed zijn als synchronisatiesignaal. In de simulatie nemen we ook twee toon-stoorzenders op, op 60 en -50 graden. Let op: deze simulatie bevat geen tijd- of frequentieverschuiving; anders zouden we SOI-synchronisatie in het LMS-proces moeten opnemen (dus gecombineerde bundelvorming en synchronisatie). In de animatie hieronder sweepen we de AoA van de SOI en plotten we het bundelpatroon dat LMS na 10k samples oplevert. Je ziet dat LMS de gain richting de SOI op exact 0 dB houdt (tenzij er een interferer precies bovenop zit), terwijl nullen naar de stoorzenders worden gezet. + +.. image:: ../_images/doa_lms_animation.gif + :scale: 100 % + :align: center + +.. code-block:: python + + # Scenario + sample_rate = 1e6 + d = 0.5 # halve-golflengteafstand + N = 100000 # aantal te simuleren samples + Nr = 8 # elementen + theta_soi = 20 / 180 * np.pi # omzetten naar radialen + theta2 = 60 / 180 * np.pi + theta3 = -50 / 180 * np.pi + t = np.arange(N)/sample_rate # tijdsvector + s1 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta_soi)).reshape(-1,1) # 8x1 + s2 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta2)).reshape(-1,1) + s3 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta3)).reshape(-1,1) + + # SOI is een Gold-code, herhaald, lengte 127 + gold_code = np.array([-1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1]) + soi_samples_per_symbol = 8 + soi = np.repeat(gold_code, soi_samples_per_symbol) + num_sequence_repeats = int(N / soi.shape[0]) + 1 # aantal herhalingen om N samples te vullen + soi = np.tile(soi, num_sequence_repeats)[:N] # herhaal reeks over simulatieduur en knip af + soi = soi.reshape(1, -1) # 1xN + + # Interferentie, bv. toonjammers, uit verschillende richtingen + tone2 = np.exp(2j*np.pi*0.02e6*t).reshape(1,-1) + tone3 = np.exp(2j*np.pi*0.03e6*t).reshape(1,-1) + + # Simuleer ontvangen signaal + r = s1 @ soi + s2 @ tone2 + s3 @ tone3 + n = np.random.randn(Nr, N) + 1j*np.random.randn(Nr, N) + r = r + 0.5*n # 8xN + + # LMS: richting van SOI is onbekend, SOI-signaal zelf is wel bekend + mu = 0.5e-5 # LMS-stapgrootte + w_lms = np.zeros((Nr, 1), dtype=np.complex128) # start met nullen + + # Loop over ontvangen samples + error_log = [] + for i in range(N): + r_sample = r[:, i].reshape(-1, 1) # 8x1 + soi_sample = soi[0, i] # scalar + y = w_lms.conj().T @ r_sample # pas de gewichten toe + y = y.squeeze() # maak er een scalar van + error = soi_sample - y + error_log.append(np.abs(error)**2) + w_lms += mu * np.conj(error) * r_sample # gewichten zijn nog steeds 8x1 + + w_lms /= np.linalg.norm(w_lms) # normaliseer gewichten + + plt.plot(error_log) + plt.xlabel('Iteration') + plt.ylabel('Mean Square Error') + plt.show() + + # Plot het bundelpatroon zoals eerder getoond + +Probeer :code:`theta_soi`, de hoeveelheid ruis (dus :code:`0.5*n`) en de stapgrootte :code:`mu` te variëren om te zien hoe het LMS-algoritme presteert. + ******************* -ESPRIT +Trainingsdata ******************* -Coming soon! +Binnen array processing bestaat het concept "training", waarbij je covariantiematrix :code:`R` vastlegt voordat een mogelijke SOI aanwezig is. Dit wordt vooral in radar gebruikt, waar meestal geen SOI aanwezig is en het detectieproces bestaat uit het testen van hoeken om te zien of er ergens een SOI zit. Als we :code:`R` vóór aanwezigheid van de SOI berekenen, kunnen we met methoden zoals MVDR gewichten bepalen waarin alleen stoorzenders en ruisomgeving zijn opgenomen. Zo voorkom je dat MVDR een null op of vlak bij de SOI-richting zet. Daarna passen we de gewichten toe op het ontvangen signaal om te testen of de SOI nu op die hoek aanwezig is. -********************* -Radar-Style Scenario -********************* +Om de waarde van trainingsdata te laten zien voeren we MVDR uit op een opname van een echte 16-element-array (met het QUAD-MxFE-platform van Analog Devices). Eerst doen we MVDR op de gebruikelijke manier, dus met het volledige ontvangen signaal voor :code:`R` en de gewichten. Daarna gebruiken we een aparte opname, gemaakt voordat de SOI werd ingeschakeld, om :code:`R` en de gewichten te berekenen. -In all of the previous DOA examples, we had one or more signals and we were interested in finding the directions of all of them. Now we will shift gears to a more radar-oriented scenario, where you have an environment with noise and interferers, and then a signal of interest (SOI) that is only present during certain times. A training phase, occurring when you know the SOI is not present, is performed, to capture the characteristics of the interference. We will be using the MVDR beamformer. +Deze opnames zijn gemaakt op 3,3 GHz RF, met een array-elementafstand van 0,045 meter, dus :math:`d = 0.495`. Er is een samplefrequentie van 30 MHz gebruikt. We noemen de drie signalen A, B en C. Signaal C is de aangewezen SOI, A en B zijn stoorzenders. Daarom hebben we een opname nodig met alleen A en B om trainingsdata te maken, zonder dat A en B verplaatsen tussen de trainingsopname en de opname waarin C ook aanwezig is. Hieronder staan de links naar de twee opnames: -A new scenario is used in the Python simulation below, involving one jammer and one SOI. In addition to simulating the samples of both signals combined (with noise), we also simulate just the jammer (with noise), which represents samples taken before the SOI was present. The received samples :code:`r` that only contain the jammer, are used as part of a training step, where we calculate the :code:`R_inv` in the MVDR equation. We then "turn on" the SOI by using :code:`r` that contains both the jammer and SOI, and the rest of the code is the same as normal MVDR DOA, except for one little but important detail- the :code:`R_inv`'s we use in the MVDR equation have to be: +https://github.com/777arc/777arc.github.io/raw/master/3p3G_A_B.npy -.. math:: +https://github.com/777arc/777arc.github.io/raw/master/3p3G_A_B_C.npy + +Laten we beginnen met normale MVDR op de A_B_C-opname. Die opname staat in :code:`np.save()`-formaat met een 2D-array: eerste dimensie is het aantal elementen in de array, tweede dimensie het aantal samples. + +.. code-block:: python + + import matplotlib.pyplot as plt + import numpy as np + + # Arrayparameters + center_freq = 3.3e9 + sample_rate = 30e6 + d = 0.045 * center_freq / 3e8 + print("d:", d) - w_{mvdr} = \frac{R_{jammer}^{-1} a}{a^H R_{both}^{-1} a} + # Bevat alle drie signalen; C noemen we onze SOI + filename = '3p3G_A_B_C.npy' + X = np.load(filename) + Nr = X.shape[0] -The full Python code example is as follows, try tweaking :code:`Nr` and :code:`theta1`: +Daarna voeren we basis-DOA met MVDR uit om de aankomstrichtingen van de drie signalen te bepalen: .. code-block:: python - # 1 jammer 1 SOI, generating two different received signals so we can isolate jammer for the training step - Nr = 4 # number of elements - theta1 = 20 / 180 * np.pi # Jammer - theta2 = 30 / 180 * np.pi # SOI - a1 = np.exp(-2j * np.pi * d * np.arange(Nr) * np.sin(theta1)).reshape(-1,1) # Nr x 1 - a2 = np.exp(-2j * np.pi * d * np.arange(Nr) * np.sin(theta2)).reshape(-1,1) - tone1 = np.exp(2j*np.pi*0.01*np.arange(N)).reshape(1,-1) # assume sample rate = 1 Hz, its arbitrary - tone2 = np.exp(2j*np.pi*0.02*np.arange(N)).reshape(1,-1) - r_jammer = a1 @ tone1 + 0.1*(np.random.randn(Nr, N) + 1j*np.random.randn(Nr, N)) - r_both = a1 @ tone1 + a2 @ tone2 + 0.1*(np.random.randn(Nr, N) + 1j*np.random.randn(Nr, N)) + # Voer DOA uit om de aankomstrichting van C te vinden + theta_scan = np.linspace(-1*np.pi/2, np.pi/2, 10000) # tussen -90 en +90 graden + results = [] + R = X @ X.conj().T # bereken covariantiematrix; dit geeft een Nr x Nr-matrix van de samples + Rinv = np.linalg.pinv(R) # pseudo-inverse werkt meestal beter dan een echte inverse + for theta_i in theta_scan: + a = np.exp(2j * np.pi * d * np.arange(X.shape[0]) * np.sin(theta_i)) # stuurvector in de gewenste richting theta_i + a = a.reshape(-1,1) # maak er een kolomvector van + power = 1/(a.conj().T @ Rinv @ a).squeeze() # MVDR power equation + power_dB = 10*np.log10(np.abs(power)) # vermogen in dB, zodat kleine en grote lobben tegelijk zichtbaar zijn + results.append(power_dB) + results -= np.max(results) # normalize to 0 dB at peak + +Dit is zo'n situatie waarin een rechthoekige plot handiger is dan een poolplot. We hebben de signalen A, B en C gelabeld. + +.. image:: ../_images/DOA_without_training.svg + :align: center + :target: ../_images/DOA_without_training.svg + :alt: DOA without training data - # "Training" step, with just jammer present - Rinv_jammer = np.linalg.pinv(r_jammer @ r_jammer.conj().T) # Nr x Nr, inverse covariance matrix estimate using the received samples +Als we C als SOI willen gebruiken en MVDR-gewichten willen maken die A en B nullen maar C behouden, moeten we de exacte aankomstrichting van C kennen. Dat doen we met een argmax op de DOA-resultaten van hierboven, maar pas nadat we de hoeken van A en B hebben onderdrukt (door de bovenste 60% van de DOA-resultaten op een zeer lage waarde te zetten). - # Now add in the SOI and perform DOA - theta_scan = np.linspace(-1*np.pi, np.pi, 1000) # sweep theta between -180 and +180 degrees - results = [] - for theta_i in theta_scan: - s = np.exp(-2j * np.pi * d * np.arange(Nr) * np.sin(theta_i)) # steering vector in the desired direction theta - s = s.reshape(-1,1) # make into a column vector (size Nr x 1) - Rinv_both = np.linalg.pinv(r_both @ r_both.conj().T) # could be outside for loop but more clear having it here - w = (Rinv_jammer @ s)/(s.conj().T @ Rinv_both @ s) # MVDR/Capon equation! Note which R's are being used where - r_weighted = w.conj().T @ r_both # apply weights to the signal that contains both jammer and SOI - power_dB = 10*np.log10(np.var(r_weighted)) # power in signal, in dB so its easier to see small and large lobes at the same time - results.append(power_dB) +.. code-block:: python - results -= np.max(results) # normalize + # Haal de hoek van C eruit na het onderdrukken van hoeken met stoorzenders + results_temp = np.array(results) + results_temp[int(len(results)*0.4):] = -9999*np.ones(int(len(results)*0.6)) + max_angle = theta_scan[np.argmax(results_temp)] # radians + print("max_angle:", max_angle) - fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}) - ax.plot(theta_scan, results) - ax.set_theta_zero_location('N') # make 0 degrees point up - ax.set_theta_direction(-1) # increase clockwise - ax.set_rlabel_position(55) # Move grid labels away from other labels - ax.set_ylim([-40, 0]) # only plot down to -40 dB +Het blijkt dat C binnenkomt op -0,3407 radialen, en die waarde gebruiken we dus bij het berekenen van de MVDR-gewichten. Dat hebben we al vaker gedaan; het is gewoon de MVDR-vergelijking: - plt.show() +.. code-block:: python + + # Bereken MVDR-gewichten + s = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(max_angle)) # stuurvector in de gewenste richting theta + s = s.reshape(-1,1) # maak er een kolomvector van + w = (Rinv @ s)/(s.conj().T @ Rinv @ s) # MVDR/Capon-vergelijking + +Als laatste plotten we het bundelpatroon van de zojuist berekende MVDR-gewichten, samen met de eerdere DOA-resultaten en een groene stippellijn op :code:`max_angle`: + +.. raw:: html + +
    + Klap dit open voor de plotcode (niets nieuws) -.. image:: ../_images/doa_radar_scenario.svg +.. code-block:: python + + # Bereken bundelpatroon + w = w.squeeze() + N_fft = 2048 + w_padded = np.concatenate((w, np.zeros(N_fft - Nr))) # zero-pad naar N_fft elementen voor meer FFT-resolutie + w_fft_dB = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(w_padded)))**2) # FFT-magnitude in dB + w_fft_dB -= np.max(w_fft_dB) # normalize to 0 dB at peak + theta_bins = np.arcsin(np.linspace(-1, 1, N_fft)) # map FFT-bins naar hoeken in radialen + + # Plot bundelpatroon en DOA-resultaten + plt.plot(theta_bins * 180 / np.pi, w_fft_dB) # GEBRUIK RADIALEN VOOR EEN POOLPLOT + plt.plot(theta_scan * 180 / np.pi, results, 'r') + plt.vlines(ymax=np.max(results), ymin=np.min(results) , x=max_angle*180/np.pi, color='g', linestyle='--') + plt.xlabel("Angle [deg]") + plt.ylabel("Magnitude [dB]") + plt.title("Bundelpatroon en DOA-resultaten, zonder training") + plt.grid() + plt.show() + +.. raw:: html + +
    + +.. image:: ../_images/DOA_without_training_pattern.svg :align: center - :target: ../_images/doa_radar_scenario.svg + :target: ../_images/DOA_without_training_pattern.svg + :alt: DOA without training data DOA and MVDR beam pattern -As you can see, there is a peak at the SOI (30 degrees) and null in the direction of the jammer (20 degrees). The jammers null is not as low as the -90 to 0 degree region (which are so low they are not even displayed on the plot), but that's only because there are no signals coming from that direction, and even though we are nulling the jammer, it's not perfectly nulled out because it's so close to the angle of arrival of the SOI and we only simulated 4 elements. +Het is gelukt om nullen op A en B te maken. Op de positie van C (groene stippellijn) hebben we geen null, maar ook niet echt een uitgesproken hoofdlob; eerder een verlaagde lob. Dat komt deels doordat er buiten de richtingen van A, B en C weinig tot geen energie binnenkomt, dus extra lobben (bijv. rond -70, 25 en 40 graden) maken in de praktijk weinig uit. Een andere reden dat de lob bij C niet sterker is, is dat de hoofdlob als het ware concurreert met nullen die MVDR zou plaatsen als we niet exact op die richting gericht waren. Een sterke hoofdlob op :code:`max_angle` zou mooier zijn, en daarvoor gebruiken we **trainingsdata**. -Note that you don't have to perform full DOA, your goal may be simply to receive the SOI (at an angle you already know) with the interferers nulled out as well as possible, e.g., if you were receiving a radar pulse from a certain direction and wanted to check if it contained energy above a threshold. +We laden nu de opname met alleen A en B om trainingsdata op te bouwen. In een radarsituatie is dit vergelijkbaar met :code:`R` berekenen voordat je een radar-puls uitzendt (idealiter kort daarvoor). -************************** -Quiescent Antenna Pattern -************************** +.. code-block:: python + + # Laad trainingsdata met alleen A en B, en bereken daarna Rinv + filename = '3p3G_A_B.npy' + X_A_B = np.load(filename) + R_training = X_A_B @ X_A_B.conj().T # bereken covariantiematrix + Rinv_training = np.linalg.pinv(R_training) -Recall that our steering vector we keep seeing, +Het grote verschil is nu dat we :code:`Rinv_training` gebruiken bij het berekenen van de MVDR-gewichten. We hergebruiken :code:`max_angle` van eerder. Zo richten we op C, maar nemen we C niet op in het ontvangen signaal dat voor :code:`R` en :code:`R_inv` wordt gebruikt. .. code-block:: python - np.exp(-2j * np.pi * d * np.arange(Nr) * np.sin(theta)) + # Bereken MVDR-gewichten met training-Rinv + s = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(max_angle)) # stuurvector in de gewenste richting theta + s = s.reshape(-1,1) # maak er een kolomvector van (grootte 3x1) + w = (Rinv_training @ s)/(s.conj().T @ Rinv_training @ s) # MVDR/Capon-vergelijking + +Met dezelfde plotmethode krijgen we: + +.. image:: ../_images/DOA_with_training.svg + :align: center + :target: ../_images/DOA_with_training.svg + :alt: DOA with training data DOA and MVDR beam pattern + +Let op dat we nog steeds nullen bij A en B krijgen (de null van B is minder diep, maar B is ook een zwakker signaal), maar nu zien we een sterke hoofdlob richting onze interessehoek C. Dit is precies de kracht van trainingsdata, en waarom het zo belangrijk is in radar-toepassingen. + +**************************************** +Simulatie van breedband-stoorzenders +**************************************** + +De methode die we dit hoofdstuk gebruikten om signalen op een bepaalde aankomstrichting op de array te simuleren (stuurvector maal verzonden signaal) gaat uit van een smalbandige-aanname: het signaal wordt als enkelvoudige frequentie beschouwd en de stuurvector wordt op die frequentie berekend. Dat is voor veel signalen een goede benadering, maar werkt minder goed voor breedband-signalen, bijvoorbeeld met bandbreedte groter dan circa 5% van de middenfrequentie. We behandelen kort een truc om breedband-**ruis** uit een bepaalde richting te simuleren (bijv. barrage jamming uit één hoekrichting). -encapsulates the array geometry, and its only other parameter is the direction you want to steer towards. We can calculate and plot the "quiescent" antenna pattern (array response) when steered towards a certain direction, which will tell us the arrays natural response if we don't do any additional beamforming. This can be done by taking the FFT of the complex conjugated weights, no for loop needed. The tricky part is mapping the bins of the FFT output to angle in radians or degrees, which involves an arcsine as you can see in the full example below: +Deze methode werkt door een covariantiematrix :code:`R` op te bouwen als som van bijdragen van elke breedband-ruisbron. Daarna berekenen we de wortelmatrix :code:`A`, en genereren we de sampleset :code:`X` door standaard complexe Gaussische ruis met :code:`A` te "kleuren". Een belangrijke parameter is :code:`fractional_bw`: de bandbreedte van het ruissignaal gedeeld door de middenfrequentie. Als :code:`fractional_bw=0` moet de code hieronder hetzelfde scenario geven als de traditionele methode voor ontvangen-signaalsimulatie. De onderstaande Python-code kun je in eerdere voorbeelden gebruiken om :code:`X` te simuleren. .. code-block:: python - N_fft = 512 - theta = theta_degrees / 180 * np.pi # doesnt need to match SOI, we arent processing samples, this is just the direction we want to point at - w = np.exp(-2j * np.pi * d * np.arange(Nr) * np.sin(theta)) # steering vector - w = np.conj(w) # or else our answer will be negative/inverted - w_padded = np.concatenate((w, np.zeros(N_fft - Nr))) # zero pad to N_fft elements to get more resolution in the FFT - w_fft_dB = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(w_padded)))**2) # magnitude of fft in dB - w_fft_dB -= np.max(w_fft_dB) # normalize to 0 dB at peak + N = 10 # aantal elementen in ULA + num_samples = 10000 + d = 0.5 - # Map the FFT bins to angles in radians - theta_bins = np.arcsin(np.linspace(-1, 1, N_fft)) # in radians + num_jammers = 3 + jammer_pow_dB = np.array([30, 30, 30]) # jammervermogens in dB + jammer_aoa_deg = np.array([-70, -20, 40]) # jammerhoeken in graden + jammer_aoa = np.sin(np.deg2rad(jammer_aoa_deg)) * np.pi + element_gain_dB = np.zeros(N) # gains in dB voor array-elementen (hier overal 0 dB) + element_gain_linear = 10.0 ** (element_gain_dB / 10) # converteer arraygains naar lineaire waarden + fractional_bw = 0.1 # als dit 0 is, komt deze methode overeen met traditionele arrayfactor-simulatie - # find max so we can add it to plot - theta_max = theta_bins[np.argmax(w_fft_dB)] + # Bouw NxN-jammer-covariantiematrix R + R = np.zeros((N, N), dtype=complex) + for m in range(N): + for n in range(N): + for j in range(num_jammers): + total_element_gain = np.sqrt(element_gain_linear[m] * element_gain_linear[n]) + sinc_term = np.sinc(0.5 * fractional_bw * (m - n) * jammer_aoa[j] / np.pi) + exp_term = np.exp(1j * (m - n) * jammer_aoa[j]) + R[m, n] += 10.0 ** (jammer_pow_dB[j] / 10) * total_element_gain * sinc_term * exp_term + R = np.eye(N, dtype=complex) + R - fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}) - ax.plot(theta_bins, w_fft_dB) # MAKE SURE TO USE RADIAN FOR POLAR - ax.plot([theta_max], [np.max(w_fft_dB)],'ro') - ax.text(theta_max - 0.1, np.max(w_fft_dB) - 4, np.round(theta_max * 180 / np.pi)) - ax.set_theta_zero_location('N') # make 0 degrees point up - ax.set_theta_direction(-1) # increase clockwise - ax.set_rlabel_position(55) # Move grid labels away from other labels - ax.set_thetamin(-90) # only show top half - ax.set_thetamax(90) - ax.set_ylim([-30, 1]) # because there's no noise, only go down 30 dB - plt.show() + # Genereer ontvangen samples + A = fractional_matrix_power(R, 0.5) # bereken matrixwortel (effectieve Cholesky-factorisatie) + A = A / np.sqrt(2) + X = np.zeros((N, num_samples), dtype=complex) + for k in range(num_samples): + noise_vec = np.random.randn(N) + 1j * np.random.randn(N) # complexe ruis + X[:, k] = A.conj().T @ noise_vec -.. image:: ../_images/doa_quiescent.svg +In de onderstaande plots zijn de MVDR-gewichten berekend voor 20 graden en in zwart weergegeven, terwijl de conventionele bundelvormer op 20 graden als blauwe stippellijn staat. De drie ruisbronnen zijn rood aangegeven. In de eerste plot is de fractionele bandbreedte 0, wat betekent dat de MVDR-gewichten overeen moeten komen met eerdere smalbandscenario's. Volgens de plot werkt dit prima, maar als de werkelijke ruis breedband is (en je SOI ook breedband is, waardoor je ruis niet simpel kunt wegfilteren), dan komt de simulatie niet overeen met de praktijk. + +.. image:: ../_images/doa_covariance_method_1.svg :align: center - :target: ../_images/doa_quiescent.svg + :target: ../_images/doa_covariance_method_1.svg + :alt: DOA Covariance method with a fractional bandwidth of 0 -It turns out that this pattern is going to almost exactly match the pattern you get when performing DOA with the conventional beamformer (delay-and-sum), when there is a single tone present at `theta_degrees` and little-to-no noise. The plot may look different because of how low the y-axis gets in dB, or due to the size of the FFT used to create this quiescent response pattern. Try tweaking :code:`theta_degrees` or the number of elements :code:`Nr` to see how the response changes. +Nu passen we een fractionele bandbreedte van 0,1 toe, waardoor de ruisbronnen effectief over een brede band worden uitgesmeerd en MVDR veel bredere nullen vormt. Voor veel praktijkscenario's is dit realistischer. + +.. image:: ../_images/doa_covariance_method_2.svg + :align: center + :target: ../_images/doa_covariance_method_2.svg + :alt: DOA Covariance method with a fractional bandwidth of 0.1 ******************* -2D DOA +Cirkelarrays ******************* -Coming soon! +We bespreken kort de Uniform Circular Array (UCA), een populaire arraygeometrie voor DOA omdat deze de 180-gradenambiguiteit van ULA's omzeilt. De KrakenSDR is bijvoorbeeld een 5-element-array, en vaak worden die vijf elementen in een cirkel met gelijke tussenafstand geplaatst. In theorie zijn maar drie elementen nodig om een UCA te vormen, net zoals je met twee elementen al een ULA kunt maken. -******************* -Steering Nulls -******************* +Alle code die we tot nu toe hebben bekeken geldt ook voor UCA's; we hoeven alleen de stuurvectorvergelijking te vervangen door de UCA-variant: + +.. code-block:: python + + radius = 0.05 # genormaliseerd op golflengte! + d = np.sqrt(2 * radius**2 * (1 - np.cos(2*np.pi/Nr))) + sf = 1.0 / (np.sqrt(2.0) * np.sqrt(1.0 - np.cos(2*np.pi/Nr))) # schaalfactor op basis van geometrie; bij een hexagoon is dit bv. 1.0 + x = d * sf * np.cos(2 * np.pi / Nr * np.arange(Nr)) + y = -1 * d * sf * np.sin(2 * np.pi / Nr * np.arange(Nr)) + s = np.exp(1j * 2 * np.pi * (x * np.cos(theta) + y * np.sin(theta))) + s = s.reshape(-1, 1) # Nrx1 + +Tot slot wil je hier van 0 tot 360 graden scannen, in plaats van -90 tot +90 zoals bij een ULA. + +Voor 2D-arrays (bijv. rechthoekig), zie :ref:`2d-beamforming-chapter`. + +************************** +Conclusie en Referenties +************************** -Coming soon! +Alle Python-code, inclusief de code waarmee de figuren/animaties zijn gemaakt, staat `op de GitHub-pagina van het boek `_. -************************* -Conclusion and References -************************* +* DOA-implementatie in GNU Radio - https://github.com/EttusResearch/gr-doa +* DOA-implementatie gebruikt door KrakenSDR - https://github.com/krakenrf/krakensdr_doa/blob/main/_signal_processing/krakenSDR_signal_processor.py -All Python code, including code used to generate the figures/animations, can be found `on the textbook's GitHub page `_. +[1] Mailloux, Robert J. Phased Array Antenna Handbook. Second edition, Artech House, 2005 -* DOA implementation in GNU Radio - https://github.com/EttusResearch/gr-doa -* DOA implementation used by KrakenSDR - https://github.com/krakenrf/krakensdr_doa/blob/main/_signal_processing/krakenSDR_signal_processor.py +[2] Van Trees, Harry L. Optimum Array Processing: Part IV of Detection, Estimation, and Modulation Theory. Wiley, 2002. .. |br| raw:: html diff --git a/content-nl/frequency_domain.rst b/content-nl/frequency_domain.rst index c8d10db7..5ee9344e 100644 --- a/content-nl/frequency_domain.rst +++ b/content-nl/frequency_domain.rst @@ -142,17 +142,17 @@ Het is als volgt gedefinieerd: .. math:: X(f) = \int x(t) e^{-j2\pi ft} dt -Voor een tijdsignaal x(t) kunnen we de frequentiedomein-versie, X(f), vinden met deze formule. -We willen de tijddomein-versie van een functie met x(t) of y(t) aangeven, en de corresponderende frequentiedomein-versie met X(f) en Y(F). -Hierbij staat de "t" voor tijd en "f" voor frequentie. -De "j" is simpelweg de imaginaire eenheid. -Misschien herken je dit als "i" van de wiskundelessen. +Voor een tijdsignaal :math:`x(t)` kunnen we de frequentiedomein-versie, :math:`X(f)`, vinden met deze formule. +We willen de tijddomein-versie van een functie met :math:`x(t)` of :math:`y(t)` aangeven, en de corresponderende frequentiedomein-versie met :math:`X(f)` en :math:`Y(f)`. +Hierbij staat de :math:`t` voor tijd en :math:`f` voor frequentie. +De :math:`j` is simpelweg de imaginaire eenheid. +Misschien herken je dit als :math:`i` van de wiskundelessen. We gebruiken "j" in de elektrotechniek en computerkunde omdat "i" vaak gebruikt wordt voor stroom en bij programmeren voor een iterator. -Teruggaan naar het tijddomein vanuit het frequentiedomein is bijna hetzelfde, afgezien van een vermenigvuldigingsfactor en het minteken: +Teruggaan naar het tijddomein vanuit het frequentiedomein is bijna hetzelfde, afgezien van het minteken: .. math:: - x(t) = \frac{1}{2 \pi} \int X(f) e^{j2\pi ft} df + x(t) = \int X(f) e^{j2\pi ft} df Veel boeken gebruiken :math:`w` in plaats van :math:`2\pi f`. :math:`w` is de hoekfrequentie in radialen per seconde terwijl :math:`f` in Hz is. Het enige wat je moet weten is @@ -349,6 +349,30 @@ Dus het signaal dat op ongeveer 97.5 MHz zat, is wanneer we het digitaal bekijke Reëel gezien is dit gewoon een frequentie die lager is dan de middenfrequentie. Dit wordt logischer wanneer we meer over samplen leren en ervaring opdoen met onze SDR's. +Wiskundig kunnen we negatieve frequenties ook zien door naar de complexe exponentiële functie te kijken: :math:`e^{2j \pi f t}`. Negatieve frequenties kun je dan zien als een complex sinusoide die in de tegenovergestelde richting draait. + +.. math:: + e^{2j \pi f t} = \cos(2 \pi f t) + j \sin(2 \pi f t) \quad \mathrm{\textcolor{blue}{blue}} + +.. math:: + e^{2j \pi (-f) t} = \cos(2 \pi f t) - j \sin(2 \pi f t) \quad \mathrm{\textcolor{red}{red}} + +.. image:: ../_images/negative_freq_animation.gif + :align: center + :scale: 75 % + :target: ../_images/negative_freq_animation.gif + :alt: Animation of a positive and negative frequency sinusoid on the complex plane + +De reden om complexe exxponenten te gebruiken is omdat een enkele :math:`cos()` of :math:`sin()` zowel positieve als negatieve frequenties bevat, zoals te zien is door de Euler's formule op een sinus met frequentie :math:`f` over tijd :math:`t` toe te passen: + +.. math:: + \cos(2 \pi f t) = \underbrace{\frac{1}{2} e^{2j \pi f t}}_\text{positief} + \underbrace{\frac{1}{2} e^{-2j \pi f t}}_\text{negatief} + +.. math:: + \sin(2 \pi f t) = \underbrace{\frac{1}{2j} e^{2j \pi f t}}_\text{positief} - \underbrace{\frac{1}{2j} e^{-2j \pi f t}}_\text{negatief} + +We gebruiken over het algemeen dus complexe exponenten in de RF-signaalbewerking, in plaats van sinussen en cosinnusen. + ********************************** Volgorde in de tijd maakt niet uit ********************************** @@ -402,7 +426,7 @@ Als we de inhoud van :code:`S` bekijken, dan zien we dat het een array van compl S = array([-0.01865008 +0.00000000e+00j, -0.01171553 -2.79073782e-01j,0.02526446 -8.82681208e-01j, 3.50536075 -4.71354150e+01j, -0.15045671 +1.31884375e+00j, -0.10769903 +7.10452463e-01j, -0.09435855 +5.01303240e-01j, -0.08808671 +3.92187956e-01j, -0.08454414 +3.23828386e-01j, -0.08231753 +2.76337148e-01j, -0.08081535 +2.41078885e-01j, -0.07974909 +2.13663710e-01j,... -Hint: Wat je ook aan het doen bent, als je ooit complexe getallen tegenkomt, bereken dan de modulus en fase en bekijk of dat er logischer uitziet. Laten we dat doen en de modulus en fase weergeven. In de meeste talen geeft de abs()-functie de modulus van een complex getal. De functie om de fase te bepalen varieert, maar in Python kan dit met :code:`np.angle()`. +Hint: Wat je ook aan het doen bent, als je ooit complexe getallen tegenkomt, bereken dan de modulus en fase en bekijk of dat er logischer uitziet. Laten we dat doen en de modulus en fase weergeven. In de meeste talen geeft de abs()-functie de modulus van een complex getal. De functie om de fase te bepalen varieert tussen programmeertalen, maar in Python kan dit met de NumPy functie :code:`np.angle()`. Dit geeft de fase terug in radialen. .. code-block:: python diff --git a/content-nl/intro.rst b/content-nl/intro.rst index d72ed591..2e92a88e 100644 --- a/content-nl/intro.rst +++ b/content-nl/intro.rst @@ -73,10 +73,14 @@ Bedankt aan iedereen die dit boek heeft gelezen en van feedback heeft voorzien, - James Hayek - Deidre Stuffer - Tarik Benaddi voor het `vertalen van PySDR naar het Frans `_ -- Daniel Versluis voor het `vertalen van PySDR naar het Nederlands `_ +- `Daniel Versluis `_ voor het `vertalen van PySDR naar het Nederlands `_ - `mrbloom `_ voor het `vertalen van PySDR naar het Ukraiens `_ - `Yimin Zhao `_ voor het `vertalen van PySDR naar het Chinees `_ - `Eduardo Chancay `_ voor het `vertalen van PySDR naar het Spaans `_ +- John Marcovici +- `Vishwaksen Reddy Dhareddy `_ for contributing the Detection Chapter section on real-time packet detection + +En alle `PySDR Patreon `_ supporters! ********************** Nederlandse vertaling diff --git a/content-nl/noise.rst b/content-nl/noise.rst index d3128310..8d29b3f8 100644 --- a/content-nl/noise.rst +++ b/content-nl/noise.rst @@ -324,6 +324,352 @@ Signal-to-Interference-plus-noise verhouding (SINR) of signaal-tot-verstoring-pl Wat die verstoring inhoudt, verschilt per toepassing/situatie, maar meestal gaat het om een ander ongewenst signaal wat het signaal van interesse verstoort op zo'n manier dat het niet weg te filteren is. +**************************************** +Diepere duik in stochastische variabelen +**************************************** + +Tot nu toe hebben we de wiskunde wat licht gehouden, maar nu doen we een stap terug en introduceren we het concept stochastische variabelen en hoe die in draadloze communicatie en SDR worden gebruikt. Een **stochastische variabele** is een wiskundig object dat uitkomsten van een willekeurig experiment op numerieke waarden afbeeldt. Stochastische variabelen beschrijven grootheden waarvan de waarde pas bekend is nadat je die observeert of meet, zoals onze ruissamples. Denk aan het gooien van een dobbelsteen. Voor de worp weet je niet welk getal valt. We kunnen een stochastische variabele :math:`X` definieren als de uitkomst van die worp. De waarde van :math:`X` ligt in {1, 2, 3, 4, 5, 6}, maar welke het wordt weten we pas na de worp. + +In draadloze communicatie en SDR zijn stochastische variabelen overal: + +* Thermische ruis in een ontvanger wordt op elk tijdstip als stochastische variabele gemodelleerd +* De amplitude van een ontvangen signaal met multipadfading is willekeurig +* De fase-offset door een veranderend kanaal kan als stochastische variabele tussen :math:`0` en :math:`2\pi` worden gezien +* Zelfs de databits die we verzenden kun je als stochastische variabelen beschouwen + +**Een sample versus veel samples** + +Dit onderscheid is cruciaal en zorgt vaak voor verwarring: + +* Een **enkele uitkomst** of **enkel sample** van een stochastische variabele is slechts een getal: een uitkomst van het willekeurige experiment +* Om een stochastische variabele te karakteriseren (gemiddelde, spreiding, enz.) heb je **veel uitkomsten** nodig + +Roep je in Python ``np.random.randn()`` zonder argumenten aan, dan krijg je een enkel willekeurig getal uit een Gauss-verdeling. Met dat ene getal weet je vrijwel niets over de verdeling. Roep je ``np.random.randn(10000)`` aan en genereer je 10.000 samples, dan kun je eigenschappen zoals gemiddelde en variantie schatten. + +.. code-block:: python + + import numpy as np + + # Single sample - just one number + x_single = np.random.randn() + print(x_single) # might be 0.534, -1.23, or any other value + + # Many samples - now we can characterize the distribution + x_many = np.random.randn(10000) + print(np.mean(x_many)) # will be close to 0 + print(np.var(x_many)) # will be close to 1 + +Gezamenlijke verdelingen +######################## + +Tot nu toe keken we naar losse stochastische variabelen. Werk je met twee of meer stochastische variabelen tegelijk, dan gebruik je een **gezamenlijke verdeling**. + +Voor continue variabelen :math:`X` en :math:`Y` wordt dit beschreven door de **gezamenlijke PDF**: + +.. math:: + f_{X,Y}(x,y) + +De gezamenlijke PDF vertelt hoe waarschijnlijk het is dat :math:`X` waarde :math:`x` aanneemt *en* :math:`Y` tegelijk waarde :math:`y`. + +Uit de gezamenlijke PDF kunnen we berekenen: + +* Marginale PDF's (bijv. :math:`f_X(x)` of :math:`f_Y(y)`) +* Verwachtingswaarden zoals :math:`E[XY]` +* Covariantie en correlatie +* Kansen waarin beide variabelen voorkomen + +De marginale PDF van :math:`X` krijg je bijvoorbeeld door over :math:`Y` te integreren: + +.. math:: + f_X(x) = \int_{-\infty}^{\infty} f_{X,Y}(x,y)\,dy + +Gezamenlijke verdelingen vormen de wiskundige basis om afhankelijkheid, correlatie en onafhankelijkheid tussen stochastische variabelen te begrijpen. + + +Kansverdelingen +############### + +Een **kansverdeling** beschrijft hoe waarschijnlijk verschillende waarden van een stochastische variabele zijn. Voor een continue stochastische variabele gebruiken we een **probability density function (PDF)**, genoteerd als :math:`f_X(x)`. De PDF geeft de relatieve waarschijnlijkheid van verschillende waarden. + +De belangrijkste verdeling in SDR en communicatie is de **Gauss- (normale) verdeling**. Een Gaussische stochastische variabele :math:`X` met gemiddelde :math:`\mu` en variantie :math:`\sigma^2` heeft de PDF: + +.. math:: + f_X(x) = \frac{1}{\sqrt{2\pi\sigma^2}} e^{-\frac{(x-\mu)^2}{2\sigma^2}} + +Dit is de bekende "klokvorm". De verdeling wordt volledig bepaald door twee parameters: + +* **Gemiddelde** :math:`\mu`: het centrum van de verdeling +* **Variantie** :math:`\sigma^2`: de spreiding van de verdeling (standaardafwijking :math:`\sigma` is de wortel van de variantie) + +In Python genereert ``np.random.randn()`` samples uit een **standaard-Gaussverdeling** met :math:`\mu = 0` en :math:`\sigma^2 = 1`. Dat kunnen we visualiseren: + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + + # Generate 10,000 samples from standard Gaussian + x = np.random.randn(10000) + + # Create histogram to visualize the distribution + plt.hist(x, bins=50, density=True, alpha=0.7, edgecolor='black') + plt.xlabel('Value') + plt.ylabel('Probability Density') + plt.title('Gaussian Distribution (μ=0, σ²=1)') + plt.grid(True) + plt.show() + +.. image:: ../_images/gaussian_histogram.png + :scale: 80% + :align: center + :alt: Histogram of Gaussian distributed samples + :target: ../_images/gaussian_histogram.png + +Verwachtingswaarde (oftewel gemiddelde) +####################################### + +De **verwachtingswaarde** van een stochastische variabele, genoteerd als :math:`E[X]` of :math:`\mu`, is de gemiddelde waarde over veel realisaties. Voor een continue stochastische variabele met PDF :math:`f_X(x)` is de verwachting: + +.. math:: + E[X] = \int_{-\infty}^{\infty} x \cdot f_X(x) \, dx + +In de praktijk, met :math:`N` samples :math:`x_1, x_2, \ldots, x_N` uit de verdeling, schatten we de verwachting met het **steekproefgemiddelde**: + +.. math:: + \hat{\mu} = \frac{1}{N} \sum_{n=1}^{N} x_n + +De verwachtingswaarde is een **lineaire operator**, dus: + +* :math:`E[aX + b] = aE[X] + b` voor constanten :math:`a` en :math:`b` +* :math:`E[X + Y] = E[X] + E[Y]` voor willekeurige stochastische variabelen + +Die lineariteit is erg nuttig in signaalverwerking. + +Variantie en standaardafwijking +############################### + +De **variantie** van een stochastische variabele, genoteerd als :math:`\text{Var}(X)` of :math:`\sigma^2`, meet hoe ver waarden rond het gemiddelde zijn uitgespreid. Definitie: de verwachtingswaarde van de gekwadrateerde afwijking van het gemiddelde. + +.. math:: + \text{Var}(X) = E[(X - \mu)^2] = E[X^2] - (E[X])^2 + +Met :math:`N` samples schatten we de variantie met: + +.. math:: + \hat{\sigma}^2 = \frac{1}{N} \sum_{n=1}^{N} (x_n - \hat{\mu})^2 + +De **standaardafwijking** :math:`\sigma` is de wortel van de variantie: :math:`\sigma = \sqrt{\sigma^2}`. + +Let op het :math:`\enspace \hat{} \enspace`-symbool ("hoedje") bij :math:`\sigma` en bij het steekproefgemiddelde. Dat geeft aan dat het om een schatting gaat. Die is niet exact gelijk aan de werkelijke waarde, maar benadert die steeds beter naarmate je meer samples gebruikt. + +**Belangrijke eigenschap:** Als :math:`X` variantie :math:`\sigma^2` heeft, dan: + +* Schalen: :math:`\text{Var}(aX) = a^2 \text{Var}(X)` +* Verschuiven: :math:`\text{Var}(X + b) = \text{Var}(X)` (een constante optellen verandert de spreiding niet) + +En dus voor standaardafwijking :math:`\sigma`: + +* Schalen: :math:`\sigma(aX) = a\sigma(X)` +* Verschuiven: :math:`\sigma(X+b) = \sigma(X)` + +.. image:: ../_images/gaussian_transformed.png + :scale: 80% + :align: center + :alt: Scaling and shifting the Gaussian Distribution. (notice the scales on x and y axes) + :target: ../_images/gaussian_transformed.png + +Schalen en verschuiven van de Gaussverdeling (let op de asschalen van x en y). + +**Variantie en vermogen** + +In signaalverwerking geldt voor een **nulgemiddeld** signaal (gemiddelde ~ 0) dat de variantie gelijk is aan het **gemiddelde vermogen**. Daarom gebruiken we die termen vaak door elkaar: + +.. math:: + P = \text{Var}(X) = E[X^2] \quad \text{(when } E[X] = 0\text{)} + +Deze relatie is fundamenteel bij analyse van ruisvermogen, signaal-ruisverhouding (SNR) en linkbudgets. + +.. code-block:: python + + noise_power = 2.0 + n = np.random.randn(N) * np.sqrt(noise_power) + print(np.var(n)) # will be approximately 2.0 + +Covariantie +########### + +De **covariantie** tussen twee stochastische variabelen :math:`X` en :math:`Y` is gedefinieerd als: + +.. math:: + \text{Cov}(X,Y) = E[(X - E[X])(Y - E[Y])] + +Een equivalente en vaak handigere vorm is: + +.. math:: + \text{Cov}(X,Y) = E[XY] - E[X]E[Y] + +Covariantie meet hoe twee variabelen samen variëren: + +* Positieve covariantie: ze nemen meestal samen toe of af +* Negatieve covariantie: als de ene toeneemt, neemt de andere vaak af +* Nul covariantie: ze zijn ongecorreleerd + +Als beide variabelen nulgemiddeld zijn, vereenvoudigt dit tot: + +.. math:: + \text{Cov}(X,Y) = E[XY] + +Covariantie heeft een eenheid (is niet genormaliseerd), daarom gebruiken we in de praktijk vaak de **correlatiecoefficient** (of gewoon correlatie): + +.. math:: + \rho_{XY} = \frac{\text{Cov}(X,Y)}{\sigma_X \sigma_Y} + +Dit levert een dimensieloze waarde tussen -1 en +1. + +Variantie van een som van variabelen +#################################### + +In signaalverwerking werken we vaak met sommen van stochastische variabelen, zoals signaal plus ruis: + +.. math:: + Z = X + Y + +De variantie van die som hangt af van of :math:`X` en :math:`Y` onafhankelijk zijn (of algemener: gecorreleerd). + +In de algemene vorm: + +.. math:: + \text{Var}(X + Y) = \text{Var}(X) + \text{Var}(Y) + 2\,\text{Cov}(X,Y) + +waar :math:`\text{Cov}(X,Y)` de **covariantie** tussen :math:`X` en :math:`Y` is. + +**Onafhankelijk geval** + +Als :math:`X` en :math:`Y` onafhankelijk zijn (of eenvoudiger: ongecorreleerd), dan vereenvoudigt dit tot: + +.. math:: + \text{Var}(X + Y) = \text{Var}(X) + \text{Var}(Y) + +Dit resultaat is erg belangrijk in communicatiesystemen. Bijvoorbeeld, als een ontvangen signaal is: + +.. math:: + R = S + N + +waar :math:`S` het signaal is en :math:`N` onafhankelijke ruis, dan is het totale vermogen simpelweg de som van signaal- en ruisvermogen. + +Daarom zijn SNR-berekeningen zo rechttoe rechtaan. + +********************************* +Complexe stochastische variabelen +********************************* + +In SDR werken we veel met **complexe signalen**, dus ook met complexe stochastische variabelen. Zo'n variabele heeft de vorm: + +.. math:: + Z = X + jY + +waar :math:`X` en :math:`Y` reele stochastische variabelen zijn voor de in-phase (I) en quadratuur (Q)-component. + +**Complexe Gaussische ruis** + +De meest voorkomende complexe stochastische variabele in draadloze communicatie is **complexe Gaussische ruis**, waarbij :math:`X` en :math:`Y` onafhankelijke Gaussische variabelen met dezelfde variantie zijn. + +Als bijvoorbeeld :math:`X \sim \mathcal{N}(\alpha_1, \sigma_1^2)` en :math:`Y \sim \mathcal{N}(\alpha_2, \sigma_2^2)` onafhankelijk zijn, dan heeft :math:`Z = X + jY`: + +* Gemiddelde: :math:`E[Z] = E[X] + jE[Y] = \alpha_1 + j\alpha_2` +* Variantie (vermogen): :math:`\text{Var}(Z) = \text{Var}(X) + \text{Var}(Y) = \sigma_1^2 + \sigma_2^2` + +.. image:: ../_images/gaussian_IQ.png + :scale: 80% + :align: center + :alt: Complex Gaussian noise visualized as two independent Gaussian random variables on the I and Q axes + :target: ../_images/gaussian_IQ.png + +Daarom gebruiken we bij complexe Gaussische ruis met eenheidsvermogen (variantie = 1): + +.. code-block:: python + + N = 10000 + n = (np.random.randn(N) + 1j*np.random.randn(N)) / np.sqrt(2) + print(np.var(n)) # ~ 1 + +De deling door :math:`\sqrt{2}` zorgt dat het totale vermogen (som van I- en Q-variantie) gelijk is aan 1. + +.. code-block:: python + + # Without normalization: + n_raw = np.random.randn(N) + 1j*np.random.randn(N) + print(np.var(np.real(n_raw))) # ~ 1 + print(np.var(np.imag(n_raw))) # ~ 1 + print(np.var(n_raw)) # ~ 2 (total power) + + # With normalization: + n_norm = n_raw / np.sqrt(2) + print(np.var(n_norm)) # ~ 1 (unit power) + +**************** +Toevalsprocessen +**************** + +Tot nu toe bespraken we stochastische variabelen: willekeurige waarden op een enkel punt. Een **toevalsproces** (ook wel **stochastisch proces**) is een verzameling stochastische variabelen geindexeerd door de tijd: + +.. math:: + X(t) \quad \text{or} \quad X[n] \text{ for discrete time} + +Op elk tijdstip :math:`t` is :math:`X(t)` een stochastische variabele. Zie een toevalsproces als een signaal dat in de tijd willekeurig evolueert. + +Voorbeelden in draadloze communicatie: + +* Ruis in de ontvanger: :math:`N(t)` of :math:`N[n]` +* Een signaal met tijdsafhankelijke fading: :math:`H(t)S(t)` +* Samples uit een SDR: elke batch is een realisatie van een toevalsproces + +**Stationaire processen** + +Een toevalsproces is **stationair** als de statistische eigenschappen niet in de tijd veranderen. In het bijzonder heeft een **wide-sense stationary (WSS)** proces: + +* Constant gemiddelde: :math:`E[X(t)] = \mu` voor alle :math:`t` +* Autocorrelatie die alleen van tijdsverschil afhangt: :math:`E[X(t)X(t+\tau)]` hangt alleen van :math:`\tau` af, niet van :math:`t` + +Veel ruisbronnen in draadloze systemen zijn ongeveer stationair, wat de analyse sterk vereenvoudigt. + +**Witte ruis** + +**Witte ruis** is een toevalsproces waarbij samples op verschillende tijdstippen ongecorreleerd zijn en de vermogensspectrale dichtheid over alle frequenties constant is. Additive White Gaussian Noise (AWGN) is tegelijk: + +* **White**: ongecorreleerd in de tijd, vlak spectrum +* **Gaussian**: elke sample is Gaussisch verdeeld + +Als we in Python ruis maken met ``np.random.randn(N)``, is elke van de :math:`N` samples een onafhankelijke Gaussische stochastische variabele, samen een wit-ruisproces. + + +Onafhankelijkheid en correlatie +############################### + +Twee stochastische variabelen :math:`X` en :math:`Y` zijn **onafhankelijk** als kennis van de ene niets zegt over de andere. Wiskundig factoriseert dan de gezamenlijke PDF: + +.. math:: + f_{X,Y}(x,y) = f_X(x) \cdot f_Y(y) + +Onafhankelijkheid is een sterke voorwaarde. Een zwakkere voorwaarde is **ongecorreleerd**, wat betekent: + +.. math:: + E[XY] = E[X]E[Y] + +Voor Gaussische stochastische variabelen impliceert ongecorreleerd ook onafhankelijk (een speciale eigenschap van Gaussische variabelen). + +Bij complexe Gaussische ruis zijn de I- en Q-component onafhankelijk: + +.. code-block:: python + + N = 10000 + I = np.random.randn(N) + Q = np.random.randn(N) + + # Check independence via correlation + correlation = np.corrcoef(I, Q)[0, 1] + print(f"Correlation between I and Q: {correlation:.4f}") # ~ 0 + ************************* Extra leesmateriaal ************************* diff --git a/content-nl/phaser.rst b/content-nl/phaser.rst index 87471777..8de82891 100644 --- a/content-nl/phaser.rst +++ b/content-nl/phaser.rst @@ -1,75 +1,69 @@ .. _phaser-chapter: #################################### -Phased Arrays with Phaser +Phased Arrays met Phaser #################################### -In this chapter we use the `Analog Devices Phaser `_, (a.k.a. CN0566 or ADALM-PHASER) which is an 8-channel low-cost phased array SDR that combines a PlutoSDR, Raspberry Pi, and ADAR1000 beamformers, designed to operate around 10.25 GHz. We will cover the setup and calibration steps, and then go through some beamforming examples in Python. For those that do not have a Phaser, we have included screenshots and animations of what the user would see. +In dit hoofdstuk gebruiken we de `Analog Devices Phaser `_ (ook bekend als CN0566 of ADALM-PHASER), een voordelige 8-kanaals phased-array-SDR die een PlutoSDR, Raspberry Pi en ADAR1000-bundelvormers combineert en ontworpen is voor gebruik rond 10,25 GHz. We behandelen de installatie- en calibratiestappen en lopen daarna door enkele voorbeelden van bundelvorming in Python. Voor wie geen Phaser heeft, zijn screenshots en animaties toegevoegd van wat je normaal zou zien. .. image:: ../_images/phaser_on_tripod.png :scale: 60 % :align: center - :alt: The Phaser (CN0566) by Analog Devices + :alt: De Phaser (CN0566) van Analog Devices ************************ -Intro to Phased Arrays -************************ - -Coming soon! - -************************ -Hardware Overview +Hardware-overzicht ************************ .. image:: ../_images/phaser_front_and_back.png :scale: 40 % :align: center - :alt: The front and back of the Phaser unit + :alt: Voor- en achterkant van de Phaser-unit -The Phaser is a single board containing the phased array and a bunch of other components, with a Raspberry Pi plugged in on one side and a Pluto mounted to the other side. The high-level block diagram is shown below. Some items to note: +De Phaser is een enkel bord met daarop de phased array en diverse andere componenten, met aan de ene zijde een Raspberry Pi en aan de andere zijde een Pluto. Het blokschema op hoofdlijnen staat hieronder. Enkele belangrijke punten: -1. Even though it looks like a 32-element 2d array, it's really an 8-element 1d array -2. Both receive channels on the Pluto are used (the second channel uses a u.FL connector) -3. The LO onboard is used to downconvert the received signal from around 10.25 GHz to around 2 GHz, so that the Pluto can receive it -4. Each ADAR1000 has four phase shifters with adjustable gain, and all four channels are summed together before being sent to the Pluto -5. The Phaser essentially contains two "subarrays" which each subarray containing four channels -6. Not shown below are GPIO and serial signals from the Raspberry Pi used to control various components on the Phaser +1. Hoewel het op een 32-element 2D-array lijkt, is het in werkelijkheid een 8-element 1D-array +2. Beide ontvangstkanalen van de Pluto worden gebruikt (het tweede kanaal gebruikt een u.FL-connector) +3. De onboard LO wordt gebruikt om het ontvangen signaal van rond 10,25 GHz naar rond 2 GHz te downconverten, zodat de Pluto het kan ontvangen +4. Elke ADAR1000 heeft vier faseschuivers met instelbare gain, en alle vier kanalen worden opgeteld voordat ze naar de Pluto gaan +5. De Phaser bevat in essentie twee "subarrays", elk met vier kanalen +6. Niet getoond: GPIO- en seriele signalen van de Raspberry Pi die verschillende onderdelen op de Phaser aansturen .. image:: ../_images/phaser_components.png :scale: 40 % :align: center - :alt: The components of the Phaser (CN0566) including ADF4159, LTC5548, ADAR1000 + :alt: Componenten van de Phaser (CN0566), inclusief ADF4159, LTC5548 en ADAR1000 -For now let's ignore the transmit side of the Phaser, as in this chapter we will only be using the HB100 device as a test transmitter. The ADF4159 is a frequency synthesizer that produces a tone up to 13 GHz in frequency, what we call the local oscillator or LO. This LO is fed into a mixer, the LTC5548, which is able to do upconversion or downconversion, although we'll be using it for downconversion. For downconversion it takes in the LO as well as a signal anywhere from 2 - 14 GHz, and multiplies the two together which performs a frequency shift. The resulting downconverted signal can be anywhere from DC to 6 GHz, although we are going to target around 2 GHz. The ADAR1000 is a 4-channel analog beamformer, so the Phaser utilizes two of them. An analog beamformer has independently adjustable phase shifters and gain for each channel, allowing each channel to be time-delayed and attenuated before being summed together in the analog domain (resulting in a single channel). On the Phaser, each ADAR1000 outputs a signal which gets downconverted and then received by the Pluto. Using the Raspberry Pi we can control the phase and gain of all eight channels in real-time, to perform beamforming. We also have the option to do two-channel digital beamforming/array processing, discussed in the next chapter. +Voor nu negeren we de zendkant van de Phaser, omdat we in dit hoofdstuk alleen de HB100 als testzender gebruiken. De ADF4159 is een frequentiesynthesizer die een toon tot 13 GHz kan maken; dit is onze lokale oscillator (LO). Deze LO gaat naar de mixer LTC5548, die zowel upconversion als downconversion kan doen, maar wij gebruiken downconversion. Daarbij worden LO en een signaal tussen 2 en 14 GHz met elkaar vermenigvuldigd, wat een frequentieverschuiving geeft. Het resulterende downconverted signaal kan tussen DC en 6 GHz liggen, al mikken wij op ongeveer 2 GHz. De ADAR1000 is een 4-kanaals analoge bundelvormer; daarom gebruikt de Phaser er twee. Een analoge bundelvormer heeft per kanaal onafhankelijk instelbare fase en gain, zodat elk kanaal tijdsvertraging en attenuatie kan krijgen voordat alle kanalen in het analoge domein worden opgeteld (tot een enkel kanaal). Op de Phaser levert elke ADAR1000 een signaal dat wordt downconverted en daarna door de Pluto wordt ontvangen. Met de Raspberry Pi kunnen we fase en gain van alle acht kanalen realtime regelen voor bundelvorming. We hebben ook de optie voor tweekanaals digitale bundelvorming/arrayverwerking, besproken in het volgende hoofdstuk. -For those interested, a slightly more detailed block diagram is provided below. +Voor geinteresseerden staat hieronder een iets gedetailleerder blokschema. .. image:: ../_images/phaser_detailed_block_diagram.png :scale: 80 % :align: center - :alt: Detailed block diagram of the Phaser (CN0566) + :alt: Gedetailleerd blokschema van de Phaser (CN0566) ************************ -SD Card Preparation +SD-kaartvoorbereiding ************************ -We will assume you are using the Raspberry Pi onboard the Phaser (directly, with a monitor/keyboard/mouse). This simplifies setup, as Analog Devices publishes a pre-built SD card image with all the necessary drivers and software. You can download the SD card image and find SD imaging instructions `here `_. The image is based on Raspberry Pi OS and includes all the software you'll need already installed. +We gaan ervan uit dat je de Raspberry Pi op de Phaser gebruikt (direct, met monitor/toetsenbord/muis). Dat vereenvoudigt de setup, omdat Analog Devices een kant-en-klaar SD-kaartimage aanbiedt met alle benodigde drivers en software. Je kunt het SD-image downloaden en instructies voor het flashen vinden `hier `_. Het image is gebaseerd op Raspberry Pi OS en bevat de benodigde software al vooraf geinstalleerd. ************************ -Hardware Preparation +Hardwarevoorbereiding ************************ -1. Connect Pluto's CENTER micro-USB port to Raspberry Pi -2. Optionally, carefully thread the tripod into the tripod mount -3. We will assume you're using an HDMI display, USB keyboard, and USB mouse connected to the Raspberry pi -4. Power the Pi and Phaser board through the type-C port of the Phaser (CN0566), i.e. do NOT connect a supply to the Raspberry Pi's USB C +1. Verbind de MIDDELSTE micro-USB-poort van de Pluto met de Raspberry Pi +2. Optioneel: schroef voorzichtig het statief in de statiefaansluiting +3. We gaan ervan uit dat je een HDMI-scherm, USB-toetsenbord en USB-muis op de Raspberry Pi gebruikt +4. Voed de Pi en het Phaser-bord via de USB-C-poort van de Phaser (CN0566), dus sluit GEEN aparte voeding op de USB-C van de Raspberry Pi aan ************************ -Software Install +Software-installatie ************************ -Once you have booted into the Raspberry Pi using the pre-build image, using the default user/pass analog/analog, it is recommended to run the following steps: +Nadat je met het voorgebouwde image bent opgestart op de Raspberry Pi (standaard gebruiker/wachtwoord: analog/analog), is het aanbevolen om de volgende stappen uit te voeren: .. code-block:: bash @@ -80,69 +74,69 @@ Once you have booted into the Raspberry Pi using the pre-build image, using the sudo raspi-config -For more assistance setting up the Phaser, reference the `Phaser wiki quickstart page `_. +Voor extra hulp bij het opzetten van de Phaser, zie de `Phaser wiki quickstart-pagina `_. ************************ -HB100 Setup +HB100-setup ************************ .. image:: ../_images/phaser_hb100.png :scale: 50 % :align: center - :alt: HB100 that comes with Phaser + :alt: HB100 die met de Phaser wordt meegeleverd -The HB100 that comes with the Phaser is a low-cost Doppler radar module that we will be using as a test transmitter, as it transmits a continuous tone around 10 GHz. It runs off 2 AA batteries or a 3V benchtop supply, and when it's on it will have a solid red LED. +De HB100 die bij de Phaser wordt geleverd is een voordelige Doppler-radarmodule die we als testzender gebruiken, omdat deze een continue toon rond 10 GHz uitzendt. Hij werkt op 2 AA-batterijen of een 3V-labvoeding, en bij inschakelen brandt er een constante rode LED. -Because the HB100 is low-cost and uses cheap RF components, its transmit frequency varies from unit to unit, over hundreds of MHz, which is a range that is greater than the highest bandwidth we can receive using the Pluto (56 MHz). So to make sure we are tuning our Pluto and downconverter in a manner that will always receive the HB100 signal, we must determine the HB100's transmit frequency. This is done using an example app from Analog Devices, which performs a frequency sweep and calculates FFTs while looking for a spike. Make sure your HB100 is on and in the general vicinity of the Phaser, and then run the utility with: +Omdat de HB100 goedkoop is en eenvoudige RF-componenten gebruikt, varieert de zendfrequentie per exemplaar met honderden MHz, een bereik groter dan de maximale bandbreedte die de Pluto kan ontvangen (56 MHz). Om de Pluto en downconverter zo af te stemmen dat we het HB100-signaal zeker ontvangen, moeten we dus eerst de zendfrequentie van de HB100 bepalen. Dat doen we met een voorbeeldapp van Analog Devices die een frequentiesweep uitvoert en FFT's berekent om een piek te vinden. Zorg dat de HB100 aan staat en in de buurt van de Phaser is, en voer daarna het hulpprogramma uit met: .. code-block:: bash cd ~/pyadi-iio/examples/phaser python phaser_find_hb100.py -It should create a file called hb100_freq_val.pkl in the same directory. This file contains the HB100 transmit frequency in Hz (pickled, so not viewable in plaintext) which we will use in the next step. +Dit zou in dezelfde map een bestand genaamd hb100_freq_val.pkl moeten maken. Dat bestand bevat de HB100-zendfrequentie in Hz (gepickled, dus niet als platte tekst leesbaar), die we in de volgende stap gebruiken. ************************ Calibration ************************ -Lastly, we need to calibrate the phased array. This requires holding the HB100 at the array's boresight (0 degrees). The side of the HB100 with the barcode is the side that transmits the signal, so that face should be held a few feet away from the Phaser, right in-front and centered to it, and then pointed straight at the Phaser. In the next step you can experiment with different angles and orientations, but for now let's run the calibration utility: +Tot slot moeten we de phased array calibreren. Daarvoor houd je de HB100 op boresight van de array (0 graden). De zijde van de HB100 met de barcode is de zendzijde; houd die op enige afstand recht voor en gecentreerd op de Phaser en richt hem direct op de Phaser. In de volgende stap kun je met verschillende hoeken en orientaties experimenteren, maar voer nu eerst de calibratietool uit: .. code-block:: bash python phaser_examples.py cal -This will create two more pickle files: phase_cal_val.pkl and gain_cal_val.pkl, in the same directory. Each one contains an array of 8 numbers corresponding to the phase and gain tweaks needed to calibrate each channel. These values are unique to each Phaser, as they can very during manufacturing. Subsequent runs of this utility will lead to slightly different values which is normal. +Dit maakt in dezelfde map nog twee picklebestanden aan: phase_cal_val.pkl en gain_cal_val.pkl. Elk bestand bevat een array met 8 waarden die de fase- en gain-correcties per kanaal aangeven. Deze waarden zijn uniek per Phaser, omdat productievariaties een rol spelen. Herhaalde runs van deze tool geven normaal gesproken licht verschillende waarden. -************************ -Pre-built Example App -************************ +************************* +Voorgebouwde Voorbeeldapp +************************* -Now that we have calibrated our Phaser and found the HB100 frequency, we can run the example app that Analog Devices provides. +Nu we de Phaser hebben gecalibreerd en de HB100-frequentie kennen, kunnen we de voorbeeldapp van Analog Devices starten. .. code-block:: bash python phaser_gui.py -If you check the "Auto Refresh Data" checkbox in the bottom-left it should begin running. You should see something similar to the following when holding the HB100 in the Phaser's boresight. +Als je linksonder het vakje "Auto Refresh Data" aanvinkt, zou de app moeten starten. Wanneer je de HB100 op boresight van de Phaser houdt, zou je iets als het volgende moeten zien. .. image:: ../_images/phaser_gui.png :scale: 50 % :align: center - :alt: Phaser example GUI tool by Analog Devices + :alt: Phaser-voorbeeldtool met GUI van Analog Devices ************************ Phaser in Python ************************ -We will now dive into the hands-on Python portion. For those who don't have a Phaser, screenshots and animations are provided. +We gaan nu naar het praktische Python-gedeelte. Voor wie geen Phaser heeft, zijn screenshots en animaties toegevoegd. -Initializing Phaser and Pluto +Phaser en Pluto initialiseren ############################## -The following Python code sets up our Phaser and Pluto. By this point you should have already run the calibration steps, which produce three pickle files. Make sure you are running the Python script below from within the same directory as these pickle files. +De volgende Python-code zet onze Phaser en Pluto op. Op dit punt heb je de calibratiestappen al uitgevoerd, die drie picklebestanden opleveren. Zorg dat je het onderstaande script uitvoert vanuit dezelfde map als die picklebestanden. -There are a lot of settings to deal with, so it's OK if you don't absorb the entire code snippet below, just note that we are using a sample rate of 30 MHz, manual gain which we set very low, we set all of the element gains to the same value, and point the array towards boresight (0 degrees). +Er zijn veel instellingen, dus het is prima als je niet direct de hele code begrijpt. Let vooral op dat we een sample rate van 30 MHz gebruiken, handmatige gain op een lage waarde zetten, alle elementgains gelijk maken en de array op boresight (0 graden) richten. .. code-block:: python @@ -204,10 +198,10 @@ There are a lot of settings to deal with, so it's OK if you don't absorb the ent phaser.lo = int(signal_freq + sdr.rx_lo - offset) -Receiving Samples from the Pluto +Samples Ontvangen van de Pluto ################################ -At this point the Phaser and Pluto are configured and ready to go. We can now start receiving data from the Pluto. Let's grab a single batch of 1024 samples, then take the FFT of each of the two channels. +Op dit punt zijn de Phaser en Pluto geconfigureerd en klaar. We kunnen nu data van de Pluto ontvangen. Laten we een enkele batch van 1024 samples ophalen en daarna van beide kanalen de FFT nemen. .. code-block:: python @@ -235,31 +229,31 @@ At this point the Phaser and Pluto are configured and ready to go. We can now s plt.tight_layout() plt.show() -What you see at this point will depend if your HB100 is on and where it's pointing. If you hold it a few feet from the Phaser and point it towards the center, you should see something like this: +Wat je hier ziet hangt af van of de HB100 aan staat en waar hij op gericht is. Als je hem op enige afstand van de Phaser houdt en naar het midden richt, zou je ongeveer dit moeten zien: .. image:: ../_images/phaser_rx_psd.png :scale: 100 % :align: center - :alt: Phaser initial example + :alt: Eerste Phaser-voorbeeld -Note the strong spike near 0 Hz, the 2nd shorter spike is simply an artifact that can be ignored, since it's around 40 dB down. The top plot, showing the time domain, displays the real part of the two channels, so the relative amplitude between the two will vary slightly depending on where you hold the HB100. +Let op de sterke piek rond 0 Hz; de tweede, kleinere piek is een artefact dat je kunt negeren, omdat die ongeveer 40 dB lager ligt. De bovenste plot in het tijddomein toont het reele deel van de twee kanalen, waardoor de relatieve amplitude iets varieert afhankelijk van de positie van de HB100. -Performing Beamforming +Bundelvorming Uitvoeren ############################## -Next, let's actually sweep the phase! In the following code we sweep the phase from negative 180 to positive 180 degrees, at a 2 degree step. Note that this is not the angle the beamformer points; it's the phase difference between adjacent channels. We must calculate the angle of arrival corresponding to each phase step, using knowledge of the speed of light, the RF frequency of the received signal, and the Phaser's element spacing. The phase difference between adjacent elements is given by: +Nu gaan we echt de fase sweepen. In de volgende code sweepen we de fase van -180 tot +180 graden, met stappen van 2 graden. Let op: dit is niet direct de hoek waar de bundelvormer naartoe wijst; het is het faseverschil tussen aangrenzende kanalen. We moeten de bijbehorende aankomsthoek per fasestap berekenen met de lichtsnelheid, de RF-frequentie van het ontvangen signaal en de elementafstand van de Phaser. Het faseverschil tussen aangrenzende elementen is: .. math:: \phi = \frac{2 \pi d}{\lambda} \sin(\theta_{AOA}) -where :math:`\theta_{AOA}` is the angle of arrival of the signal with respect to boresight, :math:`d` is the antenna spacing in meters, and :math:`\lambda` is the wavelength of the signal. Using the formula for wavelength and solving for :math:`\theta_{AOA}` we get: +waar :math:`\theta_{AOA}` de aankomsthoek van het signaal is ten opzichte van boresight, :math:`d` de antenneafstand in meter, en :math:`\lambda` de golflengte van het signaal. Met de formule voor golflengte en opgelost naar :math:`\theta_{AOA}` krijgen we: .. math:: \theta_{AOA} = \sin^{-1}\left(\frac{c \phi}{2 \pi f d}\right) -You'll see this when we calculate :code:`steer_angle` below: +Dat zie je terug bij de berekening van :code:`steer_angle` hieronder: .. code-block:: python @@ -290,16 +284,16 @@ You'll see this when we calculate :code:`steer_angle` below: plt.ylabel("Magnitude [dB]") plt.show() -For each :code:`phase` value (remember, this is the phase between adjacent elements) we set the phase shifters, after adding in the phase calibration values and forcing the degrees to be between 0 and 360. We then grab one batch of samples with :code:`rx()`, sum the two channels, then calculate the power in the signal. We then plot power over angle of arrival. The result should look something like this: +Voor elke :code:`phase`-waarde (dit is dus het faseverschil tussen aangrenzende elementen) zetten we de faseschuivers, na optellen van de fasecalibratiewaarden en normalisatie van graden naar 0-360. Daarna halen we met :code:`rx()` een batch samples op, sommeren we de twee kanalen en berekenen we het signaalvermogen. Vervolgens plotten we vermogen tegen aankomsthoek. Het resultaat ziet er ongeveer zo uit: .. image:: ../_images/phaser_sweep.png :scale: 100 % :align: center - :alt: Phaser single sweep + :alt: Phaser enkele sweep -In this example the HB100 was held slightly to the side of boresight. +In dit voorbeeld werd de HB100 iets naast boresight gehouden. -If you want a polar plot you can instead using the following: +Als je een polaire plot wilt, kun je in plaats daarvan het volgende gebruiken: .. code-block:: python @@ -317,14 +311,14 @@ If you want a polar plot you can instead using the following: .. image:: ../_images/phaser_sweep_polar.png :scale: 100 % :align: center - :alt: Phaser single sweep using a polar plot + :alt: Phaser enkele sweep met polaire plot -By taking the max we can estimate the direction of arrival of the signal! +Door het maximum te nemen kunnen we de aankomstrichting van het signaal schatten. -Real-time and with Spatial Tapering +Realtime en met Ruimtelijke Tapering ###################################### -Now let's take a moment to talk about spatial tapering. So far we have left the gain adjustments of each channel to equal values, so that all eight channels get summed equally. Just like we applied a window before taking an FFT, we can apply a window in the spatial domain by applying weights to these eight channels. We'll use the exact same windowing functions like Hanning, Hamming, etc. Let's also tweak the code to run in real-time so that it's a little more fun: +Laten we nu kort stilstaan bij ruimtelijke tapering. Tot nu toe hielden we de gaininstellingen van elk kanaal gelijk, zodat alle acht kanalen gelijk worden opgeteld. Net zoals we een venster toepassen voor een FFT, kunnen we in het ruimtelijke domein een venster toepassen door gewichten op deze acht kanalen te zetten. We gebruiken dezelfde vensterfuncties zoals Hanning, Hamming, enzovoort. We passen de code ook aan voor realtime uitvoering: .. code-block:: python @@ -372,36 +366,36 @@ Now let's take a moment to talk about spatial tapering. So far we have left the except KeyboardInterrupt: sys.exit() # quit python -You should see a real-time version of the previous exercise. Try switching which :code:`gain_list` is used, to play around with the different windows. Here is an example of the Rectangular window (i.e., no windowing function): +Je zou nu een realtimeversie van de vorige oefening moeten zien. Wissel eens van :code:`gain_list` om met verschillende vensters te experimenteren. Hier is een voorbeeld met het rechthoekige venster (dus zonder vensterfunctie): .. image:: ../_images/phaser_animation_rect.gif :scale: 100 % :align: center - :alt: Beamforming animation using the Phaser and a rectangular window + :alt: Bundelvormingsanimatie met de Phaser en rechthoekig venster -and here is an example of the Hamming window: +en hier een voorbeeld met het Hamming-venster: .. image:: ../_images/phaser_animation_hamming.gif :scale: 100 % :align: center - :alt: Beamforming animation using the Phaser and a Hamming window + :alt: Bundelvormingsanimatie met de Phaser en Hamming-venster -Note the lack of sidelobes for Hamming. In fact, every window aside from Rectangular will greatly reduce the sidelobes, but in return the main lobe will be a little wider. +Let op het ontbreken van sidelobes bij Hamming. In feite zal elk venster behalve Rectangular de sidelobes sterk verminderen, maar in ruil daarvoor wordt de hoofdlob iets breder. ************************ Monopulse Tracking ************************ -Up until this point we have been performing individual sweeps in order to find the angle of arrival of a test transmitter (the HB100). But lets say we wish to continuously receive a communications or radar signal, that may be moving an causing the angle of arrival to change over time. We refer to this process as tracking, and it assumes we already have a rough estimate of the angle of arrival (i.e., the initial sweep has identified a signal of interest). We will use monopulse tracking to adaptively update the weights in order to keep the main lobe pointed at the signal over time, although note that there are other methods of tracking besides monopulse. +Tot nu toe voerden we losse sweeps uit om de aankomsthoek van een testzender (de HB100) te vinden. Stel nu dat we continu een communicatie- of radarsignaal willen ontvangen dat beweegt en daardoor een veranderende aankomsthoek heeft. Dit noemen we tracking, en het veronderstelt dat we al een ruwe schatting van de aankomsthoek hebben (de eerste sweep heeft dus een interessant signaal gevonden). We gebruiken monopulse-tracking om de gewichten adaptief bij te werken en de hoofdlob in de tijd op het signaal gericht te houden, al zijn er ook andere trackingmethoden. -Invented in 1943 by Robert Page at the Naval Research Laboratory (NRL), the basic concept of monopulse tracking is to use two beams, both slightly offset from the current angle of arrival (or at least our estimate of it), but on different sides as shown in the diagram below. +Monopulse-tracking werd in 1943 bedacht door Robert Page bij het Naval Research Laboratory (NRL). Het basisidee is om twee bundels te gebruiken die beide iets afwijken van de huidige aankomsthoek (of onze schatting daarvan), maar aan tegengestelde kanten zoals in het diagram hieronder. .. image:: ../_images/monopulse.svg :align: center :target: ../_images/monopulse.svg - :alt: Monopulse beam diagram showing two beams and the sum beam + :alt: Monopulse-diagram met twee bundels en de sombundel -We then take both the sum and difference (a.k.a. delta) of these two beams digitally, which means we must use two digital channels of the Phaser, making this a hybrid array approach (although you could certainly do the sum and difference in analog with custom hardware). The sum beam will equate to a beam centered at the current angle of arrival estimate, as shown above, which means this beam can be used for demod/decoding the signal of interest. The delta beam, as we will call it, is harder to visualize, but it will have a null at the angle of arrival estimate. We can use the ratio between the sum beam and delta beam (refered to as the error) to perform our tracking. This process is best explained with a short Python snippet; recall that the :code:`rx()` function returns a batch of samples from both channels, so in the code below :code:`data[0]` is the first channel of the Pluto (first set of four Phaser elements) and :code:`data[1]` is the second channel (second set of four elements). In order to create two beams, we will steer each of the two sets separately. We can calculate the sum, delta, and error as follows: +Vervolgens nemen we digitaal zowel de som als het verschil (delta) van deze twee bundels. Dat betekent dat we twee digitale kanalen van de Phaser gebruiken, dus dit is een hybride array-aanpak (al kun je som en verschil ook analoog realiseren met aangepaste hardware). De sombundel is gecentreerd rond de huidige aankomsthoekschatting, zoals hierboven, en kan worden gebruikt voor demodulatie/decodering van het doelsignaal. De delta-bundel is lastiger te visualiseren, maar heeft een null op de geschatte aankomsthoek. We kunnen de verhouding tussen sombundel en delta-bundel (de error) gebruiken voor tracking. Dit wordt het duidelijkst met een korte Python-snippet; de :code:`rx()`-functie geeft een batch samples van beide kanalen terug. In de code hieronder is :code:`data[0]` het eerste Pluto-kanaal (eerste set van vier Phaser-elementen) en :code:`data[1]` het tweede kanaal (tweede set van vier elementen). Om twee bundels te maken sturen we deze twee sets apart aan. Som, delta en error berekenen we als volgt: .. code-block:: python @@ -410,9 +404,9 @@ We then take both the sum and difference (a.k.a. delta) of these two beams digit delta_beam = data[0] - data[1] error = np.mean(np.real(delta_beam / sum_beam)) -The sign of the error tells us which direction the signal is actually coming from, and the magnitude tells us how far off we are from the signal. We can then use this information to update the angle of arrival estimate and weights. By repeating this process in real-time we can track the signal. +Het teken van de error vertelt ons aan welke kant het signaal werkelijk zit, en de grootte van de error geeft aan hoe ver we van het signaal af zitten. Met die informatie werken we de aankomsthoekschatting en de gewichten bij. Door dit realtime te herhalen kunnen we het signaal volgen. -Now jumping into the full Python example, we will start by copying the code we used earlier to perform a 180 degree sweep. The only code we will add is to pull out the phase at which the received power was maximum: +In het volledige Python-voorbeeld beginnen we met de code van de eerdere 180-gradensweep. De enige toevoeging is dat we de fase nemen waarbij het ontvangen vermogen maximaal was: .. code-block:: python @@ -421,7 +415,7 @@ Now jumping into the full Python example, we will start by copying the code we u current_phase = phase_angles[np.argmax(powers)] print("max_phase:", current_phase) -Next we will create two beams, we will start by trying 5 degrees lower and 5 degrees higher than the current estimate, although note that this is in units of phase, we haven't converted to steering angle, although they are similar. The following code is essentially two copies of the code we used earlier to set the phase shifters of each channel, except we use the first 4 elements for the lower beam and last 4 elements for upper beam: +Vervolgens maken we twee bundels: eerst 5 graden lager en 5 graden hoger dan de huidige schatting. Let op dat dit in fase-eenheden is; we hebben nog niet naar stuurhoek omgerekend, al zijn die vergelijkbaar. De volgende code is in essentie twee kopieen van de eerdere code voor faseschuivers per kanaal, met dit verschil: de eerste 4 elementen voor de lage bundel en de laatste 4 voor de hoge bundel: .. code-block:: python @@ -439,7 +433,7 @@ Next we will create two beams, we will start by trying 5 degrees lower and 5 deg phaser.elements.get(i + 1).rx_phase = channel_phase phaser.latch_rx_settings() # apply settings -Before doing the actual tracking, lets test the above by keeping the beam weights constant and moving the HB100 left and right (after it finishes initializing to find the starting angle): +Voordat we echte tracking doen, testen we dit eerst door de bundelgewichten constant te houden en de HB100 links en rechts te bewegen (nadat de initialisatie de starthoek heeft bepaald): .. code-block:: python @@ -463,11 +457,11 @@ Before doing the actual tracking, lets test the above by keeping the beam weight .. image:: ../_images/monopulse_waving.svg :align: center :target: ../_images/monopulse_waving.svg - :alt: Showing error function for monopulse tracking without actually updating the weights + :alt: Errorfunctie voor monopulse-tracking zonder de gewichten bij te werken -What's happening in this example is I'm moving the HB100 around. I start by holding it in a steady position while the 180 degree sweep happens, then after it's done I move it a little to the right, and wiggle it around, then I move it to the left of where I started and wiggle it around. Then around time = 400 in the plot I move it back to the other side and hold it there for a moment, before waving it around one more time. The take-away is that the further the HB100 gets from the starting angle, the higher the error, and the sign of the error tells us which side the HB100 is on relative to the starting angle. +Wat hier gebeurt: ik beweeg de HB100 rond. Ik begin met een vaste positie terwijl de 180-gradensweep loopt, daarna beweeg ik hem iets naar rechts en wiebel ik ermee, vervolgens naar links van de startpositie en weer wat beweging. Rond tijd = 400 in de plot ga ik weer naar de andere kant en houd ik hem kort stil, daarna nogmaals wat beweging. De kern: hoe verder de HB100 van de starthoek zit, hoe groter de error, en het teken van de error geeft aan aan welke kant de HB100 zich bevindt ten opzichte van de starthoek. -Now lets use the error value to update the weights. We will get rid of the previous for loop, and make a new for loop around the entire process. For the sake of clarity we have the entire code example below, except for the initial part where we did the 180 degree sweep: +Laten we nu de error gebruiken om de gewichten bij te werken. We vervangen de vorige for-loop door een nieuwe for-loop rond het volledige proces. Voor de duidelijkheid staat hieronder het complete codevoorbeeld, behalve het initiele deel met de 180-gradensweep: .. code-block:: python @@ -526,21 +520,21 @@ Now lets use the error value to update the weights. We will get rid of the prev .. image:: ../_images/monopulse_tracking.svg :align: center :target: ../_images/monopulse_tracking.svg - :alt: Monopulse tracking demo using a Phaser and HB100 being waved around infront of it + :alt: Monopulse-trackingdemo met een Phaser en een bewegende HB100 ervoor -You can see the error is essentially the derivative of the phase estimate; because we're performing successful tracking, the phase estimate is more or less the actual angle of arrival. It's not clear looking only at these plots, but when there is a sudden movement, it takes the system a small fraction of a second to adjust and catch up. The goal is for the change in angle of arrival to never be so quick that the signal arrives beyond the main lobes of the two beams. +Je ziet dat de error in essentie de afgeleide van de faseschatting is; omdat tracking hier werkt, benadert de faseschatting de werkelijke aankomsthoek. Alleen op basis van deze plots is dat niet altijd direct zichtbaar, maar bij een plotselinge beweging heeft het systeem een kleine fractie van een seconde nodig om bij te sturen. Het doel is dat de verandering in aankomsthoek nooit zo snel gaat dat het signaal buiten de hoofdlobben van de twee bundels terechtkomt. -It is a lot easier to visualize the process when the array is only 1D, but practical use-cases of monopulse tracking are almost always 2D (using a 2D/planar array instead of a linear array like the Phaser). For the 2D case, there are four beams created instead of two, and after process there is a single sum beam and four delta beams used to steer in both dimensions. +Het proces is veel makkelijker te visualiseren met een 1D-array, maar praktische toepassingen van monopulse-tracking zijn vrijwel altijd 2D (met een 2D/planaire array in plaats van een lineaire array zoals de Phaser). In het 2D-geval maak je vier bundels in plaats van twee, en na verwerking houd je een enkele sombundel en vier delta-bundels over voor sturing in beide dimensies. ************************ Radar with Phaser ************************ -Coming soon! +Komt binnenkort! ************************ -Conclusion +Conclusie ************************ -The entire code used to generate the figures in this chapter is available on the textbook's GitHub page. +Alle code die is gebruikt om de figuren in dit hoofdstuk te genereren is beschikbaar op de GitHub-pagina van het leerboek. diff --git a/content-nl/pulse_shaping.rst b/content-nl/pulse_shaping.rst index 7bfee0f8..79dfe63f 100644 --- a/content-nl/pulse_shaping.rst +++ b/content-nl/pulse_shaping.rst @@ -163,7 +163,6 @@ Python Oefeningen ********************************** Laten we eens met Python wat pulsen gaan vormgeven. We zullen hiervoor BPSK-symbolen gebruiken omdat dit reële symbolen zijn en we dus alleen het I-deel hoeven te weergeven, wat iets makkelijker is om te volgen. -.. todo - dit is nog een vage onderbouwing We gaan 8 samples per symbool toepassen. In plaats van een blokgolf die varieert tussen 1 en -1 zullen we een rij aan pulsen gebruiken. Wanneer je een impuls in een filter stopt zul je de impulsresponsie eruit krijgen. Dus, als je een rij aan pulsen wilt hebben dan zul je het moeten opvullen met nullen zodat je niet een blokgolf krijgt. .. code-block:: python @@ -211,7 +210,7 @@ Met de manier waarop de filtervergelijking werkt willen we het tijdstip 0 in het # het RC filter bouwen num_taps = 101 beta = 0.35 - Ts = sps # sample rate is 1 Hz, periodetijd is 1, *symbool*periodetijd is 8 + Ts = sps # samplerate is 1 Hz, sampleperiode is 1, *symbool*periode is 8 t = np.arange(num_taps) - (num_taps-1)//2 # neemt laatste nummer niet mee h = 1/Ts*np.sinc(t/Ts) * np.cos(np.pi*beta*t/Ts) / (1 - (2*beta*t/Ts)**2) plt.figure(1) @@ -280,3 +279,120 @@ En hier is nog een voorbeeld, ergens tussen bovenstaande voorbeelden in. Nu hebb .. image:: ../_images/symbol_sync4.png :scale: 40 % :align: center + +De Q waarden worden niet getoond op de tijdsdomein plot omdat ze ongeveer nul zijn, waardoor de IQ-plots alleen horizontaal kunnen spreiden. + + +************* +OQPSK en MSK +************* + +Gewone QPSK kan flinke amplitudeschommelingen hebben, omdat de I- en Q-component soms tegelijk veranderen. Dat kan een probleem zijn voor vermogensversterkers die juist goed werken met een zo constant mogelijke envelop. Hieronder zie je een voorbeeld van QPSK met raised-cosine pulsvorming: boven staan baseband I en Q in het tijddomein apart weergegeven, onder staat de magnitude. Let op de grote schommelingen in magnitude door de bijna-nuldoorgangen wanneer I en Q tegelijk omschakelen. Let ook op de verticale stippellijnen, die de symboolgrenzen aangeven; op die punten zijn zowel I als Q exact 1 of -1. Je ziet ook dat de magnitude op sommige momenten heel dicht bij nul komt. + +.. image:: ../_images/qpsk_magnitude.svg + :align: center + :target: ../_images/qpsk_magnitude.svg + :alt: Voorbeeld van QPSK-magnitude met grote schommelingen door bijna-nuldoorgangen + +**Offset QPSK (OQPSK)** is een kleine variatie op standaard QPSK die dit probleem vermindert. Dat werkt door de Q-component een halve symboolperiode te vertragen, zodat I en Q nooit tegelijk veranderen. Het resultaat is dat het signaal op elk moment alleen fase-overgangen van 90 graden maakt (in plaats van mogelijke sprongen van 180 graden), waardoor de envelop veel stabieler blijft. Hieronder zie je OQPSK; we hebben verticale stippellijnen toegevoegd met een halve symboolperiode offset om te laten zien waar de Q-component verandert (dus in het midden van het symbool). + +.. image:: ../_images/oqpsk_magnitude.svg + :align: center + :target: ../_images/oqpsk_magnitude.svg + :alt: Voorbeeld van OQPSK-magnitude met veel kleinere schommelingen door de offset tussen I en Q + +De Python-code om OQPSK met raised-cosine pulsvorming te genereren is als volgt: + +.. code-block:: python + + # Parameters + num_symbols = 200 + sps = 32 # samples per symbool + beta = 0.35 # roll-offfactor + span = 6 # filterlengte in symbolen (per kant) + + # Genereer QPSK-symbolen + bits = np.random.randint(0, 4, num_symbols) + symbols = np.exp(1j * (np.pi/4 + bits * np.pi/2)).astype(complex) # punten op 45, 135, 225 en 315 graden + + # RC-filter + t = np.arange(-span * sps, span * sps + 1) / sps # in symboolperioden + h = np.sinc(t) * np.cos(np.pi * beta * t) / (1 - (2 * beta * t)**2 + 1e-20) + + # Vertraag Q-impulsen met een halve symboolperiode voor filtering, zodat het + # pulsvormingsfilter de opbouw natuurlijk afhandelt (geen opvulartefacten na filtering) + half = sps // 2 + I_up = np.zeros(num_symbols * sps) + Q_up = np.zeros(num_symbols * sps) + I_up[::sps] = np.real(symbols) + Q_up[half::sps] = np.imag(symbols) + I_filt = np.convolve(I_up, h, mode='same') + Q_filt = np.convolve(Q_up, h, mode='same') + signal = I_filt + 1j * Q_filt + +We kunnen nog een stap verder gaan: als we raised-cosine pulsvorming vervangen door een ander type pulsvorming, namelijk half-sine, krijgen we een perfect constante envelop. Het half-sine pulsvormingsfilter is gedefinieerd als :math:`h(t) = \sin\left(\frac{\pi t}{T}\right)`, en deze vorm laat elk symbool vloeiend in- en uitlopen zodat de fase continu en lineair van het ene naar het volgende symbool verandert. Het resultaat heet **Minimum Shift Keying (MSK)** en is een speciaal geval van OQPSK. Als we in de vorige code het raised-cosine filter vervangen door de volgende half-sine filtercode, krijgen we MSK: + +.. code-block:: python + + # ... + + # Half-sine pulsvorm (plaats dit op de plek van de RC-filterregels) + t = np.arange(sps) + h = np.sin(np.pi * t / sps) + + # ... + +.. image:: ../_images/msk_magnitude.svg + :align: center + :target: ../_images/msk_magnitude.svg + :alt: Example of MSK magnitude showing a constant envelope + +De geprinte envelop hierboven zal in essentie constant zijn; dat is precies het kenmerk van MSK. + +Let op dat bij OQPSK en MSK de termen "symboolperiode" en "samples per symbool" verwarrend kunnen zijn, omdat een symbool zowel kan verwijzen naar een volledig I+Q-tijdsblok als naar alleen de tijd tussen veranderingen in I of Q (dus half zo lang). In de code hierboven gebruiken we de eerste definitie: een symbool is het volledige I+Q-tijdsblok. Dat is echter niet altijd zo, en je kunt daarom factoren 2 tegenkomen in vergelijkingen zoals die van half-sine. + +Een korte blik op de vorm in het frequentiedomein (power spectral density) van deze signalen: voor QPSK of OQPSK met raised-cosine pulsvorming is het spectrum hetzelfde. Het is compact en rolt af volgens de roll-off factor, precies waarom raised-cosine pulsvorming zo populair is. + +.. image:: ../_images/qpsk_psd.svg + :align: center + :target: ../_images/qpsk_psd.svg + :alt: Voorbeeld van QPSK- of OQPSK-PSD wanneer een RC-filter voor pulsvorming wordt gebruikt + +Bij MSK zorgt de raised-sine vorm ervoor dat de hoofdlob veel breder is, en het signaal duidelijk hogere sidelobes heeft. Bij signalen met lage SNR zie je die sidelobes vaak niet eens, omdat ze onder de ruisvloer liggen (meer dan 20 dB lager). De afruil is dat we wel een perfect constante envelop krijgen. + +.. image:: ../_images/msk_psd.svg + :align: center + :target: ../_images/msk_psd.svg + :alt: Voorbeeld van MSK-PSD waarbij een raised-sine filter voor pulsvorming wordt gebruikt + +MSK wordt vaak gebruikt in toepassingen zoals satellietcommunicatie en deep-space communicatie, waar een constante envelop efficiëntere vermogensversterking mogelijk maakt en spectrumbesparing minder belangrijk is dan maximaal vermogensrendement. Zowel OQPSK als MSK vragen wel om een iets complexere ontvanger dan gewone QPSK, vanwege de offset tussen I en Q. + +MSK kun je ook vanuit een heel andere invalshoek afleiden: als een speciaal geval van **Continuous-Phase FSK (CPFSK)**. In CPFSK wordt elk symbool met een van twee frequenties verzonden, en belangrijk is dat de fase nooit wordt gereset; die loopt vloeiend door vanaf het vorige symbool. Die continuiteit houdt de envelop constant en het spectrum compact. MSK is CPFSK met modulatie-index :math:`h = 0.5`, wat betekent dat de twee tonen precies :math:`\Delta f = \frac{1}{2T}` Hz uit elkaar liggen, waarbij :math:`T` de symboolperiode is. Het basebandsignaal is: + +.. math:: + + s(t) = e^{j 2\pi \frac{h}{2T} \int_{-\infty}^{t} d(\tau)\, d\tau} + +waar :math:`d(\tau) \in \{-1, +1\}` de NRZ-datastroom is. In de praktijk stapelt de integraal simpelweg fase op: elk bit roteert de fase met :math:`\pm \frac{\pi}{2}` over een symboolperiode. De Python-code om MSK via de CPFSK-aanpak te genereren is als volgt. Let op dat :code:`sps` overal door 2 is gedeeld, omdat de symboolperiode half zo lang is in de CPFSK-aanpak: elk symbool komt dan overeen met een verandering in I of Q, niet in beide tegelijk. + +.. code-block:: python + + bits = np.random.randint(0, 2, num_symbols) + symbols = 2 * bits - 1 # map {0,1} naar {-1, +1} + + # Bouw de instantane frequentieafwijking op + mod_index = 0.5 + t = np.arange(num_symbols * sps / 2) / (sps / 2) + freq_dev = np.zeros(num_symbols * sps // 2) + for k, a in enumerate(symbols): + freq_dev[k * sps // 2 : (k + 1) * sps // 2] = a * mod_index / 2.0 + + phase = 2.0 * np.pi * np.cumsum(freq_dev) / (sps / 2) # fase cumulatief opbouwen + signal = np.exp(1j * phase) + +En zoals je ziet, ziet het er exact hetzelfde uit als onze eerdere MSK, maar nu gegenereerd via een volledig andere aanpak. + +.. image:: ../_images/cpfsk_magnitude.svg + :align: center + :target: ../_images/cpfsk_magnitude.svg + :alt: Voorbeeld van CPFSK-magnitude die laat zien dat het overeenkomt met MSK diff --git a/content-nl/pyqt.rst b/content-nl/pyqt.rst new file mode 100644 index 00000000..93d0419e --- /dev/null +++ b/content-nl/pyqt.rst @@ -0,0 +1,881 @@ +.. _pyqt-chapter: + +########################## +Realtime GUI's met PyQt +########################## + +In dit hoofdstuk leren we hoe je realtime grafische gebruikersinterfaces (GUI's) in Python maakt met PyQt, de Python-bindings voor Qt. Als onderdeel van dit hoofdstuk bouwen we een spectrum analyzer met tijd-, frequentie- en spectrogram/waterfall-weergave, plus invoerwidgets om verschillende SDR-parameters aan te passen. Het voorbeeld ondersteunt PlutoSDR, USRP en een simulatiemodus. + +**************** +Introductie +**************** + +Qt (uitgesproken als het engelse woord "Cute") is een framework om GUI-applicaties te maken die op Linux, Windows, macOS en zelfs Android kunnen draaien. Het is een krachtig framework dat in veel commerciële applicaties wordt gebruikt en in C++ is geschreven voor hoge prestaties. PyQt is de Python-verbinding met Qt en biedt daarmee een manier om GUI-applicaties in Python te bouwen, terwijl je profiteert van de prestaties van het onderliggende C++-framework. In dit hoofdstuk gebruiken we PyQt om een realtime spectrum analyzer te bouwen die met een SDR (of met een gesimuleerd signaal) werkt. De analyzer krijgt tijd-, frequentie- en spectrogram/waterfall-weergaven, plus invoerwidgets om SDR-parameters bij te sturen. Voor het plotten gebruiken we `PyQtGraph `_, een aparte library bovenop PyQt. Voor invoer gebruiken we sliders, combo-boxes en push-buttons. Het voorbeeld ondersteunt PlutoSDR, USRP en simulatiemodus. Hoewel de voorbeeldcode PyQt6 gebruikt, is vrijwel elke regel identiek aan PyQt5 (op de :code:`import` na); qua API is er weinig veranderd tussen die versies. Dit hoofdstuk bevat daarom veel Python-code met uitleg via voorbeelden. Aan het einde heb je de belangrijkste bouwstenen in handen om je eigen interactieve SDR-app te maken. + +**************** +Qt-overzicht +**************** + +Qt is een groot framework en we behandelen slechts een klein deel van de mogelijkheden. Er zijn wel enkele kernconcepten die belangrijk zijn bij werken met Qt/PyQt: + +- **Widgets**: Widgets zijn de bouwstenen van een Qt-applicatie en vormen de GUI. Er zijn veel soorten widgets, zoals knoppen, sliders, labels en plots. Widgets worden in layouts geplaatst, die bepalen hoe ze op het scherm staan. + +- **Layouts**: Layouts worden gebruikt om widgets in een venster te ordenen. Er zijn meerdere types, waaronder horizontale, verticale, grid- en form-layouts. Layouts maken complexe GUI's mogelijk die goed reageren op veranderingen in venstergrootte. + +- **Signals en Slots**: Signals en slots zijn een manier om tussen onderdelen van een Qt-applicatie te communiceren. Een signal wordt uitgezonden wanneer een gebeurtenis plaatsvindt en is gekoppeld aan een slot (een callbackfunctie) die dan wordt uitgevoerd. Dit maakt een event-driven structuur mogelijk en houdt de GUI responsief. + +- **Style Sheets**: Style sheets worden gebruikt om het uiterlijk van widgets aan te passen. Ze zijn geschreven in een CSS-achtige taal en kunnen kleur, lettertype en grootte wijzigen. + +- **Graphics**: Qt heeft een krachtig graphics-framework om custom grafische elementen te maken. Het bevat classes voor lijnen, rechthoeken, ellipsen en tekst, plus klassen voor muis- en toetsenbordevents. + +- **Multithreading**: Qt ondersteunt multithreading ingebouwd en biedt classes om worker-threads op de achtergrond te draaien. Daarmee kun je langdurige taken uitvoeren zonder de hoofd-GUI-thread te blokkeren. + +- **OpenGL**: Qt heeft ingebouwde OpenGL-ondersteuning en classes voor 3D-graphics. Dat is nuttig voor toepassingen die hoge 3D-prestaties vragen. In dit hoofdstuk richten we ons alleen op 2D-toepassingen. + +******************************* +Basislayout van een Applicatie +******************************* + +Voordat we de verschillende Qt-widgets behandelen, kijken we naar de layout van een typische Qt-applicatie. Een Qt-app bestaat uit een hoofdvenster met daarin een centrale widget, die op zijn beurt de hoofdinhoud bevat. Met PyQt kunnen we een minimale app maken met slechts een enkele QPushButton: + +.. code-block:: python + + from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton + + # Subclass QMainWindow to customize your application's main window + class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + + # Example GUI component + example_button = QPushButton('Push Me') + def on_button_click(): + print("beep") + example_button.clicked.connect(on_button_click) + + self.setCentralWidget(example_button) + + app = QApplication([]) + window = MainWindow() + window.show() # Windows are hidden by default + app.exec() # Start the event loop + +Probeer de code zelf uit; waarschijnlijk moet je :code:`pip install PyQt6` uitvoeren. Merk op dat de allerlaatste regel blokkerend is: alles wat je daaronder zet, draait pas nadat je het venster sluit. De gemaakte QPushButton heeft zijn :code:`clicked`-signal gekoppeld aan een callback die "beep" naar de console print. + +******************************* +Applicatie met Worker-thread +******************************* + +Er is een probleem met het minimale voorbeeld: er is geen goede plek voor SDR/DSP-code. De :code:`__init__` van :code:`MainWindow` is bedoeld voor GUI-configuratie en callbacks, maar daar wil je geen andere logica (zoals SDR of DSP) in stoppen. De reden: de GUI is single-threaded. Als je de GUI-thread blokkeert met langdurige code, bevriest of stottert de interface. Daarom gebruiken we een worker-thread om SDR/DSP op de achtergrond uit te voeren. + +Het onderstaande voorbeeld breidt het minimale voorbeeld uit met een worker-thread die code in de :code:`run`-functie continu laat draaien. We gebruiken bewust geen :code:`while True:`, omdat we door de interne werking van PyQt willen dat :code:`run` periodiek afrondt en opnieuw start. Daarom koppelen we het :code:`end_of_run`-signal van de worker-thread (volgende sectie) aan een callback die :code:`run` opnieuw triggert. We initialiseren de worker-thread in :code:`MainWindow`, door een :code:`QThread` te maken en onze custom worker eraan toe te wijzen. Dit lijkt misschien complex, maar het is een veelgebruikt patroon in PyQt-apps. Belangrijkste punt: GUI-code hoort in :code:`MainWindow`, SDR/DSP-code in de worker-thread (:code:`run`). + +.. code-block:: python + + from PyQt6.QtCore import QThread, pyqtSignal, QObject, QTimer + from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton + import time + + # Non-GUI operations (including SDR) need to run in a separate thread + class SDRWorker(QObject): + end_of_run = pyqtSignal() + + # Main loop + def run(self): + print("Starting run()") + time.sleep(1) + self.end_of_run.emit() # let MainWindow know we're done + + # Subclass QMainWindow to customize your application's main window + class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + + # Initialize worker and thread + self.sdr_thread = QThread() + worker = SDRWorker() + worker.moveToThread(self.sdr_thread) + + # Example GUI component + example_button = QPushButton('Push Me') + def on_button_click(): + print("beep") + example_button.clicked.connect(on_button_click) + self.setCentralWidget(example_button) + + # This is what keeps the run() function repeating nonstop + def end_of_run_callback(): + QTimer.singleShot(0, worker.run) # Run worker again immediately + worker.end_of_run.connect(end_of_run_callback) + + self.sdr_thread.started.connect(worker.run) # kicks off the first run() when the thread starts + self.sdr_thread.start() # start thread + + app = QApplication([]) + window = MainWindow() + window.show() # Windows are hidden by default + app.exec() # Start the event loop + +Probeer de code hierboven uit. Je zou elke seconde "Starting run()" in de console moeten zien en de knop moet zonder merkbare vertraging blijven werken. In de worker-thread doen we nu alleen print en sleep, maar zo voegen we straks eenvoudig SDR- en DSP-code toe. + +************************* +Signals en Slots +************************* + +In het vorige voorbeeld gebruikten we :code:`end_of_run` om tussen worker-thread en GUI-thread te communiceren. Dit is een veelvoorkomend patroon in PyQt, het "signals en slots"-mechanisme. Een signal wordt uitgezonden door een object (hier: de worker-thread) en gekoppeld aan een slot (hier: callback :code:`end_of_run_callback` in de GUI-thread). Een signal kan aan meerdere slots gekoppeld worden, en een slot aan meerdere signals. Een signal kan ook argumenten meedragen die aan het slot worden doorgegeven. Dit werkt ook andersom: de GUI-thread kan een signal naar een slot in de worker-thread sturen. Het signal/slot-mechanisme is een krachtige manier om onderdelen van een PyQt-app event-driven te laten samenwerken en komt veel terug in de code hieronder. Denk simpel: een slot is een callbackfunctie; een signal triggert die callback. + +************************* +PyQtGraph +************************* + +PyQtGraph is een library bovenop PyQt en NumPy die snelle, efficiente plotting biedt, omdat PyQt zelf te algemeen is om uitgebreide plotfunctionaliteit standaard te bevatten. De library is ontworpen voor realtime toepassingen en geoptimaliseerd voor snelheid. In veel opzichten lijkt het op Matplotlib, maar PyQtGraph is meer gericht op continue updates dan op losse statische plots. Met het eenvoudige voorbeeld hieronder kun je de prestaties van PyQtGraph vergelijken met Matplotlib door :code:`if True:` te wijzigen naar :code:`False:`. Op een Intel Core i9-10900K @ 3.70 GHz haalde PyQtGraph meer dan 1000 FPS, terwijl Matplotlib rond 40 FPS zat. Als Matplotlib jou toch voordeel geeft (bijvoorbeeld ontwikkeltijd of een specifieke feature), kun je Matplotlib-plots ook in een PyQt-app integreren, met de onderstaande code als startpunt. + +.. raw:: html + +
    + Expand for comparison code + +.. code-block:: python + + import numpy as np + import time + import matplotlib + matplotlib.use('Qt5Agg') + from PyQt6 import QtCore, QtWidgets + from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas + from matplotlib.figure import Figure + import pyqtgraph as pg # tested with pyqtgraph==0.13.7 + + n_data = 1024 + + if True: + class MplCanvas(FigureCanvas): + def __init__(self): + fig = Figure(figsize=(13, 8), dpi=100) + self.axes = fig.add_subplot(111) + super(MplCanvas, self).__init__(fig) + + + class MainWindow(QtWidgets.QMainWindow): + def __init__(self): + super(MainWindow, self).__init__() + + self.canvas = MplCanvas() + self._plot_ref = self.canvas.axes.plot(np.arange(n_data), '.-r')[0] + self.canvas.axes.set_xlim(0, n_data) + self.canvas.axes.set_ylim(-5, 5) + self.canvas.axes.grid(True) + self.setCentralWidget(self.canvas) + + # Setup a timer to trigger the redraw by calling update_plot. + self.timer = QtCore.QTimer() + self.timer.setInterval(0) # causes the timer to start immediately + self.timer.timeout.connect(self.update_plot) # causes the timer to start itself again automatically + self.timer.start() + self.start_t = time.time() # used for benchmarking + + self.show() + + def update_plot(self): + self._plot_ref.set_ydata(np.random.randn(n_data)) + self.canvas.draw() # Trigger the canvas to update and redraw. + print('FPS:', 1/(time.time()-self.start_t)) # got ~42 FPS on an i9-10900K + self.start_t = time.time() + + else: + class MainWindow(QtWidgets.QMainWindow): + def __init__(self): + super(MainWindow, self).__init__() + + self.time_plot = pg.PlotWidget() + self.time_plot.setYRange(-5, 5) + self.time_plot_curve = self.time_plot.plot([]) + self.setCentralWidget(self.time_plot) + + # Setup a timer to trigger the redraw by calling update_plot. + self.timer = QtCore.QTimer() + self.timer.setInterval(0) # causes the timer to start immediately + self.timer.timeout.connect(self.update_plot) # causes the timer to start itself again automatically + self.timer.start() + self.start_t = time.time() # used for benchmarking + + self.show() + + def update_plot(self): + self.time_plot_curve.setData(np.random.randn(n_data)) + print('FPS:', 1/(time.time()-self.start_t)) # got ~42 FPS on an i9-10900K + self.start_t = time.time() + + app = QtWidgets.QApplication([]) + w = MainWindow() + app.exec() + +.. raw:: html + +
    + +Qua gebruik van PyQtGraph importeren we het met :code:`import pyqtgraph as pg` en maken daarna een Qt-widget voor een 1D-plot, zoals hieronder (deze code hoort in :code:`MainWindow.__init__`): + +.. code-block:: python + + # Example PyQtGraph plot + time_plot = pg.PlotWidget(labels={'left': 'Amplitude', 'bottom': 'Time'}) + time_plot_curve = time_plot.plot(np.arange(1000), np.random.randn(1000)) # x and y + time_plot.setYRange(-5, 5) + + self.setCentralWidget(time_plot) + +.. image:: ../_images/pyqtgraph_example.png + :scale: 80 % + :align: center + :alt: PyQtGraph-voorbeeld + +Je ziet dat een plot opzetten relatief eenvoudig is en dat het resultaat gewoon een extra widget in je GUI is. Naast 1D-plots heeft PyQtGraph ook een equivalent van Matplotlib's :code:`imshow()` voor 2D-weergave met colormap, wat we gebruiken voor onze realtime spectrogram/waterfall. Een groot voordeel is dat de plots gewone Qt-widgets zijn, zodat je met pure PyQt extra elementen kunt toevoegen (bijvoorbeeld een rechthoek op een bepaalde locatie). Dat komt doordat PyQtGraph gebruikmaakt van PyQt's :code:`QGraphicsScene`, een oppervlak voor veel 2D-objecten. Je kunt dus zonder probleem lijnen, rechthoeken, tekst, ellipsen, polygonen en bitmaps toevoegen met standaard PyQt. + +******* +Layouts +******* + +In de voorbeelden hierboven gebruikten we :code:`self.setCentralWidget()` om de hoofdwidget van het venster te zetten. Dat is eenvoudig, maar beperkt voor complexere layouts. Daarvoor gebruik je layouts om widgets te rangschikken. Er zijn meerdere types, waaronder :code:`QHBoxLayout`, :code:`QVBoxLayout`, :code:`QGridLayout` en :code:`QFormLayout`. :code:`QHBoxLayout` en :code:`QVBoxLayout` plaatsen widgets respectievelijk horizontaal en verticaal. :code:`QGridLayout` plaatst widgets in een raster, en :code:`QFormLayout` in twee kolommen met labels links en invoerwidgets rechts. + +Om een nieuwe layout te maken en widgets toe te voegen, probeer het volgende in :code:`MainWindow.__init__`: + +.. code-block:: python + + layout = QHBoxLayout() + layout.addWidget(QPushButton("Left-Most")) + layout.addWidget(QPushButton("Center"), 1) + layout.addWidget(QPushButton("Right-Most"), 2) + self.setLayout(layout) + +In dit voorbeeld stapelen we widgets horizontaal. Door :code:`QHBoxLayout` te vervangen door :code:`QVBoxLayout` stapel je ze verticaal. De functie :code:`addWidget` voegt widgets toe aan de layout, en het optionele tweede argument is een stretchfactor die bepaalt hoeveel ruimte de widget relatief inneemt. + +:code:`QGridLayout` heeft extra parameters omdat je rij en kolom expliciet opgeeft. Je kunt optioneel ook aangeven over hoeveel rijen en kolommen een widget moet lopen (standaard 1 en 1). Voorbeeld: + +.. code-block:: python + + layout = QGridLayout() + layout.addWidget(QPushButton("Button at (0, 0)"), 0, 0) + layout.addWidget(QPushButton("Button at (0, 1)"), 0, 1) + layout.addWidget(QPushButton("Button at (0, 2)"), 0, 2) + layout.addWidget(QPushButton("Button at (1, 0)"), 1, 0) + layout.addWidget(QPushButton("Button at (1, 1)"), 1, 1) + layout.addWidget(QPushButton("Button at (1, 2)"), 1, 2) + layout.addWidget(QPushButton("Button at (2, 0) spanning 2 columns"), 2, 0, 1, 2) + self.setLayout(layout) + +.. image:: ../_images/qt_layouts.svg + :align: center + :target: ../_images/qt_layouts.svg + :alt: Qt-layouts met voorbeelden van QHBoxLayout, QVBoxLayout en QGridLayout + +Voor onze spectrum analyzer gebruiken we :code:`QGridLayout` als hoofdlayout, maar voegen we ook :code:`QHBoxLayout` toe om widgets horizontaal te stapelen binnen een cel van het grid. Layouts kun je eenvoudig nesten door een nieuwe layout te maken en die aan de bovenliggende layout toe te voegen, bijvoorbeeld: + +.. code-block:: python + + layout = QGridLayout() + self.setLayout(layout) + inner_layout = QHBoxLayout() + layout.addLayout(inner_layout) + +******************* +:code:`QPushButton` +******************* + +De eerste widget die we behandelen is :code:`QPushButton`, een eenvoudige klikbare knop. We zagen al hoe je een :code:`QPushButton` maakt en het :code:`clicked`-signal aan een callback koppelt. :code:`QPushButton` heeft ook andere signals, zoals :code:`pressed`, :code:`released` en :code:`toggled`. Het :code:`toggled`-signal komt vrij wanneer een knop wordt in- of uitgeschakeld en is handig voor toggle-knoppen. Verder zijn er properties zoals :code:`text`, :code:`icon` en :code:`checkable`. Er is ook een :code:`click()`-methode om een klik te simuleren. In onze SDR spectrum analyzer gebruiken we knoppen om auto-range voor plots te triggeren op basis van actuele data. Omdat we :code:`QPushButton` al gebruikt hebben, gaan we hier niet dieper in op details; zie de `QPushButton-documentatie `_. + +*************** +:code:`QSlider` +*************** + +De :code:`QSlider` is een widget waarmee de gebruiker een waarde uit een bereik kiest. Belangrijke properties zijn :code:`minimum`, :code:`maximum`, :code:`value` en :code:`orientation`. Belangrijke signals zijn :code:`valueChanged`, :code:`sliderPressed` en :code:`sliderReleased`. Met :code:`setValue()` zet je de sliderwaarde, wat we vaak gebruiken. De documentatie staat `hier voor QSlider `_. + +In onze spectrum analyzer gebruiken we :code:`QSlider`-widgets om centerfrequentie en gain van de SDR aan te passen. Hieronder staat de snippet uit de uiteindelijke app voor de gain-slider: + +.. code-block:: python + + # Gain slider with label + gain_slider = QSlider(Qt.Orientation.Horizontal) + gain_slider.setRange(0, 73) # min and max, inclusive. interval is always 1 + gain_slider.setValue(50) # initial value + gain_slider.setTickPosition(QSlider.TickPosition.TicksBelow) + gain_slider.setTickInterval(2) # for visual purposes only + gain_slider.sliderMoved.connect(worker.update_gain) + gain_label = QLabel() + def update_gain_label(val): + gain_label.setText("Gain: " + str(val)) + gain_slider.sliderMoved.connect(update_gain_label) + update_gain_label(gain_slider.value()) # initialize the label + layout.addWidget(gain_slider, 5, 0) + layout.addWidget(gain_label, 5, 1) + +Een belangrijk punt bij :code:`QSlider`: deze werkt met gehele getallen. Met bereik 0 tot 73 kan de slider dus alleen integers tussen die waarden kiezen (inclusief begin en eind). :code:`setTickInterval(2)` is alleen visueel. Daarom gebruiken we kHz als eenheid voor de frequentieslider, zodat we tot 1 kHz resolutie hebben. + +Halverwege de code zie je dat we een :code:`QLabel` maken, een tekstlabel voor weergave. Om daar de actuele sliderwaarde in te tonen, maken we een slot (callbackfunctie) die het label bijwerkt. Die callback koppelen we aan :code:`sliderMoved`, dat automatisch wordt uitgezonden bij het bewegen van de slider. We roepen de callback ook eenmalig aan om het label met de beginwaarde te initialiseren (50 in ons geval). Daarnaast koppelen we :code:`sliderMoved` aan een slot in de worker-thread die de SDR-gain aanpast (SDR-beheer en DSP willen we niet in de hoofd-GUI-thread doen). Die slot-callback bespreken we later. + +***************** +:code:`QComboBox` +***************** + +De :code:`QComboBox` is een dropdown-widget waarmee de gebruiker een item uit een lijst kiest. Belangrijke properties zijn :code:`currentText`, :code:`currentIndex` en :code:`count`. Belangrijke signals zijn :code:`currentTextChanged`, :code:`currentIndexChanged` en :code:`activated`. Daarnaast heeft :code:`QComboBox` methodes zoals :code:`addItem()` om items toe te voegen en :code:`insertItem()` om op een specifieke index in te voegen; die laatste gebruiken we in dit voorbeeld niet. De documentatie staat `hier voor QComboBox `_. + +In onze spectrum analyzer gebruiken we :code:`QComboBox` om de sample rate uit een vooraf gedefinieerde lijst te kiezen. Aan het begin van de code zetten we bijvoorbeeld :code:`sample_rates = [56, 40, 20, 10, 5, 2, 1, 0.5]`. Binnen :code:`MainWindow.__init__` maken we de :code:`QComboBox` als volgt: + +.. code-block:: python + + # Sample rate dropdown using QComboBox + sample_rate_combobox = QComboBox() + sample_rate_combobox.addItems([str(x) + ' MHz' for x in sample_rates]) + sample_rate_combobox.setCurrentIndex(0) # must give it the index, not string + sample_rate_combobox.currentIndexChanged.connect(worker.update_sample_rate) + sample_rate_label = QLabel() + def update_sample_rate_label(val): + sample_rate_label.setText("Sample Rate: " + str(sample_rates[val]) + " MHz") + sample_rate_combobox.currentIndexChanged.connect(update_sample_rate_label) + update_sample_rate_label(sample_rate_combobox.currentIndex()) # initialize the label + layout.addWidget(sample_rate_combobox, 6, 0) + layout.addWidget(sample_rate_label, 6, 1) + +Het belangrijkste verschil met de slider is :code:`addItems()` (je geeft een lijst strings als opties mee) en :code:`setCurrentIndex()` (je zet de startwaarde via index). + +**************** +Lambdafuncties +**************** + +Herinner je de code van hierboven waar we dit deden: + +.. code-block:: python + + def update_sample_rate_label(val): + sample_rate_label.setText("Sample Rate: " + str(sample_rates[val]) + " MHz") + sample_rate_combobox.currentIndexChanged.connect(update_sample_rate_label) + +We maken hier een functie met slechts een regel code en geven die functie (functies zijn ook objecten) door aan :code:`connect()`. Om dit patroon te vereenvoudigen, schrijven we het eerst om in basis-Python: + +.. code-block:: python + + def my_function(x): + print(x) + y.call_that_takes_in_function_obj(my_function) + +In deze situatie heeft de functie maar een regel code en gebruiken we die functie maar eenmaal, bij het zetten van de :code:`connect`-callback. In zulke gevallen kun je een lambdafunctie gebruiken, een manier om een functie in een regel te definieren. De code hierboven herschreven met lambda: + +.. code-block:: python + + y.call_that_takes_in_function_obj(lambda x: print(x)) + +Als je nog niet eerder lambdafuncties hebt gebruikt, kan dit vreemd overkomen. Je bent niet verplicht ze te gebruiken, maar ze besparen vaak enkele regels en maken code compacter. Werking: de tijdelijke argumentnaam staat na "lambda", en alles na de dubbele punt is de code die op dat argument werkt. Dit ondersteunt ook meerdere argumenten met komma's, of zelfs geen argumenten met :code:`lambda : `. Als oefening kun je :code:`update_sample_rate_label` hierboven herschrijven met een lambdafunctie. + +************************ +PlotWidget van PyQtGraph +************************ + +PyQtGraph's :code:`PlotWidget` is een PyQt-widget voor 1D-plots, vergelijkbaar met Matplotlib's :code:`plt.plot(x,y)`. Wij gebruiken deze voor tijd- en frequentieplots (PSD), al werkt hij ook goed voor IQ-plots (die onze analyzer niet bevat). Voor wie dieper wil: PlotWidget is een subclass van PyQt's `QGraphicsView `_, een widget om de inhoud van een `QGraphicsScene `_ te tonen. Die scene is een oppervlak voor veel 2D-grafische items in Qt. Belangrijk voor gebruik: PlotWidget is in de kern gewoon een widget met een enkel `PlotItem `_. Vanuit documentatieperspectief kun je daarom vaak direct naar de PlotItem-documentatie gaan: ``_. Een PlotItem bevat een ViewBox voor de data plus AxisItems en labels voor assen en titel. + +Het eenvoudigste voorbeeld van PlotWidget-gebruik is als volgt (plaats dit in :code:`MainWindow.__init__`): + +.. code-block:: python + + import pyqtgraph as pg + plotWidget = pg.plot(title="My Title") + plotWidget.plot(x, y) + +waar x en y doorgaans NumPy-arrays zijn, net als bij Matplotlib's :code:`plt.plot()`. Dit is echter een statische plot waarin de data niet verandert. Voor onze spectrum analyzer willen we data in de worker-thread updaten, dus bij initialisatie van de plot hoeven we nog geen data mee te geven; alleen opzetten is genoeg. Zo initialiseren we de tijd-domeinplot: + +.. code-block:: python + + # Time plot + time_plot = pg.PlotWidget(labels={'left': 'Amplitude', 'bottom': 'Time [microseconds]'}) + time_plot.setMouseEnabled(x=False, y=True) + time_plot.setYRange(-1.1, 1.1) + time_plot_curve_i = time_plot.plot([]) + time_plot_curve_q = time_plot.plot([]) + layout.addWidget(time_plot, 1, 0) + +Je ziet dat we twee curves maken: een voor I en een voor Q. De rest spreekt grotendeels voor zich. Om de plot te kunnen updaten, maken we een slot (callbackfunctie) in :code:`MainWindow.__init__`: + +.. code-block:: python + + def time_plot_callback(samples): + time_plot_curve_i.setData(samples.real) + time_plot_curve_q.setData(samples.imag) + +Dit slot koppelen we aan het signal van de worker-thread dat wordt uitgezonden wanneer nieuwe samples beschikbaar zijn, zoals later te zien is. + +Het laatste dat we in :code:`MainWindow.__init__` doen is rechts naast de plot een paar knoppen toevoegen die auto-range triggeren. De ene gebruikt de huidige min/max, de andere zet het bereik op -1.1 tot 1.1 (de ADC-limieten van veel SDR's plus 10% marge). We maken hiervoor een geneste layout, specifiek QVBoxLayout, om de twee knoppen verticaal te stapelen. De code: + +.. code-block:: python + + # Time plot auto range buttons + time_plot_auto_range_layout = QVBoxLayout() + layout.addLayout(time_plot_auto_range_layout, 1, 1) + auto_range_button = QPushButton('Auto Range') + auto_range_button.clicked.connect(lambda : time_plot.autoRange()) # lambda just means its an unnamed function + time_plot_auto_range_layout.addWidget(auto_range_button) + auto_range_button2 = QPushButton('-1 to +1\n(ADC limits)') + auto_range_button2.clicked.connect(lambda : time_plot.setYRange(-1.1, 1.1)) + time_plot_auto_range_layout.addWidget(auto_range_button2) + +En zo ziet het er uiteindelijk uit: + +.. image:: ../_images/pyqt_time_plot.png + :scale: 50 % + :align: center + :alt: PyQtGraph tijdplot + +Voor de frequentiedomeinplot (PSD) gebruiken we een vergelijkbaar patroon. + +*********************** +ImageItem van PyQtGraph +*********************** + +Een spectrum analyzer is niet compleet zonder waterfall (realtime spectrogram), en daarvoor gebruiken we PyQtGraph's ImageItem, dat beelden met 1, 3 of 4 "kanalen" rendert. Een kanaal betekent dat je een 2D-array met floats of ints aanbiedt; vervolgens wordt via een lookup table (LUT) een colormap toegepast om het beeld te maken. Je kunt ook RGB (3 kanalen) of RGBA (4 kanalen) aanleveren. Wij berekenen ons spectrogram als 2D NumPy-array met floats en geven die direct aan ImageItem. We kiezen een colormap en gebruiken ook de ingebouwde LUT-weergave die de waardeverdeling van de data en de kleurtoewijzing laat zien. + +De initialisatie van de waterfall-plot is vrij eenvoudig: we gebruiken een PlotWidget als container (zodat x- en y-as zichtbaar blijven) en voegen daar een ImageItem aan toe: + +.. code-block:: python + + # Waterfall plot + waterfall = pg.PlotWidget(labels={'left': 'Time [s]', 'bottom': 'Frequency [MHz]'}) + imageitem = pg.ImageItem(axisOrder='col-major') # this arg is purely for performance + waterfall.addItem(imageitem) + waterfall.setMouseEnabled(x=False, y=False) + waterfall_layout.addWidget(waterfall) + +Het slot/de callback voor het updaten van de waterfall-data, eveneens in :code:`MainWindow.__init__`, is: + +.. code-block:: python + + def waterfall_plot_callback(spectrogram): + imageitem.setImage(spectrogram, autoLevels=False) + sigma = np.std(spectrogram) + mean = np.mean(spectrogram) + self.spectrogram_min = mean - 2*sigma # save to window state + self.spectrogram_max = mean + 2*sigma + +Hierbij is spectrogram een 2D NumPy-array met floats. Naast het zetten van de beelddata berekenen we een min en max voor de colormap op basis van gemiddelde en variantie van de data, die we later gebruiken. Het laatste GUI-deel voor het spectrogram is de colorbar, die ook de gebruikte colormap bepaalt: + +.. code-block:: python + + # Colorbar for waterfall + colorbar = pg.HistogramLUTWidget() + colorbar.setImageItem(imageitem) # connects the bar to the waterfall imageitem + colorbar.item.gradient.loadPreset('viridis') # set the color map, also sets the imageitem + imageitem.setLevels((-30, 20)) # needs to come after colorbar is created for some reason + waterfall_layout.addWidget(colorbar) + +De tweede regel is belangrijk: die koppelt de colorbar daadwerkelijk aan het ImageItem. Hier kiezen we ook de colormap en de startniveaus (-30 dB tot +20 dB in ons geval). In de worker-thread-code zie je hoe de 2D spectrogramarray wordt berekend/opgeslagen. Hieronder staat een screenshot van dit GUI-deel; let op de sterke ingebouwde functionaliteit van colorbar en LUT-weergave. De zijwaartse klokvormige curve is de verdeling van spectrogramwaarden, wat erg nuttig is. + +.. image:: ../_images/pyqt_spectrogram.png + :scale: 50 % + :align: center + :alt: PyQtGraph-spectrogram en colorbar + +*********************** +Worker-thread +*********************** + +Aan het begin van dit hoofdstuk zagen we hoe je een aparte thread maakt met een class genaamd SDRWorker en een run()-functie. Daar zetten we alle SDR- en DSP-code in, behalve de SDR-initialisatie die we voorlopig globaal doen. De worker-thread werkt ook de drie plots bij door signals uit te zenden zodra nieuwe samples beschikbaar zijn. Die triggeren callbacks in :code:`MainWindow` die de plots daadwerkelijk verversen. De SDRWorker-class is op te delen in drie onderdelen: + +#. :code:`init()` - initialiseert status, bijvoorbeeld de 2D spectrogramarray +#. PyQt Signals - hier definieren we custom signals die we uitzenden +#. PyQt Slots - callbacks die reageren op GUI-events, zoals een bewegende slider +#. :code:`run()` - de hoofdloop die continu draait + +*********************** +PyQt-signals +*********************** + +In de GUI-code hoefden we geen eigen signals te definieren, omdat die al in widgets ingebouwd zijn, zoals :code:`QSlider.valueChanged`. Onze SDRWorker-class is custom, dus de signals die we willen uitzenden moeten we zelf definieren voordat :code:`run()` wordt gebruikt. Hieronder de vier gebruikte signals met hun datatypen: + +.. code-block:: python + + # PyQt Signals + time_plot_update = pyqtSignal(np.ndarray) + freq_plot_update = pyqtSignal(np.ndarray) + waterfall_plot_update = pyqtSignal(np.ndarray) + end_of_run = pyqtSignal() # happens many times a second + +De eerste drie signals sturen een enkel object mee (een NumPy-array). Het laatste signal stuurt geen object mee. Je kunt ook meerdere objecten tegelijk sturen door datatypen met komma's te scheiden, maar dat is hier niet nodig. Binnen :code:`run()` kun je op elke plek een signal naar de GUI-thread uitsturen met een regel code, bijvoorbeeld: + +.. code-block:: python + + self.time_plot_update.emit(samples) + +Er is nog een laatste stap voor alle signal/slot-koppelingen: in de GUI-code (helemaal aan het eind van :code:`MainWindow.__init__`) moeten we de signals van de worker-thread verbinden met slots in de GUI, bijvoorbeeld: + +.. code-block:: python + + worker.time_plot_update.connect(time_plot_callback) # connect the signal to the callback + +Onthoud dat :code:`worker` de instantie is van SDRWorker die we in de GUI-code hebben gemaakt. We koppelen hierboven dus het worker-signal :code:`time_plot_update` aan het GUI-slot :code:`time_plot_callback` dat eerder is gedefinieerd. Dit is een goed moment om de snippets terug te bekijken en te zien hoe alles samenwerkt, zodat duidelijk is hoe GUI-thread en worker-thread communiceren; dat is cruciaal in PyQt-programmering. + +************************* +Slots in de Worker-thread +************************* + +De slots van de worker-thread zijn callbacks die door GUI-events worden getriggerd, zoals het bewegen van de gain-slider. Ze zijn vrij rechttoe rechtaan; dit slot zet bijvoorbeeld de SDR-gain op de nieuwe sliderwaarde: + +.. code-block:: python + + def update_gain(self, val): + print("Updated gain to:", val, 'dB') + sdr.set_rx_gain(val) + +************************** +Run() van de Worker-thread +************************** + +In de :code:`run()`-functie gebeurt het eigenlijke DSP-werk. In onze applicatie start elke run met het ophalen van samples uit de SDR (of met simulatie als je geen SDR hebt). + +.. code-block:: python + + # Main loop + def run(self): + if sdr_type == "pluto": + samples = sdr.rx()/2**11 # Receive samples + elif sdr_type == "usrp": + streamer.recv(recv_buffer, metadata) + samples = recv_buffer[0] # will be np.complex64 + elif sdr_type == "sim": + tone = np.exp(2j*np.pi*self.sample_rate*0.1*np.arange(fft_size)/self.sample_rate) + noise = np.random.randn(fft_size) + 1j*np.random.randn(fft_size) + samples = self.gain*tone*0.02 + 0.1*noise + # Truncate to -1 to +1 to simulate ADC bit limits + np.clip(samples.real, -1, 1, out=samples.real) + np.clip(samples.imag, -1, 1, out=samples.imag) + + ... + +Zoals je ziet genereren we in de simulatie een toon met wat witte ruis en begrenzen we samples daarna op -1 tot +1. + +Nu het DSP-deel: we hebben een FFT nodig voor zowel frequentieplot als spectrogram. De PSD van deze sample-set kan direct dienen als een rij in het spectrogram. We schuiven dus de waterfall een rij op en vullen de nieuwe rij onderaan (of bovenaan) in. Voor elke plotupdate sturen we een signal met de bijgewerkte data. Daarna signaleren we het einde van :code:`run()`, zodat de GUI-thread meteen een nieuwe :code:`run()` start. Al met al is het weinig code: + +.. code-block:: python + + ... + + self.time_plot_update.emit(samples[0:time_plot_samples]) + + PSD = 10.0*np.log10(np.abs(np.fft.fftshift(np.fft.fft(samples)))**2/fft_size) + self.PSD_avg = self.PSD_avg * 0.99 + PSD * 0.01 + self.freq_plot_update.emit(self.PSD_avg) + + self.spectrogram[:] = np.roll(self.spectrogram, 1, axis=1) # shifts waterfall 1 row + self.spectrogram[:,0] = PSD # fill last row with new fft results + self.waterfall_plot_update.emit(self.spectrogram) + + self.end_of_run.emit() # emit the signal to keep the loop going + # end of run() + +Let op dat we niet de hele samplebatch naar de tijdplot sturen; dat zijn te veel punten. In plaats daarvan sturen we alleen de eerste 500 samples (instelbaar bovenin het script, hier niet getoond). Voor de PSD-plot gebruiken we een running average door de vorige PSD op te slaan en daar 1% van de nieuwe PSD aan toe te voegen. Dat is een eenvoudige manier om de PSD-plot te egaliseren. De volgorde van :code:`emit()`-aanroepen maakt daarbij niet uit; ze hadden ook allemaal aan het einde van :code:`run()` kunnen staan. + +**************************** +Volledige Eindvoorbeeldcode +**************************** + +Tot nu toe bekeken we losse snippets van de spectrum analyzer-app, maar nu kijken we naar de volledige code en proberen we die te draaien. De code ondersteunt momenteel PlutoSDR, USRP en simulatiemodus. Heb je geen Pluto of USRP, laat de code dan zoals die is; dan gebruikt hij simulatiemodus. Anders wijzig je :code:`sdr_type`. In simulatiemodus zie je bij maximale gain dat het signaal in het tijddomein wordt afgeknipt, wat spurs in het frequentiedomein veroorzaakt. + +Gebruik deze code gerust als startpunt voor je eigen realtime SDR-app. Hieronder staat ook een animatie van de app in actie: met een Pluto eerst op de 750 MHz cellulaire band en daarna op 2,4 GHz WiFi. Een hogere kwaliteit versie staat op YouTube `hier `_. + +.. image:: ../_images/pyqt_animation.gif + :scale: 100 % + :align: center + :alt: Geanimeerde gif van de PyQt spectrum analyzer-app in actie + +Bekende bugs (om te helpen oplossen kun je `dit bewerken `_): + +#. De x-as van de waterfall wordt niet bijgewerkt bij wijzigen van centerfrequentie (de PSD-plot wel) + +Volledige code: + +.. code-block:: python + + from PyQt6.QtCore import QSize, Qt, QThread, pyqtSignal, QObject, QTimer + from PyQt6.QtWidgets import QApplication, QMainWindow, QGridLayout, QWidget, QSlider, QLabel, QHBoxLayout, QVBoxLayout, QPushButton, QComboBox # tested with PyQt6==6.7.0 + import pyqtgraph as pg # tested with pyqtgraph==0.13.7 + import numpy as np + import time + import signal # lets control-C actually close the app + + # Defaults + fft_size = 4096 # determines buffer size + num_rows = 200 + center_freq = 750e6 + sample_rates = [56, 40, 20, 10, 5, 2, 1, 0.5] # MHz + sample_rate = sample_rates[0] * 1e6 + time_plot_samples = 500 + gain = 50 # 0 to 73 dB. int + + sdr_type = "sim" # or "usrp" or "pluto" + + # Init SDR + if sdr_type == "pluto": + import adi + sdr = adi.Pluto("ip:192.168.1.10") + sdr.rx_lo = int(center_freq) + sdr.sample_rate = int(sample_rate) + sdr.rx_rf_bandwidth = int(sample_rate*0.8) # antialiasing filter bandwidth + sdr.rx_buffer_size = int(fft_size) + sdr.gain_control_mode_chan0 = 'manual' + sdr.rx_hardwaregain_chan0 = gain # dB + elif sdr_type == "usrp": + import uhd + #usrp = uhd.usrp.MultiUSRP(args="addr=192.168.1.10") + usrp = uhd.usrp.MultiUSRP(args="addr=192.168.1.201") + usrp.set_rx_rate(sample_rate, 0) + usrp.set_rx_freq(uhd.libpyuhd.types.tune_request(center_freq), 0) + usrp.set_rx_gain(gain, 0) + + # Set up the stream and receive buffer + st_args = uhd.usrp.StreamArgs("fc32", "sc16") + st_args.channels = [0] + metadata = uhd.types.RXMetadata() + streamer = usrp.get_rx_stream(st_args) + recv_buffer = np.zeros((1, fft_size), dtype=np.complex64) + + # Start Stream + stream_cmd = uhd.types.StreamCMD(uhd.types.StreamMode.start_cont) + stream_cmd.stream_now = True + streamer.issue_stream_cmd(stream_cmd) + + def flush_buffer(): + for _ in range(10): + streamer.recv(recv_buffer, metadata) + + class SDRWorker(QObject): + def __init__(self): + super().__init__() + self.gain = gain + self.sample_rate = sample_rate + self.freq = 0 # in kHz, to deal with QSlider being ints and with a max of 2 billion + self.spectrogram = -50*np.ones((fft_size, num_rows)) + self.PSD_avg = -50*np.ones(fft_size) + + # PyQt Signals + time_plot_update = pyqtSignal(np.ndarray) + freq_plot_update = pyqtSignal(np.ndarray) + waterfall_plot_update = pyqtSignal(np.ndarray) + end_of_run = pyqtSignal() # happens many times a second + + # PyQt Slots + def update_freq(self, val): # TODO: WE COULD JUST MODIFY THE SDR IN THE GUI THREAD + print("Updated freq to:", val, 'kHz') + if sdr_type == "pluto": + sdr.rx_lo = int(val*1e3) + elif sdr_type == "usrp": + usrp.set_rx_freq(uhd.libpyuhd.types.tune_request(val*1e3), 0) + flush_buffer() + + def update_gain(self, val): + print("Updated gain to:", val, 'dB') + self.gain = val + if sdr_type == "pluto": + sdr.rx_hardwaregain_chan0 = val + elif sdr_type == "usrp": + usrp.set_rx_gain(val, 0) + flush_buffer() + + def update_sample_rate(self, val): + print("Updated sample rate to:", sample_rates[val], 'MHz') + if sdr_type == "pluto": + sdr.sample_rate = int(sample_rates[val] * 1e6) + sdr.rx_rf_bandwidth = int(sample_rates[val] * 1e6 * 0.8) + elif sdr_type == "usrp": + usrp.set_rx_rate(sample_rates[val] * 1e6, 0) + flush_buffer() + + # Main loop + def run(self): + start_t = time.time() + + if sdr_type == "pluto": + samples = sdr.rx()/2**11 # Receive samples + elif sdr_type == "usrp": + streamer.recv(recv_buffer, metadata) + samples = recv_buffer[0] # will be np.complex64 + elif sdr_type == "sim": + tone = np.exp(2j*np.pi*self.sample_rate*0.1*np.arange(fft_size)/self.sample_rate) + noise = np.random.randn(fft_size) + 1j*np.random.randn(fft_size) + samples = self.gain*tone*0.02 + 0.1*noise + # Truncate to -1 to +1 to simulate ADC bit limits + np.clip(samples.real, -1, 1, out=samples.real) + np.clip(samples.imag, -1, 1, out=samples.imag) + + self.time_plot_update.emit(samples[0:time_plot_samples]) + + PSD = 10.0*np.log10(np.abs(np.fft.fftshift(np.fft.fft(samples)))**2/fft_size) + self.PSD_avg = self.PSD_avg * 0.99 + PSD * 0.01 + self.freq_plot_update.emit(self.PSD_avg) + + self.spectrogram[:] = np.roll(self.spectrogram, 1, axis=1) # shifts waterfall 1 row + self.spectrogram[:,0] = PSD # fill last row with new fft results + self.waterfall_plot_update.emit(self.spectrogram) + + print("Frames per second:", 1/(time.time() - start_t)) + self.end_of_run.emit() # emit the signal to keep the loop going + + + # Subclass QMainWindow to customize your application's main window + class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + + self.setWindowTitle("The PySDR Spectrum Analyzer") + self.setFixedSize(QSize(1500, 1000)) # window size, starting size should fit on 1920 x 1080 + + self.spectrogram_min = 0 + self.spectrogram_max = 0 + + layout = QGridLayout() # overall layout + + # Initialize worker and thread + self.sdr_thread = QThread() + self.sdr_thread.setObjectName('SDR_Thread') # so we can see it in htop, note you have to hit F2 -> Display options -> Show custom thread names + worker = SDRWorker() + worker.moveToThread(self.sdr_thread) + + # Time plot + time_plot = pg.PlotWidget(labels={'left': 'Amplitude', 'bottom': 'Time [microseconds]'}) + time_plot.setMouseEnabled(x=False, y=True) + time_plot.setYRange(-1.1, 1.1) + time_plot_curve_i = time_plot.plot([]) + time_plot_curve_q = time_plot.plot([]) + layout.addWidget(time_plot, 1, 0) + + # Time plot auto range buttons + time_plot_auto_range_layout = QVBoxLayout() + layout.addLayout(time_plot_auto_range_layout, 1, 1) + auto_range_button = QPushButton('Auto Range') + auto_range_button.clicked.connect(lambda : time_plot.autoRange()) # lambda just means its an unnamed function + time_plot_auto_range_layout.addWidget(auto_range_button) + auto_range_button2 = QPushButton('-1 to +1\n(ADC limits)') + auto_range_button2.clicked.connect(lambda : time_plot.setYRange(-1.1, 1.1)) + time_plot_auto_range_layout.addWidget(auto_range_button2) + + # Freq plot + freq_plot = pg.PlotWidget(labels={'left': 'PSD', 'bottom': 'Frequency [MHz]'}) + freq_plot.setMouseEnabled(x=False, y=True) + freq_plot_curve = freq_plot.plot([]) + freq_plot.setXRange(center_freq/1e6 - sample_rate/2e6, center_freq/1e6 + sample_rate/2e6) + freq_plot.setYRange(-30, 20) + layout.addWidget(freq_plot, 2, 0) + + # Freq auto range button + auto_range_button = QPushButton('Auto Range') + auto_range_button.clicked.connect(lambda : freq_plot.autoRange()) # lambda just means its an unnamed function + layout.addWidget(auto_range_button, 2, 1) + + # Layout container for waterfall related stuff + waterfall_layout = QHBoxLayout() + layout.addLayout(waterfall_layout, 3, 0) + + # Waterfall plot + waterfall = pg.PlotWidget(labels={'left': 'Time [s]', 'bottom': 'Frequency [MHz]'}) + imageitem = pg.ImageItem(axisOrder='col-major') # this arg is purely for performance + waterfall.addItem(imageitem) + waterfall.setMouseEnabled(x=False, y=False) + waterfall_layout.addWidget(waterfall) + + # Colorbar for waterfall + colorbar = pg.HistogramLUTWidget() + colorbar.setImageItem(imageitem) # connects the bar to the waterfall imageitem + colorbar.item.gradient.loadPreset('viridis') # set the color map, also sets the imageitem + imageitem.setLevels((-30, 20)) # needs to come after colorbar is created for some reason + waterfall_layout.addWidget(colorbar) + + # Waterfall auto range button + auto_range_button = QPushButton('Auto Range\n(-2σ to +2σ)') + def update_colormap(): + imageitem.setLevels((self.spectrogram_min, self.spectrogram_max)) + colorbar.setLevels(self.spectrogram_min, self.spectrogram_max) + auto_range_button.clicked.connect(update_colormap) + layout.addWidget(auto_range_button, 3, 1) + + # Freq slider with label, all units in kHz + freq_slider = QSlider(Qt.Orientation.Horizontal) + freq_slider.setRange(0, int(6e6)) + freq_slider.setValue(int(center_freq/1e3)) + freq_slider.setTickPosition(QSlider.TickPosition.TicksBelow) + freq_slider.setTickInterval(int(1e6)) + freq_slider.sliderMoved.connect(worker.update_freq) # there's also a valueChanged option + freq_label = QLabel() + def update_freq_label(val): + freq_label.setText("Frequency [MHz]: " + str(val/1e3)) + freq_plot.autoRange() + freq_slider.sliderMoved.connect(update_freq_label) + update_freq_label(freq_slider.value()) # initialize the label + layout.addWidget(freq_slider, 4, 0) + layout.addWidget(freq_label, 4, 1) + + # Gain slider with label + gain_slider = QSlider(Qt.Orientation.Horizontal) + gain_slider.setRange(0, 73) + gain_slider.setValue(gain) + gain_slider.setTickPosition(QSlider.TickPosition.TicksBelow) + gain_slider.setTickInterval(2) + gain_slider.sliderMoved.connect(worker.update_gain) + gain_label = QLabel() + def update_gain_label(val): + gain_label.setText("Gain: " + str(val)) + gain_slider.sliderMoved.connect(update_gain_label) + update_gain_label(gain_slider.value()) # initialize the label + layout.addWidget(gain_slider, 5, 0) + layout.addWidget(gain_label, 5, 1) + + # Sample rate dropdown using QComboBox + sample_rate_combobox = QComboBox() + sample_rate_combobox.addItems([str(x) + ' MHz' for x in sample_rates]) + sample_rate_combobox.setCurrentIndex(0) # should match the default at the top + sample_rate_combobox.currentIndexChanged.connect(worker.update_sample_rate) + sample_rate_label = QLabel() + def update_sample_rate_label(val): + sample_rate_label.setText("Sample Rate: " + str(sample_rates[val]) + " MHz") + sample_rate_combobox.currentIndexChanged.connect(update_sample_rate_label) + update_sample_rate_label(sample_rate_combobox.currentIndex()) # initialize the label + layout.addWidget(sample_rate_combobox, 6, 0) + layout.addWidget(sample_rate_label, 6, 1) + + central_widget = QWidget() + central_widget.setLayout(layout) + self.setCentralWidget(central_widget) + + # Signals and slots stuff + def time_plot_callback(samples): + time_plot_curve_i.setData(samples.real) + time_plot_curve_q.setData(samples.imag) + + def freq_plot_callback(PSD_avg): + # TODO figure out if there's a way to just change the visual ticks instead of the actual x vals + f = np.linspace(freq_slider.value()*1e3 - worker.sample_rate/2.0, freq_slider.value()*1e3 + worker.sample_rate/2.0, fft_size) / 1e6 + freq_plot_curve.setData(f, PSD_avg) + freq_plot.setXRange(freq_slider.value()*1e3/1e6 - worker.sample_rate/2e6, freq_slider.value()*1e3/1e6 + worker.sample_rate/2e6) + + def waterfall_plot_callback(spectrogram): + imageitem.setImage(spectrogram, autoLevels=False) + sigma = np.std(spectrogram) + mean = np.mean(spectrogram) + self.spectrogram_min = mean - 2*sigma # save to window state + self.spectrogram_max = mean + 2*sigma + + def end_of_run_callback(): + QTimer.singleShot(0, worker.run) # Run worker again immediately + + worker.time_plot_update.connect(time_plot_callback) # connect the signal to the callback + worker.freq_plot_update.connect(freq_plot_callback) + worker.waterfall_plot_update.connect(waterfall_plot_callback) + worker.end_of_run.connect(end_of_run_callback) + + self.sdr_thread.started.connect(worker.run) # kicks off the worker when the thread starts + self.sdr_thread.start() + + + app = QApplication([]) + window = MainWindow() + window.show() # Windows are hidden by default + signal.signal(signal.SIGINT, signal.SIG_DFL) # this lets control-C actually close the app + app.exec() # Start the event loop + + if sdr_type == "usrp": + stream_cmd = uhd.types.StreamCMD(uhd.types.StreamMode.stop_cont) + streamer.issue_stream_cmd(stream_cmd) diff --git a/content-nl/sampling.rst b/content-nl/sampling.rst index 1d767810..ff8ba12c 100644 --- a/content-nl/sampling.rst +++ b/content-nl/sampling.rst @@ -68,7 +68,7 @@ We moeten de hoogste frequentiecomponent vinden, verdubbelen, en op die snelheid :scale: 70% :align: center -Wanneer we te langzaam samplen krijgen we een effect genaamd aliasing (Nederlands: vouwvervorming) waar we later meer over zullen leren, maar dit willen we altijd zien te voorkomen. Wat onze SDR's en bijna alle ontvangers doen, is eerst alles boven Fs/2 wegfilteren voordat er gesampled wordt. Wanneer we dan een signaal proberen te ontvangen en samplen met een te lage snelheid, dan zal het filter dat deel erboven wegkappen. Onze SDR's doen een hoop om ervoor te zorgen dat onze samples vrij zijn van vouwvervorming en andere imperfecties. +Wanneer we te langzaam samplen krijgen we een effect genaamd aliasing (Nederlands: vouwvervorming) waar we later meer over zullen leren, maar dit willen we altijd zien te voorkomen. Wat onze SDR's en bijna alle ontvangers doen, is eerst alles boven Fs/2 wegfilteren voordat er gesampled wordt. Wanneer we dan een signaal proberen te ontvangen en samplen met een te lage snelheid, dan zal het filter dat deel erboven wegkappen. Onze SDR's doen een hoop om ervoor te zorgen dat onze samples vrij zijn van vouwvervorming en andere imperfecties. Het anti-aliasing-filter heeft ook een overgangsgebied, de vuistregel is dan dat alleen de middelste 80% van de samplerate bruikbaar is. ************************* Kwadratuursamplen @@ -95,14 +95,49 @@ Dit kunnen we ook grafisch weergeven door I en Q gelijk te stellen aan 1: De cos() noemen we het "in fase" component, daarom de I, en de sin() is het 90 graden uit fase of "kwadratuur" component, vandaar de Q. Maar als je per ongeluk de Q aan de cos() en de I aan de sin() koppelt, dan maakt dat in de meeste situaties niets uit. -IQ-sampling is gemakkelijker te begrijpen bekeken vanuit de zender, dus vanuit het zenden van een RF signaal door de lucht. -We willen een enkele sinus met bepaalde fase versturen, wat gedaan kan worden door een sin() en cos() zonder faseverschuiving bij elkaar op te tellen. Dit is mogelijk vanwege de volgende eigenschap: :math:`a \cos(x) + b \sin(x) = A \cos(x-\phi)`. -Laten we zeggen dat we het signaal x(t) willen versturen: +Het is makkelijker om IQ sampling te begrijpen als we vanuit de zender gaan kijken. +Stel dat we op een zekere frequentie :math:`f` eem RF-signaal gaan uitzenden. Van deze sinus met frequentie :math:`f` willen we dan de amplitude :math:`A` en fase :math:`\phi` kunnen controleren: .. math:: - x(t) = I \cos(2\pi ft) + Q \sin(2\pi ft) -Wat zou er gebeuren wanneer we een sinus en cosinus optellen? Of eigenlijk, wat zou er gebeuren wanneer we twee sinusoïden optellen die 90 graden uit fase lopen. In de onderstaande video zijn er sliders om I en Q mee aan te passen. Wat geplot wordt zijn de cosinus, sinus en de som van beide. + A \cos(2 \pi f t - \phi) + +Het minteken is hierbij een conventie en niet van belang om het concept te begrijpen. Op elk moment in de tijd zullen we een andere fase en amplitude willen uitzenden, dus beiden zijn een functie van de tijd, formeel geschreven als: + +.. math:: + + A(t) \cos(2 \pi f t - \phi(t)) + +Nu blijkt dat het makkelijk is om de amplitude van een sinus te controleren met RF-schakelingen, maar de fase veel lastiger. Wat we dus kunnen doen is gebruik maken van de goniometrische identiteit: :math:`a \cos(x) + b \sin(x) = A \cos(x - \phi)` die ons vertelt dat een som van een cos() en sin() van dezelfde frequentie, elk met een fase van 0, gelijk is aan een enkele cos() met amplitude :math:`A` en fase :math:`\phi`. Door I en Q te gebruiken in plaats van :math:`a` en :math:`b`, en door onze :math:`2 \pi f t` weer toe te voegen, krijgen we: + +.. math:: + A \cos(2 \pi f t - \phi) + + = I \cos(2 \pi f t) + Q \sin(2 \pi f t) + +waarbij + +.. math:: + A = \sqrt{I^2 + Q^2} + + \phi = \tan^{-1}\left(\frac{Q}{I}\right) + +Door deze aanpak kunnen we met behulp van I en Q elke amplitude of fase genreren dat we zouden willen. Dat zou er ongeveer zo uitzien: + +.. image:: ../_images/IQ_diagram.png + :scale: 80% + :align: center + :alt: Diagram showing how I and Q are modulated onto a carrier + +Stel dat we een IQ sample hebben dat wordt beschreven door het complexe getal :math:`I+JQ`. We kunnen dit IQ sample op de sinus **moduleren**, waarbij de amplitude en fase worden bepaald door het IQ sample: + +.. math:: + + x(t) = I \cos(2\pi ft) + Q \sin(2\pi ft) + + \qquad \qquad \qquad \qquad = \left(\sqrt{I^2+Q^2}\right) \cos\left(2\pi ft - \tan^{-1}\left(\frac{Q}{I}\right)\right) + +Nu we de wiskunde hebben bekeken, laten we even gaan spelen door twee sinusoïden op te tellen die 90 graden uit fase lopen. In de onderstaande video zijn er sliders om I en Q mee aan te passen dus de fase en amplitude van de cosinus en sinus. Wat geplot wordt zijn de cosinus (rood), sinus (blauw) en de som van beide (groen). .. image:: ../_images/IQ3.gif :scale: 100% @@ -112,14 +147,7 @@ Wat zou er gebeuren wanneer we een sinus en cosinus optellen? Of eigenlijk, wat (De code voor deze Python-app kun je hier vinden: `link `_) -Wat je hier uit moet onthouden is dat wanneer de cos() en sin() worden opgeteld, we een andere zuivere sinusoïde krijgen met een andere fase en amplitude. Daarnaast verschuift de fase wanneer we langzaam een van de twee delen groter of kleiner maken. De amplitude verandert ook mee. Dit is allemaal het gevolg van de goniometrische identiteit: :math:`a \cos(x) + b \sin(x) = A \cos(x-\phi)`, waar we dadelijk op terug komen. Het "nut" van dit gedrag is dat we de fase en amplitude van de resulterende sinusoïde kunnen controleren door I en Q aan te passen (we hoeven niets de doen met de fase van cosinus of sinus). We kunnen bijvoorbeeld I en Q op zo'n manier aanpassen dat de amplitude constant blijft en de fase naar wens wordt ingesteld. Omdat we weten dat we een sinusoïde signaal moeten versturen om het door de lucht te laten vliegen als een elektromagnetische golf, is deze mogelijkheid voor een zender extreem handig. Het is daarnaast veel makkelijker om twee amplitudes aan te passen en een optelling uit te voeren, dan amplitude en fase moeten aanpassen. Het resultaat is dat onze zender er ongeveer zo uit zal zien: - -.. image:: ../_images/IQ_diagram.png - :scale: 80% - :align: center - :alt: Diagram showing how I and Q are modulated onto a carrier - -We hoeven alleen een cosinus te genereren en deze 90 graden op te schuiven om het Q gedeelte te krijgen. +Wat je hier uit moet onthouden is dat wanneer de cos() en sin() worden opgeteld, we een andere zuivere sinusoïde krijgen met een andere fase en amplitude maar dezelfde frequentie. Daarnaast verschuift de fase wanneer we langzaam een van de twee delen groter of kleiner maken (en de amplitude verandert ook mee). Dit is allemaal het gevolg van de goniometrische identiteit: :math:`a \cos(x) + b \sin(x) = A \cos(x-\phi)`, waar we dadelijk op terug komen. Het "nut" van dit gedrag is dat we de fase en amplitude van de resulterende sinusoïde kunnen controleren door I en Q aan te passen (we hoeven niets de doen met de fase van cosinus of sinus). We kunnen bijvoorbeeld I en Q op zo'n manier aanpassen dat de amplitude constant blijft en de fase naar wens wordt ingesteld. Omdat we weten dat we een sinusoïde signaal moeten versturen om het door de lucht te laten vliegen als een elektromagnetische golf, is deze mogelijkheid voor een zender extreem handig. Het is daarnaast veel makkelijker om twee amplitudes aan te passen en een optelling uit te voeren, dan amplitude en fase moeten aanpassen. Hiermee kunnen ook makkelijk het basisband signaal weergeven, onafhankelijk van de draaggolf. ************************* Complexe Getallen @@ -197,27 +225,18 @@ Nog een laatste belangrijke opmerking: Het figuur hierboven laat zien wat er **b Draaggolven en frequentieverschuiving ************************************* -Tot nu toe hebben we de frequentie nog niet behandelt, maar er was wel een :math:`f` in de vergelijkingen met de cos() en sin(). Deze frequentie is de middenfrequentie waarop we echt een signaal door de lucht sturen (de frequentie van de elektromagnetische golf). Dit noemen we de "draaggolf" omdat het ons signaal *draagt* op een bepaalde RF-frequentie. Wanneer we onze SDR afstellen op een bepaalde frequentie en samples ontvangen, dan wordt de informatie opgeslagen in I en Q; deze draaggolf verschijnt niet in I en Q. - -.. image:: images/carrier.svg - :scale: 140% - :align: center +Tot nu toe hebben we de frequentie nog niet behandelt, maar er was wel een :math:`f` in de vergelijkingen met de cos() en sin(). Deze frequentie is de middenfrequentie waarop we echt een signaal door de lucht sturen (de frequentie van de elektromagnetische golf). Dit noemen we de "draaggolf" omdat het ons signaal *draagt* op een bepaalde RF-frequentie. Wanneer we onze SDR afstellen op een bepaalde frequentie en samples ontvangen, dan wordt de informatie opgeslagen in I en Q. Ter referentie, radiosignalen zoals FM-radio, WiFi, Bluetooth, LTE, GPS, etc., gebruiken meestal een frequentie (dus een draaggolf) tussen de 100 MHz en 6 GHz. Deze frequenties vliegen erg goed door de lucht, maar hebben niet een superlange antenne nodig of een hoop vermogen om te versturen of te ontvangen. Jouw magnetron maakt het eten warm met elektromagnetische golven op 2.5 GHz. Als de deur signalen zou lekken dan zou de magnetron jouw WiFi verstoren en misschien je huid verbranden. Een andere vorm van elektromagnetische golven is licht. Zichtbaar licht heeft een frequentie rond de 500 THz. Dit is zo hoog dat we geen antennes nodig hebben om licht te versturen. We gebruiken methoden zoals halfgeleider leds. Ze creëren licht wanneer een elektron tussen de atomaire banen van het halfgeleider materiaal springt, en de afstand die wordt gesprongen bepaalt de kleur. Technisch gezien worden frequenties tussen de 20 kHz en 300 GHz beschouwt als radiofrequenties (RF). Dit zijn de frequenties waarbij de energie van een oscillerende stroom door een geleider (antenne) uit kan stralen en door de ruimte bewegen. De meest nuttige frequenties voor moderne toepassingen liggen tussen de 100 MHz en 6 GHz. De frequenties daarboven wordt al decennia gebruikt door radar en satellietcommunicatie en worden nu ook toegepast in 5G "mmWave" (24 - 29 GHz) om de lagere frequenties een helpende hand te bieden en de snelheid te verhogen. -Wanneer we onze IQ-waarden snel veranderen en via onze draaggolf versturen wordt dit het "moduleren" van de draaggolf genoemd (met data of wat we ook willen). Wanneer we de I en Q aanpassen veranderen we dus de fase en amplitude van de draaggolf. Een andere optie is om de frequentie van de draaggolf aan te passen, dus een beetje hoger of lager, dat is wat een FM-zender doet. +Wanneer we onze IQ-waarden snel veranderen en via onze draaggolf versturen wordt dit het "moduleren" van de draaggolf genoemd (met data of wat we ook willen). Wanneer we de I en Q aanpassen veranderen we dus de fase en amplitude van de draaggolf. Een andere optie is om de frequentie van de draaggolf aan te passen, dus een beetje hoger of lager, dat is wat een FM-zender doet. Het is makkelijk om het onderscheid te verliezen tussen het signaal wat we willen versturen (met typisch een hoop frequentiecomponenenten), en de frequentie waarop het verstuurd wordt (de draaggolf). Hopelijk wordt dit duidelijk wanneer we basisband- en banddoorlaatsignalen behandelen. -Als een simpel voorbeeld kunnen we het IQ sample 1+0j en vervolgens 0+1j versturen. Dan versturen we eersst :math:`\cos(2\pi ft)` en dan :math:`\sin(2\pi ft)`. Dit betekent dat onze draaggolf 90 graden van fase verandert wanneer we schakelen van het ene naar het andere sample. - -Het is makkelijk om het onderscheid te verliezen tussen het signaal wat we willen versturen (met typisch een hoop frequentiecomponenenten), en de frequentie waarop het verstuurd wordt (de draaggolf). Hopelijk wordt dit duidelijk wanneer we basisband- en banddoorlaatsignalen behandelen. - -Nu even terug naar samplen. Wat als we, zoals we het hoofdstuk zijn begonnen, in plaats van samples te ontvangen door het antennesignaal te vermenigvuldigen met een cos() en sin(), en I en Q te samplen, we het antennesignaal direct in een ADC zouden stoppen? Stel de draaggolf is 2.4 GHz, zoals bij WiFi of Bluetooth. Zoals we hebben geleerd, zou dat betekenen dat we op 4.8 GHz moeten samplen. Dat is extreem snel! En een ADC die zo snel kan samplen kost duizenden euro's. In plaats hiervan verschuiven we eerst het signaal naar "beneden", zodat het signaal dat we willen samplen gecentreerd is rond DC of 0 Hz. Deze verschuiving vindt plaats voor het samplen. We gaan van: +Nu even terug naar samplen. Wat als we in plaats van samples te ontvangen door het antennesignaal te vermenigvuldigen met een cos() en sin(), en I en Q te samplen, we het antennesignaal direct in een ADC zouden stoppen? Stel de draaggolf is 2.4 GHz, zoals bij WiFi of Bluetooth. Zoals we hebben geleerd, zou dat betekenen dat we op 4.8 GHz moeten samplen. Dat is extreem snel! En een ADC die zo snel kan samplen kost duizenden euro's. In plaats hiervan verschuiven we eerst het signaal naar "beneden", zodat het signaal dat we willen samplen gecentreerd is rond DC of 0 Hz. Deze verschuiving vindt plaats voor het samplen. We gaan van: .. math:: - I \cos(2\pi ft) - - Q \sin(2\pi ft) + + I \underbrace{\cos(2\pi ft)}_{draaggolf} \ + \ \ Q \underbrace{\sin(2\pi ft)}_{draaggolf} Naar alleen I en Q. @@ -258,6 +277,7 @@ Het figuur uit de "ontvangende kant" sectie, laat zien hoe het signaal wordt ver *********************************** Basisband- en Banddoorlaatsignalen *********************************** + We noemen de band waar het signaal rond de 0 Hz zit de "basisband". Andersom, "bandoorlaat" refereert naar wanneer een signaal nergens in de buurt van de 0 Hz zit, maar omhoog is geschoven met draadloze transmissie als doel. Iets als een *basisbandtransmissie* bestaat niet, want je kunt niet iets imaginairs versturen. Een signaal kan in de basisband perfect gecentreerd zijn rond 0 Hz, net als de rechterkant van figuur :numref:`verschuiving`. Het signaal kan ook *in de buurt* van 0 Hz zitten, zoals de twee signalen hieronder. Die signalen worden nog steeds opgevat als basisband. Er is ook een banddoorlaatsignaal weergegeven, gecentreerd op een erg hoge frequentie :math:`f_c`. .. image:: ../_images/baseband_bandpass.png @@ -265,9 +285,11 @@ We noemen de band waar het signaal rond de 0 Hz zit de "basisband". Andersom, "b :align: center :alt: Baseband vs bandpass -Misschien ben je ook de term "intermediate frequency" (IF) of tussenfrequentie tegengekomen; zie IF voor nu als een tussenstap tussen de basisband en RF/bandoorlaatband. +Misschien ben je ook de term "intermediate frequency" (IF) of tussenfrequentie tegengekomen als een tussenstap tussen de basisband en RF/bandoorlaatband. + +We maken, analyseren of slaan signalen op vanuit de basisband zodat we op een lagere sample-frequentie kunnen werken (zoals eerder uitgelegd). Hierbij is het belangrijk op te merken dat basisbandsignalen meestal **complex** zijn, terwijl bandoorlaatsignalen (dus te versturen RF signalen) **reëel** zijn. Als je erover nadenkt: signalen die door een antenne gaan moeten reëel zijn, je kunt geen complex/imaginair signaal uitzenden. Wanneer het negatieve en positieve deel van het frequentiespectrum niet precies hetzelfde zijn, dan weet je zeker dat het signaal complex is. Negatieve frequenties worden immers met complexe getallen weergegeven. In de werkelijkheid bestaan negatieve frequenties niet, alleen frequenties onder de draaggolf. -We maken, analyseren of slaan signalen op vanuit de basisband zodat we op een lagere sample-frequentie kunnen werken (zoals eerder uitgelegd). Hierbij is het belangrijk op te merken dat basisbandsignalen meestal complex zijn, terwijl bandoorlaatsignalen (dus te versturen RF signalen) reëel zijn. Als je erover nadenkt: signalen die door een antenne gaan moeten reëel zijn, je kunt geen complex/imaginair signaal uitzenden. Wanneer het negatieve en positieve deel van het frequentiespectrum niet precies hetzelfde zijn, dan weet je zeker dat het signaal complex is. Negatieve frequenties worden immers met complexe getallen weergegeven. In de werkelijkheid bestaan negatieve frequenties niet, alleen frequenties onder de draaggolf. +Als ons signaal geen imaganair component bevat, dan hebben we geen Q-waarden (of je kunt denken dat alle Q-waarden gelijk zijn aan nul). Dit betekent op zijn beurt dat we alleen cosinus signalen hebben zonder enige faseverschuiving. Een som van cosinus signalen zonder enige faseverschuiving zal symmetrisch zijn rond de y-as om jet frequentiedomein. Dit komt omdat een cosinus dezelfde positieve als negatieve componenten bevat. Eerder speelden we met het complexe punt 0.7 - 0.4j, dat was in feite een sample van een basisbandsignaal. In de meeste gevallen, als je complexe samples (IQ-samples) ziet, ben je in de basisband bezig. Vanwege de hoeveelheid data dat het in beslag zou nemen, worden signalen zelden opgeslagen op RF-frequenties, en om het feit dat we meestal alleen geïnteresseerd zijn in een smal deel van het RF spectrum. @@ -291,7 +313,7 @@ Wanneer alleen een DC-piek te zien is, en de rest van de FFT lijkt op ruis, dan De DC-offset is een gevolg van directe conversie ontvangers, de architectuur die gebruikt wordt door SDR's zoals de PlutoSDR, RTL-SDR, LimeSDR, en veel Ettus USRP's. In directe conversie ontvangers verschuift een oscillator, de LO, het signaal van zijn frequentie naar de basisband. Met als resultaat dat lekkage van de LO in het midden van de waargenomen band verschijnt. LO-lekkage is de extra energie die ontstaat bij het combineren van frequenties. Het is moeilijk deze extra ruis te verwijderen omdat het dicht bij het gewenste uitgangssignaal zit. Veel RF ic's hebben DC offset filters ingebouwd, maar meestal moet er een signaal aanwezig zijn om te kunnen werken. Om deze reden is de DC-piek sterk aanwezig op het moment dat er geen signalen zijn. -Een snelle manier om met DC-offset om te gaan is om het signaal te oversamplen en de LO af te stellen naast de signaalfrequentie. Stel we willen 5 MHz van het spectrum rond 100 MHz bekijken. Wat we dan doen is samplen met bijvoorbeeld 20 MHz en afstellen op 95 MHz. +Een snelle manier om met DC-offset om te gaan is om het signaal te oversamplen en de LO af te stellen naast de signaalfrequentie. Deze techniek wordt *offset tuning* genoemd. Stel we willen 5 MHz van het spectrum rond 100 MHz bekijken. Wat we dan doen is samplen met bijvoorbeeld 20 MHz en afstellen op 95 MHz. .. _afstellen: .. figure:: ../_images/offtuning.png diff --git a/content-nl/sync.rst b/content-nl/sync.rst index c12c6e76..91fe5230 100644 --- a/content-nl/sync.rst +++ b/content-nl/sync.rst @@ -58,7 +58,7 @@ We zullen eerst wat pythoncode gaan bekijken waarmee we een vertraging en freque h = np.sinc(t/Ts) * np.cos(np.pi*beta*t/Ts) / (1 - (2*beta*t/Ts)**2) # signaal x filteren. - samples = np.convolve(pulse_train, h) + samples = np.convolve(pulse_train, h, "same") .. raw:: html @@ -459,6 +459,143 @@ Hieronder zie je een animatie van de tijdsynchronisatie en frequentiecorrectie a :align: center :alt: Costas loop animation +Het volgende (ingeklapte) codeblok geeft het volledige Pythonvoorbeeld van het hoofdstuk tot nu toe, dit is getest met Python 3.12.3 en NumPy 1.26.4. Het bevat ook een bit error check aan het einde, hoewel AWGN is weggelaten om te kunnen zien hoe strak de BPSK door alleen synchronisatie kan komen, je bent welkom om AWGN toe te voegen, bijvoorbeeld direct na het toevoegen van de fractionele vertraging. Let op dat de plot van IQ over tijd is vóór frequentiesynchronisatie, zodat je kunt zien hoe de BPSK-energie langzaam tussen I en Q verschuift. + +.. raw:: html + +
    + Volledig Pythonvoorbeeld + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + from scipy import signal + + # Create BPSK signal + num_symbols = 100 + sps = 8 + bits = np.random.randint(0, 2, num_symbols) # Our data to be transmitted, 1's and 0's + pulse_train = np.array([]) + for bit in bits: + pulse = np.zeros(sps) + pulse[0] = bit*2-1 # set the first value to either a 1 or -1 + pulse_train = np.concatenate((pulse_train, pulse)) # add the 8 samples to the signal + + # Apply pulse shaping to the BPSK + num_taps = 101 + beta = 0.35 + Ts = sps # Assume sample rate is 1 Hz, so sample period is 1, so *symbol* period is 8 + t = np.arange(-51, 52) # remember it's not inclusive of final number + h = np.sinc(t/Ts) * np.cos(np.pi*beta*t/Ts) / (1 - (2*beta*t/Ts)**2) + samples = np.convolve(pulse_train, h, 'same') + + # Create and apply fractional delay filter to emulate a random timing offset + delay = 0.456 # fractional delay, in samples + N = 21 # number of taps, keep this odd + n = np.arange(-(N-1)//2, N//2+1) # -10,-9,...,0,...,9,10 + h = np.sinc(n - delay) # calc filter taps + h *= np.hamming(N) # window the filter to make sure it decays to 0 on both sides + h /= np.sum(h) # normalize to get unity gain, we don't want to change the amplitude/power + samples = np.convolve(samples, h) # apply filter + + # Apply a pretty significant freq offset + fs = 1e6 # assume our sample rate is 1 MHz + fo = 13000 # simulate freq offset THIS REPRESENTS A COARSE OFFSET! + Ts = 1/fs # calc sample period + t = np.arange(0, Ts*len(samples), Ts) # create time vector + samples = samples * np.exp(1j*2*np.pi*fo*t) # perform freq shift + + # Estimate and correct for the coarse freq offset + samples_sq = samples**2 + psd = np.fft.fftshift(np.abs(np.fft.fft(samples_sq, 2048))) + f = np.linspace(-fs/2.0, fs/2.0, len(psd)) + max_freq = f[np.argmax(psd)] / 2.0 + print(f"Estimated freq offset: {max_freq:.2f} Hz") + Ts = 1/fs # calc sample period + t = np.arange(0, Ts*len(samples), Ts) # create time vector + samples = samples * np.exp(-1j*2*np.pi*max_freq*t) + + # At this point there should be less than 1kHz of freq offset in our signal, depending how large an FFT you used above + + # Symbol/Timing Sync + mu = 0 # initial estimate of phase of sample + out = np.zeros(len(samples) // sps + 2, dtype=np.complex64) + out_rail = np.zeros(len(samples) // sps + 2, dtype=np.complex64) # stores values, each iteration we need the previous 2 values plus current value + i_in = 0 # input samples index + i_out = 2 # output index (let first two outputs be 0) + interpolation_factor = 16 + samples_interpolated = signal.resample_poly(samples, interpolation_factor, 1) + while i_out < len(samples) and i_in+16 < len(samples): + out[i_out] = samples_interpolated[i_in*interpolation_factor + int(mu*interpolation_factor)] + out_rail[i_out] = int(np.real(out[i_out]) > 0) + 1j*int(np.imag(out[i_out]) > 0) + x = (out_rail[i_out] - out_rail[i_out-2]) * np.conj(out[i_out-1]) + y = (out[i_out] - out[i_out-2]) * np.conj(out_rail[i_out-1]) + mm_val = np.real(y - x) + mu += sps + 0.3*mm_val + i_in += int(np.floor(mu)) # round down to nearest int since we are using it as an index + mu = mu - np.floor(mu) # remove the integer part of mu + i_out += 1 # increment output index + out = out[3:i_out] # remove the first few due to filter transients, and anything after i_out (that was never filled out) + samples = out + + plt.figure(2) + plt.plot(np.real(samples)) + plt.plot(np.imag(samples)) + plt.xlabel('Sample Index') + plt.ylabel('Sample Value') + plt.legend(['I', 'Q']) + plt.grid() + + N = len(samples) + phase = 0 + freq = 0 + # These next two params is what to adjust, to make the feedback loop faster or slower (which impacts stability) + alpha = 0.132 + beta = 0.00932 + out = np.zeros(N, dtype=np.complex64) + freq_log = [] + for i in range(N): + out[i] = samples[i] * np.exp(-1j*phase) # adjust the input sample by the inverse of the estimated phase offset + error = np.real(out[i]) * np.imag(out[i]) # This is the error formula for 2nd order Costas Loop (e.g. for BPSK) + + # Advance the loop (recalc phase and freq offset) + freq += (beta * error) + freq_log.append(freq * fs / (2*np.pi)) # convert from angular velocity to Hz for logging + phase += freq + (alpha * error) + + # Optional: Adjust phase so its always between 0 and 2pi, recall that phase wraps around every 2pi + while phase >= 2*np.pi: + phase -= 2*np.pi + while phase < 0: + phase += 2*np.pi + + # Calc BER + rx_bits = (np.real(out) > 0).astype(int) + num_bit_errors = np.sum(rx_bits != bits[:len(rx_bits)]) + print(f"Number of bit errors: {num_bit_errors} out of {len(rx_bits)} bits, BER: {num_bit_errors/len(rx_bits):.4f}") + + # Plot freq over time to see how long it takes to hit the right offset + plt.figure(0) + plt.plot(freq_log,'.-') + plt.xlabel('Sample Index') + plt.ylabel('Frequency Offset Estimate (Hz)') + + # Appears to be synced after ~80 samples so lets plot the constellation of the remaining 20 samples + plt.figure(1) + plt.plot(np.real(out[80:]), np.imag(out[80:]), '.') + plt.xlabel('I') + plt.ylabel('Q') + plt.xlim(-1.5, 1.5) + plt.ylim(-1.5, 1.5) + plt.grid() + plt.show() + +.. raw:: html + +
    + + *************************** Frame-synchronisatie *************************** diff --git a/content-ukraine/cyclostationary.rst b/content-ukraine/cyclostationary.rst index 3bf41512..1041ca07 100644 --- a/content-ukraine/cyclostationary.rst +++ b/content-ukraine/cyclostationary.rst @@ -8,13 +8,13 @@ У співавторстві з Sam Brown -У цьому розділі ми розкриваємо суть обробки циклостаціонарних сигналів (cyclostationary signal processing, або CSP) — відносно нішової галузі обробки радіочастотних сигналів (RF), яка використовується для аналізу або виявлення сигналів із циклостаціонарними властивостями (часто з дуже низьким рівнем сигнал шум SNR!), до цих сигналів зокрема відносяться більшісті сигналів з сучасними схемами цифрової модуляції. В цьому розділі ми розглянемо циклічну автокореляційну функцію (CAF), спектральну кореляційну функцію (SCF), функцію спектральної когерентності (COH), їхні спряжені варіанти та способи застосування. Розділ містить кілька повних реалізацій на Python з прикладами, що охоплюють BPSK, QPSK, OFDM та суміш кількох одночасних сигналів. +У цьому розділі ми розкриваємо суть обробки циклостаціонарних сигналів (cyclostationary signal processing, або CSP) — відносно нішової галузі обробки радіочастотних сигналів (RF), яка використовується для аналізу або виявлення сигналів із циклостаціонарними властивостями (часто з дуже низьким рівнем сигнал/шум SNR!), до цих сигналів зокрема відносяться більшісті сигналів з сучасними схемами цифрової модуляції. В цьому розділі ми розглянемо циклічну автокореляційну функцію (CAF), спектральну кореляційну функцію (SCF), функцію спектральної когерентності (COH), їхні спряжені варіанти та способи застосування. Розділ містить кілька повних реалізацій на Python з прикладами, що охоплюють BPSK, QPSK, OFDM та суміш кількох сигналів. **************** Вступ **************** -Циклостаціонарна обробка сигналів (CSP або просто циклостаціонарна обробка) — це набір технік, що дозволяє використовувати циклостаціонарну властивість, притаманну багатьом реальним сигналам зв'язку. Це можуть бути модульовані сигнали, як-от трансляції AM/FM/ТБ мовлення, сигнали стільникового та WiFi зв’язку, а також сигнали радари й інші сигнали, статистика яких має періодичність. Значна частина класичних методів обробки сигналів ґрунтується на припущенні, що сигнал стаціонарний, тобто його статистичні характеристики, такі як середнє значення, дисперсія та моменти вищих порядків, не змінюються з часом. Однак більшість реальних RF-сигналів є циклостаціонарними, тобто їхня статистика змінюється *періодично* з часом. Техніки CSP використовують цю циклостаціонарну властивість і можуть застосовуватися для виявлення зашумлених сигналів, розпізнавання модуляції та розділення сигналів, що перетинаються як по часу, так і по частоті. +Циклостаціонарна обробка сигналів (CSP або просто циклостаціонарна обробка) — це набір технік, що дозволяє використовувати циклостаціонарну властивість, притаманну багатьом реальним сигналам зв'язку. Це можуть бути модульовані сигнали, як от трансляції AM/FM/ТБ мовлення, сигнали стільникового та WiFi зв’язку, а також сигнали радарів або інші сигнали, статистика яких має періодичність. Значна частина класичних методів обробки сигналів ґрунтується на припущенні, що сигнал стаціонарний, тобто його статистичні характеристики, такі як середнє значення, дисперсія та моменти вищих порядків, не змінюються з часом. Однак більшість реальних RF-сигналів є циклостаціонарними, тобто їхня статистика змінюється *періодично* з часом. Техніки CSP використовують цю циклостаціонарну властивість і можуть застосовуватися для виявлення зашумлених сигналів, розпізнавання модуляції та розділення сигналів, що перетинаються як по часу, так і по частоті. Якщо після читання цього розділу та експериментів з Python ви захочете глибше зануритися в CSP, перегляньте підручник Вільяма Гарднера 1994 року `Cyclostationarity in Communications and Signal Processing `_, його підручник 1987 року `Statistical Spectral Analysis `_, або `збірку публікацій у блозі Чада Спунера `_. @@ -29,7 +29,7 @@ .. math:: R_x(\tau) = E[x(t)x^*(t-\tau)] -де :math:`E` — оператор математичного сподівання, :math:`\tau` — часовий зсув, а :math:`*` позначає комплексне спряження. У дискретному часі з обмеженою кількістю відліків, що нас і цікавить, маємо: +де :math:`E` — оператор математичного сподівання, :math:`\tau` — часовий зсув, а :math:`*` позначає комплексне спряження. А у дискретному часі з обмеженою кількістю відліків, який нас і цікавить, маємо: .. math:: R_x(\tau) = \frac{1}{N} \sum_{n=-N/2}^{N/2} x\left[ n+\frac{\tau}{2} \right] x^*\left[ n-\frac{\tau}{2} \right] @@ -39,7 +39,7 @@ Якщо сигнал має певну періодичність, наприклад періодичну форму символів у QPSK, то автокореляція, обчислена на проміжку різних :math:`\tau`, теж буде періодичною. Наприклад, якщо QPSK-сигнал має 8 відліків на символ, то для :math:`\tau`, кратних 8, міра «подібності» значно вища, ніж для інших значень :math:`\tau`. Період автокореляції — це те, що зрештою виявляють методи CSP. ************************************************ -Циклічна автокореляційна функція (CAF) +Циклічна автокореляційна функція (Cyclic Autocorrelation Function CAF) ************************************************ Як зазначено вище, ми прагнемо визначити, чи є періодичність в автокореляції. Пригадаємо формулу перетворення Фур’є: якщо ми хочемо з’ясувати, наскільки сильно в деякому сигналі :math:`x(t)` присутня певна частота :math:`f`, ми можемо обчислити: @@ -57,11 +57,11 @@ .. math:: R_x(\tau, \alpha) = \frac{1}{N} \sum_{n=-N/2}^{N/2} x\left[ n+\frac{\tau}{2} \right] x^*\left[ n-\frac{\tau}{2} \right] e^{-j2\pi \alpha n} -Це дозволяє перевірити, наскільки сильною є частота :math:`\alpha`. Наведений вище вираз називається циклічною автокореляційною функцією (CAF). Інший спосіб інтерпретації CAF — це набір коефіцієнтів ряду Фур’є, які описують згадану періодичність. Іншими словами, CAF — це амплітуда та фаза гармонік, присутніх в автокореляції сигналу. Ми використовуємо термін «циклічно-стаціонарний», щоб описати сигнали, автокореляція яких є періодичною або майже періодичною. CAF є розширенням традиційної автокореляційної функції для циклічно-стаціонарних сигналів. +Це дозволяє перевірити, наскільки сильною є частота :math:`\alpha`. Наведений вище вираз називається циклічною автокореляційною функцією (Cyclic Autocorrelation Function CAF). Інший спосіб інтерпретації CAF — це набір коефіцієнтів ряду Фур’є, які описують згадану періодичність. Іншими словами, CAF — це амплітуда та фаза гармонік, присутніх в автокореляції сигналу. Ми використовуємо термін «циклічно-стаціонарний», щоб описати сигнали, автокореляція яких є періодичною або майже періодичною. CAF є розширенням традиційної автокореляційної функції для циклічно-стаціонарних сигналів. Видно, що CAF залежить від двох змінних: затримки :math:`\tau` (tau) та циклічної частоти :math:`\alpha`. Циклічні частоти в CSP відображають швидкість зміни статистики сигналу, що у випадку CAF означає момент другого порядку або дисперсію. Тож циклічні частоти часто відповідають виразним періодичним явищам, таким як символи, що модулюються в сигналах зв'язку. Ми побачимо, наприклад, як символьна швидкість сигналу BPSK та її цілі кратні (гармоніки) проявляються як циклічні частоти у CAF. -У Python CAF базового сигналу :code:`samples` для заданих :code:`alpha` та :code:`tau` можна обчислити за допомогою такого фрагмента коду (незабаром додамо обрамлювальний код): +У Python CAF модулюючого baseband сигналу :code:`samples` для заданих :code:`alpha` та :code:`tau` можна обчислити за допомогою такого фрагмента коду (пізніше додамо обрамлювальний код): .. code-block:: python @@ -71,7 +71,7 @@ Ми використовуємо :code:`np.roll()` для зсуву одного набору відліків на :code:`tau`, адже потрібно зміщувати на ціле число відліків. Якби ми зсували обидва набори у протилежних напрямках, ми пропускали б кожне друге зміщення. Також необхідно додати частотний зсув, щоб компенсувати те, що ми зміщуємо на 1 відлік за раз і лише з одного боку (замість половини відліку в обидва боки, як у базовому рівнянні CAF). Частота цього зсуву дорівнює :code:`alpha/2`. -Щоб погратися з CAF у Python, спершу змоделюємо приклад сигналу. Поки що використаємо прямокутний сигнал BPSK (тобто BPSK без формування імпульсу) з 20 відліками на символ та додамо білий гаусів шум (AWGN). Ми навмисне внесемо частотний зсув у сигнал BPSK, аби пізніше продемонструвати, як циклічно-стаціонарна обробка допомагає оцінювати і частотний зсув, і циклічну частоту. Цей зсув відповідає ситуації, коли приймач не ідеально налаштований на частоту сигналу: або трохи хибить, або суттєво, але не настільки, щоб сигнал виходив за межі смуги дискретизації. +Щоб погратися з CAF у Python, спершу змоделюємо якийсь сигнал. Візьмемо для приклад поки що прямокутний сигнал BPSK (тобто BPSK без формування імпульсу/pulse-shaping) з 20 відліками на символ та додамо білий гаусів шум (AWGN). Ми навмисне внесемо частотний зсув у сигнал BPSK, аби пізніше продемонструвати, як циклічно-стаціонарна обробка допомагає оцінювати і частотний зсув, і циклічну частоту. Цей зсув відповідає ситуації, коли приймач не ідеально налаштований на частоту сигналу: зміщений або трохи, або суттєво, але не настільки, щоб сигнал виходив за межі смуги дискретизації. Наведений нижче код генерує IQ-відліки, які ми будемо використовувати впродовж двох наступних розділів: @@ -90,16 +90,16 @@ Оскільки абсолютні швидкість дискретизації та швидкість символів у цьому розділі не відіграють важливої ролі, ми використовуємо нормалізовані частоти, що еквівалентно припущенню, що частота дискретизації = 1 Гц. Це означає, що сигнал мусить лежати в діапазоні від -0.5 до +0.5 Гц. Тому ви *не* побачите змінної :code:`sample_rate` у коді: ми працюємо з кількістю відліків на символ (:code:`sps`). -Для розігріву погляньмо на щільність спектральної потужності (PSD, тобто FFT) сигналу до будь-якої обробки CSP: +Для розігріву погляньмо на щільність спектральної потужності (PSD, тобто FFT) сигналу до будь-якої обробки функцією CSP: .. image:: ../_images/psd_of_bpsk_used_for_caf.svg :align: center :target: ../_images/psd_of_bpsk_used_for_caf.svg - :alt: PSD прямокутного сигналу BPSK, що використовується для CAF + :alt: Щільність спектральної потужності PSD прямокутного сигналу BPSK, що використовується для CAF На графіку видно частотний зсув 0.2 Гц, який ми додали, і те, що 20 відліків на символ формують доволі вузький сигнал, але через відсутність формування імпульсу спектр спадає дуже повільно. -Тепер обчислимо CAF для правильного :math:`\alpha` та діапазону :math:`\tau` (візьмемо від -50 до +50). Правильне :math:`\alpha` у нашому випадку — це обернена величина кількості відліків на символ, тобто 1/20 = 0.05 Гц. Щоб отримати CAF у Python, проітеруємося за :math:`\tau`: +Тепер обчислимо CAF для вірного значення :math:`\alpha` та діапазону :math:`\tau` (візьмемо від -50 до +50). Вірне значення :math:`\alpha` у нашому випадку — це обернена величина кількості відліків на символ, тобто 1/20 = 0.05 Гц. Щоб отримати CAF у Python, проітеруємося за :math:`\tau`: .. code-block:: python @@ -117,9 +117,9 @@ .. image:: ../_images/caf_at_correct_alpha.svg :align: center :target: ../_images/caf_at_correct_alpha.svg - :alt: CAF для правильного значення alpha + :alt: CAF для вірного значення значення alpha -Вигляд трохи дивний, але зважайте, що :math:`\tau` представляє часову вісь, а найважливіше — велика енергія CAF для цього :math:`\alpha`, адже воно відповідає циклічній частоті нашого сигналу. Щоб переконатися, розгляньмо CAF для «неправильного» :math:`\alpha`, скажімо 0.08 Гц: +Вигляд трохи дивний, але ж згадайте, що :math:`\tau` представляє часову вісь, і найважливіше, що велика енергія CAF при цьому значені :math:`\alpha`, адже воно відповідає циклічній частоті нашого сигналу. Щоб переконатися, розгляньмо CAF для «неправильного» :math:`\alpha`, скажімо 0.08 Гц: .. image:: ../_images/caf_at_incorrect_alpha.svg :align: center @@ -128,7 +128,7 @@ Зверніть увагу на вісь Y — енергії CAF тепер значно менше. Конкретні шаблони поки не такі важливі; вони стануть зрозумілішими після вивчення SCF у наступному розділі. -Ще один підхід — обчислити CAF у діапазоні :math:`\alpha`, а для кожного :math:`\alpha` знайти потужність CAF, взявши модуль і суму (або середнє — тут не суттєво). Потім, якщо побудувати цю потужність залежно від :math:`\alpha`, побачимо сплески на циклічних частотах сигналу. Наступний код додає цикл :code:`for` та використовує крок :math:`\alpha` 0.005 Гц (зверніть увагу, що виконання триватиме довго!): +Ще один підхід — обчислити CAF у якомусь діапазоні :math:`\alpha`, і для кожного :math:`\alpha` знайти потужність CAF, взявши модуль і суму (або середнє — тут не суттєво). Потім, якщо побудувати цю потужність залежно від :math:`\alpha`, побачимо сплески на циклічних частотах сигналу. Наступний код додає цикл :code:`for` та використовує крок :math:`\alpha` 0.005 Гц (зверніть увагу, що виконання триватиме довго!): .. code-block:: python @@ -151,13 +151,13 @@ Бачимо очікуваний пік на 0.05 Гц, а також на цілих кратних 0.05 Гц. Це тому, що CAF — це ряд Фур’є, і гармоніки основної частоти присутні в CAF, особливо для PSK/QAM без формування імпульсу. Енергія на :math:`\alpha = 0` відповідає загальній потужності у PSD сигналу, хоча зазвичай ми її занулюємо, адже 1) PSD часто будують окремо і 2) вона псує динамічний діапазон колірної карти, коли ми починаємо відображати 2D-дані. -Хоч CAF цікавий, ми зазвичай хочемо побачити циклічну частоту *як функцію RF-частоти*, а не лише циклічну частоту, як у графіку вище. Це приводить нас до спектральної кореляційної функції (SCF), яку розглянемо далі. +Хоч CAF цікавий, ми зазвичай хочемо побачити циклічну частоту *як функцію RF-частоти*, а не лише циклічну частоту, як у графіку вище. Це приводить нас до спектральної кореляційної функції (SCF), яку розглянемо нижче. ************************************************ -Спектральна кореляційна функція (SCF) +Спектральна кореляційна функція (Spectral Correlation Function SCF) ************************************************ -Подібно до того, як CAF показує періодичність в автокореляції сигналу, SCF демонструє періодичність у PSD сигналу. Автокореляція та PSD є парою перетворення Фур’є, тож не дивно, що CAF і SCF також є парою перетворення Фур’є. Це співвідношення називають *циклічним співвідношенням Вінера* (Cyclic Wiener Relationship). Воно стає ще зрозумілішим, якщо згадати, що CAF і SCF при :math:`\alpha = 0` відповідають автокореляції та PSD відповідно. +Подібно тому, як CAF показує періодичність в автокореляції сигналу, SCF демонструє періодичність у PSD сигналу. Автокореляція та PSD є парою перетворення Фур’є, тож не дивно, що CAF і SCF також є парою перетворення Фур’є. Це співвідношення називають *циклічним співвідношенням Вінера* (Cyclic Wiener Relationship). Воно стає ще зрозумілішим, якщо згадати, що CAF і SCF при :math:`\alpha = 0` відповідають автокореляції та PSD відповідно. SCF можна отримати простим перетворенням Фур’є CAF. Повернімося до нашого BPSK із 20 відліками на символ і розгляньмо SCF для правильного :math:`\alpha` (0.05 Гц). Все, що треба, — взяти FFT від CAF та побудувати модуль. Наведений нижче код доповнює попередній приклад, де ми обчислювали одне значення :math:`\alpha`: @@ -174,11 +174,11 @@ SCF можна отримати простим перетворенням Фур :target: ../_images/fft_of_caf.svg :alt: FFT від CAF -Зверніть увагу, що видно частотний зсув 0.2 Гц, який ми внесли під час симуляції BPSK (він не пов’язаний із циклічною частотою чи кількістю відліків на символ). Саме тому CAF у часовій області виглядав синусоїдальним — домінувала RF-частота, яка у нашому прикладі досить висока. +Зверніть увагу, що видно частотний зсув 0.2 Гц, який ми внесли під час симуляції сигналу BPSK (він не пов’язаний із циклічною частотою чи кількістю відліків на символ). Саме тому CAF у часовій області виглядав синусоїдальним — домінувала радіо-частота, яка у нашому прикладі досить висока. -На жаль, повторювати цю операцію для тисяч або мільйонів :math:`\alpha` надзвичайно витратно обчислювально. Інший недолік простого FFT від CAF — відсутність усереднення. Практичні алгоритми обчислення SCF зазвичай включають певне усереднення — за часом або частотою, як ми побачимо у двох наступних розділах. +На жаль, повторювати цю операцію надзвичайно витратно обчислювально для тисяч або мільйонів значень :math:`\alpha`. Інший недолік взятття просто FFT від CAF — відсутність усереднення. Ефективне та практичне обчислення SCF зазвичай передбачає певну форму усереднення — або за часом, або за частотою, — як ми побачимо в наступних двох розділах. -Нижче наведено інтерактивний JavaScript-додаток, що реалізує SCF та дозволяє експериментувати з різними параметрами сигналу і SCF, формуючи інтуїцію. Частота сигналу — доволі очевидний регулятор, він показує, наскільки добре SCF може визначити RF-частоту. Спробуйте вимкнути прямокутні імпульси (Rectangular Pulse) і попрацювати з різними коефіцієнтами згладжування (roll-off). Зауважте, що з типовим кроком по :math:`\alpha` не всі значення відліків на символ призведуть до видимого піку в SCF. Ви можете зменшити крок, але це збільшить час обробки. +Нижче наведено інтерактивний JavaScript-додаток, що реалізує SCF та дозволяє експериментувати з різними параметрами сигналу і SCF, для того щоб у вас з'явились певна інтуїція, як різні параметри впливають на результат. Частота сигналу — доволі очевидний параметр, він показує, наскільки добре SCF може визначити RF-частоту. Спробуйте вимкнути прямокутні імпульси (Rectangular Pulse) і попрацювати з різними коефіцієнтами згладжування (roll-off). Зауважте, що з типовим кроком по :math:`\alpha` не всі значення відліків на символ призведуть до видимого піку в SCF. Ви можете зменшити крок, але це збільшить час обробки. .. raw:: html @@ -232,10 +232,10 @@ SCF можна отримати простим перетворенням Фур ******************************** -Метод згладжування за частотою (FSM) +Метод частотного згладжування (Frequency Smoothing Method FSM) ******************************** -Тепер, коли ми маємо гарне інтуїтивне уявлення про SCF, розгляньмо, як обчислити її ефективно. Спершу пригадаємо періодограму — це просто квадрат модуля амплітуд перетворення Фур’є сигналу: +Тепер, коли ми маємо добре концептуальне розуміння SCF, розгляньмо, як можна ефективно його обчислювати. Спершу згадаємо періодограму — це просто квадрат модуля від перетворення Фур’є сигналу: .. math:: @@ -247,19 +247,19 @@ SCF можна отримати простим перетворенням Фур I(u,f,\alpha) = \frac{1}{N}X(u,f + \alpha/2) X^*(u,f - \alpha/2) -Обидва вирази є оцінками PSD та SCF, але щоб отримати істинне значення SCF, потрібно усереднити або за часом, або за частотою. Усереднення за часом відоме як метод згладжування за часом (TSM): +Обидва вирази є оцінками PSD та SCF, але щоб отримати істинне значення SCF, потрібно усереднити або за часом, або за частотою. Усереднення за часом відоме як часовий метод згладжування (TSM): .. math:: S_X(f, \alpha) = \lim_{T\rightarrow\infty} \frac{1}{T} \lim_{U\rightarrow\infty} \frac{1}{U} \int_{-U/2}^{U/2} X(t,f + \alpha/2) X^*(t,f - \alpha/2) dt -а усереднення за частотою називається методом згладжування за частотою (FSM): +а усереднення за частотою називається частотним методом згладжування (FSM): .. math:: S_X(f, \alpha) = \lim_{\Delta\rightarrow 0} \lim_{T\rightarrow \infty} \frac{1}{T} g_{\Delta}(f) \otimes \left[X(t,f + \alpha/2) X^*(t,f - \alpha/2)\right] -де функція :math:`g_{\Delta}(f)` виконує згладжування за невеликим діапазоном частот. +де функція :math:`g_{\Delta}(f)` виконує згладжування в невеликому діапазоні частот. -Нижче наведено мінімальну реалізацію FSM на Python — частотно-орієнтований метод усереднення для обчислення SCF сигналу. Спершу обчислюється циклічна періодограма через множення двох зсунених FFT, а потім кожен зріз фільтрується вікном, довжина якого визначає роздільну здатність отриманої оцінки SCF. Отже, довші вікна дають більш згладжений результат із нижчою роздільністю, коротші — навпаки. +Нижче наведено мінімальну реалізацію FSM на Python — частотно-орієнтований метод усереднення для обчислення SCF сигналу. Спершу обчислюється циклічна періодограма через множення двох зсунених FFT, а потім кожен зріз фільтрується у вікні, довжина якого визначає роздільну здатність отриманої оцінки SCF. Тобто, довші вікна дають більш згладжений результат із нижчою роздільністю, коротші — навпаки. .. code-block:: python @@ -290,15 +290,15 @@ SCF можна отримати простим перетворенням Фур .. image:: ../_images/scf_freq_smoothing.svg :align: center :target: ../_images/scf_freq_smoothing.svg - :alt: SCF, обчислена методом згладжування за частотою (FSM) + :alt: SCF, обчислена методом частотного згладжування (FSM) -Цей метод вимагає лише одного великого FFT, але потребує численних операцій згортки для згладжування. Зверніть увагу на проріджування після згортки :code:`[::Nw]`; воно не обов’язкове, але дуже бажане, щоб зменшити кількість пікселів для відображення, і завдяки способу обчислення SCF ми не «викидаємо» інформацію, проріджуючи по :code:`Nw`. +Цей метод має ту перевагу що вимагає лише одного великого FFT, але недолік - потребує численних операцій згортки для згладжування. Зверніть увагу на проріджування після згортки :code:`[::Nw]`; воно не обов’язкове, але дуже бажане, щоб зменшити кількість пікселів для відображення, і завдяки способу обчислення SCF ми не «викидаємо» інформацію, проріджуючи по :code:`Nw`. *************************** -Метод згладжування за часом (TSM) +Метод часового згладжування (Time Smoothing Method TSM) *************************** -Далі розглянемо реалізацію TSM у Python. Наведений нижче код ділить сигнал на *num_windows* блоків, кожен довжини *Nw* з перекриттям *Noverlap*. Зверніть увагу, що перекриття не є обов’язковим, але зазвичай дає приємніший результат. Сигнал множиться на віконну функцію (у цьому прикладі — вікно Ганна, але можна використовувати будь-яке) і береться FFT. Потім SCF обчислюється шляхом усереднення результатів для кожного блоку. Довжина вікна відіграє таку саму роль, як і в FSM, визначаючи компроміс між роздільністю та згладженістю. +Далі розглянемо реалізацію TSM на Python. Наведений нижче код ділить сигнал на *num_windows* блоків, кожен довжини *Nw* з перекриттям на *Noverlap* кількість відліків. Зверніть увагу, що перекриття не є обов’язковим, але зазвичай дає кращий результат. Сигнал множиться на віконну функцію (у нашому випадку — вікно Ганна, але можна використовувати будь-яке) і береться FFT. Потім SCF обчислюється шляхом усереднення результатів для кожного блоку. Довжина вікна відіграє таку саму роль, як і в FSM, визначаючи компроміс між роздільністю та згладженістю. .. code-block:: python @@ -336,7 +336,7 @@ SCF можна отримати простим перетворенням Фур Результат дуже схожий на FSM! ***************** -BPSK із формуванням імпульсу +BPSK із формуванням імпульсу Pulse-Shaped ***************** Досі ми розглядали CSP лише для *прямокутного* сигналу BPSK. Проте в реальних RF-системах майже ніколи не зустрінеш прямокутних імпульсів (виняток — чипова послідовність BPSK у DSSS, яка приблизно прямокутна). @@ -346,16 +346,16 @@ BPSK із формуванням імпульсу .. math:: h(t) = \mathrm{sinc}\left( \frac{t}{T} \right) \frac{\cos\left(\frac{\pi\beta t}{T}\right)}{1 - \left( \frac{2 \beta t}{T} \right)^2} -Параметр :math:`\beta` визначає, наскільки швидко фільтр спадає в часі, що обернено пропорційно швидкості спадання у частоті: +Параметр :math:`\beta` визначає, наскільки швидко фільтр спадає в часі, що обернено пропорційно швидкості спадання по частоті: .. image:: ../_images/raised_cosine_freq.svg :align: center :target: ../_images/raised_cosine_freq.svg - :alt: Частотна характеристика фільтра з піднятим косинусом для різних коефіцієнтів roll-off + :alt: Частотна характеристика фільтра з піднятим косинусом для різних коефіцієнтів спадання roll-off -Зверніть увагу: :math:`\beta=0` відповідає нескінченно довгому імпульсу, тож такий варіант непрактичний. Також :math:`\beta=1` *не* означає прямокутний імпульс. На практиці коефіцієнт roll-off зазвичай вибирають у діапазоні 0.2–0.4. +Зверніть увагу: :math:`\beta=0` відповідає нескінченно високому імпульсу, тож такий варіант непрактичний. Також :math:`\beta=1` *не* означає прямокутний імпульс. На практиці коефіцієнт спадання roll-off зазвичай вибирають у діапазоні 0.2–0.4. -Змоделювати сигнал BPSK із формуванням імпульсу RC можна наступним кодом; зауважте, що перші 5 рядків і останні 4 — ті самі, що й для прямокутного BPSK: +Змоделювати сигнал BPSK із формуванням імпульсу з RC можна за допомогою наступного коду; зауважте, що перші 5 рядків і останні 4 — ті самі, що й для прямокутного BPSK: .. code-block:: python @@ -381,7 +381,7 @@ BPSK із формуванням імпульсу noise = np.random.randn(N) + 1j*np.random.randn(N) # complex white Gaussian noise samples = bpsk + 0.1*noise # add noise to the signal -Змінна :code:`pulse_train` — це наші символи, між якими вставлено :code:`sps - 1` нулів, напр.: +Зауважте, що змінна :code:`pulse_train` — це наші символи, між якими вставлено :code:`sps - 1` нулів, напр.: .. code-block:: bash @@ -395,9 +395,9 @@ BPSK із формуванням імпульсу .. image:: ../_images/pulse_shaped_BSPK.svg :align: center :target: ../_images/pulse_shaped_BSPK.svg - :alt: Сигнал BPSK із формуванням імпульсу RC + :alt: Сигнал BPSK із формуванням імпульсу з RC -Обчислимо SCF цього сигналу з коефіцієнтом roll-off 0.3, 0.6 та 0.9. Використаємо той самий частотний зсув 0.2 Гц і реалізацію FSM з тими самими параметрами, що й у прикладі з прямокутним BPSK, для чесного порівняння: +Обчислимо SCF цього сигналу з коефіцієнтом roll-off 0.3, 0.6 та 0.9. для чесного порівняння використаємо той самий частотний зсув 0.2 Гц і реалізацію FSM з тими самими параметрами, що й у прикладі з прямокутним BPSK: :code:`beta = 0.3`: @@ -420,13 +420,13 @@ BPSK із формуванням імпульсу :target: ../_images/scf_freq_smoothing_pulse_shaped_bpsk3.svg :alt: SCF сигналу BPSK із формуванням імпульсу (FSM), beta = 0.9 -В усіх трьох випадках ми більше не бачимо бічних пелюсток на осі частоти, а на осі циклічної частоти відсутні потужні гармоніки базової циклічної частоти. Це тому, що RC-фільтр забезпечує набагато краще обмеження спектра порівняно з прямокутними імпульсами, тож бічні пелюстки значно слабші. У результаті сигнали з формуванням імпульсу мають набагато «чистішу» SCF, схожу на один пік із розмиттям над ним. Це стосується всіх одноносійних цифрових сигналів, не лише BPSK. Зі збільшенням :math:`\beta` пік на осі частоти розширюється, оскільки сигнал займає більшу смугу. +В усіх трьох випадках ми більше не бачимо бічних пелюсток по осі частоти, а на осі циклічної частоти відсутні потужні гармоніки базової циклічної частоти. Це тому, що RC-фільтр забезпечує набагато краще обмеження спектра порівняно з прямокутними імпульсами, тож бічні пелюстки значно слабші. У результаті сигнали з формуванням імпульсу мають набагато «чистішу» SCF, схожу на один пік із розмиттям над ним. Це стосується всіх цифрових сигналів з одною несучою частотою, не лише BPSK. Зі збільшенням :math:`\beta` пік на осі частоти розширюється, оскільки сигнал займає більшу смугу. ******************************** SNR та кількість символів ******************************** -Незабаром! Ми розглянемо, чому після певного порогу збільшення SNR не допомагає — натомість потрібна більша кількість символів, і як пакетні хвилі призводять до обмеженої кількості символів у передачі. +Незабаром! Ми розглянемо, чому після певного порогу збільшення SNR не допомагає — натомість потрібна більша кількість символів, і як пакетні форми сигналів призводять до обмеженої кількості символів у передачі. ******************************** QPSK та модуляції вищих порядків @@ -435,25 +435,25 @@ QPSK та модуляції вищих порядків Незабаром! У розділі буде QPSK, вищі порядки PSK, QAM та короткий вступ до циклічних моментів і кумулянтів вищих порядків. ******************************** -Кілька перекривних сигналів +Кілька сигналів, що перекриваються ******************************** -Досі ми розглядали по одному сигналу, але що, якщо в отриманому сигналі одночасно присутні кілька сигналів, які перекриваються за частотою, часом і навіть циклічною частотою (тобто мають однакову кількість відліків на символ)? Якщо сигнали зовсім не перекриваються в частоті, можна застосувати просте фільтрування та PSD для їх виявлення (за умови, що вони вище шумового порога). Якщо вони не перекриваються в часі, можна визначити моменти увімкнення/вимкнення кожної передачі й обробляти кожну окремо. У CSP нас зазвичай цікавить виявлення сигналів на різних циклічних частотах, які перекриваються одночасно і за часом, і за частотою. +Досі ми розглядали один сигнал, але що буде, якщо в отриманому сигналі одночасно присутні кілька сигналів, які перекриваються по частоті та часу і навіть по циклічній частоті (тобто мають однакову кількість відліків на символ)? Якщо сигнали зовсім не перекриваються по частоті, можна застосувати просте фільтрування та PSD для їх виявлення (за умови, що сигнали вище шумового порога). Якщо сигнали не перетинаються в часі, можна визначити моменти увімкнення/вимкнення кожної передачі, а потім обробляти кожен сигнал окремо. У CSP нас зазвичай цікавить виявлення сигналів на різних циклічних частотах, які перекриваються одночасно і по часу, і по частоті. Змоделюємо три сигнали з різними властивостями: -* Сигнал 1: прямокутний BPSK із 20 відліками на символ і частотним зсувом 0.2 Гц -* Сигнал 2: BPSK із формуванням імпульсу, 20 відліків на символ, частотний зсув -0.1 Гц, коефіцієнт roll-off 0.35 -* Сигнал 3: QPSK із формуванням імпульсу, 4 відліки на символ, частотний зсув 0.2 Гц, коефіцієнт roll-off 0.21 +* Сигнал 1: прямокутний BPSK з 20 відліками на символ і частотним зсувом 0.2 Гц +* Сигнал 2: BPSK із формуванням імпульсу, 20 відліків на символ, частотний зсув -0.1 Гц, коефіцієнт спадання roll-off 0.35 +* Сигнал 3: QPSK із формуванням імпульсу, 4 відліки на символ, частотний зсув 0.2 Гц, коефіцієнт спадання roll-off 0.21 -Отже, маємо два сигнали з однаковою циклічною частотою та два — з однаковою RF-частотою. Це дозволить дослідити різні ступені перекриття параметрів. +Отже, маємо два сигнали з однаковою циклічною частотою та два — з однаковою радіо-частотою. Це дозволить дослідити різні ступені перекриття параметрів. -До кожного сигналу додається фільтр дробової затримки з довільною (нецілою) затримкою, щоб уникнути артефактів, пов’язаних із синхронним розташуванням відліків (докладніше про це в розділі :ref:`sync-chapter`). Потужність прямокутного BPSK зменшено порівняно з двома іншими, оскільки сигнали з прямокутними імпульсами мають дуже виражені циклічно-стаціонарні властивості й схильні домінувати в SCF. +До кожного сигналу додається фільтр дробової затримки з довільною (нецілою) затримкою. Це треба, щоб уникнути артефактів, пов’язаних із синхронним розташуванням відліків (докладніше дивись про це в розділі :ref:`sync-chapter`). Потужність прямокутного BPSK зменшено порівняно з двома іншими, оскільки сигнали з прямокутними імпульсами мають дуже виражені циклічно-стаціонарні властивості й схильні домінувати в SCF. .. raw:: html
    - Показати код Python для симуляції трьох сигналів + Код Python для симуляції трьох сигналів .. code-block:: python @@ -524,15 +524,15 @@ QPSK та модуляції вищих порядків .. image:: ../_images/scf_freq_smoothing_pulse_multiple_signals.svg :align: center :target: ../_images/scf_freq_smoothing_pulse_multiple_signals.svg - :alt: SCF трьох сигналів, обчислена методом згладжування за частотою (FSM) + :alt: SCF трьох сигналів, обчислена методом частотного згладжування (FSM) -Зауважте, що сигнал 1, хоч і з прямокутними імпульсами, переважно маскується «конусом» над сигналом 3. На PSD сигнал 1 «ховався» за сигналом 3. Завдяки CSP ми можемо виявити присутність сигналу 1 та приблизно визначити його циклічну частоту, яку потім можна використати для синхронізації. Ось у чому сила циклічно-стаціонарної обробки! +Зауважте, що сигнал 1, хоч він і з прямокутними імпульсами, і має гармоніки, але вони переважно маскуються «конусом» сигналом 3. PSD сигнал 3 «ховає» сигналом 1. Завдяки CSP ми можемо виявити присутність сигналу 1 та приблизно визначити його циклічну частоту, яку потім можна використати для синхронізації. Ось у чому сила циклічно-стаціонарної обробки! ************************ Альтернативні ознаки CSP ************************ -SCF — не єдиний спосіб виявляти циклічно-стаціонарність сигналу, особливо якщо вам не потрібно розглядати циклічну частоту як функцію RF-частоти. Проста (і концептуально, і обчислювально) техніка передбачає взяття **FFT від модуля** сигналу й пошук піків. У Python це виглядає так: +SCF — не єдиний спосіб виявляти для сигналу його циклічно-стаціонарність, особливо якщо вам не потрібно розглядати циклічну частоту з прив'язкою до радіочастоти. Простий (і концептуально, і з точки зору обчислювальних ресурсів) метод передбачає взяття **FFT від амплідтуд** сигналу й пошук піків. На Python це виглядає так: .. code-block:: python @@ -540,9 +540,9 @@ SCF — не єдиний спосіб виявляти циклічно-ста #samples_mag = samples * np.conj(samples) # pretty much the same as line above magnitude_metric = np.abs(np.fft.fft(samples_mag)) -Зверніть увагу, що цей метод еквівалентний множенню сигналу на власне комплексне спряження з наступним взяттям FFT. +Зверніть увагу, що цей метод еквівалентний множенню сигналу на власне комплексне спряження з подальшим взяттям FFT. -Перед побудовою графіка занулімо DC-компонент, бо вона містить багато енергії й псує динамічний діапазон. Також відкиньмо половину виходу FFT, оскільки вхід реальний, а отже результат симетричний. Після цього можна побудувати графік і побачити піки: +Перед побудовою графіка усунемо постійну складову з сигналу, бо вона містить багато енергії й псує динамічний діапазон. Також відкиньмо половину виходу FFT, оскільки на вході в нас дійсні значне, а отже вихідний результат буде симетричний. Після цього можна побудувати графік і побачити піки: .. code-block:: python @@ -551,18 +551,18 @@ SCF — не єдиний спосіб виявляти циклічно-ста f = np.linspace(-0.5, 0.5, len(samples)) plt.plot(f, magnitude_metric) -Далі можна застосувати алгоритм пошуку піків, наприклад :code:`signal.find_peaks()` зі SciPy. На рисунку нижче показано :code:`magnitude_metric` для кожного з трьох сигналів із попереднього розділу (спершу окремо, потім разом): +Далі можна застосувати алгоритм пошуку піків, наприклад :code:`signal.find_peaks()` зі SciPy. На рисунку нижче показано :code:`magnitude_metric` для кожного з трьох сигналів із попереднього розділу (спершу показан результат для кожного сигналу окремого, потім результат для їх суми): .. image:: ../_images/non_csp_metric.svg :align: center :target: ../_images/non_csp_metric.svg :alt: Метрика для виявлення циклічно-стаціонарності без використання CAF чи SCF -Гармоніки прямокутного BPSK, на жаль, перекриваються з циклічними частотами інших сигналів — це демонструє недолік цього альтернативного підходу: він не дозволяє розглядати циклічну частоту як функцію RF-частоти, як це робить SCF. +Гармоніки прямокутного BPSK, на жаль, перекриваються з циклічними частотами інших сигналів і це демонструє недолік цього альтернативного підходу: він не дозволяє розглядати циклічну частоту з прив'язкою до радіочастоти, як це може робить SCF. -Хоч цей метод і використовує циклічно-стаціонарність сигналів, його зазвичай не відносять до «технік CSP», можливо, через простоту... +Хоч цей метод і використовує циклічну-стаціонарність сигналів, його зазвичай не відносять до «технік CSP», можливо, через простоту... -Для пошуку RF-частоти сигналу, тобто зсуву несучої, існує схожий прийом. Для сигналів BPSK достатньо взяти FFT від сигналу у квадраті (вхід FFT буде комплексним). Це дасть пік на частоті, що дорівнює подвоєному зсуву несучої. Для QPSK можна взяти FFT від сигналу в четвертій степені й отримати пік на частоті, що дорівнює зсуву несучої, помноженому на 4. +Для пошуку RF-частоти сигналу, тобто зсуву несучої, існує схожий прийом. Для сигналів BPSK достатньо взяти FFT від сигналу у квадраті (вхідні значення для FFT буде комплексними значеннями). Це дасть пік на частоті, що дорівнює подвоєному зсуву несучої. Для QPSK можна взяти FFT від сигналу в четвертій степені й отримати пік на частоті, що дорівнює зсуву несучої, помноженому на 4. .. code-block:: python @@ -574,35 +574,35 @@ SCF — не єдиний спосіб виявляти циклічно-ста quartic_metric = np.abs(np.fft.fftshift(np.fft.fft(samples_quartic)))/len(samples) quartic_metric[len(quartic_metric)//2] = 0 # null out the DC component -Спробуйте цей метод на своїх симульованих чи записаних сигналах — він дуже корисний і поза CSP. +Спробуйте цей метод на своїх синтизованих чи записаних сигналах — він дуже корисний і поза межами CSP. ********************************* -Функція спектральної когерентності (COH) +Функція спектральної когерентності (Spectral Coherence Function COH) ********************************* *Коротко: функція спектральної когерентності — це нормалізована версія SCF, яка в деяких випадках є кориснішою за звичайну SCF.* -Ще одна міра циклічно-стаціонарності, що в багатьох випадках може дати більше інформації, ніж «сире» SCF, — це функція спектральної когерентності (COH). COH нормалізує SCF так, що результат лежить у діапазоні від -1 до 1 (ми розглядатимемо модуль, тобто 0–1). Це корисно, адже із результату вилучається інформація про спектр потужності сигналу, яку містить «сире» SCF. Нормалізація залишає лише впливи циклічної кореляції. +Ще однією мірою циклостаціонарності, яка в багатьох випадках може бути більш інформативною, ніж «необробленій» SCF, є спектральна функція когерентності (Spectral Coherence Function, COH). COH отримують шляхом нормалізації SCF таким чином, що результат лежить у межах від −1 до 1 (хоча надалі ми розглядатимемо модуль, який знаходиться в діапазоні від 0 до 1). Це корисно, оскільки COH відокремлює інформацію про циклостаціонарні властивості сигналу від інформації про його спектр потужності, обидві з яких присутні в необробленій SCF. Завдяки нормалізації вплив спектра потужності усувається, і в результаті залишаються лише ефекти циклічної кореляції. -Щоб краще зрозуміти COH, згадаємо `коефіцієнт кореляції `_ зі статистики. Коефіцієнт кореляції :math:`\rho_{X,Y}` вимірює зв’язок між двома випадковими величинами :math:`X` і :math:`Y` у діапазоні -1…1. Він визначається як ковариація, поділена на добуток стандартних відхилень: +Щоб краще зрозуміти COH, згадаємо що таке `коефіцієнт кореляції `_ зі статистики. Коефіцієнт кореляції :math:`\rho_{X,Y}` вимірює зв’язок між двома випадковими величинами :math:`X` і :math:`Y` у діапазоні -1…1. Він визначається як ковариація, поділена на добуток стандартних відхилень: .. math:: \rho_{X,Y} = \frac{E[(X-\mu_X)(Y-\mu_Y)]}{\sigma_X \sigma_Y} -COH розширює цю концепцію на спектральну кореляцію: він оцінює, наскільки PSD сигналу на одній частоті пов’язана з PSD того самого сигналу на іншій частоті. Ці дві частоти — це частотні зсуви, які ми застосовуємо під час обчислення SCF. Щоб обчислити COH, спершу обчислюємо SCF (позначимо його :math:`S_X(f,\alpha)`), а потім нормалізуємо, поділивши на добуток двох зсунених PSD, аналогічно до поділу на добуток стандартних відхилень: +COH позширює цю концепцію на спектральну кореляцію: він оцінює, наскільки PSD сигналу на одній частоті пов’язана з PSD того самого сигналу на іншій частоті. Ці дві частоти — це частотні зсуви, які ми застосовуємо під час обчислення SCF. Щоб обчислити COH, спершу обчислюємо SCF (позначимо його :math:`S_X(f,\alpha)`), а потім нормалізуємо, поділивши на добуток двох зсунених PSD, аналогічно до поділу на добуток стандартних відхилень: .. math:: \rho = C_x(f, \alpha) = \frac{S_X(f,\alpha)}{\sqrt{C_x^0(f + \alpha/2) C_x^0(f - \alpha/2)}} -Знаменник — ключовий новий елемент: :math:`C_x^0(f + \alpha/2)` та :math:`C_x^0(f - \alpha/2)` — це PSD, зсунуті на :math:`\alpha/2` та :math:`-\alpha/2`. Іншими словами, SCF — це крос-спектральна густина (спектр потужності з двома вхідними сигналами), а нормувальні члени в знаменнику — автоспектральні густини (спектри потужності для одного сигналу). +Знаменник це ключовий новий елемент: :math:`C_x^0(f + \alpha/2)` та :math:`C_x^0(f - \alpha/2)` — це просто PSD, зсунуті на :math:`\alpha/2` та :math:`-\alpha/2`. Іншими словами, SCF — це крос-спектральна густина (спектр потужності з двома вхідними сигналами), а нормувальні члени в знаменнику — автоспектральні густини (спектри потужності для одного вхідного сигналу). -Застосуймо це до нашого коду, зокрема до SCF, обчисленого методом FSM. Оскільки FSM виконує усереднення в частотній області, ми вже маємо :math:`C_x^0(f + \alpha/2)` та :math:`C_x^0(f - \alpha/2)`, які в коді відповідають :code:`np.roll(X, -shift)` та :code:`np.roll(X, shift)`, адже :code:`X` — це FFT сигналу. Тож залишилось перемножити їх, взяти корінь і поділити зріз SCF на цей результат (зверніть увагу, що це відбувається всередині циклу за :math:`\alpha`): +Застосуймо це в нашому коді для отримання, зокрема до SCF, обчисленого методом FSM. Оскільки FSM виконує усереднення в частотній області, ми вже маємо :math:`C_x^0(f + \alpha/2)` та :math:`C_x^0(f - \alpha/2)`, рядки які в коді відповідають за це обчислиння :code:`np.roll(X, -shift)` та :code:`np.roll(X, shift)`, адже :code:`X` — це FFT сигналу. Тож залишилось перемножити їх, взяти корінь і поділити зріз SCF на цей результат (зверніть увагу, що це відбувається всередині циклу по :math:`\alpha`): .. code-block:: python COH_slice = SCF_slice / np.sqrt(np.roll(X, -shift) * np.roll(X, shift)) -Нарешті повторимо згортку та проріджування, як і для SCF: +Після чого повторимо згортку та проріджування, як і для фінального нарізання SCF: .. code-block:: python @@ -653,21 +653,21 @@ COH розширює цю концепцію на спектральну кор
    -Обчислимо COH (та звичайну SCF) для прямокутного BPSK із 20 відліками на символ і частотним зсувом 0.2 Гц: +Тепер обчислимо COH (а також звичайну SCF) для прямокутного BPSK із 20 відліками на символ і частотним зсувом 0.2 Гц: .. image:: ../_images/scf_coherence.svg :align: center :target: ../_images/scf_coherence.svg :alt: SCF і COH прямокутного сигналу BPSK із 20 відліками на символ і зсувом 0.2 Гц -Бачимо, що в COH значно виразніші високі значення :math:`\alpha`, ніж у SCF. Якщо запустити той самий код для BPSK із формуванням імпульсу, різниця буде не такою помітною: +Бачимо, що порівняно з SCF в COH значно виразніші високі значення :math:`\alpha`. Якщо запустити той самий код для BPSK із формуванням імпульсу, різниця буде не такою помітною: .. image:: ../_images/scf_coherence_pulse_shaped.svg :align: center :target: ../_images/scf_coherence_pulse_shaped.svg :alt: SCF і COH сигналу BPSK з формуванням імпульсу, 20 відліків на символ, зсув 0.2 Гц -Спробуйте обчислити SCF і COH для вашої задачі, щоб визначити, який варіант підходить краще! +Спробуйте обчислити SCF і COH для вашої задачі, щоб визначити, який варіант вам підходить краще! ********** Спряжені варіанти @@ -679,7 +679,7 @@ COH розширює цю концепцію на спектральну кор R_x(\tau,\alpha) = \lim_{T\rightarrow\infty} \frac{1}{T} \int_{-T/2}^{T/2} x(t + \tau/2)x^*(t - \tau/2)e^{-j2\pi \alpha t}dt \\ S_X(f,\alpha) = \lim_{T\rightarrow\infty} \frac{1}{T} \lim_{U\rightarrow\infty} \frac{1}{U} \int_{-U/2}^{U/2} X(t,f + \alpha/2) X^*(t,f - \alpha/2) dt -Однак існує альтернативна форма CAF і SCF без спряження. Їх називають *спряженою CAF* та *спряженою SCF*. Назва трохи заплутана, але головне пам’ятати, що існує «звичайна» версія CAF/SCF і спряжена версія. Спряжені варіанти дозволяють отримати більше інформації із сигналу, але не завжди потрібні залежно від ситуації. Визначення спряжених функцій: +Однак існує альтернативна форма знаходження CAF і SCF без спряження. Ці форми відповідно називають *спряженою CAF* та *спряженою SCF*. Назва трохи заплутає, але головне пам’ятати, що існує «звичайна» версія CAF/SCF і спряжена версія. Спряжені варіанти дозволяють отримати більше інформації із сигналу, але залежно від ситуації не завжди потрібні. Визначення спряжених функцій наступне: .. math:: R_{x^*}(\tau,\alpha) = \lim_{T\rightarrow\infty} \frac{1}{T} \int_{-T/2}^{T/2} x(t + \tau/2)x(t - \tau/2)e^{-j2\pi \alpha t}dt \\ @@ -692,21 +692,21 @@ COH розширює цю концепцію на спектральну кор .. math:: y(t) = x_I(t) \cos(2\pi f_c t + \phi) + x_Q(t) \sin(2\pi f_c t + \phi) -де :math:`x_I(t)` та :math:`x_Q(t)` — відповідно інфазна та квадратурна компоненти сигналу, тобто IQ-відліки, які ми обробляємо на базовій частоті. +де :math:`x_I(t)` та :math:`x_Q(t)` — відповідно інфазна та квадратурна компоненти сигналу, тобто IQ-відліки немодульованого сигналу, який ми обробляємо за допомогою СSP. Використовуючи формулу Ейлера :math:`e^{jx} = \cos(x) + j \sin(x)`, перепишемо вище наведений вираз через комплексні експоненти: .. math:: y(t) = \frac{x_I(t) - j x_Q(t)}{2} e^{j 2\pi f_c t + j \phi} + \frac{x_I(t) + j x_Q(t)}{2} e^{-j 2\pi f_c t - j \phi} -Можемо представити реальний сигнал :math:`y(t)` через комплексну огинаючу :math:`z(t)`, припускаючи, що смуга сигналу значно вужча за несучу :math:`f_c`, що типовою для RF-застосувань: +Можемо представити реальний сигнал :math:`y(t)` через комплексну огинаючу :math:`z(t)`, припускаючи, що смуга сигналу значно вужча за несучу :math:`f_c`, що типово для радіо-сигналів: .. math:: y(t) = z(t) e^{j 2 \pi f_c t + j \phi} + z^*(t) e^{-j 2 \pi f_c t - j \phi} -Це називається комплексно-базовим представленням. +Це називається комплексним представленням немодульованого сигналу (complex-baseband representation). -Повернімося до CAF і спробуймо обчислити «лаговий добуток», тобто частину :math:`x(t + \tau/2) x(t - \tau/2)`: +Повернімося до CAF і спробуймо обчислити «добуток затримок», тобто частину :math:`x(t + \tau/2) x(t - \tau/2)`: .. math:: \left(z(t + \tau/2) e^{j 2 \pi f_c (t + \tau/2) + j \phi} + z^*(t + \tau/2) e^{-j 2 \pi f_c (t + \tau/2) - j \phi}\right) \times \\ @@ -722,18 +722,18 @@ COH розширює цю концепцію на спектральну кор Виявляється, що перший та четвертий доданки по суті несуть однакову інформацію, як і другий із третім. Тож залишаються дві справді важливі комбінації — зі спряженням і без нього. Підсумовуючи: щоб отримати всю статистичну інформацію зі :math:`y(t)`, потрібно розглянути всі комбінації спряжених та неспряжених членів. -Щоб реалізувати спряжену SCF методом FSM, потрібно зробити ще один крок понад просте видалення :code:`conj()`, адже ми беремо один великий FFT і усереднюємо в частотній області. Існує властивість перетворення Фур’є: комплексне спряження у часовій області відповідає перевернутому й спряженому спектру: +Щоб реалізувати спряжену SCF методом FSM, потрібно зробити ще один крок окрім простого видалення :code:`conj()`, адже ми беремо один великий FFT і потім усереднюємо в частотній області. Існує властивість перетворення Фур’є: комплексне спряження у часовій області відповідає перевернутому й спряженому спектру: .. math:: x^*(t) \leftrightarrow X^*(-f) -Оскільки в звичайній SCF ми вже брали комплексне спряження другого множника (пригадайте код :code:`SCF_slice = np.roll(X, -shift) * np.conj(np.roll(X, shift))`), при додатковому спряженні воно просто зникає, і залишається таке: +Оскільки при обчислеині звичайного SCF ми вже брали комплексне спряження другого множника (пригадайте код :code:`SCF_slice = np.roll(X, -shift) * np.conj(np.roll(X, shift))`), то при додатковому спряженні воно просто зникає, і залишається наступне: .. code-block:: python SCF_slice = np.roll(X, -shift) * np.flip(np.roll(X, -shift - 1)) -Зверніть увагу на доданий :code:`np.flip()` та те, що зсув :code:`roll()` відбувається в протилежному напрямку. Повна реалізація FSM для спряженої SCF виглядає так: +Зверніть увагу на доданий :code:`np.flip()` та те, що зсув :code:`roll()` відбувається в протилежному напрямку. Повна реалізація FSM для спряженої SCF виглядає наступним чином: .. code-block:: python @@ -758,7 +758,7 @@ COH розширює цю концепцію на спектральну кор plt.ylabel('Cyclic Frequency [Normalized Hz]') plt.show() -Ще одна важлива відмінність спряженої SCF — необхідність обчислювати :math:`\alpha` у діапазоні від -1 до +1, тоді як у звичайній SCF ми використовували 0.0–0.5 через симетрію. Ви зрозумієте чому, коли побачите приклади спряженої SCF. +Ще одна важлива відмінність спряженої SCF — це необхідність обчислювати :math:`\alpha` у діапазоні від -1 до +1, тоді як у звичайній SCF ми використовували 0.0–0.5 через симетрію. Ви побачите, чому саме так, на практиці, коли почнемо розглядати спряжену SCF для сигналів прикладів. Що ж нам дає спряжена SCF? Для початку подивімося на спряжену SCF нашого базового прямокутного BPSK із 20 відліками на символ (циклічна частота 0.05 Гц) і частотним зсувом 0.2 Гц: @@ -767,12 +767,12 @@ COH розширює цю концепцію на спектральну кор :target: ../_images/scf_conj_rect_bpsk.svg :alt: Спряжена SCF прямокутного BPSK, обчислена методом FSM -Головний висновок: у спряженій SCF з’являються піки на циклічній частоті +/- **подвійний** зсув несучої, позначимо його :math:`f_c`. На осі частоти вони зосереджені навколо 0 Гц, а не :math:`f_c`. У нашому прикладі :math:`f_c = 0.2` Гц, тож спостерігаємо піки на 0.4 +/- 0.05 Гц. Якщо запам’ятати щось одне про спряжену SCF, то це таке співвідношення: +Головний висновок: у спряженій SCF з’являються піки з'являються на циклічній частоті +/- **подвійний** зсув несучої, який ми позначимо як :math:`f_c`. На осі частоти спряжена SCF зосереджена навколо 0 Гц, а не :math:`f_c`. У нашому прикладі :math:`f_c = 0.2` Гц, тож спостерігаємо піки на 0.4 +/- 0.05 Гц. Основне запам’ятати про спряжену SCF те, що піки знаходяться на: .. math:: 2f_c \pm \alpha -Розгляньмо BPSK із формуванням імпульсу з тими ж параметрами (зсув 0.2 Гц, 20 відліків на символ, roll-off 0.3): +Розгляньмо BPSK із формуванням імпульсу з тими ж параметрами (зсув 0.2 Гц, 20 відліків на символ, з коефіцієнтом згасання roll-off 0.3): .. image:: ../_images/scf_conj_pulseshaped_bpsk.svg :align: center @@ -788,7 +788,7 @@ COH розширює цю концепцію на спектральну кор :target: ../_images/scf_conj_rect_qpsk.svg :alt: Спряжена SCF прямокутного QPSK, обчислена методом FSM -Спершу може здатися, що в коді помилка, але погляньте на кольорову шкалу — вона показує, які значення відповідають кольорам. Якщо використовувати :code:`plt.imshow()` зі стандартним масштабуванням, треба пам’ятати, що кольори (у нас — від фіолетового до жовтого) завжди масштабуються від мінімального до максимального значення вхідного 2D-масиву. У випадку спряженої SCF QPSK весь результат дуже малий, адже *піки відсутні*. Ось той самий результат, але зі шкалою, як у попередніх прикладах BPSK: +Спершу може здатися, що в коді помилка, але погляньте на кольорову шкалу — вона показує, які значення відповідають яким кольорам. Якщо використовувати :code:`plt.imshow()` зі стандартним масштабуванням, треба пам’ятати, що кольори (у нас — від фіолетового до жовтого) завжди масштабуються від мінімального до максимального значення вхідного 2D-масиву. У випадку спряженої SCF QPSK весь результат дуже малий, адже *піки відсутні*. Ось той самий результат, але зі шкалою, як у попередніх прикладах з BPSK: .. image:: ../_images/scf_conj_rect_qpsk_scaled.svg :align: center @@ -797,7 +797,7 @@ COH розширює цю концепцію на спектральну кор Зверніть увагу на діапазон кольорової шкали. -Спряжена SCF для QPSK, а також для PSK та QAM вищих порядків, фактично дорівнює нулю/шуму. Це означає, що спряжену SCF можна використати для виявлення сигналів BPSK (наприклад, чипової послідовності в DSSS), навіть якщо одночасно присутні численні сигнали QPSK/QAM. Дуже потужний інструмент у наборі CSP! +Спряжена SCF для QPSK, а також для PSK та QAM вищих порядків, фактично дорівнює нулю або шуму. Це означає, що спряжену SCF можна використати для виявлення сигналів BPSK (наприклад, чипової послідовності в DSSS), навіть якщо одночасно присутні численні сигнали QPSK/QAM. Це дуже потужний інструмент CSP! Розгляньмо спряжену SCF для сценарію з трьома сигналами, який ми використовували раніше: @@ -810,7 +810,7 @@ COH розширює цю концепцію на спектральну кор :target: ../_images/scf_conj_multiple_signals.svg :alt: Спряжена SCF трьох сигналів, обчислена методом FSM -Бачимо обидва сигнали BPSK, а сигнал QPSK не проявляється — інакше ми б побачили пік на :math:`\alpha = 0.65` та 0.15 Гц. Якщо придивитися, видно піки на 0.4 +/- 0.05 Гц і -0.2 +/- 0.05 Гц. +Бачимо обидва сигнали BPSK, а сигнал QPSK не проявляється — інакше ми б побачили пік на :math:`\alpha = 0.65` та 0.15 Гц. Якщо придивитися при збільшені, видно піки на 0.4 +/- 0.05 Гц і -0.2 +/- 0.05 Гц. ******************************** Метод накопичення FFT (FAM) diff --git a/content-zh/about_author.rst b/content-zh/about_author.rst index a32f2baa..9129f666 100644 --- a/content-zh/about_author.rst +++ b/content-zh/about_author.rst @@ -8,16 +8,15 @@ 专长于 SDR(软件定义无线电),机器学习,LTE/5G-NR,以及频谱感知。 他是马里兰大学的兼职教授,在那里他创立了一门课程,该课程成为了他编写这本教科书的基础。 他的课程是一个面向对 SDR/DSP(数字信号处理)感兴趣的计算机科学本科生的四年级选修课。 -这门课程使他更好地了解了如何深入浅出地吸引并教会那些编程能力很强但几乎不了解物理层知识的学生。 +这门课程使他更好地了解了如何深入浅出地吸引并教会那些编程能力很强但几乎没有无线通信和信号处理背景的学生。 在马克的课程中遇到迷你黑客马拉松并不奇怪,学生们必须利用他们最近学到的知识来找到或解码(由 Marc 发送)的隐藏的信号。 Marc 也是 `GNU Radio项目 `_ 的主要负责人之一。 GNU Radio 是一个开源的 SDR 框架,在学术界和国防相关研究中被广泛应用。 -虽然 Python 非常适合学习、快速实验和开发,但它并不适合大型和计算复杂的应用程序。 -GNU Radio 能够实现更高级的 DSP 应用程序,而且使用 GNU Radio 开发的 App 或单独的 Block 非常容易与他人共享。 +GNU Radio 可以用来实现更高级的 DSP 应用程序,而且使用 GNU Radio 开发的 App 或单独的 Block 非常容易与他人共享。 -Marc 目前和他的妻子 Lindsey 以及他们的多只猫和狗一起住在华盛顿特区地区。 -他的爱好包括木工制作、激光切割、演奏单簧管/萨克斯风、帆船、园艺、制作/操纵无人机、制作/骑行电动滑板,以及钻研高级溜溜球技巧。 +Marc 目前和他的妻子以及他们的多只猫和狗一起住在华盛顿特区地区。 +他的爱好包括木工制作、机加工、激光切割、单簧管/萨克斯风、帆船、园艺和弹球机。 邮箱: marc@pysdr.org diff --git a/content-zh/bladerf.rst b/content-zh/bladerf.rst new file mode 100644 index 00000000..2c72fe4d --- /dev/null +++ b/content-zh/bladerf.rst @@ -0,0 +1,458 @@ +.. _bladerf-chapter: + +###################### +Python 玩转 bladeRF +###################### + +`Nuand `_ 推出的 bladeRF 2.0(也叫 bladeRF 2.0 micro)是一款基于 USB 3.0 的 SDR,具备两路接收通道、两路发射通道,可调谐频率范围为 47 MHz 到 6 GHz,最高可支持 61 MHz 的采样率,经过 hack 后甚至可以到 122 MHz。 +它和 USRP B210 以及 PlutoSDR 一样,使用的是 AD9361 射频集成电路(RFIC),因此射频性能会比较接近。 +bladeRF 2.0 于 2021 年发布,尺寸保持在 2.5" x 4.5" 的小体积,并提供两种不同 FPGA 容量的版本(xA4 和 xA9)。 +虽然本章聚焦于 bladeRF 2.0,但其中不少代码同样适用于最早 `于 2013 年推出 `_ 的初代 bladeRF。 + +.. image:: ../_images/bladeRF_micro.png + :scale: 35 % + :align: center + :alt: bladeRF 2.0 宣传照 + +******************************** +bladeRF 架构 +******************************** + +从高层来看,bladeRF 2.0 基于 AD9361 RFIC,搭配 Cyclone V FPGA(49 kLE 的 :code:`5CEA4` 或 301 kLE 的 :code:`5CEA9`),以及一颗 Cypress FX3 USB 3.0 控制器,其内部带有 200 MHz 的 ARM9 核,并加载了定制固件。 +bladeRF 2.0 的方框图如下所示: + +.. image:: ../_images/bladeRF-2.0-micro-Block-Diagram-4.png + :scale: 80 % + :align: center + :alt: bladeRF 2.0 方框图 + +FPGA 负责控制 RFIC、执行数字滤波、将数据打包后通过 USB 传输(以及其他一些工作)。 +FPGA 镜像的 `源代码 `_ 使用 VHDL 编写,如果你想编译自定义镜像,则需要使用免费的 Quartus Prime Lite 设计软件。 +预编译镜像可以在 `这里 `_ 获取。 + +Cypress FX3 固件的 `源代码 `_ 也是开源的,其中包含以下功能代码: + +1. 加载 FPGA 镜像 +2. 通过 USB 3.0 在 FPGA 与主机之间传输 IQ 样本 +3. 通过 UART 控制 FPGA 的 GPIO + +从信号流的角度看,它有两路接收通道和两路发射通道,而且每个通道根据所用频段的不同,都对应 RFIC 的低频和高频输入/输出路径。 +正因为如此,在 RFIC 与 SMA 接头之间需要一个单刀双掷(SPDT)电子射频开关。 +Bias Tee(也叫 Bias-T)是板载电路,它会在 SMA 接头上提供约 4.5V 的直流电,用来方便地为外部放大器或其他射频器件供电。 +这部分额外的直流偏置位于 SDR 的射频侧,因此不会干扰基本的收发操作。 + +JTAG 是一种调试接口,可用于在开发过程中测试和验证设计。 + +在本章末尾,我们还会讨论 VCTCXO 振荡器、PLL,以及扩展接口。 + +******************************** +bladeRF 的软件与硬件配置 +******************************** + +在 Ubuntu 上安装 bladeRF(或 WSL 中的 Ubuntu) +############################################################ + +在 Ubuntu 以及其他基于 Debian 的系统上,可以使用下面的命令安装 bladeRF 软件: + +.. code-block:: bash + + sudo apt update + sudo apt install cmake python3-pip libusb-1.0-0 + cd ~ + git clone --depth 1 https://github.com/Nuand/bladeRF.git + cd bladeRF/host + mkdir build && cd build + cmake .. + make -j8 + sudo make install + sudo ldconfig + cd ../libraries/libbladeRF_bindings/python + sudo python3 setup.py install + +这会安装 libbladerf 库、Python 绑定、bladeRF 命令行工具、固件下载器,以及 FPGA 比特流下载器。 +要检查你安装的库版本,可以使用 :code:`bladerf-tool version` (本文写作时使用的是 libbladeRF v2.5.0)。 + +如果你是通过 WSL 使用 Ubuntu,那么在 Windows 侧需要先把 bladeRF 的 USB 设备转发到 WSL。 +首先安装最新版本的 `usbipd utility msi `_ (本文默认你使用的是 usbipd-win 4.0.0 或更高版本),然后以管理员模式打开 PowerShell 并执行: + +.. code-block:: bash + + usbipd list + # (找到标记为 bladeRF 2.0 的 BUSID,并代入下面的命令) + usbipd bind --busid 1-23 + usbipd attach --wsl --busid 1-23 + +在 WSL 这边,你应该能通过 :code:`lsusb` 看到一个新设备项,名称类似 :code:`Nuand LLC bladeRF 2.0 micro`。 +注意,如果你希望它自动重新连接,可以在 :code:`usbipd attach` 命令后加上 :code:`--auto-attach` 参数。 + +(可能不需要)对于原生 Linux 和 WSL,我们都需要安装 udev 规则,以避免权限错误: + +.. code-block:: + + sudo nano /etc/udev/rules.d/88-nuand.rules + +然后把下面这行内容粘贴进去: + +.. code-block:: + + ATTRS{idVendor}=="2cf0", ATTRS{idProduct}=="5250", MODE="0666" + +保存并退出 nano 的方法是:先按 control-o,然后回车,再按 control-x。 +要刷新 udev,请执行: + +.. code-block:: bash + + sudo udevadm control --reload-rules && sudo udevadm trigger + +如果你使用的是 WSL,并且它提示 :code:`Failed to send reload request: No such file or directory`,那就说明 udev 服务没有运行。 +这时你需要执行 :code:`sudo nano /etc/wsl.conf`,并加入以下内容: + +.. code-block:: bash + + [boot] + command="service udev start" + +然后在管理员 PowerShell 中执行以下命令来重启 WSL: :code:`wsl.exe --shutdown` 。 + +拔下再重新插上你的 bladeRF(WSL 用户还需要重新 attach),然后用下面的命令测试权限: + +.. code-block:: bash + + bladerf-tool probe + bladerf-tool info + +如果看到列出了你的 bladeRF 2.0,并且 **没有** 出现 :code:`Found a bladeRF via VID/PID, but could not open it due to insufficient permissions`,就说明配置成功了。 +如果成功,请顺便记下输出里的 FPGA Version 和 Firmware Version。 + +(可选)安装最新版本的固件和 FPGA 镜像(本文写作时分别是 v2.4.0 和 v0.15.0): + +.. code-block:: bash + + cd ~/Downloads + wget https://www.nuand.com/fx3/bladeRF_fw_latest.img + bladerf-tool flash_fw bladeRF_fw_latest.img + + # xA4 版本使用: + wget https://www.nuand.com/fpga/hostedxA4-latest.rbf + bladerf-tool flash_fpga hostedxA4-latest.rbf + + # xA9 版本使用: + wget https://www.nuand.com/fpga/hostedxA9-latest.rbf + bladerf-tool flash_fpga hostedxA9-latest.rbf + +然后给 bladeRF 断电重启一次,也就是拔掉再插上。 + +接下来我们通过在 FM 广播频段接收 100 万个样本、采样率设为 10 MHz,并把数据写入 :code:`/tmp/samples.sc16`,来测试它的基本功能: + +.. code-block:: bash + + bladerf-tool rx --num-samples 1000000 /tmp/samples.sc16 100e6 10e6 + +出现少量 :code:`Hit stall for buffer` 是正常的;如果最终你看到了一个 4 MB 的 :code:`/tmp/samples.sc16` 文件,就说明它工作正常。 + +最后,使用下面的命令测试 Python API: + +.. code-block:: bash + + python3 + import bladerf + bladerf.BladeRF() + exit() + +如果你看到类似 :code:`)>` 的输出,并且没有 warning/error,那么就说明 Python API 也工作正常。 + +Windows 与 macOS 下安装 bladeRF +######################################## + +如果你使用 Windows(并且不打算走 WSL),请参考 https://github.com/Nuand/bladeRF/wiki/Getting-Started%3A-Windows ;如果你使用 macOS,请参考 https://github.com/Nuand/bladeRF/wiki/Getting-started:-Mac-OSX 。 + +******************************** +bladeRF Python API 基础 +******************************** + +首先,让我们用下面这段脚本从 bladeRF 中查询一些有用的信息。 **不要把你的脚本命名为** ``bladerf.py``,否则它会和 bladeRF 的 Python 模块本身发生冲突! + +.. code-block:: python + + from bladerf import _bladerf + import numpy as np + import matplotlib.pyplot as plt + + sdr = _bladerf.BladeRF() + + print("Device info:", _bladerf.get_device_list()[0]) + print("libbladeRF version:", _bladerf.version()) # v2.5.0 + print("Firmware version:", sdr.get_fw_version()) # v2.4.0 + print("FPGA version:", sdr.get_fpga_version()) # v0.15.0 + + rx_ch = sdr.Channel(_bladerf.CHANNEL_RX(0)) # 这里传入 0 或 1 + print("sample_rate_range:", rx_ch.sample_rate_range) + print("bandwidth_range:", rx_ch.bandwidth_range) + print("frequency_range:", rx_ch.frequency_range) + print("gain_modes:", rx_ch.gain_modes) + print("manual gain range:", sdr.get_gain_range(_bladerf.CHANNEL_RX(0))) # 通道 0 或 1 + +对于 bladeRF 2.0 xA9,输出应大致类似下面这样: + +.. code-block:: python + + Device info: Device Information + backend libusb + serial f80a27b1010448dfb7a003ef7fa98a59 + usb_bus 2 + usb_addr 5 + instance 0 + libbladeRF version: v2.5.0 ("2.5.0-git-624994d") + Firmware version: v2.4.0 ("2.4.0-git-a3d5c55f") + FPGA version: v0.15.0 ("0.15.0") + sample_rate_range: Range + min 520834 + max 61440000 + step 2 + scale 1.0 + + bandwidth_range: Range + min 200000 + max 56000000 + step 1 + scale 1.0 + + frequency_range: Range + min 70000000 + max 6000000000 + step 2 + scale 1.0 + + gain_modes: [, , , , ] + + manual gain range: Range + min -15 + max 60 + step 1 + scale 1.0 + +带宽参数决定了 SDR 在接收时使用的滤波器,因此我们通常把它设置为与 :code:`sample_rate/2` 相等或略小。 +增益模式也很重要:设备既支持手动增益模式(由你以 dB 指定增益),也支持自动增益控制(AGC),并提供 fast、slow、hybrid 三种设置。 +对于频谱监测这类应用,通常更建议使用手动增益(这样你能看出信号什么时候进来、什么时候消失);而对于接收某个你预期一定存在的特定信号时,AGC 更实用,因为它会自动调节增益,使信号尽可能填满模数转换器(ADC)的动态范围。 + +要设置 SDR 的主要参数,我们可以加上下面这些代码: + +.. code-block:: python + + sample_rate = 10e6 + center_freq = 100e6 + gain = 50 # -15 到 60 dB + num_samples = int(1e6) + + rx_ch.frequency = center_freq + rx_ch.sample_rate = sample_rate + rx_ch.bandwidth = sample_rate/2 + rx_ch.gain_mode = _bladerf.GainMode.Manual + rx_ch.gain = gain + +******************************** +在 Python 中接收 bladeRF 样本 +******************************** + +接下来,我们基于上一段代码,在 FM 广播频段以 10 MHz 的采样率接收 100 万个样本,就像前面在命令行里做的那样。 +只要天线接在 RX1 口上,通常都应该能收到 FM 广播,因为它的信号一般很强。 +下面这段代码展示了 bladeRF 的同步流(synchronous stream)API 是如何工作的;在开始接收之前,必须先完成流配置,并创建接收缓冲区。 +:code:`while True:` 循环会一直接收,直到达到所请求的样本数。 +接收到的样本会被存入一个单独的 numpy 数组中,这样我们就可以在循环结束之后再处理它们。 + +.. code-block:: python + + # 配置同步流 + sdr.sync_config(layout = _bladerf.ChannelLayout.RX_X1, # 或 RX_X2 + fmt = _bladerf.Format.SC16_Q11, # int16 + num_buffers = 16, + buffer_size = 8192, + num_transfers = 8, + stream_timeout = 3500) + + # 创建接收缓冲区 + bytes_per_sample = 4 # 不要修改,它始终使用 int16 + buf = bytearray(1024 * bytes_per_sample) + + # 启用模块 + print("Starting receive") + rx_ch.enable = True + + # 接收循环 + x = np.zeros(num_samples, dtype=np.complex64) # 用来存储 IQ 样本 + num_samples_read = 0 + while True: + if num_samples > 0 and num_samples_read == num_samples: + break + elif num_samples > 0: + num = min(len(buf) // bytes_per_sample, num_samples - num_samples_read) + else: + num = len(buf) // bytes_per_sample + sdr.sync_rx(buf, num) # 读入缓冲区 + samples = np.frombuffer(buf, dtype=np.int16) + samples = samples[0::2] + 1j * samples[1::2] # 转换为复数类型 + samples /= 2048.0 # 缩放到 -1 到 1(它使用的是 12 位 ADC) + x[num_samples_read:num_samples_read+num] = samples[0:num] # 将 buf 存入 samples 数组 + num_samples_read += num + + print("Stopping") + rx_ch.enable = False + print(x[0:10]) # 查看前 10 个 IQ 样本 + print(np.max(x)) # 如果这个值接近 1,说明 ADC 过载了,应当减小增益 + +在结束时出现少量 :code:`Hit stall for buffer` 是正常的。 +最后打印出来的那个数值表示接收到的最大样本值;你应当调节增益,让它大约落在 0.5 到 0.8 之间。 +如果它接近 0.999,就说明接收机已经过载/饱和,信号会发生失真(在频域中会表现为被涂抹开来)。 + +为了可视化接收到的信号,我们接下来用时频谱来显示这些 IQ 样本(关于时频谱如何工作的更多细节,请参见 :ref:`spectrogram-section` 小节)。 +把下面这段代码追加到前一个代码块的末尾: + +.. code-block:: python + + # 创建时频谱 + fft_size = 2048 + num_rows = len(x) // fft_size # // 是向下取整的整数除法 + spectrogram = np.zeros((num_rows, fft_size)) + for i in range(num_rows): + spectrogram[i,:] = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(x[i*fft_size:(i+1)*fft_size])))**2) + extent = [(center_freq + sample_rate/-2)/1e6, (center_freq + sample_rate/2)/1e6, len(x)/sample_rate, 0] + plt.imshow(spectrogram, aspect='auto', extent=extent) + plt.xlabel("Frequency [MHz]") + plt.ylabel("Time [s]") + plt.show() + +.. image:: ../_images/bladerf-waterfall.svg + :align: center + :target: ../_images/bladerf-waterfall.svg + :alt: bladeRF 时频谱示例 + +图中每一条竖着扭动的线都是一个 FM 广播信号。 +右侧那团脉冲状的东西具体是什么我也不清楚,把增益调低也没有让它消失。 + + +******************************** +在 Python 中发射 bladeRF 样本 +******************************** + +使用 bladeRF 发射样本的流程与接收非常相似。 +最主要的区别在于,我们必须先生成要发射的样本,然后通过 :code:`sync_tx` 方法把它们写入 bladeRF;这个方法可以一次处理整批样本(最多大约 40 亿个样本)。 +下面的代码展示了如何发射一个简单的单音信号,并将它重复 30 次。 +这个单音信号用 numpy 生成,然后被缩放到 -2048 到 2048 之间,以适配 12 位数模转换器(DAC)。 +随后它会被转换成表示 int16 的字节串,并作为发射缓冲区使用。 +同步流 API 用来发射这些样本,而 :code:`while True:` 循环则会持续发射,直到达到指定的重复次数。 +如果你想发射文件中的样本,也可以直接使用 :code:`samples = np.fromfile('yourfile.iq', dtype=np.int16)` (或者对应的实际数据类型) 读入样本,然后用 :code:`samples.tobytes()` 把它们转成字节。 +不过请记得 DAC 对应的数值范围是 -2048 到 2048。 + +.. code-block:: python + + from bladerf import _bladerf + import numpy as np + + sdr = _bladerf.BladeRF() + tx_ch = sdr.Channel(_bladerf.CHANNEL_TX(0)) # 这里传入 0 或 1 + + sample_rate = 10e6 + center_freq = 100e6 + gain = 0 # -15 到 60 dB。发射时应从较低值开始慢慢往上加,并确保天线已连接 + num_samples = int(1e6) + repeat = 30 # 重复发射次数 + print('duration of transmission:', num_samples/sample_rate*repeat, 'seconds') + + # 生成待发射的 IQ 样本(这里是一个简单的单音) + t = np.arange(num_samples) / sample_rate + f_tone = 1e6 + samples = np.exp(1j * 2 * np.pi * f_tone * t) # 范围是 -1 到 +1 + samples = samples.astype(np.complex64) + samples *= 2048.0 # 缩放到 -2048 到 2048(它使用的是 12 位 DAC) + samples = samples.view(np.int16) + buf = samples.tobytes() # 转成字节,并作为发射缓冲区 + + tx_ch.frequency = center_freq + tx_ch.sample_rate = sample_rate + tx_ch.bandwidth = sample_rate/2 + tx_ch.gain = gain + + # 配置同步流 + sdr.sync_config(layout=_bladerf.ChannelLayout.TX_X1, # 或 TX_X2 + fmt=_bladerf.Format.SC16_Q11, # int16 + num_buffers=16, + buffer_size=8192, + num_transfers=8, + stream_timeout=3500) + + print("Starting transmit!") + repeats_remaining = repeat - 1 + tx_ch.enable = True + while True: + sdr.sync_tx(buf, num_samples) # 写入 bladeRF + print(repeats_remaining) + if repeats_remaining > 0: + repeats_remaining -= 1 + else: + break + + print("Stopping transmit") + tx_ch.enable = False + +在结束时出现少量 :code:`Hit stall for buffer` 也是正常的。 + +如果你想同时发射和接收,那么就必须使用线程。 +这种情况下,你基本上可以直接使用 Nuand 提供的示例 `txrx.py `_ ,它就是专门做这件事的。 + +*********************************** +振荡器、PLL 与 bladeRF 校准 +*********************************** + +所有直接变频 SDR(包括所有基于 AD9361 的 SDR,例如 USRP B2X0、Analog Devices Pluto 和 bladeRF)都依赖一个单一振荡器来为射频收发器提供稳定时钟。 +这个振荡器输出频率中的任何偏移或抖动,都会转化为接收或发射信号中的频率偏移和频率抖动。 +这个振荡器本身位于板上,但也可以选择通过板上的 U.FL 接头输入一个额外的方波或正弦参考信号,对它进行约束。 + +bladeRF 板上使用的是一颗频率为 38.4 MHz 的 `Abracon VCTCXO `_ (压控温度补偿晶体振荡器,Voltage-controlled temperature-compensated oscillator)。 +其中 “温度补偿” 表示它被设计成在较宽的温度范围内都保持稳定。 +而 “压控” 则表示可以通过施加电压对振荡器频率进行细微调节;在 bladeRF 上,这个电压来自另一颗独立的 10 位 DAC,如下图中绿色部分所示。 +这意味着我们可以通过软件对振荡器频率做细调,而这正是校准(也叫 trim)bladeRF 的 VCTCXO 的方式。 +幸运的是,bladeRF 在出厂时就已经做过校准了,后文会详细提到;但如果你手头有测试设备,随着时间推移、振荡器频率发生漂移后,你依然可以进一步手动微调这一数值。 + +.. image:: ../_images/bladeRF-2.0-micro-Block-Diagram-4-oscillator.png + :scale: 80 % + :align: center + :alt: bladeRF 2.0 振荡器方框图 + +当使用外部频率参考时(几乎可以是任意不超过 300 MHz 的频率),参考信号会被直接送入 bladeRF 板上的 `Analog Devices ADF4002 `_ PLL。 +这个 PLL 会锁定参考信号,并向 VCTCXO 发送一个控制信号(上图蓝色部分),其大小与(经过比例缩放后的)参考输入和 VCTCXO 输出之间的频率差与相位差成正比。 +当 PLL 锁定之后,PLL 和 VCTCXO 之间的这个信号就会变成一个稳态直流电压,使 VCTCXO 输出维持在 “精确的” 38.4 MHz(前提是参考源本身足够准确),并与参考输入保持相位锁定。 +在使用外部参考时,你必须启用 :code:`clock_ref` (无论是在 Python 中还是在 CLI 中),并设置输入参考频率(也叫 :code:`refin_freq`),其默认值是 10 MHz。 +使用外部参考的理由包括更高的频率精度,以及让多台 SDR 共享同一个参考源从而实现同步。 + +每台 bladeRF 的 VCTCXO DAC trim 值在出厂时都会被校准到室温下 38.4 MHz 误差不超过 1 Hz。 +你可以把序列号输入到 `这个页面 `_ 查看出厂校准值(序列号可以在板上找到,也可以通过 :code:`bladerf-tool probe` 查看)。 +根据 Nuand 的说法,一块新板卡通常会优于 0.5 ppm,很多时候甚至接近 0.1 ppm。 +如果你手头有频率精度测试设备,或者只是想把它恢复到出厂值,可以使用下面的命令: + +.. code-block:: bash + + $ bladeRF-cli -i + bladeRF> flash_init_cal 301 0x2049 + +其中,把 :code:`301` 替换为你的 bladeRF 容量型号,把 :code:`0x2049` 替换为你的 VCTCXO DAC trim 十六进制值。 +修改后必须重新上电才会生效。 + +*********************************** +以 122 MHz 采样 +*********************************** + +敬请期待! + +*********************************** +bladeRF 扩展接口 +*********************************** + +bladeRF 2.0 提供了一个使用 BSH-030 连接器的扩展接口。 +关于如何使用这个接口,后续再补充。 + +******************************** +bladeRF 延伸阅读 +******************************** + +#. `bladeRF Wiki `_ +#. `Nuand 的 txrx.py 示例 `_ diff --git a/content-zh/digital_modulation.rst b/content-zh/digital_modulation.rst index 97adf0f2..ffdd9862 100644 --- a/content-zh/digital_modulation.rst +++ b/content-zh/digital_modulation.rst @@ -100,7 +100,7 @@ 注意,图中无线信号的纵坐标平均值为零。在讨论调制时,人们往往喜欢这样展现数据和绘图。 -我们可以使用多于两个幅度级别,从而让每个符号携带更多比特。以下是 4-ASK 的示例。 +我们可以使用多于两个幅度级别,从而让每个符号携带更多比特。以下是 4-ASK 的示例(幅度为 0 也是四种级别之一)。 在这种情况下,每个符号携带 2 比特的信息。 .. image:: ../_images/ask2.svg @@ -133,7 +133,7 @@ 上图中,顶图展示的是由红色点表示的离散采样点(即我们生成的数字信号),底图展示的是调制后的真正能在空中发出的信号。 在真实的通信系统中,载波的频率通常远远高于符号变化的频率: -在这个例子中,每个符号包含载波(正弦波)的三个周期,但在实际中可能包含数千个周期,具体取决于载波频率有多高。 +在这个例子中,每个符号包含载波(正弦波)的 2.5 个周期,但在实际中可能包含数千个周期,具体取决于载波频率有多高。如需了解更多关于 ASK 的信息,推荐参阅 `这篇资料 `_ 。 ************************ 相移键控(PSK) @@ -227,7 +227,7 @@ IQ 图/星座图 现在,让我们暂时回到 ASK 方案。 我们可以像展示 PSK 一样在 IQ 图上展示 ASK。 -以下是双极(Bipolar) 2-ASK、4-ASK 和 8-ASK,以及单极(Unipolar) 2-ASK 和 4-ASK 的 IQ 图。 +以下是双极(Bipolar) 2-ASK、4-ASK 和 8-ASK,以及单极(Unipolar) 2-ASK 和 4-ASK 的 IQ 图。在这里,双极意味着调制信号可以取正和负的幅度值,而单极 ASK 只使用正幅度。 .. image:: ../_images/ask_set.png :scale: 50 % @@ -286,13 +286,12 @@ FSK 是相当容易理解的---我们在 N 个频率之间切换,每个频率 因为我们是在调制载波,所以实际上是在载波频率上加减这 N 种频率。 例如,我们可能在 1.2 GHz 的载波频率上切换以下四个频率: -1. 1.2005 GHz -2. 1.2010 GHz -3. 1.1995 GHz -4. 1.1990 GHz +1. 1.2001 GHz +2. 1.2003 GHz +3. 1.1999 GHz +4. 1.1997 GHz -上面这个例子就是一个 4-FSK, 每个符号携带 2 比特的信息。 -在频域中,一个 4-FSK 信号可能看起来像这样: +上面这个例子就是一个 4-FSK,每个符号携带 2 比特的信息。频率间距为 200 kHz,整个信号的带宽略大于 600 kHz。这个 4-FSK 信号在基带频域中(对多个符号进行 FFT 后)可能看起来像这样: .. image:: ../_images/fsk.svg :align: center @@ -302,9 +301,8 @@ FSK 是相当容易理解的---我们在 N 个频率之间切换,每个频率 在设计 FSK 时,你一定会遇到一个关键问题:相邻频率之间的频谱间距应该是多少? 我们通常把这个间距用 :math:`\Delta f` 表示(单位是 Hz)。 我们希望在频域中避免频率重叠,这样接收机才能根据不同的频率辨别符号,所以 :math:`\Delta f` 必须足够大。 -而每种频率的宽度则取决于我们的符号速率:每秒需要传输的符号越多,每个符号的持续时间越短,其频率宽度就越宽(回忆一下时间和频率之间的反比关系)。 +而每种频率的宽度则取决于我们的符号速率以及所应用的脉冲整形滤波器:每秒需要传输的符号越多,每个符号的持续时间越短,其频率宽度就越宽(回忆一下时间和频率之间的反比关系)。 那么相应的,:math:`\Delta f` 就需要越大,以避免不同频率之间出现重叠。 -我们暂时不会在本教材中深入讨论 FSK 的设计细节。 IQ 图无法展示不同的频率,它们展示的是幅度和相位。 虽然在时域中展示 FSK 是可能的,但是超过 2 个频率仍然会使符号之间的区分变得困难: @@ -318,9 +316,10 @@ IQ 图无法展示不同的频率,它们展示的是幅度和相位。 不同于 FSK 中不同符号所使用的离散频率,FM 广播使用连续的音频信号来调制载波频率。 下面是调频(FM)和调幅(AM)的示例,顶部的 “信号” 是需要调制到载波上的音频信号。 -.. image:: ../_images/Carrier_Mod_AM_FM.webp +.. image:: ../_images/am_fm_animation.gif :align: center - :target: ../_images/Carrier_Mod_AM_FM.webp + :scale: 75 % + :target: ../_images/am_fm_animation.gif :alt: AM 和 FM 调制后的载波在时域上的示例动画。 在本教材中,我们主要关注数字信号调制方法。 diff --git a/content-zh/frequency_domain.rst b/content-zh/frequency_domain.rst index 58b24e3e..ace46c5b 100644 --- a/content-zh/frequency_domain.rst +++ b/content-zh/frequency_domain.rst @@ -150,23 +150,23 @@ 为信号 :math:`x(t)` 我们可以使用下面的公式得到其频域版本 :math:`X(f)` 。 我们将以 :math:`x(t)` 或 :math:`y(t)` 来表示函数的时域版本, 相应的以 :math:`X(f)` 和 :math:`Y(f)` 来表示其频域版本。 -注意“ :math:`t` ”代表时间,而“ :math:`f` ”代表频率。“ :math:`j` ”只是虚数单位而已。 -你可能在高中数学课上见过用“ :math:`i` ”来表示它。 -在工程和计算机科学中使用“ :math:`j` ”,因为在这些领域中“ :math:`i` ”通常指电流,并且在编程中常常作为循环变量使用。 +注意 :math:`t` 代表时间,而 :math:`f` 代表频率。 :math:`j` 只是虚数单位而已, +你可能在高中数学课上见过用 :math:`i` 来表示它。 +在工程和计算机科学中使用” :math:`j` “,因为在这些领域中” :math:`i` “通常指电流,并且在编程中常常作为循环变量使用。 -要从频域返回到时域几乎是一样的,除了多了一个缩放因子和一个负号: +要从频域返回到时域几乎是一样的,除了一个负号: .. math:: - x(t) = \frac{1}{2 \pi} \int X(f) e^{j2\pi ft} df + x(t) = \int X(f) e^{j2\pi ft} df -请注意,许多教科书和其他资源使用 :math:`w` 代替 :math:`2\pi f`。:math:`w` 是以弧度每秒为单位的角频率, +请注意,许多教科书和其他资源使用 :math:`w` 代替 :math:`2\pi f`,其中 :math:`w` 是以弧度每秒为单位的角频率, 而 :math:`f` 是以 Hz 为单位。你只需要知道: .. math:: \omega = 2 \pi f -即使它在许多方程中增加了一个 :math:`2 \pi` 项,在实际中我们更倾向于使用频率的 Hz 单位。 -最终,你在 SDR 应用中使用的将是 Hz 单位。 +即使它在许多方程中增加了一个 :math:`2 \pi` 项,在实际中我们更倾向于使用频率的 Hz 单位, +因为在大多数 SDR 和射频信号处理应用中我们使用的都是 Hz 单位。 上述傅里叶变换的方程是连续形式,其实你只会在数学问题中看到它。离散形式的方程才更接近于它在代码中实现的形态: @@ -356,6 +356,30 @@ FFT 令人疑惑的一点在于,其输出总是在频域中的,所以当我 虽然接收信号的中心频率被调到了 100MHz,但是在接受结果中,97.5 MHz 的信号实际会显示为 -2.5 MHz,负频率出现了! 但是实际上,仅仅是因为它低于中心频率而已。当我们学习更多关于采样的知识并且积累了 SDR 设备的使用经验后,你将彻底明白为什么会发生这个转换。 +从数学角度来看,通过观察复指数函数 :math:`e^{2j \pi f t}` 可以理解负频率。如果我们代入一个负频率,可以看到它是一个沿相反方向旋转的复正弦波。 + +.. math:: + e^{2j \pi f t} = \cos(2 \pi f t) + j \sin(2 \pi f t) \quad \mathrm{\textcolor{blue}{blue}} + +.. math:: + e^{2j \pi (-f) t} = \cos(2 \pi f t) - j \sin(2 \pi f t) \quad \mathrm{\textcolor{red}{red}} + +.. image:: ../_images/negative_freq_animation.gif + :align: center + :scale: 75 % + :target: ../_images/negative_freq_animation.gif + :alt: Animation of a positive and negative frequency sinusoid on the complex plane + +之所以用复指数来解释,是因为单独的 :math:`cos()` 或 :math:`sin()` 其实同时包含正频率和负频率成分,这可以从欧拉公式应用于频率为 :math:`f` 的正弦波看出来: + +.. math:: + \cos(2 \pi f t) = \underbrace{\frac{1}{2} e^{2j \pi f t}}_\text{positive} + \underbrace{\frac{1}{2} e^{-2j \pi f t}}_\text{negative} + +.. math:: + \sin(2 \pi f t) = \underbrace{\frac{1}{2j} e^{2j \pi f t}}_\text{positive} - \underbrace{\frac{1}{2j} e^{-2j \pi f t}}_\text{negative} + +因此,在射频信号处理中,我们通常使用复指数而不是余弦和正弦函数。 + **************************** 时域中的顺序并不重要 **************************** @@ -529,6 +553,8 @@ FFT 窗口大小设置 例如,即使你只从每 100k 个样本中选取 1,024 个样本进行 FFT,只要目标信号是连续的,得到的结果通常也是可以接受的。 +.. _spectrogram-section: + ****************************************** 时频谱/瀑布图 ****************************************** @@ -586,14 +612,16 @@ FFT 窗口大小设置 for i in range(num_rows): spectrogram[i,:] = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(x[i*fft_size:(i+1)*fft_size])))**2) - plt.imshow(spectrogram, aspect='auto', extent = [sample_rate/-2/1e6, sample_rate/2/1e6, 0, len(x)/sample_rate]) + # 时间从顶部开始向下递增,例如 x[0] 会作为显示的第一行(最顶行)的一部分 + plt.imshow(spectrogram, aspect='auto', extent = [sample_rate/-2/1e6, sample_rate/2/1e6, len(x)/sample_rate, 0]) plt.xlabel("Frequency [MHz]") plt.ylabel("Time [s]") plt.show() 该操作应会生成以下结果,这算不上一个很有趣的时频谱,因为没有频率时变行为。 它有两个音调是因为我们模拟了一个真实信号,而真实信号总是有一个与正侧相匹配的负功率谱密度(PSD)。 -想看更多有趣的时频谱示例,请访问 https://www.IQEngine.org! +请注意,在这种实现方式中,最顶行对应的是信号的起始部分。 +想看更多有趣的时频谱示例,请访问 https://www.IQEngine.org ! .. image:: ../_images/spectrogram.svg :align: center diff --git a/content-zh/hackrf.rst b/content-zh/hackrf.rst new file mode 100644 index 00000000..16e11f14 --- /dev/null +++ b/content-zh/hackrf.rst @@ -0,0 +1,299 @@ +.. _hackrf-chapter: + +######################## +Python 玩转 HackRF One +######################## + +Great Scott Gadgets 推出的 `HackRF One `_ 是一款基于 USB 2.0 的 SDR,能够在 1 MHz 到 6 GHz 之间进行发射或接收,采样率范围为 2 到 20 MHz。 +它于 2014 年发布,并在这些年里经历了几次小幅改进。 +它是少数能够下探到 1 MHz 的低成本可发射 SDR 之一,因此除了更高频段的玩法之外,也非常适合 HF 应用(例如业余无线电)。 +它的最大发射功率 15 dBm 也高于大多数其他 SDR;完整的发射功率规格请参见 `这个页面 `_ 。 +它采用半双工工作方式,这意味着任意时刻它只能处于发射或接收其中一种模式,并且它使用的是 8 位 ADC/DAC。 + +.. image:: ../_images/hackrf1.jpeg + :scale: 60 % + :align: center + :alt: HackRF One + +******************************** +HackRF 架构 +******************************** + +HackRF 的核心是 Analog Devices 的 MAX2839 芯片,它本质上是一颗 2.3 GHz 到 2.7 GHz 的收发器,最初是为 WiMAX 设计的。 +它还搭配了一颗 MAX5864 射频前端芯片(本质上就是 ADC 和 DAC),以及一颗 RFFC5072 宽带合成器/VCO(用于在频率上对信号进行上变频和下变频)。 +这与大多数其他低成本 SDR 不同,因为后者通常会使用一颗被称为 RFIC 的单芯片方案。 +除了设置 RFFC5072 内部生成的频率之外,我们后续会调整的其他参数,比如衰减和模拟滤波,基本都发生在 MAX2839 中。 +HackRF 没有像许多 SDR 那样使用 FPGA 或片上系统(SoC),而是使用了一颗复杂可编程逻辑器件(CPLD)作为简单的胶合逻辑,以及一颗基于 ARM 的 LPC4320 微控制器来完成所有板载 DSP 和通过 USB 与主机的交互(包括双向 IQ 样本传输以及 SDR 参数控制)。 +下面这张来自 Great Scott Gadgets 的精美方框图展示了最新版 HackRF One 的架构: + +.. image:: ../_images/hackrf_block_diagram.webp + :align: center + :alt: HackRF One 方框图 + :target: ../_images/hackrf_block_diagram.webp + +HackRF One 具有很强的可扩展性,也很适合拿来折腾。 +塑料外壳内部有四组排针(P9、P20、P22 和 P28),具体说明可以 `在这里查看 `_ 。 +其中,8 路 GPIO 和 4 路 ADC 输入位于 P20 排针,而 SPI、I2C 和 UART 位于 P22 排针。 +P28 排针则可以通过触发输入和输出,与其他设备(例如 TR 开关、外部放大器,或另一台 HackRF)同步触发发射/接收操作,其延迟小于一个采样周期。 + +.. image:: ../_images/hackrf2.jpeg + :scale: 50 % + :align: center + :alt: HackRF One PCB + +HackRF 用于本振和 ADC/DAC 的时钟,既可以来自板上的 25 MHz 振荡器,也可以来自通过 SMA 输入的外部 10 MHz 参考时钟。 +无论使用哪一种时钟源,HackRF 都会在 CLKOUT 上输出一个 10 MHz 时钟信号;这是一个标准的 3.3V、10 MHz 方波,面向高阻抗负载。 +CLKIN 接口则用于输入类似的 10 MHz、3.3V 方波;当检测到输入时钟时,HackRF One 会在开始发射或接收操作时切换为使用这个外部输入,而不是内部晶振。 + +******************************** +HackRF 的软件与硬件配置 +******************************** + +软件安装流程分为两步:首先安装 Great Scott Gadgets 提供的 HackRF 主库,然后安装 Python API。 + +安装 HackRF 主库 +############################# + +以下步骤已经在 Ubuntu 22.04 上验证可用(使用的是 2025 年 3 月的 commit hash `17f3943`): + +.. code-block:: bash + + git clone https://github.com/greatscottgadgets/hackrf.git + cd hackrf + git checkout 17f3943 + cd host + mkdir build + cd build + cmake .. + make + sudo make install + sudo ldconfig + sudo cp /usr/local/bin/hackrf* /usr/bin/. + +安装好 :code:`hackrf` 后,你将能够使用以下工具: + +* :code:`hackrf_info` - 读取 HackRF 设备信息,例如序列号和固件版本。 +* :code:`hackrf_transfer` - 使用 HackRF 发送和接收信号。输入/输出文件采用 8 位有符号正交采样格式。 +* :code:`hackrf_sweep` - 命令行频谱分析仪。 +* :code:`hackrf_clock` - 读取和写入时钟输入/输出配置。 +* :code:`hackrf_operacake` - 配置连接到 HackRF 的 Opera Cake 天线切换器。 +* :code:`hackrf_spiflash` - 用于给 HackRF 刷写新固件,参见 `HackRF 官方固件更新说明 `_ 。 +* :code:`hackrf_debug` - 用于读取和写入寄存器以及其他底层调试配置。 + +如果你是通过 WSL 使用 Ubuntu,那么在 Windows 侧需要先把 HackRF 的 USB 设备转发到 WSL。 +首先安装最新版本的 `usbipd utility msi `_ (本文默认你使用的是 usbipd-win 4.0.0 或更高版本),然后以管理员模式打开 PowerShell 并运行: + +.. code-block:: bash + + usbipd list + # 找到标记为 HackRF One 的 BUSID,并代入下面两条命令 + usbipd bind --busid 1-10 + usbipd attach --wsl --busid 1-10 + +在 WSL 这边,你应该可以通过 :code:`lsusb` 看到一个新设备项,名称类似 :code:`Great Scott Gadgets HackRF One`。 +注意,如果你希望它自动重新连接,可以在 :code:`usbipd attach` 命令后加上 :code:`--auto-attach` 参数。 +最后,你还需要通过下面的命令添加 udev 规则: + +.. code-block:: bash + + echo 'ATTR{idVendor}=="1d50", ATTR{idProduct}=="6089", SYMLINK+="hackrf-one-%k", MODE="660", TAG+="uaccess"' | sudo tee /etc/udev/rules.d/53-hackrf.rules + sudo udevadm trigger + +然后把 HackRF One 拔掉再重新插上(并重新执行一次 :code:`usbipd attach` 这一步)。 +需要注意的是,在做下面的测试步骤之前,我一度遇到了权限问题,直到我在 Windows 侧改用 `WSL USB Manager `_ 来管理转发到 WSL 的 USB 设备;它似乎也顺便处理了 udev 规则相关的问题。 + +无论你使用的是原生 Linux 还是 WSL,到这里你都应该可以运行 :code:`hackrf_info`,并看到类似下面的输出: + +.. code-block:: bash + + hackrf_info version: git-17f39433 + libhackrf version: git-17f39433 (0.9) + Found HackRF + Index: 0 + Serial number: 00000000000000007687865765a765 + Board ID Number: 2 (HackRF One) + Firmware Version: 2024.02.1 (API:1.08) + Part ID Number: 0xa000cb3c 0x004f4762 + Hardware Revision: r10 + Hardware appears to have been manufactured by Great Scott Gadgets. + Hardware supported by installed firmware: HackRF One + +我们再顺手录制一段 FM 频段的 IQ 数据,带宽设为 10 MHz、中心频率设为 100 MHz,并抓取 100 万个样本: + +.. code-block:: bash + + hackrf_transfer -r out.iq -f 100000000 -s 10000000 -n 1000000 -a 0 -l 30 -g 50 + +这个工具会生成一个 int8 格式的二进制 IQ 文件(每个 IQ 样本占 2 字节),在我们的这个例子里文件应当是 2 MB。 +如果你感兴趣,这个录制下来的信号可以通过下面的 Python 代码读入: + +.. code-block:: python + + import numpy as np + samples = np.fromfile('out.iq', dtype=np.int8) + samples = samples[::2] + 1j * samples[1::2] + print(len(samples)) + print(samples[0:10]) + print(np.max(samples)) + +如果你的最大值是 127(也就是 ADC 已经饱和),那么就要把命令末尾那两个增益值调低一些。 + +安装 HackRF Python API +############################# + +最后,我们还需要安装 HackRF One 的 `Python 绑定 `_ ,它由 `GvozdevLeonid `_ 维护。 +以下步骤已在 Ubuntu 22.04 上于 2024 年 11 月 4 日使用当时最新的 main 分支验证可用。 + +.. code-block:: bash + + sudo apt install libusb-1.0-0-dev + pip install python_hackrf==1.2.7 + +我们可以用下面这段代码来测试安装是否成功;如果运行时没有报错(同时也不会有任何输出),那基本就说明一切正常了。 + +.. code-block:: python + + from python_hackrf import pyhackrf # type: ignore + pyhackrf.pyhackrf_init() + sdr = pyhackrf.pyhackrf_open() + sdr.pyhackrf_set_sample_rate(10e6) + sdr.pyhackrf_set_antenna_enable(False) + sdr.pyhackrf_set_freq(100e6) + sdr.pyhackrf_set_amp_enable(False) + sdr.pyhackrf_set_lna_gain(30) # LNA 增益 - 0 到 40 dB,步进为 8 dB + sdr.pyhackrf_set_vga_gain(50) # VGA 增益 - 0 到 62 dB,步进为 2 dB + sdr.pyhackrf_close() + +至于真正接收样本的测试,请看下文给出的示例代码。 + +******************************** +HackRF 收发增益 +******************************** + +HackRF 接收端增益 +############################ + +HackRF One 在接收端有三个不同的增益级: + +* RF (:code:`amp`,只能是 0 或 11 dB) +* IF (:code:`lna`,0 到 40 dB,步进为 8 dB) +* 基带 (:code:`vga`,0 到 62 dB,步进为 2 dB) + +在接收大多数信号时,通常建议保持 RF 放大器关闭(0 dB),除非你面对的是一个极其微弱的信号,并且附近可以确定没有强信号存在。 +IF(LNA)增益是最关键的那一级,它决定了你能否在避免 ADC 饱和的同时最大化信噪比,因此它是第一优先级要调的旋钮。 +基带增益则通常可以保持在较高的值,例如我们这里就直接保持在 50 dB。 + +HackRF 发射端增益 +############################ + +在发射端,HackRF 有两个增益级: + +* RF(只能是 0 或 11 dB) +* IF(0 到 47 dB,步进为 1 dB) + +你大概率会希望打开 RF 放大器,然后再根据实际需求调整 IF 增益。 + +************************************************** +在 Python 中通过 HackRF 接收 IQ 样本 +************************************************** + +目前 :code:`python_hackrf` 这个 Python 包并没有提供用于接收样本的便捷函数;它本质上只是把 HackRF 的 C++ API 映射成了一组 Python 绑定。 +这意味着,如果我们要接收 IQ 样本,就必须写不少代码。 +这个 Python 包是通过回调函数来接收更多样本的,也就是说,我们必须自己准备一个回调函数;但一旦设置好,只要 HackRF 有更多样本可读,这个函数就会被自动调用。 +这个回调函数始终必须接收四个特定参数,并且如果我们还想继续接收下一批样本,它就必须返回 :code:`0`。 +在下面的代码中,每次回调函数被调用时,我们都会把样本转换成 NumPy 的复数类型,缩放到 -1 到 +1,然后存入一个更大的 :code:`samples` 数组中。 + +运行下面这段代码之后,如果你在时域图中看到样本已经碰到了 ADC 的上下限 -1 和 +1,那么就应当把 :code:`lna_gain` 每次减少 8 dB,直到它明显不再打到边界为止。 + +.. code-block:: python + + from python_hackrf import pyhackrf # type: ignore + import matplotlib.pyplot as plt + import numpy as np + import time + + # 这些设置应与书中 hackrf_transfer 示例保持一致,得到的瀑布图应该看起来也差不多 + recording_time = 1 # 秒 + center_freq = 100e6 # Hz + sample_rate = 10e6 + baseband_filter = 7.5e6 + lna_gain = 30 # 0 到 40 dB,步进为 8 dB + vga_gain = 50 # 0 到 62 dB,步进为 2 dB + + pyhackrf.pyhackrf_init() + sdr = pyhackrf.pyhackrf_open() + + allowed_baseband_filter = pyhackrf.pyhackrf_compute_baseband_filter_bw_round_down_lt(baseband_filter) # 根据期望值计算最接近且受支持的带宽 + + sdr.pyhackrf_set_sample_rate(sample_rate) + sdr.pyhackrf_set_baseband_filter_bandwidth(allowed_baseband_filter) + sdr.pyhackrf_set_antenna_enable(False) # 这个设置看起来是启用或禁用天线口供电。默认值为 False。固件在回到 IDLE 模式后会自动关闭它 + + sdr.pyhackrf_set_freq(center_freq) + sdr.pyhackrf_set_amp_enable(False) # 默认值为 False + sdr.pyhackrf_set_lna_gain(lna_gain) # LNA 增益 - 0 到 40 dB,步进为 8 dB + sdr.pyhackrf_set_vga_gain(vga_gain) # VGA 增益 - 0 到 62 dB,步进为 2 dB + + print(f'center_freq: {center_freq} sample_rate: {sample_rate} baseband_filter: {allowed_baseband_filter}') + + num_samples = int(recording_time * sample_rate) + samples = np.zeros(num_samples, dtype=np.complex64) + last_idx = 0 + + def rx_callback(device, buffer, buffer_length, valid_length): # 这个回调函数必须始终带这四个参数 + global samples, last_idx + + accepted = valid_length // 2 + accepted_samples = buffer[:valid_length].astype(np.int8) # -128 到 127 + accepted_samples = accepted_samples[0::2] + 1j * accepted_samples[1::2] # 转换为复数类型(将交织的 IQ 解交织) + accepted_samples /= 128 # 缩放到 -1 到 +1 + samples[last_idx: last_idx + accepted] = accepted_samples + + last_idx += accepted + + return 0 + + sdr.set_rx_callback(rx_callback) + sdr.pyhackrf_start_rx() + print('is_streaming', sdr.pyhackrf_is_streaming()) + + time.sleep(recording_time) + + sdr.pyhackrf_stop_rx() + sdr.pyhackrf_close() + pyhackrf.pyhackrf_exit() + + samples = samples[100000:] # 为了稳妥起见,丢弃最前面的 100k 样本,因为它们可能包含瞬态 + + fft_size = 2048 + num_rows = len(samples) // fft_size + spectrogram = np.zeros((num_rows, fft_size)) + for i in range(num_rows): + spectrogram[i, :] = 10 * np.log10(np.abs(np.fft.fftshift(np.fft.fft(samples[i * fft_size:(i+1) * fft_size]))) ** 2) + extent = [(center_freq + sample_rate / -2) / 1e6, (center_freq + sample_rate / 2) / 1e6, len(samples) / sample_rate, 0] + + plt.figure(0) + plt.imshow(spectrogram, aspect='auto', extent=extent) # type: ignore + plt.xlabel("Frequency [MHz]") + plt.ylabel("Time [s]") + + plt.figure(1) + plt.plot(np.real(samples[0:10000])) + plt.plot(np.imag(samples[0:10000])) + plt.xlabel("Samples") + plt.ylabel("Amplitude") + plt.legend(["Real", "Imaginary"]) + + plt.show() + +如果你使用的是能够接收 FM 频段的天线,那么应当会得到类似下面这样的结果,瀑布图里能看到多个 FM 广播电台: + +.. image:: ../_images/hackrf_time_screenshot.png + :align: center + :scale: 50 % + :alt: 从 HackRF 抓取样本后的时域图 + +.. image:: ../_images/hackrf_freq_screenshot.png + :align: center + :scale: 50 % + :alt: 从 HackRF 抓取样本后的时频谱图 diff --git a/content-zh/intro.rst b/content-zh/intro.rst index 233e06e2..7216ea64 100644 --- a/content-zh/intro.rst +++ b/content-zh/intro.rst @@ -56,7 +56,7 @@ 参与贡献 *************** -如果你从 PySDR 中获得了帮助,别忘了与你的同事、学生和其他可能对这些资料感兴趣的终身学习者分享。你还可以通过在 PySDR 的 `Patreon `_ 上捐款来表达你的支持,你的名字将会显示在每章下面的章节列表的左侧。 +如果你从 PySDR 中获得了帮助,别忘了与你的同事、学生和其他可能对这些资料感兴趣的终身学习者分享。你还可以通过在 PySDR 的 `Patreon `_ 上捐款来表达你的支持,你的名字将会显示在每章下面的章节列表的左侧。此外也可以通过 `一次性捐款 `_ 的方式支持本项目。 此外,欢迎你通过 marc@pysdr.org 向我发送问题、评论或者建议,你将为这本教科书的完善做出贡献! 你还可以直接在教科书的 `GitHub页面 `_ 上编辑源代码,欢迎你提交 Issue 或 Pull Request。 @@ -77,5 +77,7 @@ - `mrbloom `_ 将 PySDR 翻译为 `乌克兰语 `_ - `Yimin Zhao `_ 将 PySDR 翻译为 `简体中文 `_ - `Eduardo Chancay `_ 将 PySDR 翻译为 `西班牙语 `_ +- John Marcovici +- `Vishwaksen Reddy Dhareddy `_ 贡献了检测章节中的实时数据包检测部分 以及所有 `PySDR Patreon `_ 支持者! diff --git a/content-zh/iq_files.rst b/content-zh/iq_files.rst index 8ab12c52..0384c306 100644 --- a/content-zh/iq_files.rst +++ b/content-zh/iq_files.rst @@ -19,13 +19,13 @@ IQ 文件与 SigMF 以上数据对应 [I+jQ, I+jQ, I+jQ, I+jQ, I+jQ, I+jQ, I+jQ, ...] 当我们要将复数保存到文件中时,我们会使用 IQIQIQIQIQIQIQIQ 这样的格式进行保存。 -也就是说,我们按顺序存储了一系列浮点数。在读取它们时,我们必须将其重新分离成 [I+jQ, I+jQ, ...] 的形式。 +也就是说,我们按顺序存储了一系列整数或浮点数。在读取它们时,我们必须将其重新分离成 [I+jQ, I+jQ, ...] 的形式。 虽然我们可以将这一长串复数存储在文本文件或 CSV 文件中,但我们更倾向于将它们保存在所谓的 “二进制文件(Binary File)” 中以节省空间。 毕竟在高采样率下,你所记录的信号文件可能轻松超过多个 GB。 如果你直接在文本编辑器中打开一个二进制文件,它看起来可能和下面的截图差不多。 二进制文件包含了一系列字节,所以你必须自己按照约定的格式解析,但是二进制文件通常是存储数据最高效的方式(同时还有各种压缩算法可用)。 -由于我们的信号通常是随机序列般的一串浮点数,所以我们通常不会对其进行压缩。当然,二进制文件也被用于许多其他事情,例如编译过的程序。 +由于我们的信号通常是随机序列般的一串整数或浮点数,所以我们通常不会对其进行压缩。当然,二进制文件也被用于许多其他事情,例如编译过的程序。 用于保存信号时,我们称它们为二进制的 “IQ 文件”,使用文件扩展名 :code:`.iq` 。 .. image:: ../_images/binary_file.png @@ -33,10 +33,12 @@ IQ 文件与 SigMF :align: center 在 Python 中,默认的复数类型是 :code:`np.complex128`,它使用两个 64 位浮点数(:code:`'float64'`)来表示一个复数。 -但是在 DSP/SDR 领域,我们倾向于使用 32 位的浮点数(:code:`'float32'`), +但是在 DSP/SDR 领域,我们倾向于使用 16 位整数或 32 位浮点数, 毕竟我们的 SDR 设备上的 ADC 硬件并不能提供高达 :code:`'float64'` 的精度。 -因此在 Python 代码中,我们实际使用的是 **np.complex64** ,即用两个 :code:`'float32'` 来表示一个复数。 -其实在写代码时,复数到底是哪种类型并不重要。重要的是当你把数据保存到文件时,请确保它是以 :code:`np.complex64` 类型的数组存储的。 +事实上,大多数 SDR 使用 12 位 ADC,因此我们可以通过存储为 16 位整数(Python 中的 :code:`np.int16`)来最小化存储空间, +这意味着每个 IQ 采样点占用 4 字节,射频录制文件的大小(字节)将是采样率的 4 倍,这被称为 "Sean 的 4 倍法则"。 +在下面的 Python 示例中,我们将使用 **np.complex64** ,即用两个 :code:`'float32'` 来表示一个复数,因为 Python 没有原生的复数整数类型(但这并不妨碍我们将 IQ 数据以整数格式保存到文件中,后文会有说明)。 +其实在写代码处理信号时,复数到底是哪种类型并不重要。重要的是当你把数据保存到文件时,请确保它是以 :code:`np.complex64`(或交织 IQ 的 :code:`np.int16`)类型的数组存储的。 ************************* Python 代码示例 diff --git a/content-zh/noise.rst b/content-zh/noise.rst index 0c23be0d..ecd598f0 100644 --- a/content-zh/noise.rst +++ b/content-zh/noise.rst @@ -1,12 +1,15 @@ .. _noise-chapter: -################## -噪声与分贝(dB) -################## +########################## +噪声与随机变量 +########################## 本章将详细讨论噪声的相关主题,特别是噪声在无线通信系统中的建模和处理方式。 涉及的概念包括加性高斯白噪声(AWGN)、复数噪声、信噪比(SNR)、信干噪比(SINR)。 同时,我们还会介绍在无线通信和软件定义无线电(SDR)中广泛使用的分贝(dB)单位。 +最后,我们将深入探讨随机变量和随机过程的基本概念,这些概念对于理解噪声、信道效应以及无线通信中的许多信号处理技术至关重要。 +我们将涵盖概率分布、期望、方差,以及随机过程如何随时间演变。 +这些概念构成了分析噪声以及 SDR 和 DSP 中许多其他主题的数学基础。 ************************ 高斯噪声 @@ -17,6 +20,7 @@ .. image:: ../_images/noise.png :scale: 70 % :align: center + :target: ../_images/noise.png 在时间域中,图上的纵坐标的平均值为零。 如果平均值不为零,我们可以减去平均值来得到一个偏置,从而使剩余部分的平均值为零。 @@ -63,6 +67,7 @@ :scale: 70 % :align: center :alt: Depiction of why it's important to understand dB or decibels, showing a spectrogram using linear vs log scale + :target: ../_images/linear_vs_log.png 给定一个值 x,我们可以使用以下公式将 x 转换为 dB: @@ -77,7 +82,7 @@ Python 代码: 你可能会发现在其他领域中,表达式中的 :code:`10 *` 可能需要改为 :code:`20 *` 。 当处理代表功率的量时,常用系数 10,但当处理代表非功率量如电压或电流时,更适合使用系数 20。 -在DSP领域,我们通常处理代表功率的量。实际上,在本书中我们没有使用过 20,而始终使用 10。 +在 DSP 领域,我们通常处理代表功率的量。 我们使用以下方法将 dB 转换回线性数值(普通数值): @@ -104,6 +109,7 @@ dB 的对数刻度使我们能够在表达数字或绘制图形时拥有更大 .. image:: ../_images/db.png :scale: 80 % :align: center + :target: ../_images/db.png 还需要记住,dB 并不是严格意义上的 “单位”。 一个 dB 的数值本身是无单位的,就像说某物体是 “2 倍大” 一样,在上下文告诉你单位之前,它本身是没有单位的。 @@ -157,6 +163,7 @@ dB 是一个相对的概念。在音频处理中,当人们说 dB 时,他们 :scale: 110 % :align: center :alt: AWGN in the time domain is also Gaussian noise in the frequency domain, although it looks like a flat line when you take the magnitude and perform averaging + :target: ../_images/noise_freq.png 从下方的频谱图可以看到,所有频率上的功率谱密度都大致相同且相对平坦。 这证明,高斯噪声在频域中也是呈高斯分布的。 @@ -179,13 +186,14 @@ dB 是一个相对的概念。在音频处理中,当人们说 dB 时,他们 plt.plot(np.real(X), '.-') plt.show() -请注意,默认情况下,:code:`randn()` 生成的数据符合标准正态分布(均值为 0,方差为 1)。 +请注意,默认情况下, :code:`randn()` 函数生成的数据符合标准正态分布(均值为 0,方差为 1)。 代码生成的两张图像看起来都会类似这样: .. image:: ../_images/noise_python.png :scale: 100 % :align: center :alt: Example of white noise simulated in Python + :target: ../_images/noise_python.png 只需对上面的 FFT 输出取对数并进行平均,你就可以复现上文来自 GNU Radio 的那张平坦的 PSD 图像。 我们生成并进行 FFT 的信号是实信号(而不是复信号),任何实信号的 FFT 都会有相抵的负数和正数部分,所以我们只保存了 FFT 输出的正部分(第二部分)。 @@ -233,6 +241,7 @@ dB 是一个相对的概念。在音频处理中,当人们说 dB 时,他们 :scale: 80 % :align: center :alt: Complex noise simulated in Python + :target: ../_images/noise3.png 从上图可以看出来,实部和虚部是互相独立的。 @@ -249,6 +258,7 @@ dB 是一个相对的概念。在音频处理中,当人们说 dB 时,他们 :scale: 60 % :align: center :alt: Complex noise on an IQ or constellation plot, simulated in Python + :target: ../_images/noise_iq.png 它的形状符合预期:一个以原点为中心的随机斑点分布,即 0+0j。为了增加趣味性,让我们尝试在一个 QPSK 信号中引入噪声,并观察 IQ 图的变化。 @@ -256,12 +266,15 @@ dB 是一个相对的概念。在音频处理中,当人们说 dB 时,他们 :scale: 60 % :align: center :alt: Noisy QPSK simulated in Python + :target: ../_images/noisey_qpsk.png 当噪声更强时,会发生什么呢? .. image:: ../_images/noisey_qpsk2.png :scale: 50 % :align: center + :alt: Noisy QPSK with stronger noise simulated in Python + :target: ../_images/noisey_qpsk2.png 我们逐渐领悟到了无线数据传输的复杂性。 在追求高效率的同时,我们也不得不面对噪声干扰所带来的问题。 @@ -273,7 +286,7 @@ AWGN AWGN (Additive White Gaussian Noise,加性高斯白噪声)是 DSP 和 SDR 领域中经常能听到的缩写。 GN 指的是高斯噪声,我们之前已经讨论过了。Additive (加性)表示噪声是被添加到接收信号中的。 -White (白)在频域上意味着我们整个观测频带上的频谱是平坦的,在实践中,它几乎总是白噪声,或者是近似白噪声。 +White (白)在频域上意味着我们整个观测频带上的频谱是平坦的,在实践中,它几乎总是白噪声,或者近似白噪声。 在本教材中,当处理通信链路和链路预算等问题时,我们将只考虑 AWGN 作为唯一形式的噪声。 非 AWGN 噪声往往是一个专门的课题。 @@ -309,19 +322,363 @@ SNR 在实践中通常以分贝(dB)表示。在无线通信的模拟实验 干扰的构成取决于具体应用和场景,但通常是另一个信号干扰了我们感兴趣的信号(Signal Of Interest,缩写为 SOI), 并且在频率上与 SOI 重叠、或者由于某种原因无法被滤除。 -************************* -参考资料 -************************* +********************************* +深入理解随机变量 +********************************* + +到目前为止,我们一直避免过于数学化,但现在我们需要退后一步,介绍随机变量的概念以及它们在无线通信和 SDR 中的应用。 **随机变量** 是一个数学概念,它将随机实验的结果映射到数值上。随机变量表示那些在被观察或测量之前其值是不确定的量,比如我们的噪声采样点。设想掷一个六面骰子,在掷之前你不知道会出现什么数字。我们可以定义一个随机变量 :math:`X` 来表示掷骰子的结果。 :math:`X` 的值是 {1, 2, 3, 4, 5, 6} 中的一个,但在实际掷之前我们不知道是哪一个。 + +在无线通信和 SDR 的场景中,随机变量无处不在: + +* 接收机中的热噪声在每个时刻都可以建模为随机变量 +* 受多径衰落影响的接收信号的幅度是随机的 +* 变化信道引入的相位偏移可以建模为 :math:`0` 到 :math:`2\pi` 之间的随机变量 +* 甚至我们传输的数据比特也可以被视为随机变量 + +**单个样本 vs. 多个样本** + +这是一个至关重要的区别,经常引起混淆: + +* 随机变量的 **单次实现** 或 **单个样本** 只是一个数字——随机实验的一个结果 +* 要描述一个随机变量的特征(找到其均值、分布范围等),我们需要 **大量实现** ——即多个结果 + +例如,如果你在 Python 中调用 ``np.random.randn()`` 不带任何参数,它返回一个从高斯分布中抽取的随机数。这单个数字几乎无法告诉你分布本身的任何信息。但如果你调用 ``np.random.randn(10000)`` 生成 10,000 个样本,你就可以估计分布的均值和方差等属性了。 + +.. code-block:: python + + import numpy as np + + # 单个样本 - 只是一个数字 + x_single = np.random.randn() + print(x_single) # 可能是 0.534, -1.23, 或其他任何值 + + # 大量样本 - 现在我们可以描述分布的特征 + x_many = np.random.randn(10000) + print(np.mean(x_many)) # 会接近 0 + print(np.var(x_many)) # 会接近 1 + +联合分布 +#################### + +到目前为止,我们关注的是单个随机变量。当同时处理两个或更多随机变量时,我们使用 **联合分布(Joint Distribution)** 。 + +对于连续随机变量 :math:`X` 和 :math:`Y` ,联合分布由 **联合概率密度函数(Joint PDF)** 描述: + +.. math:: + f_{X,Y}(x,y) + +联合概率密度函数告诉我们 :math:`X` 取值 :math:`x` *同时* :math:`Y` 取值 :math:`y` 的可能性。 + +从联合概率密度函数中,我们可以计算: + +* 边缘概率密度函数(例如 :math:`f_X(x)` 或 :math:`f_Y(y)` ) +* 期望值,如 :math:`E[XY]` +* 协方差和相关性 +* 涉及两个变量的概率 + +例如,:math:`X` 的边缘概率密度函数可以通过对 :math:`Y` 积分得到: + +.. math:: + f_X(x) = \int_{-\infty}^{\infty} f_{X,Y}(x,y)\,dy + +联合分布是理解随机变量之间依赖性、相关性和独立性的数学基础。 + + +概率分布 +######################### + +**概率分布** 描述了随机变量取不同值的可能性。对于连续随机变量,我们使用 **概率密度函数(Probability Density Function,PDF)** ,记为 :math:`f_X(x)` 。PDF 告诉我们随机变量取不同值的相对可能性。 + +在 SDR 和通信中最重要的分布是 **高斯(正态)分布** 。均值为 :math:`\mu` 、方差为 :math:`\sigma^2` 的高斯随机变量 :math:`X` 的 PDF 为: + +.. math:: + f_X(x) = \frac{1}{\sqrt{2\pi\sigma^2}} e^{-\frac{(x-\mu)^2}{2\sigma^2}} + +这就是你可能见过的著名 "钟形曲线"。该分布完全由两个参数确定: + +* **均值** :math:`\mu` :分布的中心 +* **方差** :math:`\sigma^2` :分布的展宽程度(标准差 :math:`\sigma` 是方差的平方根) + +在 Python 中,``np.random.randn()`` 生成的样本来自 :math:`\mu = 0` 、 :math:`\sigma^2 = 1` 的 **标准高斯** 分布。我们可以这样可视化: + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + + # 从标准高斯分布生成 10,000 个样本 + x = np.random.randn(10000) + + # 创建直方图以可视化分布 + plt.hist(x, bins=50, density=True, alpha=0.7, edgecolor='black') + plt.xlabel('Value') + plt.ylabel('Probability Density') + plt.title('Gaussian Distribution (μ=0, σ²=1)') + plt.grid(True) + plt.show() + +.. image:: ../_images/gaussian_histogram.png + :scale: 80% + :align: center + :alt: Histogram of Gaussian distributed samples + :target: ../_images/gaussian_histogram.png + +期望(即均值) +######################### + +随机变量的 **期望** 或 **期望值** ,记为 :math:`E[X]` 或 :math:`\mu` ,表示其在大量实现中的平均值。对于具有 PDF :math:`f_X(x)` 的连续随机变量,期望为: + +.. math:: + E[X] = \int_{-\infty}^{\infty} x \cdot f_X(x) \, dx + +在实践中,当我们有从分布中抽取的 :math:`N` 个样本 :math:`x_1, x_2, \ldots, x_N` 时,我们使用 **样本均值** 来估计期望: + +.. math:: + \hat{\mu} = \frac{1}{N} \sum_{n=1}^{N} x_n + +期望是一个 **线性算子** ,这意味着: + +* :math:`E[aX + b] = aE[X] + b` (其中 :math:`a` 和 :math:`b` 为常数) +* :math:`E[X + Y] = E[X] + E[Y]` (对于任意两个随机变量) + +这种线性性质在信号处理中非常有用! + +方差与标准差 +############################### + +随机变量的 **方差** ,记为 :math:`\text{Var}(X)` 或 :math:`\sigma^2` ,衡量其值围绕均值的分散程度。它被定义为偏离均值的平方的期望值: + +.. math:: + \text{Var}(X) = E[(X - \mu)^2] = E[X^2] - (E[X])^2 + +当我们有 :math:`N` 个样本时,我们使用以下公式估计方差: + +.. math:: + \hat{\sigma}^2 = \frac{1}{N} \sum_{n=1}^{N} (x_n - \hat{\mu})^2 + +**标准差** :math:`\sigma` 就是方差的平方根::math:`\sigma = \sqrt{\sigma^2}` 。 + +请注意上面公式中 :math:`\sigma` 和样本均值上方的 :math:`\enspace \hat{} \enspace` 符号(称为 "hat")。这个帽子符号表示我们是在 *估计* 均值/方差,估计值不一定精确等于真实的均值/方差,但随着样本数量的增加,它会越来越接近真实值。 + +**关键性质:** 如果 :math:`X` 是方差为 :math:`\sigma^2` 的随机变量,则: + +* 缩放::math:`\text{Var}(aX) = a^2 \text{Var}(X)` +* 平移::math:`\text{Var}(X + b) = \text{Var}(X)` (加上常数不改变分散程度) + +相应地,标准差 :math:`\sigma` 的性质为: + +* 缩放::math:`\sigma(aX) = a\sigma(X)` +* 平移::math:`\sigma(X+b) = \sigma(X)` + +.. image:: ../_images/gaussian_transformed.png + :scale: 80% + :align: center + :alt: Scaling and shifting the Gaussian Distribution. (notice the scales on x and y axes) + :target: ../_images/gaussian_transformed.png + +对高斯分布进行缩放和平移(注意 x 轴和 y 轴的刻度变化) + +**方差与功率** + +在信号处理中,对于 **零均值** 信号(均值约为 0),方差等于 **平均功率** 。这就是为什么我们经常交替使用这两个术语: + +.. math:: + P = \text{Var}(X) = E[X^2] \quad \text{(当 } E[X] = 0\text{)} + +这个关系对于分析噪声功率、信噪比(SNR)和链路预算至关重要。 + +.. code-block:: python -关于AWGN,SNR和方差的更多资料可参考: + noise_power = 2.0 + n = np.random.randn(N) * np.sqrt(noise_power) + print(np.var(n)) # 会约等于 2.0 -1. https://en.wikipedia.org/wiki/Additive_white_Gaussian_noise -2. https://en.wikipedia.org/wiki/Signal-to-noise_ratio -3. https://en.wikipedia.org/wiki/Variance +协方差 +########## +两个随机变量 :math:`X` 和 :math:`Y` 之间的 **协方差(Covariance)** 定义为: +.. math:: + \text{Cov}(X,Y) = E[(X - E[X])(Y - E[Y])] + +一个等价且通常更方便的形式是: + +.. math:: + \text{Cov}(X,Y) = E[XY] - E[X]E[Y] + +协方差衡量两个变量如何共同变化: + +* 正协方差:它们趋向于一起增大或一起减小 +* 负协方差:一个趋向于在另一个减小时增大 +* 零协方差:它们是不相关的 + +如果两个变量都是零均值的,则简化为: + +.. math:: + \text{Cov}(X,Y) = E[XY] + +协方差有单位(它不是归一化的),这就是为什么在实践中我们经常使用 **相关系数** (Correlation Coefficient): + +.. math:: + \rho_{XY} = \frac{\text{Cov}(X,Y)}{\sigma_X \sigma_Y} + +相关系数是一个介于 -1 和 +1 之间的无量纲值。 + +变量之和的方差 +############################### + +在信号处理中,我们经常处理随机变量之和,比如信号加噪声: + +.. math:: + Z = X + Y + +这个和的方差取决于 :math:`X` 和 :math:`Y` 是否独立(或更一般地说,是否相关)。 + +完整的一般形式为: + +.. math:: + \text{Var}(X + Y) = \text{Var}(X) + \text{Var}(Y) + 2\,\text{Cov}(X,Y) + +其中 :math:`\text{Cov}(X,Y)` 是 :math:`X` 和 :math:`Y` 之间的 **协方差** 。 + +**独立的情况** + +如果 :math:`X` 和 :math:`Y` 是独立的(或仅仅是不相关的),则表达式简化为: + +.. math:: + \text{Var}(X + Y) = \text{Var}(X) + \text{Var}(Y) + +这个结果在通信中极其重要。例如,如果接收信号为: + +.. math:: + R = S + N + +其中 :math:`S` 是信号,:math:`N` 是独立的噪声,那么总功率就是信号功率和噪声功率之和。 + +这就是为什么 SNR 计算如此简单直接。 + +************************ +复数随机变量 +************************ + +在 SDR 中,我们大量使用 **复数值信号** ,这意味着我们也需要处理复数随机变量。复数随机变量的形式为: + +.. math:: + Z = X + jY + +其中 :math:`X` 和 :math:`Y` 都是实数值随机变量,分别代表同相(I)和正交(Q)分量。 + +**复高斯噪声** + +在无线通信中最常见的复数随机变量是 **复高斯噪声** ,其中 :math:`X` 和 :math:`Y` 都是具有相同方差的独立高斯随机变量。 +例如,如果 :math:`X \sim \mathcal{N}(\alpha_1, \sigma_1^2)` 和 :math:`Y \sim \mathcal{N}(\alpha_2, \sigma_2^2)` 是独立的,那么复数随机变量 :math:`Z = X + jY` 具有: + +* 均值::math:`E[Z] = E[X] + jE[Y] = \alpha_1 + j\alpha_2` +* 方差(功率)::math:`\text{Var}(Z) = \text{Var}(X) + \text{Var}(Y) = \sigma_1^2 + \sigma_2^2` + +.. image:: ../_images/gaussian_IQ.png + :scale: 80% + :align: center + :alt: Complex Gaussian noise visualized as two independent Gaussian random variables on the I and Q axes + :target: ../_images/gaussian_IQ.png + +这就是为什么当我们创建单位功率(方差 = 1)的复高斯噪声时,我们使用: + +.. code-block:: python + + N = 10000 + n = (np.random.randn(N) + 1j*np.random.randn(N)) / np.sqrt(2) + print(np.var(n)) # ~ 1 + +除以 :math:`\sqrt{2}` 确保了总功率(I 和 Q 方差之和)等于 1。 + +.. code-block:: python + + # 不做归一化的情况: + n_raw = np.random.randn(N) + 1j*np.random.randn(N) + print(np.var(np.real(n_raw))) # ~ 1 + print(np.var(np.imag(n_raw))) # ~ 1 + print(np.var(n_raw)) # ~ 2 (总功率) + + # 做归一化的情况: + n_norm = n_raw / np.sqrt(2) + print(np.var(n_norm)) # ~ 1 (单位功率) + +**************** +随机过程 +**************** + +到目前为止我们讨论的是随机变量——某个单一时刻的随机值。 **随机过程** (也称为 **随机过程** ,Stochastic Process)是一组按时间索引的随机变量: + +.. math:: + X(t) \quad \text{或} \quad X[n] \text{(离散时间)} + +在每个时刻 :math:`t` ,:math:`X(t)` 都是一个随机变量。可以把随机过程想象成一个随时间随机演变的信号。 + +在无线通信中的例子: + +* 接收机处的噪声::math:`N(t)` 或 :math:`N[n]` +* 经历时变衰落的信号::math:`H(t)S(t)` +* 来自 SDR 的采样数据:每批数据都是随机过程的一次实现 + +**平稳过程** + +如果一个随机过程的统计特性不随时间变化,则称其为 **平稳** 的。特别地,一个 **广义平稳(Wide-Sense Stationary,WSS)** 过程具有: + +* 恒定均值:对所有 :math:`t` ,:math:`E[X(t)] = \mu` +* 自相关仅依赖于时间差::math:`E[X(t)X(t+\tau)]` 仅依赖于 :math:`\tau` ,而不依赖于 :math:`t` + +无线系统中的许多噪声源近似为平稳的,这大大简化了分析过程。 + +**白噪声** + +**白噪声** 是一种在不同时刻的样本之间不相关的随机过程,且其功率谱密度在所有频率上是恒定的。加性高斯白噪声(AWGN)同时具有以下两个特性: + +* **白** :时间上不相关,频谱平坦 +* **高斯** :每个样本都服从高斯分布 + +当我们在 Python 中使用 ``np.random.randn(N)`` 生成噪声时,:math:`N` 个样本中的每一个都是独立的高斯随机变量,共同构成一个白噪声过程。 + + +独立性与相关性 +############################# + +如果知道一个随机变量的值不能提供关于另一个的任何信息,则这两个随机变量 :math:`X` 和 :math:`Y` 是 **独立** 的。数学上,它们的联合 PDF 可以分解为: + +.. math:: + f_{X,Y}(x,y) = f_X(x) \cdot f_Y(y) + +独立性是一个很强的条件。一个较弱的条件是 **不相关** ,即: + +.. math:: + E[XY] = E[X]E[Y] + +对于高斯随机变量,不相关意味着独立(这是高斯分布的一个特殊性质)。 + +在复高斯噪声中,I 和 Q 分量是独立的: + +.. code-block:: python + N = 10000 + I = np.random.randn(N) + Q = np.random.randn(N) + + # 通过相关性检验独立性 + correlation = np.corrcoef(I, Q)[0, 1] + print(f"Correlation between I and Q: {correlation:.4f}") # ~ 0 + +*************************** +拓展阅读 +*************************** + +1. Papoulis, A., & Pillai, S. U. (2002). *Probability, Random Variables, and Stochastic Processes*. McGraw-Hill. +2. Kay, S. M. (2006). *Intuitive Probability and Random Processes using MATLAB®*. Springer. +3. https://en.wikipedia.org/wiki/Random_variable +4. https://en.wikipedia.org/wiki/Normal_distribution +5. https://en.wikipedia.org/wiki/Stochastic_process +6. https://en.wikipedia.org/wiki/Additive_white_Gaussian_noise +7. https://en.wikipedia.org/wiki/Signal-to-noise_ratio diff --git a/content-zh/pluto.rst b/content-zh/pluto.rst new file mode 100644 index 00000000..833b2305 --- /dev/null +++ b/content-zh/pluto.rst @@ -0,0 +1,826 @@ +.. _pluto-chapter: + +#################################### +Python 玩转 PlutoSDR +#################################### + +.. image:: ../_images/pluto.png + :scale: 50 % + :align: center + :alt: Analog Devices 推出的 PlutoSDR + +在本章中,我们将学习如何使用 `PlutoSDR `_ 的 Python API,它是 Analog Devices 推出的一款低成本 SDR。 +我们会先介绍 PlutoSDR 的安装步骤,确保驱动和软件正常运行,然后讨论如何在 Python 中使用 PlutoSDR 进行发射与接收。 +最后,我们还会介绍如何借助 `Maia SDR `_ 和 `IQEngine `_ 把 PlutoSDR 变成一台强大的频谱分析仪! + +************************ +PlutoSDR 概述 +************************ + +PlutoSDR(也叫 ADALM-PLUTO)是一款低成本 SDR(售价略高于 200 美元),能够收发 70 MHz 到 6 GHz 之间的信号。 +如果你已经不满足于 20 美元级别的 RTL-SDR,那么它会是一个很不错的升级选择。 +Pluto 使用 USB 2.0 接口,因此如果你想长期以 100% 占空比接收全部样本,采样率大约会被限制在 5 MHz 左右。 +不过,它本身最高可以采样到 61 MHz,并且一次能够抓取长度约为 1000 万个样本的连续数据块,这使得 Pluto 能够一次覆盖非常宽的频谱范围。 +严格来说,它是一台 2x2 设备,但第二路发射和第二路接收通道只能通过机壳内部的 U.FL 接头访问,而且它们共用同一组本振,因此你无法同时在两个不同频率上接收。 +下图展示了 Pluto 的方框图,以及 Pluto 内部使用的 AD936x 射频集成电路(RFIC)的方框图。 + +.. image:: ../_images/adi-adalm-pluto-diagram-large.jpg + :scale: 60 % + :align: center + :alt: PlutoSDR 方框图 + +.. image:: ../_images/ad9361.svg + :align: center + :target: ../_images/ad9361.svg + :alt: PlutoSDR 内部 AD9361/AD9363 RFIC 的方框图 + +******************************** +PlutoSDR 的软件与驱动安装 +******************************** + +为 PlutoSDR 搭建 Ubuntu 22 VM +#################################### + +虽然本书提供的 Python 代码应当可以在 Windows、Mac 和 Linux 下运行,但下面的安装说明是针对 Ubuntu 22 编写的。 +如果你按照 `Analog Devices 提供的说明 `_ 在自己的操作系统上安装软件时遇到困难,我建议安装一个 Ubuntu 22 的虚拟机(VM),然后按照下面的步骤操作。 +另一种选择是,如果你使用的是 Windows 11,那么 Windows Subsystem for Linux(WSL)里的 Ubuntu 22 通常运行良好,并且开箱即用地支持图形界面。 + +1. 安装并打开 `VirtualBox `_ 。 +2. 创建一个新的 VM。内存大小建议设置为你电脑总内存的 50%。 +3. 创建虚拟硬盘时,选择 VDI,并使用动态分配。15 GB 通常就够了;如果你想更稳妥一些,也可以分配更大的空间。 +4. 下载 Ubuntu 22 Desktop 的 .iso 文件 - https://ubuntu.com/download/desktop +5. 启动 VM。它会要求你选择安装介质,请选择 Ubuntu 22 Desktop 的 .iso 文件。选择 “install Ubuntu”,使用默认选项,期间会弹出一个提醒你即将进行更改的窗口,点击继续即可。然后设置用户名和密码,等待 VM 完成初始化。安装结束后 VM 会重启,但请在重启之后先让 VM 关机。 +6. 进入 VM 设置(齿轮图标)。 +7. 在 system > processor 中至少选择 3 个 CPU。如果你的电脑有独立显卡,那么在 display > video memory 中可以把显存设得更高一些。 +8. 启动你的 VM。 +9. 建议你安装 VM Guest Additions。在 VM 内选择 Devices > Insert Guest Additions CD,弹窗出现时点击运行。按照提示完成安装后重启 VM。共享剪贴板可以通过 Devices > Shared Clipboard > Bidirectional 开启。 + +连接 PlutoSDR +################### + +1. 如果你使用的是 OSX,请在宿主机的 OSX 中而不是 VM 内,在系统偏好设置中启用 “kernel extensions”,然后安装 HoRNDIS(可能需要重启)。 +2. 如果你使用的是 Windows,请安装这个驱动: https://github.com/analogdevicesinc/plutosdr-m2k-drivers-win/releases/download/v0.7/PlutoSDR-M2k-USB-Drivers.exe +3. 如果你使用的是 Linux,通常不需要做任何额外处理。 +4. 通过 USB 把 Pluto 连接到宿主机。注意一定要使用 Pluto 中间的那个 USB 接口,因为另一个接口只负责供电。连接之后,Pluto 会表现为一个虚拟网卡,也就是说,它会像一个 USB 以太网适配器那样出现在系统里。 +5. 在宿主机(不是 VM)上打开终端或你喜欢的 ping 工具,ping :code:`192.168.2.1`。如果不通,就先停下来排查网络接口问题。 +6. 在 VM 内打开一个新的终端。 +7. Ping :code:`192.168.2.1`。如果不通,也先停下来排查。当你在 ping 的时候,拔掉 Pluto,确认 ping 会立刻中断;如果它依然持续响应,那就说明网络里还有其他设备使用了这个 IP,继续之前你得先修改 Pluto(或那个其他设备)的 IP 地址。 +8. 记下 Pluto 的 IP 地址,因为后面我们在 Python 中使用它时会用到。 + +安装 PlutoSDR 驱动及 Python API +#################################### + +下面这些终端命令会构建并安装以下库的最新版本: + +1. **libiio**,Analog Devices 的 “跨平台” 硬件接口库 +2. **libad9361-iio**,AD9361 是 PlutoSDR 内部使用的具体射频芯片 +3. **pyadi-iio**,也就是 Pluto 的 Python API,*这才是我们的最终目标*,但它依赖前面两个库 + + +.. code-block:: bash + + sudo apt-get update + sudo apt-get install build-essential git libxml2-dev bison flex libcdk5-dev cmake python3-pip libusb-1.0-0-dev libavahi-client-dev libavahi-common-dev libaio-dev + cd ~ + git clone --branch v0.23 https://github.com/analogdevicesinc/libiio.git + cd libiio + mkdir build + cd build + cmake -DPYTHON_BINDINGS=ON .. + make -j$(nproc) + sudo make install + sudo ldconfig + + cd ~ + git clone https://github.com/analogdevicesinc/libad9361-iio.git + cd libad9361-iio + mkdir build + cd build + cmake .. + make -j$(nproc) + sudo make install + + cd ~ + git clone --branch v0.0.14 https://github.com/analogdevicesinc/pyadi-iio.git + cd pyadi-iio + pip3 install --upgrade pip + pip3 install -r requirements.txt + sudo python3 setup.py install + +测试 PlutoSDR 驱动以及 Python API +#################################### + +在你的 VM 中新开一个终端,然后输入以下命令: + +.. code-block:: bash + + python3 + import adi + sdr = adi.Pluto('ip:192.168.2.1') # 或者改成你的 Pluto 实际 IP + sdr.sample_rate = int(2.5e6) + sdr.rx() + +如果运行到这里都没有报错,那就可以继续后面的内容了。 + +修改 Pluto 的 IP 地址 +#################################### + +如果默认的 :code:`192.168.2.1` 因为某些原因不适用,例如你的网络里已经存在 :code:`192.168.2.0` 这个子网,或者你想同时连接多台 Pluto,那么可以按照下面的步骤修改 IP: + +1. 打开 PlutoSDR 的 :code:`config.txt` 文件进行编辑,它位于 Pluto 的大容量存储设备中(也就是你插上 Pluto 后出现的那个看起来像 U 盘的设备)。把你想使用的新 IP 写进去。 +2. 弹出这个大容量存储设备(注意,不要拔掉 Pluto!)。在 Ubuntu 22 中,你会在文件管理器里 PlutoSDR 设备旁边看到一个弹出图标。 +3. 等待几秒钟,然后通过拔下再重新插上 Pluto 的方式重新上电。之后再次打开 :code:`config.txt`,确认你的修改是否保存成功。 + +需要注意的是,这个流程也同样用于给 Pluto 刷入不同的固件镜像。更多细节请参见 https://wiki.analog.com/university/tools/pluto/users/firmware 。 + +“Hack” PlutoSDR 以扩展射频范围 +#################################### + +PlutoSDR 出厂时的中心频率范围和采样率是受限制的,但其底层芯片实际上支持更高的频率。 +按照下面的步骤可以解锁芯片的完整频率范围。 +请注意,这个过程本身就是 Analog Devices 官方提供的,因此风险已经尽可能低。 +PlutoSDR 的频率限制与 Analog Devices 对 AD936x 芯片按高频性能要求进行 “分档(binning)” 有关。 +而对于 SDR 爱好者和实验者来说,我们通常并不会过分在意这些更高频率下的严格性能指标。 + +开始 hack 吧!打开一个终端(宿主机或 VM 都可以): + +.. code-block:: bash + + ssh root@192.168.2.1 + +默认密码是 :code:`analog` + +你应该会看到 PlutoSDR 的欢迎界面。现在你已经通过 SSH 登录到了 Pluto 本体上的 ARM CPU! +如果你的 Pluto 固件版本是 0.31 或更低,请输入下面的命令: + +.. code-block:: bash + + fw_setenv attr_name compatible + fw_setenv attr_val ad9364 + reboot + +如果是 0.32 及以上版本,则使用: + +.. code-block:: bash + + fw_setenv compatible ad9364 + reboot + +现在你应该就可以把中心频率调到最低 70 MHz、最高 6 GHz,并把采样率提高到最高 56 MHz 了! + +************************ +PlutoSDR 接收 +************************ + +使用 PlutoSDR 的 Python API 进行采样是非常直接的。 +对于任何一款 SDR,我们都知道至少要告诉它中心频率、采样率以及增益(或者是否启用自动增益控制)。 +可能还有其他细节参数,但这三项是最基本的,没有它们 SDR 就不知道该如何接收样本。 +有些 SDR 需要你显式发送一条命令才能开始采样,而 Pluto 这样的设备会在初始化完成后立即开始采样。 +当 SDR 内部缓冲区被填满后,最旧的样本就会被丢弃。 +所有 SDR API 基本都会提供某种 “接收样本” 函数,而 Pluto 中对应的就是 :code:`rx()`,它会返回一批样本。 +每一批返回多少样本,则由你事先设置好的缓冲区大小决定。 + +下面的代码假设你已经安装好了 Pluto 的 Python API。 +这段代码会初始化 Pluto,将采样率设置为 1 MHz,中心频率设置为 100 MHz,并将接收增益设置为 70 dB,同时关闭自动增益控制。 +注意,设置中心频率、增益和采样率的顺序通常并不重要。 +在下面的代码片段中,我们告诉 Pluto 每次调用 :code:`rx()` 时返回 10,000 个样本,并打印前 10 个样本。 + +.. code-block:: python + + import numpy as np + import adi + + sample_rate = 1e6 # Hz + center_freq = 100e6 # Hz + num_samps = 10000 # 每次调用 rx() 返回的样本数 + + sdr = adi.Pluto('ip:192.168.2.1') + sdr.gain_control_mode_chan0 = 'manual' + sdr.rx_hardwaregain_chan0 = 70.0 # dB + sdr.rx_lo = int(center_freq) + sdr.sample_rate = int(sample_rate) + sdr.rx_rf_bandwidth = int(sample_rate) # 滤波器带宽,这里先直接设成和采样率一样 + sdr.rx_buffer_size = num_samps + + samples = sdr.rx() # 从 Pluto 接收样本 + print(samples[0:10]) + + +目前我们还不会对这些样本做什么特别有趣的处理,但本书剩下的大部分内容都围绕这类 IQ 样本展开,并使用 Python 对它们进行处理。 + + +PlutoSDR 接收增益(Receive Gain) +#################################### + +Pluto 可以配置成固定接收增益,也可以配置成自动接收增益。 +自动增益控制(Automatic Gain Control,AGC)会自动调整接收增益,以维持一个较强的信号电平(如果你好奇的话,目标大约是 -12 dBFS)。 +AGC 不要和负责把信号数字化的模数转换器(ADC)混淆。 +从严格意义上说,AGC 是一个闭环反馈电路,它会根据接收到的信号情况来调节放大器的增益。 +它的目标是在输入功率变化时维持相对恒定的输出功率,同时既避免接收机饱和(也就是碰到 ADC 动态范围的上限),又尽可能让信号 “填满” 更多 ADC 位数。 + +PlutoSDR 内部的射频集成电路(RFIC)包含一个支持多种设置的 AGC 模块。 +(RFIC 指的是一种能够同时发射和接收无线电信号的芯片。) +首先需要注意,Pluto 的接收增益范围是 0 到 74.5 dB。 +当设置为 “manual” 模式时,AGC 会被关闭,此时你必须显式告诉 Pluto 使用多大的接收增益,例如: + +.. code-block:: python + + + sdr.gain_control_mode_chan0 = "manual" # 关闭 AGC + gain = 50.0 # 允许范围是 0 到 74.5 dB + sdr.rx_hardwaregain_chan0 = gain # 设置接收增益 + +如果你想启用 AGC,则必须从以下两种模式中选择一种: + +1. :code:`sdr.gain_control_mode_chan0 = "slow_attack"` +2. :code:`sdr.gain_control_mode_chan0 = "fast_attack"` + +启用 AGC 后,你就不需要再给 :code:`rx_hardwaregain_chan0` 赋值了。 +因为 Pluto 会自行调节增益,所以这个值会被忽略。 +Pluto 的 AGC 提供 fast attack 和 slow attack 两种模式,正如上面的代码所示。 +它们之间的差别其实很好理解:fast attack 模式对信号变化反应更快。 +换句话说,当接收信号的强度变化时,增益值也会更快地跟着变化。 +这种对信号功率变化的快速适应在时分双工(TDD)系统中尤其重要,因为 TDD 系统会在同一个频率上轮流发射和接收。 +在这种场景下,把增益控制设为 fast attack 模式,可以减小信号被过度压低的程度。 +无论使用哪种模式,如果当前没有信号、只有噪声,那么 AGC 都会把增益顶到最大;一旦信号突然出现,接收机会短暂饱和,直到 AGC 反应过来并把增益拉低。 +你也可以通过下面的代码实时查看当前的增益值: + +.. code-block:: python + + sdr._get_iio_attr('voltage0','hardwaregain', False) + +关于 Pluto 的 AGC 的更多细节,例如如何修改更高级的 AGC 设置,请参考 `这个页面中的 “RX Gain Control” 部分 `_ 。 + +************************ +PlutoSDR 发射 +************************ + +在用 Pluto 发射任何信号之前,请务必先用一根 SMA 线缆把 Pluto 的 TX 端口和充当接收机的设备连接起来。 +尤其是在你还在学习 *如何* 发射的时候,一定要先通过线缆发射,这样才能确认 SDR 的行为完全符合预期。 +发射功率务必要从极低开始,因为线缆不像无线信道那样会对信号产生衰减,接收机的射频前端有可能会过载。 +如果你手头有一个衰减器(例如 30 dB),现在正是派上用场的时候。 +如果你没有另一台 SDR 或频谱分析仪来充当接收机,理论上可以用同一台 Pluto 的 RX 端口来接收,但那会变得有些复杂。 +我更建议你买一个 10 美元级别的 RTL-SDR 作为接收端 SDR。 + +发射和接收非常相似,只不过这一次不再是告诉 SDR 要接收多少样本,而是把一批要发射的样本交给它。 +我们不再设置 :code:`rx_lo`,而是设置 :code:`tx_lo`,用于指定载波发射频率。 +采样率是 RX 和 TX 共用的,因此仍然像平常一样设置即可。 +下面给出了一个完整的发射示例:我们生成一个 +100 kHz 的正弦,然后在 915 MHz 的载波频率上发射这组复信号,因此接收端会在 915.1 MHz 看到一个载波。 +这在工程上其实没有什么实际意义,因为我们完全可以直接把 :code:`center_freq` 设为 :code:`915.1e6`,再发射一个全 1 的数组。 +这里只是为了演示如何生成复数样本。 + +.. code-block:: python + + import numpy as np + import adi + + sample_rate = 1e6 # Hz + center_freq = 915e6 # Hz + + sdr = adi.Pluto("ip:192.168.2.1") + sdr.sample_rate = int(sample_rate) + sdr.tx_rf_bandwidth = int(sample_rate) # 滤波器截止频率,这里先直接设成和采样率一样 + sdr.tx_lo = int(center_freq) + sdr.tx_hardwaregain_chan0 = -50 # 增大该值可以增大发射功率,有效范围是 -90 到 0 dB + + N = 10000 # 一次要发射的样本数 + t = np.arange(N)/sample_rate + samples = 0.5*np.exp(2.0j*np.pi*100e3*t) # 模拟一个 100 kHz 正弦,因此接收端应在 915.1 MHz 看到它 + samples *= 2**14 # PlutoSDR 要求样本范围在 -2^14 到 +2^14 之间,而不是某些 SDR 使用的 -1 到 +1 + + # 将这一批样本发射 100 次,如果 USB 跟得上,总共就相当于 1 秒的信号 + for i in range(100): + sdr.tx(samples) # 发射这一批样本一次 + +关于这段代码,这里有几点需要说明。 +首先,在仿真 IQ 样本时,你应当让它们的数值位于 -1 到 1 之间;但在真正发射之前,由于 Analog Devices 对 :code:`tx()` 函数的实现方式,我们必须把它们乘以 :math:`2^{14}`。 +如果你不确定样本的最小值和最大值是多少,最简单的方法就是用 :code:`print(np.min(samples), np.max(samples))` 打印出来,或者写一个 if 语句确保它们在乘以 :math:`2^{14}` 之前从不超过 1 或低于 -1。 +至于发射增益,它的范围是 -90 到 0 dB,其中 0 dB 对应最大的发射功率。 +我们总是希望从较低的发射功率开始,必要时再逐步往上调,因此这里默认设置为 -50 dB,属于偏低的一侧。 +不要因为信号没出现就直接把它拉到 0 dB,问题很可能出在别的地方,而你并不想把接收机烧坏。 + +重复发射样本 +############################## + +如果你想连续重复发射同一组样本,而不是像上面那样在 Python 里用 for/while 循环不断调用,可以只用一行代码告诉 Pluto 这么做: + +.. code-block:: python + + sdr.tx_cyclic_buffer = True # 启用循环缓冲区 + +然后像平常一样调用一次 :code:`sdr.tx(samples)` 即可,Pluto 会无限循环发射这组信号,直到 :code:`sdr` 对象被析构。 +如果你想更换正在循环发射的样本,不能直接再次调用 :code:`sdr.tx(samples)` 传入一组新样本,而必须先调用 :code:`sdr.tx_destroy_buffer()`,然后再调用 :code:`sdr.tx(samples)`。 + +如何合法地进行空口发射 +################################# + +我已经无数次被学生问到,在美国,使用天线配合 Pluto 发射时,哪些频率是允许发射的。 +就我所知,简短答案是:没有。 +通常,当人们引用某些提到发射功率限制的法规时,他们指的是 `FCC 的 “Title 47, Part 15” (47 CFR 15) 法规 `_ 。 +但这些规定实际上是面向在 ISM 频段设计和销售设备的制造商,讨论的是这些设备应如何被测试。 +所谓 Part 15 设备,是指个人在其所使用的频谱上操作该设备时不需要执照的设备,但设备本身在被营销和销售之前,必须先获得授权/认证,以证明其符合 FCC 法规。 +Part 15 规定确实为不同频段规定了最大发射功率和接收功率级别,但这些规定实际上并不适用于个人使用 SDR 或自制无线电设备发射信号的情形。 +我能找到的、与并非商品化产品的无线电设备相关的法规,主要只涉及在 AM/FM 广播频段运行低功率的 AM 或 FM 电台。 +法规中还有一节提到 “自制设备(home-built devices)”,但它明确表示不适用于通过套件组装出来的设备,而把一个基于 SDR 的发射系统称作自制设备也有些牵强。 +总之,FCC 法规并不是简单的 “你只能在这些频率、这些功率以下发射”,而是一整套围绕测试与合规构建出来的复杂规则。 + +换个角度看,也可以说:“这些不是 Part 15 设备,那我们就姑且按照 Part 15 的规则来约束自己。” +以 915 MHz ISM 频段为例,规则要求该频段内辐射发射的场强在 30 米处不得超过 500 微伏/米,并且测量应基于采用平均检波器的仪器。 +所以你可以看到,这并不是一个简单的 “最大发射功率是多少瓦” 的问题。 + +如果你拥有业余无线电(ham radio)执照,那么 FCC 允许你使用专门划分给业余无线电业务的频段。 +这些频段仍然有需要遵守的规则以及最大发射功率限制,但至少这些数值是以有效辐射功率多少瓦来规定的。 +`这张信息图 `_ 展示了不同执照等级(Technician、General 和 Extra)可以使用哪些频段。 +我建议所有想用 SDR 做发射的人都去考一个业余无线电执照,更多信息可参见 `ARRL 的 Getting Licensed 页面 `_ 。 + +如果有人对哪些行为被允许、哪些不被允许有更详细的信息,请给我发邮件。 + +************************************************ +同时进行发射与接收 +************************************************ + +借助 :code:`tx_cyclic_buffer` 这个技巧,你可以很容易地同时进行接收和发射,只需要先把发射机启动起来,再去接收即可。 +下面的代码展示了一个可运行的例子:在 915 MHz 频段发射一个 QPSK 信号,同时接收它,并绘制功率谱密度(PSD)。 + +.. code-block:: python + + import numpy as np + import adi + import matplotlib.pyplot as plt + + sample_rate = 1e6 # Hz + center_freq = 915e6 # Hz + num_samps = 100000 # 每次调用 rx() 返回的样本数 + + sdr = adi.Pluto("ip:192.168.2.1") + sdr.sample_rate = int(sample_rate) + + # 配置发射 + sdr.tx_rf_bandwidth = int(sample_rate) # 滤波器截止频率,这里先直接设成和采样率一样 + sdr.tx_lo = int(center_freq) + sdr.tx_hardwaregain_chan0 = -50 # 增大该值可以增大发射功率,有效范围是 -90 到 0 dB + + # 配置接收 + sdr.rx_lo = int(center_freq) + sdr.rx_rf_bandwidth = int(sample_rate) + sdr.rx_buffer_size = num_samps + sdr.gain_control_mode_chan0 = 'manual' + sdr.rx_hardwaregain_chan0 = 0.0 # dB,增大该值可以提高接收增益,但要小心不要让 ADC 饱和 + + # 创建发射波形(QPSK,每个符号 16 个样本) + num_symbols = 1000 + x_int = np.random.randint(0, 4, num_symbols) # 0 到 3 + x_degrees = x_int*360/4.0 + 45 # 45、135、225、315 度 + x_radians = x_degrees*np.pi/180.0 # sin() 和 cos() 使用的是弧度 + x_symbols = np.cos(x_radians) + 1j*np.sin(x_radians) # 生成我们的 QPSK 复符号 + samples = np.repeat(x_symbols, 16) # 每个符号 16 个样本(矩形脉冲) + samples *= 2**14 # PlutoSDR 要求样本范围在 -2^14 到 +2^14 之间,而不是某些 SDR 使用的 -1 到 +1 + + # 启动发射机 + sdr.tx_cyclic_buffer = True # 启用循环缓冲区 + sdr.tx(samples) # 开始发射 + + # 为了稳妥起见先清空一下缓冲区 + for i in range (0, 10): + raw_data = sdr.rx() + + # 接收样本 + rx_samples = sdr.rx() + print(rx_samples) + + # 停止发射 + sdr.tx_destroy_buffer() + + # 计算功率谱密度(即信号的频域表示) + psd = np.abs(np.fft.fftshift(np.fft.fft(rx_samples)))**2 + psd_dB = 10*np.log10(psd) + f = np.linspace(sample_rate/-2, sample_rate/2, len(psd)) + + # 绘制时域图 + plt.figure(0) + plt.plot(np.real(rx_samples[::100])) + plt.plot(np.imag(rx_samples[::100])) + plt.xlabel("Time") + + # 绘制频域图 + plt.figure(1) + plt.plot(f/1e6, psd_dB) + plt.xlabel("Frequency [MHz]") + plt.ylabel("PSD") + plt.show() + + +如果你的天线或线缆连接正确,你应该会看到类似下图的结果: + +.. image:: ../_images/pluto_tx_rx.svg + :align: center + +一个很好的练习是缓慢调整 :code:`sdr.tx_hardwaregain_chan0` 和 :code:`sdr.rx_hardwaregain_chan0`,确认接收到的信号会按预期变强或变弱。 + +********************************** +Maia SDR 与 IQEngine +********************************** + +想把你的 Pluto 变成电脑或手机上的实时频谱分析仪吗? +开源的 `Maia SDR `_ 项目为 Pluto 提供了一个修改过的固件镜像,它会在 Pluto 的 FPGA 上运行 FFT,并在 Pluto 的 ARM CPU 上运行一个 Web 服务器! +这个 Web 界面可以用来设置频率和其他 SDR 参数,并以瀑布图形式查看时频谱。 +你还可以录制最大 400 MB 的原始 IQ 样本,并将它们下载到电脑或手机上,或者直接在 IQEngine 中查看。 + +安装最新版本的 Maia Pluto 固件时,先下载 `latest release `_,具体要选文件名为 :code:`plutosdr-fw-maia-sdr-vX.Y.Z.zip` 的那个。 +解压后,将其中的 :code:`pluto.frm` 文件复制到 Pluto 的大容量存储设备中(它看起来就像一个 U 盘),然后弹出 Pluto(不要拔线)。 +这和升级 Pluto 固件的过程是一样的;设备会闪烁几分钟,然后自动重启。 +最后,像我们在 “hack Pluto” 一节中那样,通过终端执行 :code:`ssh root@192.168.2.1` 来 SSH 登录 Pluto,默认密码为 :code:`analog`。 +登录之后,你需要按顺序逐条执行下面这三条命令: + +.. code-block:: bash + + fw_setenv ramboot_verbose 'adi_hwref;echo Copying Linux from DFU to RAM... && run dfu_ram;if run adi_loadvals; then echo Loaded AD936x refclk frequency and model into devicetree; fi; envversion;setenv bootargs console=ttyPS0,115200 maxcpus=${maxcpus} rootfstype=ramfs root=/dev/ram0 rw earlyprintk clk_ignore_unused uio_pdrv_genirq.of_id=uio_pdrv_genirq uboot="${uboot-version}" && bootm ${fit_load_address}#${fit_config}' + + fw_setenv qspiboot_verbose 'adi_hwref;echo Copying Linux from QSPI flash to RAM... && run read_sf && if run adi_loadvals; then echo Loaded AD936x refclk frequency and model into devicetree; fi; envversion;setenv bootargs console=ttyPS0,115200 maxcpus=${maxcpus} rootfstype=ramfs root=/dev/ram0 rw earlyprintk clk_ignore_unused uio_pdrv_genirq.of_id=uio_pdrv_genirq uboot="${uboot-version}" && bootm ${fit_load_address}#${fit_config} || echo BOOT failed entering DFU mode ... && run dfu_sf' + + fw_setenv qspiboot 'set stdout nulldev;adi_hwref;test -n $PlutoRevA || gpio input 14 && set stdout serial@e0001000 && sf probe && sf protect lock 0 100000 && run dfu_sf; set stdout serial@e0001000;itest *f8000258 == 480003 && run clear_reset_cause && run dfu_sf; itest *f8000258 == 480007 && run clear_reset_cause && run ramboot_verbose; itest *f8000258 == 480006 && run clear_reset_cause && run qspiboot_verbose; itest *f8000258 == 480002 && run clear_reset_cause && exit; echo Booting silently && set stdout nulldev; run read_sf && run adi_loadvals; envversion;setenv bootargs console=ttyPS0,115200 maxcpus=${maxcpus} rootfstype=ramfs root=/dev/ram0 rw quiet loglevel=4 clk_ignore_unused uio_pdrv_genirq.of_id=uio_pdrv_genirq uboot="${uboot-version}" && bootm ${fit_load_address}#${fit_config} || set stdout serial@e0001000;echo BOOT failed entering DFU mode ... && sf protect lock 0 100000 && run dfu_sf' + +(关于为什么需要这样设置,更多信息请参见 `Maia 的安装页面 `_ 。) + +再重启一次 Pluto。 +此时,Pluto 就应该已经运行 Maia 了! +在浏览器中打开 http://192.168.2.1:8000 ,你应该会看到 Maia 的实时频谱分析界面和 SDR 控制面板,如下图所示: + +.. image:: ../_images/Maia.png + :scale: 40 % + :align: center + :alt: Maia SDR 截图 + +想测试 Maia 能跑多快,可以尝试把 :code:`Spectrum Rate` 调到 100 Hz 或更高。 +除了频率、采样率和增益等常见 SDR 旋钮之外,你还可以点击底部的 :code:`Record` 按钮,把原始 IQ 样本录制到 Pluto 的板载内存中。 +随后你可以点击 :code:`Recording` 按钮,再点击 :code:`View in IQEngine` 链接,在 IQEngine 中查看录制内容,如下图所示,或者把文件保存到你的设备上。 + +.. image:: ../_images/IQEngine_from_Maia.png + :scale: 40 % + :align: center + :alt: 从 Maia SDR 打开的 IQEngine 截图 + + +************************ +参考 API +************************ + +如果你想查看完整的 SDR 属性和可调用函数列表,请参考 `pyadi-iio 中的 Pluto Python 代码(AD936X) `_ 。 + +******************************** +PlutoSDR Python 练习 +******************************** + +与其直接给你一段现成代码去运行,不如通过几个练习来巩固。 +这些练习中大约 95% 的代码已经给出,剩下的部分只是一些相对直接的 Python 内容,需要你自己补上。 +这些练习并不是为了难住你,而是只留下足够少的空白,让你能主动思考一下。 + +练习 1:测出你的 USB 吞吐量 +######################################### + +让我们尝试从 PlutoSDR 接收样本,同时看看通过 USB 2.0 连接,每秒到底能推多少样本到主机上。 + +**你的任务是编写一个 Python 脚本,测量 Python 端每秒实际接收到的样本数。也就是说,要统计接收到的总样本数并记录所花费的时间,然后用它们算出速率。接着,尝试不同的 :code:`sample_rate` 和 :code:`buffer_size`,看看它们会如何影响可达到的最高速率。** + +请记住,如果你每秒接收到的样本数小于设定的 :code:`sample_rate`,那就说明有一部分样本丢失了,而这在高采样率下很可能发生。 +Pluto 只使用 USB 2.0。 + +下面这段代码可以作为起点,并且其中已经包含了完成任务所需的基础设置。 + +.. code-block:: python + + import numpy as np + import adi + import matplotlib.pyplot as plt + import time + + sample_rate = 10e6 # Hz + center_freq = 100e6 # Hz + + sdr = adi.Pluto("ip:192.168.2.1") + sdr.sample_rate = int(sample_rate) + sdr.rx_rf_bandwidth = int(sample_rate) # 滤波器截止频率,这里先直接设成和采样率一样 + sdr.rx_lo = int(center_freq) + sdr.rx_buffer_size = 1024 # 这是 Pluto 用来缓存样本的缓冲区大小 + samples = sdr.rx() # 从 Pluto 接收样本 + +此外,为了测量某段代码执行了多久,你可以使用下面的方式: + +.. code-block:: python + + start_time = time.time() + # 做一些事情 + end_time = time.time() + print('seconds elapsed:', end_time - start_time) + +下面是一些提示,帮助你开始: + +提示 1:你需要把 :code:`samples = sdr.rx()` 放进一个循环里反复执行很多次(例如 100 次)。每次调用 :code:`sdr.rx()` 时,都要统计返回了多少样本,同时记录经过了多少时间。 + +提示 2:虽然你要计算的是每秒样本数,但这并不意味着你必须刚好采 1 秒。你只需要把接收到的样本总数除以所经过的时间即可。 + +提示 3:就像示例里那样,先从 :code:`sample_rate = 10e6` 开始,因为这个速率已经远远超出了 USB 2.0 的承载能力。这样你就能看到究竟有多少数据真的传了过来。然后你可以调整 :code:`rx_buffer_size`,把它调得大很多,看看会发生什么。等你写好了可运行脚本并尝试过不同的 :code:`rx_buffer_size` 后,再去调整 :code:`sample_rate`。最终找出你需要把采样率降到多低,才能在 Python 中 100% 接收所有样本(也就是达到 100% 占空比采样)。 + +提示 4:在那个循环里调用 :code:`sdr.rx()` 时,尽量少做别的事情,避免额外增加执行延迟。不要在循环内部做昂贵操作,比如反复打印。 + +通过这个练习,你会对 USB 2.0 的最大吞吐量建立一个直观认识。 +你也可以上网查找资料,验证自己的结果是否合理。 + +额外挑战:试着修改 :code:`center_freq` 和 :code:`rx_rf_bandwidth`,看看它们是否会影响你从 Pluto 接收样本的速率。 + + +练习 2:创建时频谱/瀑布图 +########################################## + +在这个练习中,你将创建一个时频谱,也就是我们在 :ref:`freq-domain-chapter` 章节末尾学过的瀑布图。 +时频谱本质上就是把一堆 FFT 结果一层层堆叠显示出来。 +换句话说,它是一张图像,其中一个轴表示频率,另一个轴表示时间。 + +在 :ref:`freq-domain-chapter` 章节中,我们已经学过如何用 Python 执行 FFT。 +这个练习里,你可以复用上一题里的代码片段,再加上一点基础 Python 代码就够了。 + +提示: + +1. 可以尝试把 :code:`sdr.rx_buffer_size` 设成 FFT 大小,这样每次调用 :code:`sdr.rx()` 时就刚好执行 1 次 FFT。 +2. 构建一个二维数组来保存所有 FFT 结果,其中每一行表示 1 次 FFT。一个填满 0 的 2D 数组可以通过下面的方式创建: :code:`np.zeros((num_rows, fft_size))` 。访问数组的第 :code:`i` 行可以使用: :code:`waterfall_2darray[i,:]` 。 +3. :code:`plt.imshow()` 是显示二维数组的一个非常方便的方法,它会自动帮你缩放颜色。 + +额外挑战:让这个时频谱实时更新。 + +****** +Pluto+ +****** + +Pluto+(也叫 Pluto Plus)是原版 PlutoSDR 的非官方升级版本,主要可以在 AliExpress 上买到。 +它带有千兆以太网接口、通过 SMA 引出的两路 RX 和两路 TX、MicroSD 插槽、0.5PPM 的 VCTCXO,以及 PCB 上通过 U.FL 提供的外部时钟输入。 + +.. image:: ../_images/pluto_plus.png + :scale: 70 % + :align: center + :alt: Pluto Plus + +以太网口是一个非常大的升级,因为它极大提高了你在 100% 占空比接收或发射时能够达到的采样率。 +Pluto 和 Pluto+ 默认都用 16 位来表示 I 和 Q,尽管它实际上只有一个 12 位 ADC,因此每个 IQ 样本总共占 4 个字节。 +按 90% 传输效率估算,千兆以太网约等于 900 Mb/s,也就是 112.5 MB/s,因此若每个 IQ 样本占 4 字节,那么如果你想在较长时间内(例如超过 1 秒)把所有样本都接收下来,对应的最大采样率大约是 28 MHz。 +作为对比,USB 3.0 大约可以做到 56 MHz,而 USB 2.0 大约是 5 MHz。 +除此之外,你的电脑性能、你打算在这些样本上运行的具体 DSP 应用(或者如果你只是录制到文件中,那么磁盘写入速度)也都会形成额外瓶颈。 +对于基于 Python 的 SDR 应用来说,通过以太网使用 Pluto+ 时,更现实的采样率通常接近 10 MHz。 + +.. image:: ../_images/pluto_plus_pcb.jpg + :scale: 30 % + :align: center + :alt: Pluto Plus 的 PCB 照片 + +要给以太网口设置 IP 地址,请先通过 USB 连接 Pluto+,打开它的大容量存储设备,编辑 :code:`config.txt` 里的 :code:`[USB_ETHERNET]` 部分。 +然后给 Pluto+ 重新上电。 +此时你应该就能通过刚刚填入的 IP 地址,经由以太网 SSH 到 Pluto+ 了。 +如果这样可以工作,你就可以把 micro USB 线改插到 5V 供电口,让它只负责给 Pluto+ 供电,而所有通信都通过以太网完成。 +请记住,即使是普通的 PlutoSDR(以及 Pluto+),也能够以最高 61 MHz 的带宽进行采样,并一次抓取大约 1000 万个连续样本,只要你在两次抓取之间稍作等待即可,因此它依然非常适合做强大的频谱感知应用。 + +Pluto+ 的 Python 代码与普通 PlutoSDR 完全一样,只需要把 :code:`192.168.2.1` 替换成你为以太网设置的 IP 地址即可。 +你可以试着在循环中不断接收样本,并统计每秒接收到了多少,从而看看在 Python 端仍然能够每秒接收到接近设定采样率样本数的情况下,采样率究竟能推多高。 +提示:把 :code:`rx_buffer_size` 调得非常大,会有助于提高吞吐量。 + +************ +AntSDR E200 +************ + +AntSDR E200(下文简称 AntSDR)是一款基于 936X 的低成本 SDR,由中国上海的一家公司 MicroPhase 制造,在设计上和 Pluto、Pluto+ 非常相似。 +与 Pluto+ 类似,它使用 1 Gb 以太网连接,不过 AntSDR 不提供 USB 数据连接选项。 +AntSDR 的独特之处在于,它既可以像 Pluto 一样使用 IIO 库工作,也可以像 USRP 一样使用 UHD 库工作。 +默认情况下,它出厂时表现得像一台 Pluto,但切换到 USRP/UHD 模式只需要一次简单的固件更新。 +这两套固件本质上都是在 Analog Devices/Ettus 原始固件基础上做了极少量修改,以适配 AntSDR 的硬件。 +另一个特别之处是,你可以购买安装了 9363 或 9361 芯片的版本;虽然它们在功能上是同一类芯片,但 9361 在工厂分档时会被归为具有更高高频性能的版本。 +注意,Pluto 和 Pluto+ 都只使用 9363。 +AntSDR 的规格说明声称,基于 9363 的版本最高只能到 3.8 GHz、采样率最高 20 MHz,但事实并非如此;它实际上可以达到完整的 6 GHz,以及大约 60 MHz 的采样率(当然,1 Gb 以太网上无法长期传回 100% 的样本)。 +和其他 Pluto 一样,AntSDR 也是一台 2x2 设备,第二路发射和接收通道可以通过板上的 U.FL 接头访问。 +其余射频性能和技术指标则与 Pluto/Pluto+ 相近甚至完全相同。 +它可以从 `Crowd Supply `_ 和 AliExpress 购买。 + +.. image:: ../_images/AntSDR.png + :scale: 80 % + :align: center + :alt: 带可选外壳的 AntSDR E200 + +AntSDR 上那个小小的 DIP 开关用于在 SD 卡启动和板载 Quad SPI(QSPI)闪存启动之间切换。 +在写作本文时,E200 的 QSPI 中预装的是 Pluto 固件,而 SD 卡中预装的是 USRP/UHD 固件,因此只需拨动这个开关,就可以在两种模式之间切换,无需额外操作。 + +下面展示的是 E200 的方框图。 + +.. image:: ../_images/AntSDR_E200_block_diagram.png + :scale: 80 % + :align: center + :alt: AntSDR E200 方框图 + +以 Pluto 模式配置和使用 AntSDR 的方法与 Pluto+ 类似,只需要注意它的默认 IP 是 :code:`192.168.1.10`,并且它没有 USB 数据连接,因此也就没有可以用来更新固件或修改设置的大容量存储设备。 +相应地,你可以通过 SD 卡更新固件,通过 SSH 修改设置。 +另外,如果你能够 SSH 登录到设备,也可以使用下面这条命令修改设备的 IP 地址: :code:`fw_setenv ipaddr_eth 192.168.2.1` ,只需把这里的 IP 替换成你想要的地址即可。 +Pluto/IIO 固件可以在这里找到: `AntSDR Pluto 固件仓库`_ ,USRP/UHD 固件在这里: `AntSDR UHD 固件仓库`_ 。 + +如果你的 SD 卡里没有附带 USRP/UHD 驱动,或者你想安装最新版,那么可以参考 `MicroPhase 的 Quick Start Guide`_ ,在 AntSDR 上安装 USRP/UHD 固件,同时在你的主机上安装一份经过轻微修改的 UHD 主机端驱动。 +之后你就可以像平常一样使用 ``uhd_find_devices`` 和 ``uhd_usrp_probe`` (更多信息以及适用于 AntSDR 的 USRP 模式示例代码,请参见 USRP 章节)。 +下面这些命令是在 Ubuntu 22 上安装主机端代码时使用的: + +.. code-block:: bash + + sudo apt-get update + sudo apt-get install autoconf automake build-essential ccache cmake cpufrequtils doxygen ethtool \ + g++ git inetutils-tools libboost-all-dev libncurses5 libncurses5-dev libusb-1.0-0 libusb-1.0-0-dev \ + libusb-dev python3-dev python3-mako python3-numpy python3-requests python3-scipy python3-setuptools \ + python3-ruamel.yaml + cd ~ + git clone git@github.com:MicroPhase/antsdr_uhd.git + cd host + mkdir build + cd build + cmake -DENABLE_X400=OFF -DENABLE_N320=OFF -DENABLE_X300=OFF -DENABLE_USRP2=OFF -DENABLE_USRP1=OFF -DENABLE_N300=OFF -DENABLE_E320=OFF -DENABLE_E300=OFF ../ + # 注意:此时请确认在 “enabled components” 中能看到 ANT 和 LibUHD - Python API + make -j8 + sudo make install + sudo ldconfig + export PYTHONPATH="${PYTHONPATH}:/usr/local/lib/python3/dist-packages" + sudo sysctl -w net.core.rmem_max=1000000 + sudo sysctl -w net.core.wmem_max=1000000 + +设备端则直接使用随 AntSDR 附带的 SD 卡中已有的 USRP 固件,只需把以太网口下方的 DIP 开关拨到 “SD” 即可。 + +可以使用下面的命令识别并探测 AntSDR: + +.. code-block:: bash + + uhd_find_devices --args addr=192.168.1.10 + uhd_usrp_probe --args addr=192.168.1.10 + +下面是工作正常时的一段示例输出: + +.. code-block:: bash + + $ uhd_find_devices --args addr=192.168.1.10 + [INFO] [UHD] linux; GNU C++ version 11.3.0; Boost_107400; UHD_4.1.0.0-0-d2f0b1b1 + -------------------------------------------------- + -- UHD Device 0 + -------------------------------------------------- + Device Address: + serial: 0223D80FF0D767EBC6D3AAAA6793E64D + addr: 192.168.1.10 + name: ANTSDR-E200 + product: E200 v1 + type: ant + + $ uhd_usrp_probe --args addr=192.168.1.10 + [INFO] [UHD] linux; GNU C++ version 11.3.0; Boost_107400; UHD_4.1.0.0-0-d2f0b1b1 + [INFO] [ANT] Detected Device: ANTSDR + [INFO] [ANT] Initialize CODEC control... + [INFO] [ANT] Initialize Radio control... + [INFO] [ANT] Performing register loopback test... + [INFO] [ANT] Register loopback test passed + [INFO] [ANT] Performing register loopback test... + [INFO] [ANT] Register loopback test passed + [INFO] [ANT] Setting master clock rate selection to 'automatic'. + [INFO] [ANT] Asking for clock rate 16.000000 MHz... + [INFO] [ANT] Actually got clock rate 16.000000 MHz. + _____________________________________________________ + / + | Device: B-Series Device + | _____________________________________________________ + | / + | | Mboard: B210 + | | magic: 45568 + | | eeprom_revision: v0.1 + | | eeprom_compat: 1 + | | product: MICROPHASE + | | name: ANT + | | serial: 0223D80FF0D767EBC6D3AAAA6793E64D + | | FPGA Version: 16.0 + | | + | | Time sources: none, internal, external + | | Clock sources: internal, external + | | Sensors: ref_locked + | | _____________________________________________________ + | | / + | | | RX DSP: 0 + | | | + | | | Freq range: -8.000 to 8.000 MHz + | | _____________________________________________________ + | | / + | | | RX DSP: 1 + | | | + | | | Freq range: -8.000 to 8.000 MHz + | | _____________________________________________________ + | | / + | | | RX Dboard: A + | | | _____________________________________________________ + | | | / + | | | | RX Frontend: A + | | | | Name: FE-RX1 + | | | | Antennas: TX/RX, RX2 + | | | | Sensors: temp, rssi, lo_locked + | | | | Freq range: 50.000 to 6000.000 MHz + | | | | Gain range PGA: 0.0 to 76.0 step 1.0 dB + | | | | Bandwidth range: 200000.0 to 56000000.0 step 0.0 Hz + | | | | Connection Type: IQ + | | | | Uses LO offset: No + | | | _____________________________________________________ + | | | / + | | | | RX Frontend: B + | | | | Name: FE-RX2 + | | | | Antennas: TX/RX, RX2 + | | | | Sensors: temp, rssi, lo_locked + | | | | Freq range: 50.000 to 6000.000 MHz + | | | | Gain range PGA: 0.0 to 76.0 step 1.0 dB + | | | | Bandwidth range: 200000.0 to 56000000.0 step 0.0 Hz + | | | | Connection Type: IQ + | | | | Uses LO offset: No + | | | _____________________________________________________ + | | | / + | | | | RX Codec: A + | | | | Name: B210 RX dual ADC + | | | | Gain Elements: None + | | _____________________________________________________ + | | / + | | | TX DSP: 0 + | | | + | | | Freq range: -8.000 to 8.000 MHz + | | _____________________________________________________ + | | / + | | | TX DSP: 1 + | | | + | | | Freq range: -8.000 to 8.000 MHz + | | _____________________________________________________ + | | / + | | | TX Dboard: A + | | | _____________________________________________________ + | | | / + | | | | TX Frontend: A + | | | | Name: FE-TX1 + | | | | Antennas: TX/RX + | | | | Sensors: temp, lo_locked + | | | | Freq range: 50.000 to 6000.000 MHz + | | | | Gain range PGA: 0.0 to 89.8 step 0.2 dB + | | | | Bandwidth range: 200000.0 to 56000000.0 step 0.0 Hz + | | | | Connection Type: IQ + | | | | Uses LO offset: No + | | | _____________________________________________________ + | | | / + | | | | TX Frontend: B + | | | | Name: FE-TX2 + | | | | Antennas: TX/RX + | | | | Sensors: temp, lo_locked + | | | | Freq range: 50.000 to 6000.000 MHz + | | | | Gain range PGA: 0.0 to 89.8 step 0.2 dB + | | | | Bandwidth range: 200000.0 to 56000000.0 step 0.0 Hz + | | | | Connection Type: IQ + | | | | Uses LO offset: No + | | | _____________________________________________________ + | | | / + | | | | TX Codec: A + | | | | Name: B210 TX dual DAC + | | | | Gain Elements: None + + +最后,你可以用下面这段 Python 代码在 Python 终端或脚本里测试 Python API: + +.. code-block:: python + + import uhd + usrp = uhd.usrp.MultiUSRP("addr=192.168.1.10") + samples = usrp.recv_num_samps(10000, 100e6, 1e6, [0], 50) + print(samples[0:10]) + +这段代码会在中心频率 100 MHz、采样率 1 MHz、增益 50 dB 的设置下接收 10,000 个样本。 +它会打印前 10 个样本的 IQ 值,以确认一切正常。 +后续步骤以及更多示例,请参见 :ref:`usrp-chapter` 章节。 + +如果 :code:`import uhd` 报出 :code:`ModuleNotFoundError`,你可能需要把下面这一行加入你的 :code:`.bashrc` 文件: + +.. code-block:: bash + + export PYTHONPATH="${PYTHONPATH}:/usr/local/lib/python3/dist-packages" + + +.. _AntSDR Pluto 固件仓库: https://github.com/MicroPhase/antsdr-fw-patch +.. _AntSDR UHD 固件仓库: https://github.com/MicroPhase/antsdr_uhd +.. _MicroPhase 的 Quick Start Guide: https://github.com/MicroPhase/antsdr_uhd?tab=readme-ov-file#quick-start-guide + + + +************ +AntSDR E310 +************ + +除了 E200 之外,MicroPhase 还推出了一款名为 AntSDR E310 的型号。 +AntSDR E310 与 E200 非常相似,只不过它把第二路接收和第二路发射通道也通过前面板 SMA 接口引出,并且目前只支持 Pluto/IIO 模式(不支持 USRP 模式)。 +它使用与 E200 相同的 FPGA。 +另一个区别是,它多了一个 USB-C 接口,可以作为 USB OTG 接口使用(例如连接一个 U 盘)。 +AntSDR E310 只能在 `AliExpress `_ 上购买(不像 E200 那样也会在 Crowd Supply 销售)。 +在写作本文时,E310 的价格和 E200 差不多,因此如果你不打算使用 “USRP 模式”,并且更看重通过 SMA 暴露出来的额外通道,即便这意味着体积稍微更大一些,那么 E310 会是一个不错的选择。 + +.. image:: ../_images/AntSDR_E310.png + :scale: 80 % + :align: center + :alt: 带可选外壳的 AntSDR E310 + +.. image:: ../_images/AntSDR_Comparison.jpg + :scale: 70 % + :align: center + :alt: AntSDR E200 和 E310 对比图 diff --git a/content-zh/pulse_shaping.rst b/content-zh/pulse_shaping.rst new file mode 100644 index 00000000..2da00459 --- /dev/null +++ b/content-zh/pulse_shaping.rst @@ -0,0 +1,263 @@ +.. _pulse-shaping-chapter: + +####################### +脉冲整型 +####################### + +在本章中我们将介绍脉冲整形(Pulse Shaping),符号间干扰(Inter-Symbol-Interference, ISI),匹配滤波器(Matched Filter)和升余弦滤波器(Raised-Cosine Filter)。 +最后我们将使用 Python 为 BPSK 符号添加脉冲整形。 +你可以把本章节视为滤波器章节的后续章节,在此我们将深入讨论脉冲整形。 + +********************************** +符号间干扰(ISI) +********************************** + +在 :ref:`filters-chapter` 章节中,我们学习到了方块形状的符号/脉冲会占用相当宽的频谱,我们可以通过"整形"我们的脉冲来大大减少使用的频谱。然而,你不能使用任何低通滤波器,否则可能会出现符号间干扰(Inter-Symbol-Interference,ISI),即符号相互干扰。 + +当我们传输数字符号时,我们是连续地逐个传输它们的(而不是在符号之间等待一段时间)。当你施加脉冲整形滤波器时,它会在时域中拉长脉冲(以便在频域中压缩),从而导致相邻符号彼此重叠。只要你的脉冲整形滤波器满足以下准则,这种重叠就不会有问题:除了其中一个脉冲之外,所有脉冲在符号周期 :math:`T` 的每一个整数倍处的叠加值必须为零。通过下面这幅图可以最直观地理解这个概念: + +.. image:: ../_images/pulse_train.svg + :align: center + :target: ../_images/pulse_train.svg + :alt: A pulse train of sinc pulses + +如图所示,在 :math:`T` 的每一个整数倍处,只有一个脉冲存在峰值,而其余所有脉冲的值都为 0(它们穿过了 x 轴)。当接收机对信号进行采样时,它恰好在完美的时刻(即脉冲的峰值处)进行采样,这意味着只有那个时间点才真正重要。通常,接收机中会有一个符号同步模块来确保在峰值处对符号进行采样。 + +********************************** +匹配滤波器 +********************************** + +在无线通信中,我们使用的一个技巧叫做匹配滤波(Matched Filtering)。要理解匹配滤波,你首先需要理解以下两点: + +1. 上面讨论的那些脉冲只需要在 *接收端* 采样之前完美对齐即可。在那之前,即使存在 ISI 也没关系,也就是说,信号可以带着 ISI 在空中传播,这是完全没问题的。 + +2. 我们希望在发射机中使用低通滤波器来减少信号占用的频谱。但接收机同样需要一个低通滤波器来尽可能消除信号旁边的噪声/干扰。因此,我们在发射机(Tx)端有一个低通滤波器,在接收机(Rx)端也有一个低通滤波器,而采样发生在这两个滤波器(以及无线信道的影响)之后。 + +在现代通信中,我们会将脉冲整形滤波器均等地拆分到 Tx 和 Rx 两端。虽然它们 *不一定* 非得是相同的滤波器,但从理论上讲,在 AWGN 环境下最大化 SNR 的最优线性滤波器就是在 Tx 和 Rx 使用 *相同* 的滤波器。这种策略被称为 "匹配滤波器" 的概念。 + +另一种理解匹配滤波器的方式是:接收机将接收到的信号与已知的模板信号进行相关运算。这里的模板信号本质上就是发射机发送的脉冲,与施加在其上的相位/幅度偏移无关。回忆一下,滤波是通过卷积来完成的,而卷积基本上就是相关运算(事实上,当模板是对称的时候,它们在数学上是完全等价的)。将接收信号与模板进行相关运算,能让我们最大限度地恢复所发送的内容,这也是为什么它在理论上是最优的。打个比方,想象一个图像识别系统,它使用一个人脸模板并通过 2D 相关运算来寻找人脸: + +.. image:: ../_images/face_template.png + :scale: 70 % + :align: center + +********************************** +将滤波器拆分为两半 +********************************** + +我们具体要怎么把一个滤波器拆成两半呢?卷积运算具有结合律,即: + +.. math:: + (f * g) * h = f * (g * h) + +假设 :math:`f` 是我们的输入信号,而 :math:`g` 和 :math:`h` 是两个滤波器。先用 :math:`g` 滤波 :math:`f` ,再用 :math:`h` 滤波,等效于使用一个为 :math:`g * h` 的滤波器进行滤波。 + +另外,回忆一下时域卷积等于频域相乘: + +.. math:: + g(t) * h(t) \leftrightarrow G(f)H(f) + +要将一个滤波器拆分为两半,你可以对其频率响应取平方根。 + +.. math:: + X(f) = X_H(f) X_H(f) \quad \mathrm{where} \quad X_H(f) = \sqrt{X(f)} + +下图展示了一个简化的发射和接收链路图。其中升余弦(RC)滤波器被拆分为两个根升余弦(RRC)滤波器:发射端的一个是脉冲整形滤波器,接收端的一个是匹配滤波器。它们共同作用,使得解调器处的脉冲看起来就像经过了单个 RRC 滤波器进行脉冲整形一样。 + +.. image:: ../_images/splitting_rc_filter.svg + :align: center + :target: ../_images/splitting_rc_filter.svg + :alt: A diagram of a transmit and receive chain, with a Raised Cosine (RC) filter being split into two Root Raised Cosine (RRC) filters + +********************************** +具体的脉冲整形滤波器 +********************************** + +我们已经知道我们需要做到: + +1. 设计一个能降低信号带宽(以减少频谱占用)的滤波器,同时要求在每个符号间隔处,除了一个脉冲之外,其余脉冲的叠加值均为零。 + +2. 将该滤波器拆分为两半,一半放在 Tx,另一半放在 Rx。 + +让我们来看看一些常用的脉冲整形滤波器。 + +升余弦滤波器 +######################### + +最常用的脉冲整形滤波器似乎是 "升余弦" 滤波器。它是一个很好的低通滤波器,能够限制信号占用的带宽,同时它还具有在 :math:`T` 的整数倍处求和为零的特性: + +.. image:: ../_images/raised_cosine.svg + :align: center + :target: ../_images/raised_cosine.svg + :alt: The raised cosine filter in the time domain with a variety of roll-off values + +请注意,上图是时域图,描绘的是滤波器的脉冲响应。参数 :math:`\beta` 是升余弦滤波器唯一的参数,它决定了滤波器在时域中衰减到零的速度,而这与其在频域中衰减的速度成反比: + +.. image:: ../_images/raised_cosine_freq.svg + :align: center + :target: ../_images/raised_cosine_freq.svg + :alt: The raised cosine filter in the frequency domain with a variety of roll-off values + +之所以称之为升余弦滤波器,是因为当 :math:`\beta = 1` 时,其频域响应是一个半周期的余弦波,被抬升到 x 轴上。 + +升余弦滤波器的脉冲响应的数学表达式为: + +.. math:: + h(t) = \mathrm{sinc}\left( \frac{t}{T} \right) \frac{\cos\left(\frac{\pi\beta t}{T}\right)}{1 - \left( \frac{2 \beta t}{T} \right)^2} + +关于 :math:`\mathrm{sinc}()` 函数的更多信息可以参阅 `这里 `_ 。你可能在其他地方看到包含 :math:`\frac{1}{T}` 缩放因子的公式;这个因子使滤波器具有单位增益,即输出信号的功率与输入信号相同(这是设计滤波器时的常见做法)。然而,我们要将其应用于由符号组成的脉冲序列(例如 1 和 -1),我们不希望这些符号的幅度在脉冲整形后发生变化,因此我们省略了这个缩放因子。当我们深入到 Python 示例并绘制输出时,这一点会更加清晰。 + +记住:我们要将这个滤波器均等地拆分到 Tx 和 Rx。接下来介绍根升余弦(RRC)滤波器! + +根升余弦滤波器 +######################### + +根升余弦(Root Raised-Cosine,RRC)滤波器才是我们实际在 Tx 和 Rx 中实现的滤波器。正如前文所述,两者组合起来就构成了一个完整的升余弦滤波器。因为将滤波器拆分为两半涉及到频域上的开平方运算,所以脉冲响应看起来会稍微复杂一些: + +.. image:: ../_images/rrc_filter.png + :scale: 70 % + :align: center + +好在这是一个非常常用的滤波器,有大量现成的实现可以使用,包括 `Python 实现 `_ 。 + +其他脉冲整形滤波器 +########################### + +其他滤波器包括高斯滤波器(Gaussian Filter),其脉冲响应类似高斯函数。还有 sinc 滤波器,它等效于 :math:`\beta = 0` 时的升余弦滤波器。sinc 滤波器更接近理想滤波器,即它能够在几乎没有过渡区域的情况下消除不需要的频率。 + +********************************** +滚降因子 +********************************** + +让我们仔细研究一下参数 :math:`\beta` 。它是一个介于 0 到 1 之间的数值,称为 "滚降因子(Roll-off Factor)",有时也被称为 "过量带宽(Excess Bandwidth)"。它决定了滤波器在时域中衰减到零的速度。回忆一下,要用作滤波器,脉冲响应必须在两侧衰减到零: + +.. image:: ../_images/rrc_rolloff.svg + :align: center + :target: ../_images/rrc_rolloff.svg + :alt: Plot of the raised cosine roll-off parameter + +:math:`\beta` 越小,所需的滤波器抽头数就越多。当 :math:`\beta = 0` 时,脉冲响应永远不会完全衰减到零,因此我们试图将 :math:`\beta` 设置得尽可能低,同时又不会引发其他问题。滚降因子越低,对于给定的符号速率,我们能够在频率上把信号压缩得越紧凑,这一点始终很重要。 + +一个常用的公式用于估算给定符号速率和滚降因子下的带宽(单位为 Hz): + +.. math:: + \mathrm{BW} = R_S(\beta + 1) + +:math:`R_S` 是符号速率(单位为 Hz)。在无线通信中,我们通常选择 0.2 到 0.5 之间的滚降因子。作为经验法则,一个使用符号速率 :math:`R_S` 的数字信号将占用略多于 :math:`R_S` 的频谱,这里包括正频率和负频率部分。一旦我们将信号上变频并发射出去,两侧的频谱都很重要。如果我们以每秒 100 万个符号(MSps)的速率传输 QPSK 信号,它将占用大约 1.3 MHz 的频谱。数据速率将是 2 Mbps(回忆一下 QPSK 每个符号携带 2 比特),其中包括信道编码和帧头等开销。 + +********************************** +Python 练习 +********************************** + +作为 Python 练习,让我们来对一些脉冲进行滤波和整形。我们将使用 BPSK 符号,因为它更容易可视化——在脉冲整形步骤之前,BPSK 就是传输 1 或 -1,其 "Q" 分量等于零。由于 Q 为零,我们只需绘制 I 分量即可,这样看起来更简单。 + +在这个仿真中,我们将使用每个符号 8 个采样点,并且不使用看起来像方波的 1 和 -1 信号,而是使用由脉冲(冲激)组成的脉冲序列。当你把一个脉冲通过滤波器时,输出就是脉冲响应(这也是 "脉冲响应" 这个名称的由来)。因此,如果你想要一系列脉冲,就应该使用中间填充零的冲激序列,从而避免产生方形脉冲。 + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + from scipy import signal + + num_symbols = 10 + sps = 8 + + bits = np.random.randint(0, 2, num_symbols) # Our data to be transmitted, 1's and 0's + + x = np.array([]) + for bit in bits: + pulse = np.zeros(sps) + pulse[0] = bit*2-1 # set the first value to either a 1 or -1 + x = np.concatenate((x, pulse)) # add the 8 samples to the signal + plt.figure(0) + plt.plot(x, '.-') + plt.grid(True) + plt.show() + +.. image:: ../_images/pulse_shaping_python1.png + :scale: 80 % + :align: center + :alt: A pulse train of impulses in the time domain simulated in Python + +此时我们的符号仍然是 1 和 -1。不要纠结于我们使用了冲激这件事。实际上,*不要* 去可视化冲激响应,而是把它当作一个数组来理解可能会更简单: + +.. code-block:: python + + bits: [0, 1, 1, 1, 1, 0, 0, 0, 1, 1] + BPSK symbols: [-1, 1, 1, 1, 1, -1, -1, -1, 1, 1] + Applying 8 samples per symbol: [-1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, ...] + +我们将使用 :math:`\beta` 为 0.35 的升余弦滤波器,并将其设为 101 个抽头长度,以给信号足够的时间衰减到零。虽然升余弦方程需要我们提供符号周期和时间向量 :math:`t` ,但我们可以假设 **采样** 周期为 1 秒来 "归一化" 我们的仿真。这意味着我们的符号周期 :math:`Ts` 为 8,因为我们有每个符号 8 个采样点。于是我们的时间向量将是一个整数列表。根据升余弦方程的特性,我们希望 :math:`t=0` 位于中心。我们将生成从 -51 到 +51 的长度为 101 的时间向量。 + +.. code-block:: python + + # Create our raised-cosine filter + num_taps = 101 + beta = 0.35 + Ts = sps # Assume sample rate is 1 Hz, so sample period is 1, so *symbol* period is 8 + t = np.arange(num_taps) - (num_taps-1)//2 + h = np.sinc(t/Ts) * np.cos(np.pi*beta*t/Ts) / (1 - (2*beta*t/Ts)**2) + plt.figure(1) + plt.plot(t, h, '.') + plt.grid(True) + plt.show() + + +.. image:: ../_images/pulse_shaping_python2.png + :scale: 80 % + :align: center + +注意输出确实衰减到了零。我们使用每个符号 8 个采样点这一设定决定了这个滤波器看起来有多窄以及它衰减到零的速度有多快。上面的脉冲响应看起来就像一个典型的低通滤波器,我们实际上无法仅从外观上判断它是专门的脉冲整形滤波器还是其他普通的低通滤波器。 + +最后,我们可以用该滤波器对信号 :math:`x` 进行滤波并查看结果。不要过分关注代码中引入的 for 循环,我们会在代码块之后讨论它存在的原因。 + +.. code-block:: python + + # Filter our signal, in order to apply the pulse shaping + x_shaped = np.convolve(x, h) + plt.figure(2) + plt.plot(x_shaped, '.-') + for i in range(num_symbols): + plt.plot([i*sps+num_taps//2,i*sps+num_taps//2], [0, x_shaped[i*sps+num_taps//2]]) + plt.grid(True) + plt.show() + +.. image:: ../_images/pulse_shaping_python3.svg + :align: center + :target: ../_images/pulse_shaping_python3.svg + +这个结果信号是由许多脉冲响应叠加而成的,其中大约一半的脉冲响应先乘以了 -1。虽然看起来可能很复杂,但我们会一起来分析。 + +首先,由于滤波器和卷积运算的特性,数据前后会存在一些瞬态采样点。这些额外的采样点会包含在我们的传输中,但它们并不包含真正的脉冲 "峰值"。 + +其次,竖直线是在 for 循环中创建的,用于辅助可视化。它们旨在标示 :math:`Ts` 间隔出现的位置,这些间隔代表接收机对信号进行采样的位置。观察可以发现,在每个 :math:`Ts` 间隔处,曲线的值恰好为 1.0 或 -1.0,这使得它们成为理想的采样时刻。 + +如果我们要将这个信号上变频并发射出去,接收机就需要确定 :math:`Ts` 的边界在哪里,例如使用符号同步算法。这样接收机才能 *精确地* 知道何时采样以获得正确的数据。如果接收机采样稍早或稍晚,由于 ISI 的存在,它会看到略有偏差的值;如果偏差太大,接收到的就会是一堆奇怪的数字。 + +下面是一个使用 GNU Radio 创建的示例,它展示了在正确和错误的时刻采样时 IQ 图(即星座图)的样子。原始脉冲的比特值已标注在图上。 + +.. image:: ../_images/symbol_sync1.png + :scale: 50 % + :align: center + +下图代表理想的采样时刻以及对应的 IQ 图: + +.. image:: ../_images/symbol_sync2.png + :scale: 40 % + :align: center + :alt: GNU Radio simulation showing perfect sampling as far as timing + +与之对比,下图展示了最差的采样时刻。注意星座图中出现了三个聚类。我们恰好在每两个符号的正中间进行采样,因此采样值会有很大偏差。 + +.. image:: ../_images/symbol_sync3.png + :scale: 40 % + :align: center + :alt: GNU Radio simulation showing imperfect sampling as far as timing + +这是另一个不良采样时刻的例子,它介于理想情况和最差情况之间。注意此时出现了四个聚类。在高 SNR 下,我们或许勉强能用这个采样时刻,但这并不可取。 + +.. image:: ../_images/symbol_sync4.png + :scale: 40 % + :align: center + +请记住,时域图中没有显示 Q 值,因为它们近似为零,所以 IQ 图仅在水平方向上展开。 diff --git a/content-zh/rtlsdr.rst b/content-zh/rtlsdr.rst new file mode 100644 index 00000000..96e104b9 --- /dev/null +++ b/content-zh/rtlsdr.rst @@ -0,0 +1,257 @@ +.. _rtlsdr-chapter: + +###################### +Python 玩转 RTL-SDR +###################### + +RTL-SDR 是目前为止最便宜的 SDR,价格大约在 30 美元左右,也是非常适合入门的一款 SDR。 +虽然它只能接收、最高只能调谐到约 1.75 GHz,但依然有大量应用场景可以使用它。 +本章中,我们将学习如何配置 RTL-SDR 软件,并使用它的 Python API。 + +.. image:: ../_images/rtlsdrs.svg + :align: center + :target: ../_images/rtlsdrs.svg + :alt: RTL-SDR 示例 + +******************************** +RTL-SDR 背景 +******************************** + +RTL-SDR 大约诞生于 2010 年,当时有人发现可以 hack 那些内置 Realtek RTL2832U 芯片的低成本 DVB-T 电视棒。 +DVB-T 是一种主要在欧洲使用的数字电视标准,而 RTL2832U 真正有意思的地方在于,它可以直接访问原始 IQ 样本,因此这颗芯片就可以被拿来构建一台通用的、只接收的 SDR。 + +RTL2832U 芯片本身集成了模数转换器(ADC)和 USB 控制器,但它必须搭配一个射频调谐器一起工作。 +常见的调谐器芯片包括 Rafael Micro 的 R820T、R828D,以及 Elonics 的 E4000。 +可调谐频率范围取决于所用调谐器芯片,通常在 50 到 1700 MHz 左右。 +另一方面,最大采样率则由 RTL2832U 以及你电脑的 USB 总线决定,通常在 2.4 MHz 左右,再高就容易开始丢样本。 +还要记住,这类调谐器极其低成本,因此射频灵敏度通常比较差;如果你要接收较弱信号,往往需要额外加一个低噪声放大器(LNA)和带通滤波器。 + +RTL2832U 始终使用 8 位样本,因此主机每接收一个 IQ 样本会得到两个字节。 +高端一些的 RTL-SDR 通常会用温控振荡器(TCXO)替代更廉价的晶振,以获得更好的频率稳定性。 +另一个可选特性是 Bias Tee(也叫 Bias-T),它是一种板载电路,会在 SMA 接头上提供大约 4.5V 的直流电,用来方便地给外部 LNA 或其他射频器件供电。 +这部分额外直流偏置位于 SDR 的射频侧,因此不会干扰基本的接收操作。 + +如果你对到达方向估计(DOA)或其他波束形成应用感兴趣,那么 `KrakenSDR `_ 是一个值得关注的产品:它是由五个共享振荡器和采样时钟的 RTL-SDR 组成的一台相位相干 SDR。 + +******************************** +RTL-SDR 软件配置 +******************************** + +在 Ubuntu 上安装 RTL-SDR(或 WSL 中的 Ubuntu) +############################################################ + +在 Ubuntu 20、22 以及其他基于 Debian 的系统上,可以使用下面这条命令安装 RTL-SDR 软件。 + +.. code-block:: bash + + sudo apt install rtl-sdr + +这会安装 librtlsdr 库,以及诸如 :code:`rtl_sdr`、:code:`rtl_tcp`、:code:`rtl_fm` 和 :code:`rtl_test` 这样的命令行工具。 + +接下来,用下面的命令安装 librtlsdr 的 Python 封装: + +.. code-block:: bash + + sudo pip install pyrtlsdr + +如果你是通过 WSL 使用 Ubuntu,那么在 Windows 侧需要先下载最新版本的 `Zadig `_ ,并运行它来为 RTL-SDR 安装 “WinUSB” 驱动(可能会看到两个 Bulk-In Interface,如果是这样,就两个都安装 “WinUSB”)。 +Zadig 完成后,把 RTL-SDR 拔掉再重新插上。 + +接下来,你需要把 RTL-SDR 的 USB 设备转发到 WSL。 +首先安装最新版本的 `usbipd utility msi `_ (本文默认你使用的是 usbipd-win 4.0.0 或更高版本),然后以管理员模式打开 PowerShell 并执行: + +.. code-block:: bash + + # (先拔掉 RTL-SDR) + usbipd list + # (再插上 RTL-SDR) + usbipd list + # (找到新出现的设备,并把它的 busid 代入下面的命令) + usbipd bind --busid 1-5 + usbipd attach --wsl --busid 1-5 + +在 WSL 这边,你应该可以通过 :code:`lsusb` 看到一个新设备项,名称类似 RTL2838 DVB-T。 + +如果你遇到了权限问题(例如下面的测试只有在使用 :code:`sudo` 时才工作),那么你需要配置 udev 规则。 +先运行 :code:`lsusb` 找到 RTL-SDR 的 ID,然后创建文件 :code:`/etc/udev/rules.d/10-rtl-sdr.rules`,写入以下内容;如果你的 RTL-SDR 的 idVendor 或 idProduct 不同,请自行替换: + +.. code-block:: + + SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838", MODE="0666" + +要刷新 udev,请执行: + +.. code-block:: bash + + sudo udevadm control --reload-rules + sudo udevadm trigger + +如果你使用的是 WSL,并且它提示 :code:`Failed to send reload request: No such file or directory`,那就说明 udev 服务没有运行。 +你需要执行 :code:`sudo nano /etc/wsl.conf` 并加入以下内容: + +.. code-block:: bash + + [boot] + command="service udev start" + +然后在管理员 PowerShell 中执行下面的命令重启 WSL: :code:`wsl.exe --shutdown` 。 + +你可能还需要把 RTL-SDR 拔掉再重新插上(WSL 下则需要重新执行 :code:`usbipd attach`)。 + +Windows 下安装 RTL-SDR +######################################## + +如果你使用 Windows,请参考 https://www.rtl-sdr.com/rtl-sdr-quick-start-guide/ 。 + +******************************** +测试 RTL-SDR 软件栈 +******************************** + +如果软件配置没有问题,你应该可以运行下面的测试。 +它会把 RTL-SDR 调到 FM 广播频段,并录制 100 万个样本到 :code:`/tmp` 下一个名为 :code:`recording.iq` 的文件中。 + +.. code-block:: bash + + rtl_sdr /tmp/recording.iq -s 2e6 -f 100e6 -n 1e6 + +如果你看到 :code:`No supported devices found`,即使在命令前面加上 :code:`sudo` 也是如此,那么说明 Linux 根本看不到 RTL-SDR 设备。 +如果它在 :code:`sudo` 下可以工作,那就说明是 udev 规则的问题;请按照前面的 udev 配置步骤处理后,再尝试重启电脑。 +当然,你也可以简单粗暴地对所有命令都加 :code:`sudo`,包括运行 Python。 + +你还可以用下面这段脚本测试 Python 是否能看到 RTL-SDR: + +.. code-block:: python + + from rtlsdr import RtlSdr + + sdr = RtlSdr() + sdr.sample_rate = 2.048e6 # Hz + sdr.center_freq = 100e6 # Hz + sdr.freq_correction = 60 # PPM + sdr.gain = 'auto' + + print(len(sdr.read_samples(1024))) + sdr.close() + +其输出应类似: + +.. code-block:: bash + + Found Rafael Micro R820T tuner + [R82XX] PLL not locked! + 1024 + +******************************** +RTL-SDR Python 代码 +******************************** + +上面的代码其实就可以算是一个 RTL-SDR Python 基本使用示例。 +接下来的几个小节会更详细地介绍各种设置以及一些使用技巧。 + +避免 RTL-SDR 卡死 +############################### + +在脚本结尾,或者每次用完 RTL-SDR 准备停止抓取样本时,我们都应该调用 :code:`sdr.close()`。 +这样有助于避免 RTL-SDR 进入某种异常卡死状态,否则你可能不得不把它拔掉再插上。 +即使调用了 :code:`close()`,这种情况仍然可能发生;如果它发生了,你通常会在 :code:`read_samples()` 调用期间发现 RTL-SDR 卡住不动。 +这时你就需要把 RTL-SDR 拔掉重插,必要时甚至重启电脑。 +如果你使用的是 WSL,还需要通过 usbipd 重新 attach 这个设备。 + +RTL-SDR 增益设置 +############################# + +通过设置 :code:`sdr.gain = 'auto'`,我们启用了自动增益控制(AGC)。 +这样 RTL-SDR 会根据接收到的信号自动调整接收增益,尽量在不让 8 位 ADC 饱和的前提下把动态范围填满。 +但在很多场景下,例如制作一个频谱分析仪,让增益保持为固定值反而更有用,这就意味着我们需要设置手动增益。 +RTL-SDR 的增益不是连续可调的;你可以通过 :code:`print(sdr.valid_gains_db)` 查看所有可用的增益值。 +不过即便你设置了一个不在这个列表中的增益值,它也会自动选择最接近的合法值。 +你也可以随时用 :code:`print(sdr.gain)` 查看当前实际设置的增益。 +下面这个例子中,我们把增益设置为 49.6 dB,接收 4096 个样本,然后在时域中绘制它们: + +.. code-block:: python + + from rtlsdr import RtlSdr + import numpy as np + import matplotlib.pyplot as plt + + sdr = RtlSdr() + sdr.sample_rate = 2.048e6 # Hz + sdr.center_freq = 100e6 # Hz + sdr.freq_correction = 60 # PPM + print(sdr.valid_gains_db) + sdr.gain = 49.6 + print(sdr.gain) + + x = sdr.read_samples(4096) + sdr.close() + + plt.plot(x.real) + plt.plot(x.imag) + plt.legend(["I", "Q"]) + plt.savefig("../_images/rtlsdr-gain.svg", bbox_inches='tight') + plt.show() + +.. image:: ../_images/rtlsdr-gain.svg + :align: center + :target: ../_images/rtlsdr-gain.svg + :alt: RTL-SDR 手动增益示例 + +这里有几点值得注意。 +首先,前面大约 2k 个样本似乎没什么信号功率,因为它们主要是瞬态部分。 +因此通常建议你在每个脚本开始时先丢弃前 2k 个样本,例如调用 :code:`sdr.read_samples(2048)`,但不要对输出做任何处理。 +其次,我们会注意到 pyrtlsdr 返回给我们的样本是浮点数,范围在 -1 到 +1 之间。 +虽然 RTL-SDR 使用的是 8 位 ADC,本来产生的是整数值,但 pyrtlsdr 为了方便使用,已经自动帮我们除以了 127.0。 + +RTL-SDR 允许的采样率 +############################### + +大多数 RTL-SDR 要求采样率必须设置在 230 到 300 kHz 之间,或者 900 kHz 到 3.2 MHz 之间。 +请注意,较高的采样率,尤其是超过 2.4 MHz 时,未必能通过 USB 连接传回 100% 的样本。 +如果你给它设置了一个不支持的采样率,它只会直接报错,例如: :code:`rtlsdr.rtlsdr.LibUSBError: Error code -22: Could not set sample rate to 899000 Hz` 。 +当你设置一个合法的采样率时,你会在终端中看到实际采用的精确采样率;这个值也可以通过读取 :code:`sdr.sample_rate` 获得。 +有些应用在做计算时,使用这个更精确的实际值会更有帮助。 + +作为一个练习,我们把采样率设置为 2.4 MHz,并创建 FM 广播频段的时频谱: + +.. code-block:: python + + # ... + sdr.sample_rate = 2.4e6 # Hz + # ... + + fft_size = 512 + num_rows = 500 + x = sdr.read_samples(2048) # 丢弃前面这些空样本 + x = sdr.read_samples(fft_size*num_rows) # 读取时频谱所需的全部样本 + spectrogram = np.zeros((num_rows, fft_size)) + for i in range(num_rows): + spectrogram[i,:] = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(x[i*fft_size:(i+1)*fft_size])))**2) + extent = [(sdr.center_freq + sdr.sample_rate/-2)/1e6, + (sdr.center_freq + sdr.sample_rate/2)/1e6, + len(x)/sdr.sample_rate, 0] + plt.imshow(spectrogram, aspect='auto', extent=extent) + plt.xlabel("Frequency [MHz]") + plt.ylabel("Time [s]") + plt.show() + +.. image:: ../_images/rtlsdr-waterfall.svg + :align: center + :target: ../_images/rtlsdr-waterfall.svg + :alt: RTL-SDR 瀑布图(时频谱)示例 + +RTL-SDR 的 PPM 设置 +############################ + +如果你好奇 ppm 设置到底是什么:每一台 RTL-SDR 都会因为调谐器芯片成本低、缺乏校准,而存在一个小的频率偏移/误差。 +这个频率偏移在整个频谱上通常近似线性(而不是一个恒定的频移),因此我们可以通过输入一个以百万分之一(parts per million)为单位的 PPM 值来修正它。 +例如,如果你调到 100 MHz,并把 PPM 设为 25,那么接收到的信号将会上移 :math:`100e6/1e6*25=2500` Hz。 +对于更窄带的信号,频率误差带来的影响会更明显。 +不过,很多现代信号在解调过程中本身就包含频率同步步骤,因此无论频偏来自发射端、接收端还是多普勒效应,它最终都会被纠正掉。 + +******************************** +RTL-SDR 延伸阅读 +******************************** + +#. `RTL-SDR.com 的 About 页面 `_ +#. https://hackaday.com/2019/07/31/rtl-sdr-seven-years-later/ +#. https://osmocom.org/projects/rtl-sdr/wiki/Rtl-sdr diff --git a/content-zh/sampling.rst b/content-zh/sampling.rst index 40065c79..1f72c9e7 100644 --- a/content-zh/sampling.rst +++ b/content-zh/sampling.rst @@ -18,7 +18,7 @@ IQ 采样是软件定义无线电(SDR)以及许多数字接收机(和发 麦克风是一种传感器,它将声波转换成电信号(电压)。这个电信号被 ADC(模数转换器)转换成声波的数字表示。 简化来说,麦克风捕捉声波,将声转换成电,然后将电转换成数字。可以看出,ADC 是模拟领域和数字领域之间的桥梁。 SDR 与麦克风惊人地相似,只不过使用天线而不是麦克风接收信号,它的内部也使用了 ADC。 -在两种情况中,电压水平都是由 ADC 进行采样的。你可以把 SDR 设备想象成以无线电波而不是声波为输入的麦克风。 +在两种情况中,电压水平都是由 ADC 进行采样的。你可以把 SDR 设备想象成以无线电波为输入、数字为输出的麦克风。 无论是处理声波还是无线电波,如果我们想要数字化捕捉、处理或保存一个信号,就必须对其进行采样。 采样这个过程看似简单,实际上还挺复杂。 diff --git a/content-zh/usrp.rst b/content-zh/usrp.rst index f8659772..7eec9153 100644 --- a/content-zh/usrp.rst +++ b/content-zh/usrp.rst @@ -43,9 +43,15 @@ Python 玩转 USRP .. code-block:: bash - sudo apt-get install git cmake libboost-all-dev libusb-1.0-0-dev python3-docutils python3-mako python3-numpy python3-requests python3-ruamel.yaml python3-setuptools build-essential # 译者注:这里可以提前配置 APT 源为清华源等镜像以加速下载 + sudo apt update + sudo apt install git cmake libboost-all-dev libusb-1.0-0-dev build-essential # 译者注:这里可以提前配置 APT 源为清华源等镜像以加速下载 + sudo pip install pybind11[global] + pip install numpy==1.26.4 docutils mako requests ruamel.yaml setuptools cd ~ git clone https://github.com/EttusResearch/uhd.git # 译者注:这里需要注意网络环境 + cd uhd + git checkout v4.8.0.0 + cd host mkdir build cd build cmake -DENABLE_TESTS=OFF -DENABLE_C_API=OFF -DENABLE_PYTHON_API=ON -DENABLE_MANUAL=OFF .. @@ -325,6 +331,12 @@ Python 玩转 USRP 为了 Debug,你可以通过检查 :code:`usrp.get_mboard_sensor("ref_locked", 0)` 的返回值来验证 10 MHz 信号是否传递到了 USRP。而对于 PPS 信号而言,如果它没有传递到 USRP,那么上面代码中的第一个 while 循环将永远不会结束。 +********************************************** +多台 B210 的相位相干同步(用于 MIMO) +********************************************** + +为了执行到达方向(DOA)估计和相控阵数字波束成形等操作,通常需要所有接收通道实现相位相干,即接收通道之间的相对相位保持恒定且可以通过校准消除。B200 和 B210 USRP 基于 AD9361 射频集成电路,其本振(LO)由芯片内部生成,无法外部馈入 LO。因此即使你为 USRP 提供了 10 MHz 参考信号和 PPS,也只能实现频率和采样时钟的同步,而无法实现相位同步。这是因为每次设备开机或改变频率时,VCO/PLL 链路中的分频器都会引入一个新的随机相位偏移,更多信息请参见 `此页面 `_ 。实现相位同步的一种方法是增加硬件,将校准信号(可以是 USRP 自身生成的信号、宽带噪声源或单音信号)分路后馈入所有接收端口,每次 USRP 开机或重新调谐时进行一次快速校准。请注意,更改增益也会导致相位偏移,但只要 B210 保持相同的增益,相位差不应发生显著变化。 `Techtile 项目 `_ 提供了关于此主题的更多信息,包括可能允许多台 B210 同步重新调谐以保持同步的自定义固件镜像,但每次无线电开机时可能仍需要使用外部硬件进行校准。 + **** GPIO **** diff --git a/content/2d_beamforming.rst b/content/2d_beamforming.rst index 17fb01a9..9da95978 100644 --- a/content/2d_beamforming.rst +++ b/content/2d_beamforming.rst @@ -181,7 +181,7 @@ Instead of looking at the beam pattern in the crummy 3D plot, we'll use an alter resp = w.conj().T @ a # scalar print("Power in direction we are pointing:", 10*np.log10(np.abs(resp)[0,0]), 'dB') -This outputs 0 dB, which is what we expect because MVDR's goal is to achieve unit power in the desired direction. Now let's check the power in the directions of the two jammers, as well as a random direction and a direction that is one degree off of our desired direction (the same code is used, just update :code:`dir`). The results are shown in the table below: +This outputs 0 dB, which is what we expect because MVDR's goal is to achieve unit gain in the desired direction. Now let's check the power in the directions of the two jammers, as well as a random direction and a direction that is one degree off of our desired direction (the same code is used, just update :code:`dir`). The results are shown in the table below: .. list-table:: :widths: 70 30 @@ -208,7 +208,14 @@ The code for this section can be found `here `_ platform from Analog Devices which supports up to 16 transmit and receive channels (we only used 15 and only in receive mode). Two recordings are provided below, the first one contains one emitter located at boresight to the array, which we will use for calibration. The second recording contains two emitters at different directions, which we will use for beamforming and DOA testing. +In this section we work with some actual data recorded by `Jon Kraft `_ using a 3x5 digital array made out of a `QUAD-MxFE `_ platform from Analog Devices which supports up to 16 transmit and receive channels (we only used 15 and only in receive mode). Below are some pictures showing the setup, with transmitters labeled. + +.. image:: ../_images/2d_array_ladder_pic.png + :align: center + :target: ../_images/2d_array_ladder_pic.png + :alt: Images showing the 3x5 array used to record the data, which was made using a QUAD-MxFE platform from Analog Devices + +Two downloadable recordings are provided below, the first one contains one emitter located at boresight to the array, which we will use for calibration. The second recording contains two emitters at different directions, which we will use for beamforming and DOA testing. - `IQ recording of just C `_ (used for calibration, as C is at boresight) - `IQ recording of B and D `_ (used for beamforming/DOA testing) @@ -347,14 +354,19 @@ Next we will perform DOA estimation using the MUSIC algorithm. We will use the music_metric = np.abs(music_metric).squeeze() music_metric = np.clip(music_metric, 0, 2) # Useful for ABCD one results[i, j] = music_metric + + results = 10*np.log10(results) # convert to dB + + # Keep the top 95% + floor = np.percentile(results, 5) + print("floor:", floor) + results = np.maximum(results, floor) Our results are in 2D, because the array is 2D, so we must either use a 3D plot or a 2D heatmap plot. Let's try both. First, we will do a 3D plot that has elevation on one axis and azimuth on the other: .. code-block:: python # 3D az-el DOA results - results = 10*np.log10(results) # convert to dB - results[results < -20] = -20 # crop the z axis to some level of dB fig, ax = plt.subplots(subplot_kw={"projection": "3d", "computed_zorder": False}) surf = ax.plot_surface(np.rad2deg(theta_scan[:,None]), # type: ignore np.rad2deg(phi_scan[None,:]), diff --git a/content/about_author.rst b/content/about_author.rst index 0bfe4352..0fa4c816 100644 --- a/content/about_author.rst +++ b/content/about_author.rst @@ -4,11 +4,11 @@ About the Author ################## -Dr. Marc Lichtman is a wireless communications researcher who specializes in SDR, machine learning, LTE/5G-NR, and spectrum sensing. He is an Adjunct Professor at the University of Maryland, where he created and taught a course that served as the basis of this textbook. His course was a senior-year elective targeted towards CS undergrads interested in SDR/DSP. This course led him to better understand how to make incredibly heavy material accessible and engaging to students who were great programmers but had little-to-no wireless and signals background. It was not uncommon to begin class with a mini-hackathon, where students had to find or decode hidden signals (transmitted by Marc) using what they had recently learned. +Dr. Marc Lichtman is an RF signal processing engineer who specializes in SDR, spectrum sensing, geolocation, and beamforming/array processing. He is an Adjunct Professor at the University of Maryland, where he created and taught a course that served as the basis of this textbook. His course was a senior-year elective targeted towards CS undergrads interested in SDR/DSP. This course led him to better understand how to make heavy material accessible and engaging to students who were great programmers but had little-to-no wireless and signals background. It was not uncommon to begin class with a mini-hackathon, where students had to find or decode hidden signals (transmitted by Marc) using what they had recently learned. -Marc is also one of the leads for the `GNU Radio project `_ , an open source SDR framework widely used in academia and defense related research. GNU Radio can be used to implement advanced DSP apps, and a GNU Radio app or individual block is very easy to share with others. +Marc is also one of the leads for the `GNU Radio project `_, an open source SDR framework widely used in academia and defense. GNU Radio can be used to implement advanced DSP apps, and a GNU Radio app or individual block is very easy to share with others. -Marc currently lives in the DC area with his wife and their many cats and dogs. His hobbies include woodworking, machining, lasercutting, clarinet/sax, sailing, gardening, and pinball. +Marc currently lives in the DC area with his wife and their many cats and dogs. His hobbies include woodworking, machining, laser cutting, clarinet/sax, sailing, gardening, and pinball. Email: marc@pysdr.org @@ -19,4 +19,3 @@ University of Maryland faculty page: `cs.umd.edu/people/sdr `_, his 1987 textbook `Statistical Spectral Analysis `_, or Chad Spooner's `collection of blog posts `_. -One resource that you will find here and in no other textbook: at the end of the SCF chapter you will be rewarded with an interactive JavaScript app that allows you to play around with the SCF of an example signal, to see how the SCF changes with different signal and SCF parameters, all in your browser! While these interactive demos are free for everyone, they are largely made possible by the support of PySDR's `Patreon `_ members. +One resource that you will find here and in no other textbook: at the end of the SCF section you will be rewarded with an interactive JavaScript app that allows you to play around with the SCF of an example signal, to see how the SCF changes with different signal and SCF parameters, all in your browser! While these interactive demos are free for everyone, they are largely made possible by the support of PySDR's `Patreon `_ members. ************************* Review of Autocorrelation @@ -285,6 +285,8 @@ Below is a minimal Python implementation of the FSM, which is a frequency-based plt.ylabel('Cyclic Frequency [Normalized Hz]') plt.show() +Note that due to the way the shift is calculated and rounded to an integer number of samples, it helps to process at least :code:`2 / alpha_resolution` samples at a time. + Let's calculate the SCF for the rectangular BPSK signal we used before, with 20 samples per symbol over a range of cyclic frequencies from 0 to 0.3 using a 0.001 step size: .. image:: ../_images/scf_freq_smoothing.svg @@ -679,7 +681,7 @@ Up until this point, we have been using the following formulas for the CAF and t R_x(\tau,\alpha) = \lim_{T\rightarrow\infty} \frac{1}{T} \int_{-T/2}^{T/2} x(t + \tau/2)x^*(t - \tau/2)e^{-j2\pi \alpha t}dt \\ S_X(f,\alpha) = \lim_{T\rightarrow\infty} \frac{1}{T} \lim_{U\rightarrow\infty} \frac{1}{U} \int_{-U/2}^{U/2} X(t,f + \alpha/2) X^*(t,f - \alpha/2) dt -There is, however, an alternate form for the CAF and SCF in which there is no conjugate included. These forms are called the *conjugate CAF* and the *conjugate SCF*, respectively. The naming convention it's a little confusing, but the main thing to remember is that there's a "normal" version of the CAF/SCF, and a conjugate version. The conjugate version is useful when you want to extract more information from the signal, but it's not always necessary depending on the signal. The conjugate CAF and SCF are defined as: +There is, however, an alternate form for the CAF and SCF in which there is no conjugate included. These forms are called the *conjugate CAF* and the *conjugate SCF*, respectively. The naming convention is a little confusing, but the main thing to remember is that there's a "normal" version of the CAF/SCF, and a conjugate version. The conjugate version is useful when you want to extract more information from the signal, but it's not always necessary depending on the signal. The conjugate CAF and SCF are defined as: .. math:: R_{x^*}(\tau,\alpha) = \lim_{T\rightarrow\infty} \frac{1}{T} \int_{-T/2}^{T/2} x(t + \tau/2)x(t - \tau/2)e^{-j2\pi \alpha t}dt \\ @@ -819,6 +821,17 @@ The FSM and TSM techniques presented earlier work great, especially when you wan The minimal Python code to implement the FAM is actually fairly simple, although because we are no longer looping over alpha it is not as easy to tie back to the math. Just like the TSM, we break the signal into a bunch of time windows, with some overlap. A Hanning window is applied to each chunk of samples. There are two stages of FFTs performed as part of the FAM algorithm, and within the code note that the first FFT is performed on a 2D array, so it's doing a bunch of FFTs in one line of code. After a frequency shift, we do a second FFT to build the SCF (we then take the magnitude squared). For a more thorough explanation of the FAM, refer to the external resources at the end of this section. +.. mermaid:: + + flowchart TD + A[Input samples] --> B[Split into overlapping windows] + B --> C[Apply Hanning window] + C --> D[First FFT across each window] + D --> E[Frequency shift] + E --> F[Second FFT] + F --> G[Magnitude squared] + G --> H[SCF estimate] + .. code-block:: python N = 2**14 @@ -901,14 +914,14 @@ External Resources on FAM: OFDM ******************************** -Cyclostationarity is especially strong in OFDM signals due to OFDM's use of a cyclic prefix (CP), which is where the last several samples of each OFDM symbol is copied and added to the beginning of the OFDM symbol. This leads to a strong cyclic frequency corresponding to the OFDM symbol length (which is equal to the inverse of the subcarrier spacing, plus CP duration). +Cyclostationarity is especially strong in OFDM signals due to OFDM's use of a cyclic prefix (CP), which is where the last several samples of each OFDM symbol is copied and added to the beginning of the OFDM symbol. This leads to a strong cyclic frequency equal to the inverse of the OFDM symbol duration (which is the inverse of the subcarrier spacing, plus CP duration). -Let's play around with an OFDM signal. Below is the simulation of an OFDM signal with a CP using 64 subcarriers, 25% CP, and QPSK modulation on each subcarrier. We'll interpolate by 2x to simulate receiving at a reasonable sample rate, so that means the OFDM symbol length in number of samples will be (64 + (64*0.25)) * 2 = 160 samples. That means we should get spikes at alphas that are an integer multiple of 1/160, or 0.00625, 0.0125, 0.01875, etc. We will simulate 100k samples which corresponds to 625 OFDM symbols (recall that each OFDM symbol is fairly long). +Let's play around with an OFDM signal. Below is the simulation of an OFDM signal with a CP using 64 subcarriers, 25% CP, and QPSK modulation on each subcarrier. We'll interpolate by 2x to simulate receiving at a reasonable sample rate, so that means the OFDM symbol length in number of samples will be (64 + (64*0.25)) * 2 = 160 samples. That means we should get spikes at alphas that are an integer multiple of 1/160, or 0.00625, 0.0125, 0.01875, etc. We will simulate 200k samples which corresponds to 1250 OFDM symbols (recall that each OFDM symbol is fairly long). .. code-block:: python from scipy.signal import resample - N = 100000 # number of samples to simulate + N = 200000 # number of samples to simulate num_subcarriers = 64 cp_len = num_subcarriers // 4 # length of the cyclic prefix in symbols, in this case 25% of the starting OFDM symbol print("CP length in samples", cp_len*2) # remember there is 2x interpolation at the end @@ -941,19 +954,14 @@ Let's play around with an OFDM signal. Below is the simulation of an OFDM signa n = np.sqrt(np.var(samples) * 10**(-SNR_dB/10) / 2) * (np.random.randn(N) + 1j*np.random.randn(N)) samples = samples + n -Using the FSM to calculate the SCF at a relatively high cyclic resolution of 0.0001: - -.. image:: ../_images/scf_freq_smoothing_ofdm.svg - :align: center - :target: ../_images/scf_freq_smoothing_ofdm.svg - :alt: SCF of OFDM using the Frequency Smoothing Method (FSM) - -Note the horizontal line towards the top, indicating there is a low cyclic frequency. Zooming into the lower cyclic frequencies, we can clearly see the cyclic frequency corresponding to the OFDM symbol length (alpha = 0.0125). Not sure why we only get a spike at 2x, and not 1x or 3x or 4x... Even dropping the resolution by another 10x doesn't show anything else besides the 2x, if anyone knows feel free to use the "Suggest an Edit" link at the bottom of this page. +Because we expect spikes at 0.00625, 0.0125, 0.01875, we will use a cyclic frequency resolution of 1e-5 so we get an even multiple. For situations where it's impractical to use such a fine resolution, or the cyclic frequencies are unknown, oversampling can be used (e.g. increasing samples per symbol, in this OFDM example the oversampling factor is 2). We must also process at least :code:`2 / alpha_resolution` as part of the FSM approach, so 200k samples. Below are the results, specifically using :code:`alphas = np.arange(0, 0.02, 1e-5)` and max pooling turned on: .. image:: ../_images/scf_freq_smoothing_ofdm_zoomed_in.svg :align: center :target: ../_images/scf_freq_smoothing_ofdm_zoomed_in.svg - :alt: SCF of OFDM using the Frequency Smoothing Method (FSM) zoomed into the lower cyclic freqs + :alt: SCF of OFDM using the Frequency Smoothing Method (FSM) + +Note the three spikes, which would be even more pronounced if we squash RF frequency and plot cyclic frequency in 1D. External resources on OFDM within the context of CSP: @@ -964,3 +972,13 @@ Signal Detection With Known Cyclic Frequency ******************************************** In some applications you may want to use CSP to detect a signal/waveform that is already known, such as variants of 802.11, LTE, 5G, etc. If you know the cyclic frequency of the signal, and you know your sample rate, then you really only need to calculate a single alpha and single tau. Coming soon will be an example of this type of problem using an RF recording of WiFi. + +****************** +External Resources +****************** + +#. Antonio Napolitano's textbook `Cyclostationary Processes and Time Series: Theory, Applications, and Generalizations `_ +#. R.S. Roberts, W. A. Brown, and H. H. Loomis, Jr., "Computationally Efficient Algorithms for Cyclic Spectral Analysis," IEEE Signal Processing Magazine, April 1991, pp. 38-49. `Available here `_ +#. Da Costa, Evandro Luiz. Detection and identification of cyclostationary signals. Diss. Naval Postgraduate School, 1996. `Available here `_ +#. `Chad Spooner's Cyclostationary blog/website `_ +#. Sutton, Paul D., Keith E. Nolan, and Linda E. Doyle. "Cyclostationary signatures in practical cognitive radio applications." IEEE Journal on selected areas in Communications 26.1 (2008): 13-24. `Available here `_ diff --git a/content/detection.rst b/content/detection.rst new file mode 100644 index 00000000..c653d9d1 --- /dev/null +++ b/content/detection.rst @@ -0,0 +1,1131 @@ +.. _detection-chapter: + +##################################################### +Detection using Correlation +##################################################### + +.. raw:: html + + Co-authored by Sam Brown + +In this chapter, we learn how to detect the presence of signals and recover their timing by cross-correlating received samples with a portion of the signal that is already known to us, such as a packet preamble. That naturally leads to a simple form of classification using a bank of correlators. We introduce the core ideas of signal detection, focusing on how to decide whether a specific signal is present or absent in a noisy environment. Along the way, we cover the theory and the practical techniques used to make good decisions under uncertainty. + +**************************************************** +Signal Detection and Correlator Basics +**************************************************** + +Signal detection is the task of deciding whether an observed energy spike is a meaningful signal or just background noise. + +The challenge: in systems like radar or sonar, noise is everywhere. If the detector is too sensitive, it creates false alarms. If it is not sensitive enough, it misses the actual target. + +The solution starts with the Neyman-Pearson detector, which provides a mathematical sweet spot by maximizing the chance of finding a signal while keeping false alarms below a defined limit. CFAR detectors build on that idea by adapting to changes in the noise level. They are especially useful when the noise statistics are not stationary, meaning the noise floor and noise distribution change because of interference or evolving channel conditions. The goal is to adjust the detection threshold automatically as the background noise fluctuates, while maintaining a chosen false-alarm rate. That requires estimating the noise floor over time. + +Once a system knows that something is present, it still needs to find exactly where the data starts. Digital packets in LTE, 5G, or WiFi begin with a preamble, which is a known repeated digital pattern. A preamble correlator acts like a lock-and-key mechanism: the key is a sequence of symbols known at the receiver and unique to the signal being recovered. By sliding a copy of the preamble over the incoming signal and taking a dot product at every delay, the receiver measures how similar the template is to the received samples at each position. When the two line up closely, a sharp spike appears and tells the receiver where to start reading the data. More advanced versions also account for frequency offsets caused by small tuning differences between a phone and a cell tower, or by Doppler shifts. + +When a known signal, or preamble, is transmitted over a channel corrupted only by Additive White Gaussian Noise (AWGN), the task is to decide whether the signal is present. This is the simplest and most fundamental detection problem. + +The Cross-Correlation Function +############################### + +A correlator in its simplest form is a cross-correlation between a received signal and a template. Cross-correlation is just a dot product between two vectors as one vector slides across the other. If you learned about convolution, it is almost the same operation except that you do not flip the second vector, so it is slightly simpler. For complex signals, which is what we will be dealing with, one of the inputs must also be complex conjugated. In Python, this can be implemented as follows: + +.. code-block:: python + + def correlate(a, v): + n = len(a) + m = len(v) + result = [] + for i in range(n - m + 1): + s = 0 + for j in range(m): + s += a[i + j] * v[j].conjugate() + result.append(s) + return result + + # Example usage: + a = [1+2j, 2+1j, 3+0j, 4-1j, 5-2j] + v = [0+1j, 1+0j, 0.5-0.5j] + correlate(a, v) + +Note how we slide :code:`a` while complex conjugating :code:`v`, and how the loop involving :code:`j` and :code:`s` is really just a vector dot product. Luckily, we do not have to implement cross-correlation from scratch; in Python, we can use NumPy's :code:`correlate` function. There is also a SciPy version if you want to experiment with it. + +Python Example of a Cross-Correlation +######################################################## + +To build a basic Python example of a correlator, we first need an example signal with a known preamble embedded in noise. We will use a Zadoff-Chu sequence as the preamble because of its excellent auto-correlation properties and common use in communication systems. We will not bother with any other data portion of the signal, but in most systems there would be unknown data following the known preamble. A Zadoff-Chu sequence can be generated as follows: + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + N = 839 # Length of Zadoff-Chu sequence + u = 25 # Root of ZC sequence + t = np.arange(N) + zadoff_chu = np.exp(-1j * np.pi * u * t * (t + 1) / N) + +The resulting sequence is itself a signal. The IQ samples in :code:`zadoff_chu` represent a baseband complex signal similar to many signals we have already seen in this textbook, but it does not represent bits. We can emulate a realistic scenario by adding the Zadoff-Chu signal into a longer stream of AWGN at a random offset: + +.. code-block:: python + + signal_length = 10 * N # overall simulated signal length + offset = np.random.randint(N, signal_length - N) + print(f"True offset: {offset}") + snr_db = -15 + noise_power = 1 / (2 * (10**(snr_db / 10))) + signal = np.sqrt(noise_power/2) * (np.random.randn(signal_length) + 1j * np.random.randn(signal_length)) + signal[offset:offset+N] += zadoff_chu # place our ZC signal at the random offset + +Note that we are using a very low SNR. In fact, it is so low that if you look at the time-domain signal, you will not be able to see the Zadoff-Chu sequence at all. Our sequence is 839 samples long, out of roughly 8,000 simulated samples, and it is buried so deeply in the noise that you cannot even see a slight increase in signal magnitude. + +.. image:: ../_images/detection_basic_1.svg + :align: center + :target: ../_images/detection_basic_1.svg + :alt: Time Domain Signal with Zadoff-Chu Sequence + +Now we can implement the correlator by cross-correlating the received signal against our known Zadoff-Chu sequence with :code:`np.correlate()`. This assumes the receiver knows the exact preamble that was used. In the code above, :code:`zadoff_chu` was originally created to simulate the signal, but it now also represents the template preamble used by the receiver. The correlator can be implemented in one line of Python: + +.. code-block:: python + + correlation = np.correlate(signal, zadoff_chu, mode='valid') + +The :code:`valid` mode will be addressed shortly. We also normalize the output by the length of the sequence and take the magnitude squared to get the power, although taking only the magnitude would also work. The important part is the :code:`np.correlate()` operation itself. + +.. code-block:: python + + correlation = np.abs(correlation / N)**2 # normalize by N, and take magnitude squared + +Below we plot the magnitude squared and annotate the actual starting position of the sequence to see if the correlator was able to find it: + +.. image:: ../_images/detection_basic_2.svg + :align: center + :target: ../_images/detection_basic_2.svg + :alt: Correlator Output + +Even though the SNR is very low, the correlator output shows a clear spike exactly where the Zadoff-Chu sequence was placed. That spike marks the start of the sequence, so the 839 samples beginning there contain the preamble. This is the power of correlation-based detection combined with a long preamble. At this point we have not yet set a threshold to decide whether the spike is our signal of interest or just noise; we are only inspecting the output visually. The rest of the chapter is about automating that decision, especially when the noise floor and background interference are changing. + +Valid, Same, Full Modes +####################################### + +You may have noticed that both :code:`np.correlate()` and :code:`np.convolve()` support three modes: :code:`valid`, :code:`same`, and :code:`full`. These modes determine the length of the output array relative to the input arrays. In our case, we used :code:`valid`, which means the output only contains points where the two input arrays fully overlap. This results in an output length of :code:`len(signal) - len(zadoff_chu) + 1`. If we had used :code:`same`, the output would be the same length as the longer input signal. If we had used :code:`full`, the output would be the full discrete linear convolution, which gives a slightly longer array of length :code:`max(M, N) - min(M, N) + 1`, where :code:`M` and :code:`N` are the input lengths. In RF signal processing, convolution is often used to apply an FIR filter, where having the input and output at the same length is convenient, so :code:`same` is common in that context. For correlation-based detection, however, we usually want :code:`valid` because we only care about the points where the preamble fully overlaps the received signal, especially if we assume the signal starts after we begin receiving. + +The Neyman-Pearson Detector +############################ + +The gold standard for choosing a threshold for our correlator output is the Neyman-Pearson detector. This theory helps us make an optimal decision under a specific constraint: it finds the threshold that maximizes the probability of detection, :math:`P_{D}`, for a fixed and acceptable probability of false alarm, :math:`P_{FA}`. In simple terms, you decide how many false detections you can tolerate, such as one false alarm per hour, and the Neyman-Pearson detector gives you the best threshold for catching as many real signals as possible. For detecting a known preamble in AWGN, it uses a straightforward approach: it computes the correlation between the received signal and the known preamble pattern. If that value exceeds a predetermined threshold :math:`\tau`, it declares that the signal is present; otherwise, it assumes only noise is present. + +The performance of this detector, measured by :math:`P_{D}` and :math:`P_{FA}`, depends on the threshold :math:`\tau`, the SNR, and the preamble length :math:`L`. The probability of a false alarm depends on the threshold and the noise variance, :math:`\sigma_n^2`: + +:math:`P_{FA} = Q\left(\frac{\tau}{\sigma_n}\right)` + +The probability of detection is a function of the threshold, noise variance, and the energy of the preamble (:math:`E_s = L \cdot S`, where :math:`S` is the average symbol power): + +:math:`P_{D} = Q\left(\frac{\tau - \sqrt{E_s}}{\sigma_n}\right) = Q\left(\frac{\tau - \sqrt{L \cdot S}}{\sigma_n}\right)` + +Here, :math:`Q(x)` is the Q-function (the tail probability of the standard normal distribution), representing the probability that a standard normal random variable exceeds :math:`x`. + +Performance Analysis: ROC Curves and Pd vs. SNR Curves +################################################################# + +To quantify how well a correlator detector performs in the presence of noise, engineers rely on two primary visualizations: the Receiver Operating Characteristic (ROC) curve and the Probability of Detection (:math:`P_{d}`) vs. SNR curve. + +The ROC curve plots the Probability of Detection (:math:`P_{D}`) against the Probability of False Alarm (:math:`P_{FA}`) for a fixed SNR. By adjusting the detection threshold at the correlator output, you choose a point on this curve, so it is fundamentally a trade-off. A lower threshold increases :math:`P_{D}` by finding more real signals, but it also increases :math:`P_{FA}` by triggering more often on noise. The bow of the curve toward the top-left corner indicates a better detector. A perfect detector reaches the top-left corner, with 100% :math:`P_{D}` and 0% :math:`P_{FA}`; a diagonal line represents random guessing. + +.. image:: ../_images/detection_pd_vs_snr.svg + :align: center + :target: ../_images/detection_pd_vs_snr.svg + :alt: Pd vs SNR Curve and ROC curve + +Taken together, the equations and intuition show that the preamble length :math:`L` is a critical design parameter because it directly controls processing gain and therefore detection performance. For a fixed threshold and SNR, :math:`P_{D}` increases with :math:`L`. A longer preamble lets us collect more signal energy, making it easier to distinguish the signal from the background noise. This improvement is called processing gain, usually measured in dB as :math:`10\log_{10}(L)`. It is crucial for detecting weak signals that would otherwise be missed. By integrating energy over more samples, we can pull signals out of noise even when they are below the noise floor. GPS is a good real-world example of that effect, because the receiver has to recover very weak signals with a known code structure. + +**************************************************** +Example: Detecting GPS Signals Below the Noise Floor +**************************************************** + +Quick Primer on GPS Signals +############################### + +As of March 2026, there are 31 operational satellites in the U.S. GPS constellation, flying in medium Earth orbit (MEO) and circling the Earth twice per day. All satellites transmit a signal centered at 1575.42 MHz, called L1, and they all use the same carrier frequency. By the time the signal reaches the surface of the Earth, it is extremely weak and well below the noise floor. Orthogonality between satellites is achieved by assigning each one a unique 1023-chip pseudo-random noise (PRN) code, called the C/A code, which is why you may see the signal referred to as L1 C/A. These C/A codes use Gold codes and are carefully designed so that any two of them are nearly orthogonal; if you correlate any two satellites' codes against each other, you get almost zero output. The C/A code runs at 1.023 million chips per second and is only 1023 chips long, so it repeats every 1 ms. On top of that repeating code, each satellite slowly modulates navigation data, such as orbital position and clock corrections, at only 50 bits per second, so one data bit spans 20 full code repetitions. This use of a different code per transmitter is known as CDMA (Code Division Multiple Access), the same idea used in 3G cell phones. + +On the receiver side, finding one of the 31 satellites means generating a local copy of that satellite's PRN sequence and using a correlator to find the start of the code period. In GPS, that start can be treated like the start of a packet or frame, even though the system transmits continuously. The precise peak of the correlation is also used to estimate how far the signal has traveled before reaching the receiver; once that is known for four or more satellites, the receiver can trilaterate its position on Earth. Because the satellites are moving at about 4 km/s relative to you, the receiver must also search across a grid of possible frequency offsets to find the best correlation peak. Think of it as a 2-D search. The maximum Doppler is about +/-20 kHz (:code:`4e3 / 3e8 * 1.575e9`). This process repeats every 1 ms, although the receiver tracks delay and Doppler so it does not need to perform a full search every time. The initial search for each satellite is called acquisition, and the process of following the signal after that is called tracking. Acquisition is the more computationally expensive part, and it can take minutes if the receiver starts from scratch with no prior information about visible satellites, Doppler shifts, or its own location. + +Correlation Approach +############################### + +We cross-correlate the incoming signal, in this case a recording of L1, against a locally generated replica of each satellite's code. A large correlation peak means the satellite is visible and gives us the start of the 1 ms code period. To search across frequency as well, we use an FFT-based correlation in the frequency domain, which lets us test multiple frequency offsets efficiently by shifting the FFT bins of the local code replica. Finally, we accumulate correlation magnitude squared over multiple 1 ms blocks to improve SNR. This is called non-coherent integration, and it helps detect GPS signals that are received below the noise floor. We threshold the result against the correlation output divided by the average correlation power across all delays, which normalizes the result. + +Example Recording +############################### + +We will use an example GPS recording provided by Daniel Estévez, which you can `download here `_. It is a complex float32 file sampled at 4 MHz and centered at 1575.42 MHz. + +Below is the spectrogram of the recording. There is not much to see, and the vertical line is not the actual GPS signal; it is likely narrowband interference. The actual GPS L1 signals use a chip rate of 1.023 MHz with a very low-rate data signal modulated on top, so the signal ends up being about 2 MHz wide, which we simply do not see in the spectrogram. This is a good example of how GPS signals are received well below the noise floor, and why we need correlation-based detection to find them. + +.. image:: ../_images/detection_gps_spectrogram.svg + :align: center + :target: ../_images/detection_gps_spectrogram.svg + :alt: Spectrogram of GPS L1 Recording + +For those interested, this recording is a small portion of a much larger file hosted on `IQEngine `_ under :code:`estevez/GPS and other GNSS`; look for the recording called :code:`GPS-L1-2022-03-27`. On IQEngine, it is an int16 file in SigMF format. + +Python Example +##################### + +Make sure to change the :code:`filename` to match the location where you downloaded the IQ file. Note that :code:`num_integrations` determines how much of the recording we read in and process; the total duration is simply this number times 1 ms, with 10 being the maximum value for the shorter recording. + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + + filename = "GPS_L1_recording_10ms_4MHz_cf32.iq" + sample_rate = 4e6 + chip_rate = 1023000 # chips / sec (part of the GPS spec) + num_chips = 1023 # chips per C/A code period + samples_per_code = int(round(sample_rate / chip_rate * num_chips)) # Exact number of samples in one 1 ms code period at 4 MHz + doppler_min_hz = -5e3 # GPS Doppler ≈ ±4 kHz for stationary receiver + doppler_max_hz = 5e3 + doppler_step_hz = 500 # good enough for a coarse search + num_integrations = 10 # non-coherent power integrations (so 10 ms total), determines how much of the IQ recording we read in and process! + detection_thresh_dB = 14.0 # Peak-to-mean ratio (PMR) threshold in dB to declare a detection, GPS C/A signals are typically 14–20 dB PMR above threshold with 10ms of integration + gps_svs = list(range(1, 33)) # 1–32 + + ##### C/A Code Generation ##### + # The GPS C/A code is a Gold code formed by XOR-ing two 10-stage maximal-length + # shift registers (G1 and G2). G2 is effectively delayed by a satellite- + # specific number of chips before the XOR + # Reference: IS-GPS-200, Table 3-Ia + G2_DELAY = [ # G2 phase delay (chips) for gps_svs 1–32 + 5, 6, 7, 8, 17, 18, 139, 140, # 1– 8 + 141, 251, 252, 254, 255, 256, 257, 258, # 9–16 + 469, 470, 471, 472, 473, 474, 509, 512, # 17–24 + 513, 514, 515, 516, 859, 860, 861, 862, # 25–32 + ] + + """G1 LFSR: polynomial x^10 + x^3 + 1, all-ones init, output at stage 10.""" + reg = np.ones(10, dtype=np.int8) + G1 = np.empty(num_chips, dtype=np.int8) + for i in range(num_chips): + G1[i] = reg[9] + fb = reg[2] ^ reg[9] # stages 3 and 10 (0-indexed: 2 and 9) + reg = np.roll(reg, 1) + reg[0] = fb + + """G2 LFSR: polynomial x^10+x^9+x^8+x^6+x^3+x^2+1, all-ones init.""" + reg = np.ones(10, dtype=np.int8) + G2 = np.empty(num_chips, dtype=np.int8) + for i in range(num_chips): + G2[i] = reg[9] + fb = reg[1]^reg[2]^reg[5]^reg[7]^reg[8]^reg[9] # taps 2,3,6,8,9,10 + reg = np.roll(reg, 1) + reg[0] = fb + + # 1023-chip C/A PRN code for SV sv (1-32) as float32, 1's and -1's, so BPSK + def make_prn(sv: int) -> np.ndarray: + g2_delayed = np.roll(G2, G2_DELAY[sv - 1]) + bits = G1 ^ g2_delayed # {0, 1} + return (1 - 2 * bits).astype(np.float32) # BPSK: {+1, −1} + + def upsample_prn(sv: int) -> np.ndarray: + """Nearest-neighbour upsample 1023-chip C/A code → samples_per_code samples.""" + code = make_prn(sv) + idx = (np.arange(samples_per_code) * num_chips / samples_per_code).astype(int) + return code[idx] + + # Pre-compute template signals - conjugate FFTs of all upsampled PRN codes + template_signals = {sv: np.conj(np.fft.fft(upsample_prn(sv))) for sv in gps_svs} + + # Read in IQ file + n_needed = samples_per_code * num_integrations + iq = np.fromfile(filename, dtype=np.complex64, count=n_needed) + # For the full version from IQEngine use the following instead + #iq = np.fromfile(filename, dtype=np.int16, count=n_needed * 2) + #iq = (iq[0::2] + 1j * iq[1::2]).astype(np.complex64) + + # Search each satellite across Doppler and code phase + results = [] + detected = [] + print(f" {'SV':>3} {'Doppler (Hz)':>13} {'Phase (chips)':>14}" + f" {'Phase (samp)':>13} {'Delay (µs)':>11} {'PMR (dB)':>9}") + doppler_bins = np.arange(doppler_min_hz, doppler_max_hz + doppler_step_hz, doppler_step_hz) + for sv in gps_svs: + corr_map = np.zeros((len(doppler_bins), samples_per_code)) + n_total = samples_per_code * num_integrations + for di, f_d in enumerate(doppler_bins): + t = np.arange(n_total) / sample_rate # Time vector + mixed = iq[:n_total] * np.exp(-2j*np.pi*float(f_d)*t) # Apply the frequency shift + + # Accumulate squared correlation magnitude non-coherently + for k in range(num_integrations): + blk = mixed[k * samples_per_code:(k + 1) * samples_per_code] + sig_fft = np.fft.fft(blk) + corr = np.fft.ifft(sig_fft * template_signals[sv]) # Frequency-domain correlation + corr_map[di] += np.abs(corr)**2 + + # Normalize by the mean and convert to dB + peak_val = float(np.max(corr_map)) + mean_val = float(np.mean(corr_map)) + pmr_db = 10.0 * np.log10(peak_val / mean_val) + + peak_idx = np.unravel_index(np.argmax(corr_map), corr_map.shape) + best_doppler_hz = float(doppler_bins[peak_idx[0]]) + best_phase_samp = int(peak_idx[1]) + best_phase_chips = best_phase_samp * num_chips / samples_per_code + + r = { + "sv": sv, + "detected": pmr_db >= detection_thresh_dB, + "doppler_hz": best_doppler_hz, + "code_phase_samp": best_phase_samp, # sample offset = "start of packet" + "code_phase_chip": best_phase_chips, + "pmr_db": pmr_db, + "corr_map": corr_map, + "doppler_bins": doppler_bins, + } + results.append(r) + + # Print the result row + delay_us = r['code_phase_samp'] / sample_rate * 1e6 + flag = " ← DETECTED" if r['detected'] else "" + print(f" {sv:>3} {r['doppler_hz']:>+13.0f} {r['code_phase_chip']:>14.2f}" + f" {r['code_phase_samp']:>13d} {delay_us:>11.3f} {r['pmr_db']:>9.1f}{flag}") + +This should give the following output: + +.. code-block:: + + SV Doppler (Hz) Phase (chips) Phase (samp) Delay (µs) PMR (dB) + 1 -3000 757.79 2963 740.750 5.6 + 2 +1500 264.19 1033 258.250 9.1 + 3 -2000 316.62 1238 309.500 5.8 + 4 +5000 577.48 2258 564.500 5.0 + 5 +1000 64.96 254 63.500 5.3 + 6 +1500 511.76 2001 500.250 5.0 + 7 -4000 763.41 2985 746.250 5.0 + 8 +3500 961.62 3760 940.000 5.4 + 9 +3500 118.67 464 116.000 4.9 + 10 +0 890.52 3482 870.500 5.4 + 11 +2500 837.33 3274 818.500 14.6 ← DETECTED + 12 -500 871.60 3408 852.000 16.4 ← DETECTED + 13 +1000 137.85 539 134.750 5.9 + 14 +2500 287.72 1125 281.250 5.0 + 15 -5000 908.68 3553 888.250 5.3 + 16 +1500 292.58 1144 286.000 5.9 + 17 +500 994.61 3889 972.250 5.3 + 18 +4500 1005.61 3932 983.000 5.4 + 19 +5000 588.48 2301 575.250 5.0 + 20 +0 768.53 3005 751.250 5.4 + 21 -3000 749.60 2931 732.750 5.0 + 22 +2500 558.05 2182 545.500 14.4 ← DETECTED + 23 -5000 390.02 1525 381.250 5.3 + 24 +2500 955.48 3736 934.000 5.9 + 25 +1500 597.94 2338 584.500 15.5 ← DETECTED + 26 -1500 239.89 938 234.500 6.2 + 27 -2500 488.74 1911 477.750 4.7 + 28 +3000 858.81 3358 839.500 5.2 + 29 -4000 998.70 3905 976.250 5.2 + 30 -2000 937.58 3666 916.500 5.2 + 31 +5000 463.42 1812 453.000 15.9 ← DETECTED + 32 +1000 342.45 1339 334.750 16.2 ← DETECTED + +As you can see, we detected 6 satellites, and even though our threshold was 14.0, we can look at this list and tell pretty easily that most of the other satellites were not in view, with the exception of SV-2 which was probably in view but didn't quite reach the threshold. If anyone feels like verifying this, the recording was taken at 2022-03-27T11:32:04 somewhere in Spain. + +Plotting +########### + +Let's try plotting the results for satellite 11; the first one we detected. The first plot is the 2-D correlation map across Doppler and time/delay, and the second plot is a slice of the correlation map at the best Doppler bin, showing correlation power over time like we have seen in the previous section. + +.. code-block:: python + + # Plotting + sv = 11 # we detected 11, 12, 22, 25, 31, 32 although try looking at one we didnt find as well! + r = results[sv - 1] # print the dict of results for this SV to see what we got + cmap = r['corr_map'] # 2-D array of correlation power vs Doppler and code phase + d_bins = r['doppler_bins'] # Doppler bins corresponding + chips_axis = np.arange(samples_per_code) * num_chips / samples_per_code + + # 2-D Doppler × code-phase map + plt.figure(0, figsize=(10, 6)) + im = plt.pcolormesh(chips_axis, d_bins, cmap, shading='auto', cmap='viridis') + plt.xlabel("Code Phase (chips)") + plt.ylabel("Doppler (Hz)") + plt.title(f"SV {sv} — 2-D Acquisition Map (PMR = {r['pmr_db']:.1f} dB)") + plt.legend(fontsize=8, loc='upper right') + plt.colorbar(im, label="Correlation Power") + + # Code-phase slice at the best Doppler + best_di = int(np.argmin(np.abs(d_bins - r['doppler_hz']))) + plt.figure(1, figsize=(10, 6)) + plt.plot(chips_axis, cmap[best_di], lw=1, color='steelblue') + plt.xlabel("Code Phase (chips)") + plt.ylabel("Correlation Power") + plt.title(f"SV {sv} — Code-Phase Slice (Doppler = {r['doppler_hz']:+.0f} Hz)") + plt.legend(fontsize=8) + plt.grid(True, alpha=0.3) + + plt.show() + +.. image:: ../_images/detection_gps_2d_map.png + :align: center + :width: 700px + :alt: 2-D Acquisition Map + +.. image:: ../_images/detection_gps_code_phase_slice.svg + :align: center + :target: ../_images/detection_gps_code_phase_slice.svg + :alt: Code-Phase Slice + +We will not get into trilateration here, but the precise position of that spike is ultimately what allows the GPS receiver to determine how far the satellite is. Combined with the same information from four or more satellites, it can determine its position on Earth. + +**************************************************** +CFAR Detectors: Thriving in Changing Environments +**************************************************** + +While the Neyman-Pearson detector is optimal for a fixed noise level, real-world conditions are rarely that stable. In a dynamic environment—like a radar tracking a plane through rain or a wireless receiver in a crowded city—the background noise and interference levels fluctuate constantly. This is where the Constant False Alarm Rate (CFAR) detector becomes essential. + +CFAR detectors are the workhorses of systems where an unpredictable background makes a fixed threshold impossible to maintain: + +- Radar and Sonar are used to detect targets (planes, submarines) against "clutter"—reflections from waves, rain, or land that change as the sensor moves. +- Wireless Communications, such as Cognitive Radio and LTE/5G systems, use CFAR to help identify available spectrum or detect incoming packets when interference from other devices is bursty and unpredictable. +- Medical Imaging applies CFAR in automated ultrasound or MRI analysis to distinguish actual tissue features from varying levels of electronic noise. + +The "C" in CFAR stands for Constant because the goal is to keep the Probability of False Alarm (:math:`P_{FA}`) at a steady, predictable level. + +To set a threshold, you must assume a statistical model for the noise, which is called the noise distribution. In simple AWGN, noise follows a Gaussian distribution. However, in radar clutter, it might follow a Rayleigh or Weibull distribution. If your model is wrong, your :math:`P_{FA}` will "drift," causing the system to either go blind or be overwhelmed by false triggers. + +Instead of a hard-coded value, a CFAR detector estimates the noise power in the local "neighborhood" of the signal and multiplies this estimate by a scaling factor (:math:`T`) derived from your desired :math:`P_{FA}`. This ensures that as the noise floor rises, the threshold rises with it. + +Per-Lag vs. System-Level False Alarm Rates +#################################################### + +This is a crucial distinction often missed by beginners. When you are searching for a preamble, you are usually performing a sliding correlation, checking the threshold at thousands of different time offsets (or "lags") every second. + +Per-Lag :math:`P_{FA}`: This is the probability that a single specific correlation check results in a false alarm. If you set your math for a :math:`P_{FA}` of 0.001, each individual lag has a 1-in-1,000 chance of being a "ghost" signal. + +System-Level (Global) :math:`P_{FA}`: This is the probability that the system triggers at least one false alarm during an entire search window (e.g., across 2,048 lags). + +Mathematically, if your per-lag :math:`P_{FA}` is :math:`p`, the probability of at least one false alarm over :math:`N` lags is approximately :math:`1-(1-p)^{N}`. + +As a consequence, if you have 1,000 lags and a per-lag :math:`P_{FA}` of 0.001, your system will actually report a false alarm almost 63% of the time you search! To keep the system-level false alarm rate low, the per-lag :math:`P_{FA}` must be set to an extremely small value. + +Python Example +############### + +As a way to play around with our own CFAR detector, we'll first simulate a scenario that involves transmitting repeating QPSK packets with a known preamble over a channel with a time-varying noise floor. We'll then implement a simple Cell-Averaging CFAR (CA-CFAR) algorithm to detect the preambles in the received signal. The following Python code generates the received signal: + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + from scipy.signal import correlate + + def generate_qpsk_packets(num_packets, sps, preamble): + """Generates repeating QPSK packets with gaps and varying noise.""" + qpsk_map = np.array([1+1j, -1+1j, -1-1j, 1-1j]) / np.sqrt(2) + data_len = 200 + gap_len = 100 + full_signal = [] + + # Precompute the upsampled preamble for correlation + upsampled_preamble = np.repeat(preamble, sps) + + for _ in range(num_packets): + data = qpsk_map[np.random.randint(0, 4, data_len)] + packet = np.concatenate([preamble, data]) + full_signal.extend(np.repeat(packet, sps)) + full_signal.extend(np.zeros(gap_len * sps)) + + return np.array(full_signal), upsampled_preamble + + # Simulation parameters + sps = 4 + preamble_syms = np.array([1+1j, 1+1j, -1-1j, -1-1j, 1-1j, -1+1j]) / np.sqrt(2) + tx_signal, ref_preamble = generate_qpsk_packets(5, sps, preamble_syms) + + # Time-varying noise floor + t = np.arange(len(tx_signal)) + noise_env = 0.05 + 0.3 * np.sin(2 * np.pi * 0.0003 * t)**2 + noise = (np.random.randn(len(tx_signal)) + 1j*np.random.randn(len(tx_signal))) * noise_env + rx_signal = tx_signal + noise + +The first step is doing a single correlation of the received signal against the known preamble, in practice this is usually done in batches of samples, but we will do it in one batch for now: + +.. code-block:: python + + # Correlation spike appears when the reference matches the received segment + corr_out = correlate(rx_signal, ref_preamble, mode='same') + corr_power = np.abs(corr_out)**2 + +Now we will implement the CFAR detector, apply it to the correlator output, and visualize the results: + +.. code-block:: python + + # CFAR detection on the correlator output + def ca_cfar_adaptive(data, num_train, num_guard, pfa): + num_cells = len(data) + thresholds = np.zeros(num_cells) + alpha = num_train * (pfa**(-1/num_train) - 1) # Scaling factor + half_window = (num_train + num_guard) // 2 + guard_half = num_guard // 2 + for i in range(half_window, num_cells - half_window): + # Build the training set around the cell under test (CUT) + lagging_win = data[i - half_window : i - guard_half] + leading_win = data[i + guard_half + 1 : i + half_window + 1] + noise_floor_est = np.mean(np.concatenate([lagging_win, leading_win])) + thresholds[i] = alpha * noise_floor_est + return thresholds + + # Detect peaks in correlator power + cfar_thresholds = ca_cfar_adaptive(corr_power, num_train=60, num_guard=20, pfa=1e-5) + detections = np.where(corr_power > cfar_thresholds)[0] + # Remove edge detections where the threshold is undefined + detections = detections[cfar_thresholds[detections] > 0] + + # Subplot 1: received signal and raw power + plt.figure(figsize=(14, 8)) + plt.subplot(2, 1, 1) + plt.plot(np.abs(rx_signal)**2, color='gray', alpha=0.4, label='Rx Signal Power ($|r(t)|^2$)') + plt.title("Time-Domain Received Signal") + plt.ylabel("Power") + plt.legend() + plt.grid(True, alpha=0.3) + + # Subplot 2: correlator output vs adaptive threshold + plt.subplot(2, 1, 2) + plt.plot(corr_power, label='Correlator Output $|r(t) * p^*(-t)|^2$', color='blue') + plt.plot(cfar_thresholds, label='CFAR Adaptive Threshold', color='red', linestyle='--', linewidth=1.5) + if len(detections) > 0: # Overlay the detections + plt.scatter(detections, corr_power[detections], color='lime', edgecolors='black', label='Detections (Preamble Found)', zorder=5) + plt.title("Preamble Correlator Output with Adaptive CFAR Threshold") + plt.xlabel("Sample Index") + plt.ylabel("Correlation Power") + plt.legend() + plt.grid(True, alpha=0.3) + plt.show() + +.. image:: ../_images/detection_cfar.svg + :align: center + :target: ../_images/detection_cfar.svg + :alt: CFAR Detector Output Example + + + +Frequency Offset Resilient Preamble Correlators +#################################################### + +Detecting a preamble becomes a multi-dimensional search problem when the center frequency is unknown. In a perfectly synchronized system, a coherent correlator acts as a matched filter and maximizes SNR. However, frequency offsets introduce a time-varying phase rotation that decorrelates the signal from the local template, leading to a major loss of detection sensitivity. + +The impact of frequency offset :math:`\Delta f` depends on its magnitude relative to the preamble duration (:math:`T_{p}`): + +Slightly shifted signals, such as those affected by Doppler or clock drift, are typically caused by local oscillator (LO) ppm inaccuracies or low-velocity motion. In this case, :math:`\Delta f \cdot T_{p} \ll 1`. The correlation peak is slightly attenuated, but the timing can still be recovered. + +When the frequency offset is completely unknown, such as in cold-start satellite acquisition or high-dynamic UAV links, the coherent sum can null out to zero if the phase rotates by more than :math:`180^{\circ}` over the preamble (:math:`\Delta f > 1/(2T_{p})`). In that case, detection becomes impossible regardless of SNR. + +The loss in correlation magnitude due to a frequency offset is described by the Dirichlet kernel (or the periodic sinc function). As the frequency offset increases, the coherent sum of rotated vectors follows this sinc-like roll-off. + +The loss in dB due to frequency offset can be approximated by the following formula: + +:math:`L_{dB}(\Delta f) = 20 \log_{10} \left| \frac{\sin(\pi \Delta f N T_{s})}{N \sin(\pi \Delta f T_{s})} \right|` + +Where: + + - :math:`N`: Number of symbols in the preamble. + - :math:`T_{s}`: Symbol period. + - :math:`\Delta f`: Frequency offset in Hz. + +As :math:`\Delta f` increases, the numerator oscillates while the denominator grows, creating nulls in the detector's sensitivity. For a standard correlator, the first null occurs at :math:`\Delta f = 1/(N T_{s})`. If your offset is half of the bin width, you lose approximately 3.9 dB, which significantly degrades your effective SNR and :math:`P_{d}`. + +Methods for Resilience to Frequency Offsets +########################################### + +A. Coherent Segmented Correlator + +The preamble of length :math:`N` is divided into :math:`M` segments of length :math:`L = N/M`. Each segment is correlated coherently, and the results are combined by compensating for the phase drift between segments. + +:math:`Y_{coh} = \sum_{m=0}^{M-1} \left( \sum_{k=0}^{L-1} r[k+mL] \cdot p^{*}[k] \right) e^{-j \hat{\phi}_m}` + +Where :math:`\hat{\phi}_m` is an estimate of the phase rotation for that segment. This preserves the SNR gain of a full-length preamble but requires an accurate frequency estimate to align the phases. + +B. Non-Coherent Segmented Correlator + +Segments are correlated coherently, but their magnitudes are summed, discarding phase information. + +:math:`Y_{non-coh} = \sum_{m=0}^{M-1} \left| \sum_{k=0}^{L-1} r[k+mL] \cdot p^{*}[k] \right|^{2}` + +This approach is extremely robust to frequency offsets (up to :math:`1/(L T_{s})`). However, it suffers from Non-Coherent Integration Loss. Summing magnitudes instead of complex values allows noise to accumulate faster than the signal, effectively reducing the "post-detection" SNR. + +C. Brute-Force Frequency Search + +The receiver runs multiple parallel correlators, each shifted by a discrete frequency :math:`\Delta f_{i}`. + +This method provides the best SNR performance (full coherent gain) but is the most computationally expensive. The "bin spacing" must be tight enough (based on the Dirichlet formula) to ensure the worst-case loss between bins is acceptable (e.g., < 1 dB). + +In time-domain tapping, samples are convolved with a fixed set of weights. In a frequency search, this requires a separate FIR bank for every frequency bin. This is efficient for short preambles on FPGAs using Xilinx DSP48 slices. Frequency-Domain (FFT) Processing: To perform a search, you take the FFT of the incoming signal and the preamble. Multiplication in the frequency domain is equivalent to correlation. The "Frequency Shift Trick": To test different frequency offsets, you don't need multiple FFTs. You can simply circularly shift the FFT bins of the preamble relative to the signal before performing the point-wise multiplication and IFFT. For continuous streams, chunking methods such as Overlap-Save or Overlap-Add are used to process data in chunks without losing the correlation peaks at the edges of the FFT windows. + +Frequency-offset resilience is a trade-off between processing gain and computational complexity. Non-coherent segmented correlation is the most robust choice for high-uncertainty environments, but it requires a higher link margin. Coherent segmented and brute-force FFT searches provide better sensitivity, but they require significantly more hardware resources. Understanding the Dirichlet-driven loss is critical when choosing the bin density for any frequency-searching receiver. + +.. image:: ../_images/detection_freq_offset.svg + :align: center + :target: ../_images/detection_freq_offset.svg + :alt: Frequency Offset Impact on Correlation + +***************************************************************** +Detecting Direct Sequence Spread Spectrum (DSSS) Signals +***************************************************************** + +In a Direct Sequence Spread Spectrum (DSSS) system, the correlator detector is the link that pulls a meaningful signal out of what initially looks like random noise. By using a high-rate chip sequence, or chipping code, the system spreads the signal energy across a much wider bandwidth than the original data requires. Because the total power stays constant, spreading it over a broader frequency range lowers the power spectral density (PSD). This spectral thinning effect can drive the signal level below the thermal noise floor, making it nearly invisible to conventional narrow-band receivers. To the intended receiver, however, the same chip sequence can be applied to de-spread the signal, concentrating the energy back into the original narrow bandwidth while also spreading out narrow-band interference. That is what allows reliable detection even in very noisy environments. The next subsection looks at the timing side of that problem. + +The Role of Auto-Correlation Properties +######################################## + +Choosing the right sequence is critical for synchronization and multipath rejection. Ideally, a sequence should have perfect auto-correlation: a high peak when perfectly aligned and near-zero values at any other time offset. Sharp auto-correlation peaks allow the receiver to lock onto the signal with sub-chip timing accuracy. If a signal reflects off a building and arrives late, good auto-correlation ensures the receiver treats the delayed version as uncorrelated noise rather than destructive interference, which helps mitigate multipath. + + +Common Spreading Sequences +########################## + +Different applications require different mathematical properties in their spreading sequences. Some examples include: + +- Barker Codes, which are known for having the best possible auto-correlation properties for short lengths (up to 13), and are famously used in 802.11b Wi-Fi. +- M-Sequences (Maximal Length), generated using linear-feedback shift registers (LFSRs), provide excellent randomness and auto-correlation over very long periods. +- Gold Codes, derived from pairs of m-sequences, offer a large set of sequences with controlled cross-correlation, making them the standard for GPS and CDMA where multiple signals must coexist. +- Zadoff-Chu (ZC) Sequences are complex-valued sequences with constant amplitude and zero auto-correlation for all non-zero shifts, and are now a staple in LTE and 5G for synchronization. +- Kasami Codes are similar to Gold codes but have even lower cross-correlation for a given sequence length, making them useful in high-density environments. + +Chip-Timing Synchronization in DSSS +#################################################### + +In a DSSS system, the receiver's ability to recover data depends entirely on synchronization with the incoming chip sequence. Because chips are much shorter than data bits, even a small fractional timing error, where the receiver samples between chips, can significantly reduce the correlation peak. We can explore the impact of a fractional timing offset by simulating a simple DSSS system and plotting the correlation output as the timing offset varies from 0 to 1 chip. Note that we do not do a full correlation here; we just take a dot product at 0 lag because we already know that is where the peak will be. + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + + # Barker 11 sequence + barker11 = np.array([1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1]) + samples_per_chip = 100 + + # Upsample the sequence to simulate continuous time + sig = np.repeat(barker11, samples_per_chip) + + offsets = np.linspace(-1.5, 1.5, 500) # Fractional chip offsets + peaks = [] + + for offset in offsets: + # Shift the signal by a fractional number of chips, converted to samples + shift_samples = int(offset * samples_per_chip) + if shift_samples > 0: + shifted_sig = np.pad(sig, (shift_samples, 0))[:len(sig)] + elif shift_samples < 0: + shifted_sig = np.pad(sig, (0, abs(shift_samples)))[abs(shift_samples):] + else: + shifted_sig = sig + + # Compute normalized correlation at zero lag for this offset + correlation = np.vdot(sig, shifted_sig) / np.vdot(sig, sig) + peaks.append(np.abs(correlation)) + + plt.figure(figsize=(10, 5)) + plt.plot(offsets, peaks, label='Normalized Correlation', color='blue', linewidth=2) + plt.axvline(0, color='red', linestyle='--', alpha=0.5, label='Perfect Alignment') + plt.title('DSSS Correlation Peak vs. Fractional Chip Timing Offset') + plt.xlabel('Offset (Fraction of a Chip)') + plt.ylabel('Normalized Correlation Peak Magnitude') + plt.grid(True, which='both', linestyle='--', alpha=0.6) + plt.legend() + plt.savefig('../_images/detection_dsss.svg', bbox_inches='tight') + plt.show() + +.. image:: ../_images/detection_dsss.svg + :align: center + :target: ../_images/detection_dsss.svg + :alt: DSSS + +The peak occurs at zero offset as expected, and it drops linearly, reaching half the peak value at a half-chip offset. After more than one chip of offset, the correlation might appear to rise again, but the actual peak is low because the signal is no longer aligned to the sequence. + +**************************************************** +Real-Time Packet Detection in Continuous IQ Streams +**************************************************** + +So far we have explored the theoretical foundations of signal detection, from correlators to CFAR detectors to spread-spectrum systems. Now we bring them together to solve a common practical problem: **detecting intermittent packets in a continuous stream of IQ samples from an SDR**. Consider this scenario: a modem or IoT device transmits a data packet once per second, or at irregular intervals. Your SDR is continuously receiving samples at, say, 1 MHz. The packets arrive at unpredictable times, buried in noise and interference. You need to: + +1. Detect when a packet arrives +2. Determine the exact sample index where it starts +3. Extract the packet for further processing (demodulation, decoding, etc.) +4. Do this in real-time without missing packets + +This is fundamentally different from processing a pre-recorded IQ file, where you can analyze the entire signal at once. Here, samples arrive continuously, and you must make decisions in real time with limited computational resources. We will combine several techniques covered in this chapter: + +1. **Cross-Correlation**: To find the known preamble pattern +2. **CFAR Detection**: To adaptively set thresholds despite varying noise +3. **Buffer Management**: To handle continuous streaming data +4. **Peak Detection**: To extract precise packet timing + +To operate in real time, we accumulate samples in **buffers** of, say, 100,000 samples, run the detector on each buffer, and maintain state across buffer boundaries so that packets spanning two buffers are not missed. + +Implementation +############## + +Our detector follows this workflow: + +.. mermaid:: + + flowchart TD + A("Continuous IQ Stream from SDR
    (1 MHz sample rate)") + B("Buffer Accumulation
    (100k samples = 0.1 sec)") + C("Cross-Correlation with Known Preamble") + D("CFAR Threshold Computation") + E("Peak Detection
    (correlation > threshold)") + F("Packet Extraction & Validation") + A --> B --> C --> D --> E --> F + +To avoid missing packets that straddle buffer boundaries, we use an **overlap-save** approach, where each buffer includes the last ``N_preamble`` samples from the previous buffer. This ensures that any packet starting near the end of buffer ``i`` will be fully contained in buffer ``i+1``. It adds a small amount of computational overhead, but that is preferable to missing packets at the buffer edge. + +Let's build a complete packet detector in Python one step at a time. We will use a shorter Zadoff-Chu preamble than before and implement an adaptive CFAR detector. + +Step 1: Define the Preamble and Parameters +******************************************* + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + from scipy.signal import correlate + + # Preamble: Zadoff-Chu sequence (excellent correlation properties) + N_zc = 63 # ZC sequence length (typically prime or power of 2 - 1) + u = 5 # ZC root + t = np.arange(N_zc) + preamble = np.exp(-1j * np.pi * u * t * (t + 1) / N_zc) + + # System parameters + sample_rate = 1e6 + buffer_size = 100000 + overlap_size = len(preamble) # Overlap to catch boundary packets + + # CFAR parameters + cfar_guard = 10 + cfar_train = 50 + pfa_target = 1e-6 + + # Packet parameters (for simulation) + packet_length = 500 # Total packet length in samples (preamble + data) + snr_db = -5 + +Step 2: CFAR Detector Function +******************************* + +We'll use the Cell-Averaging CFAR (CA-CFAR) from earlier, slightly optimized: + +.. code-block:: python + + def ca_cfar_1d(signal, num_train, num_guard, pfa): + """ + 1D Cell-Averaging CFAR detector. + + Args: + signal: Input signal (typically correlation magnitude) + num_train: Number of training cells (on each side) + num_guard: Number of guard cells (on each side) + pfa: Target probability of false alarm + + Returns: + threshold: Adaptive threshold array + """ + n = len(signal) + threshold = np.zeros(n) + alpha = num_train * (pfa**(-1/num_train) - 1) + + for i in range(n): + # Define training window indices + train_start_left = max(0, i - num_guard - num_train) + train_end_left = max(0, i - num_guard) + train_start_right = min(n, i + num_guard + 1) + train_end_right = min(n, i + num_guard + num_train + 1) + + # Collect training cells (avoid guard cells and CUT) + train_cells = np.concatenate([ + signal[train_start_left:train_end_left], + signal[train_start_right:train_end_right] + ]) + + if len(train_cells) > 0: + noise_est = np.mean(train_cells) + threshold[i] = alpha * noise_est + + return threshold + +Step 3: Packet Detection Function +********************************** + +.. code-block:: python + + def detect_packets(buffer, preamble, cfar_guard, cfar_train, pfa, + min_spacing=None): + """ + Detect packets in a buffer of IQ samples. + + Args: + buffer: Complex IQ samples + preamble: Known preamble sequence + cfar_guard: CFAR guard cells + cfar_train: CFAR training cells + pfa: Target false alarm probability + min_spacing: Minimum samples between detections (prevents duplicates) + + Returns: + detections: List of sample indices where packets start + """ + # Correlate buffer with preamble + corr = correlate(buffer, preamble, mode='same') + corr_power = np.abs(corr)**2 + + # Compute adaptive threshold + threshold = ca_cfar_1d(corr_power, cfar_train, cfar_guard, pfa) + + # Find peaks above threshold + detections_raw = np.where(corr_power > threshold)[0] + + # Compensate for correlation offset (peak occurs at len(preamble)//2 after true start) + half_preamble = len(preamble) // 2 + detections_raw = detections_raw - half_preamble + + # Remove edge detections (unreliable) + half_preamble = len(preamble) // 2 + detections_raw = detections_raw[ + (detections_raw > half_preamble) & + (detections_raw < len(buffer) - half_preamble) + ] + + # Remove duplicate detections (peaks close together) + if min_spacing is None: + min_spacing = len(preamble) + + detections = [] + if len(detections_raw) > 0: + detections.append(detections_raw[0]) + for det in detections_raw[1:]: + if det - detections[-1] > min_spacing: + detections.append(det) + + return detections, corr_power, threshold + +Step 4: Simulation - Generate Test Signal +****************************************** + +.. code-block:: python + + def generate_packet_stream(preamble, packet_length, num_packets, + sample_rate, snr_db): + """ + Generate a simulated IQ stream with intermittent packets. + + Returns: + signal: Complex IQ samples + true_starts: Ground truth packet start indices + """ + # Calculate noise power from SNR + signal_power = 1.0 # Normalized preamble power + noise_power = signal_power / (10**(snr_db/10)) + noise_std = np.sqrt(noise_power / 2) # Complex noise + + # Generate QPSK data (random payload after preamble) + qpsk_map = np.array([1+1j, -1+1j, -1-1j, 1-1j]) / np.sqrt(2) + + # Time between packets (1 second +/- 20% jitter) + packets_per_sec = 1 + avg_gap = int(sample_rate / packets_per_sec) + + signal = [] + true_starts = [] + + for i in range(num_packets): + # Add gap (noise only) + if i == 0: + gap_length = np.random.randint(avg_gap//2, avg_gap) + else: + gap_length = np.random.randint(int(avg_gap*0.8), int(avg_gap*1.2)) + + noise = noise_std * (np.random.randn(gap_length) + + 1j*np.random.randn(gap_length)) + signal.extend(noise) + + # Record true packet start + true_starts.append(len(signal)) + + # Add packet (preamble + data) + data_length = packet_length - len(preamble) + data = qpsk_map[np.random.randint(0, 4, data_length)] + packet = np.concatenate([preamble, data]) + + # Add noise to packet + packet_noisy = packet + noise_std * (np.random.randn(len(packet)) + + 1j*np.random.randn(len(packet))) + signal.extend(packet_noisy) + + # Add final gap + gap_length = np.random.randint(avg_gap//2, avg_gap) + noise = noise_std * (np.random.randn(gap_length) + + 1j*np.random.randn(gap_length)) + signal.extend(noise) + + return np.array(signal), true_starts + + # Generate 5 seconds of signal with ~5 packets + signal, true_starts = generate_packet_stream( + preamble, packet_length, num_packets=5, + sample_rate=sample_rate, snr_db=snr_db + ) + + print(f"Generated {len(signal)} samples ({len(signal)/sample_rate:.1f} sec)") + print(f"True packet starts: {true_starts}") + +Step 5: Run Detection in Streaming Mode +**************************************** + +Now we process the signal in chunks, simulating real-time streaming: + +.. code-block:: python + + def process_stream(signal, preamble, buffer_size, overlap_size, + cfar_guard, cfar_train, pfa): + """ + Process continuous IQ stream in buffers (simulates real-time). + + Returns: + all_detections: List of detected packet starts (global indices) + """ + all_detections = [] + n_samples = len(signal) + current_pos = 0 + + while current_pos < n_samples: + # Define buffer with overlap + buffer_start = max(0, current_pos - overlap_size) + buffer_end = min(n_samples, current_pos + buffer_size) + buffer = signal[buffer_start:buffer_end] + + # Detect packets in this buffer + detections, corr_power, threshold = detect_packets( + buffer, preamble, cfar_guard, cfar_train, pfa + ) + + # Convert buffer-relative indices to global indices + for det in detections: + global_idx = buffer_start + det + + # Avoid duplicate detections from overlap region + if len(all_detections) == 0 or \ + global_idx - all_detections[-1] > len(preamble): + all_detections.append(global_idx) + + current_pos += buffer_size + + return all_detections + + + detected_starts = process_stream( + signal, preamble, buffer_size, overlap_size, + cfar_guard, cfar_train, pfa_target + ) + + print(f"\nDetection Results:") + print(f"True packets: {len(true_starts)}") + print(f"Detected packets: {len(detected_starts)}") + print(f"Detected starts: {detected_starts}") + +Step 6: Evaluate Performance +***************************** + +.. code-block:: python + + # Calculate detection statistics + tolerance = len(preamble) + + matched_detections = [] + false_alarms = [] + + for det in detected_starts: + # Check if detection matches any true packet + matched = False + for true_start in true_starts: + if abs(det - true_start) <= tolerance: + matched_detections.append(det) + matched = True + break + if not matched: + false_alarms.append(det) + + missed_packets = len(true_starts) - len(matched_detections) + + print(f"\nPerformance Metrics:") + print(f" Correct detections: {len(matched_detections)}/{len(true_starts)}") + print(f" Missed packets: {missed_packets}") + print(f" False alarms: {len(false_alarms)}") + + # Calculate timing errors + timing_errors = [] + for det in matched_detections: + errors = [abs(det - ts) for ts in true_starts] + timing_errors.append(min(errors)) + + if len(timing_errors) > 0: + print(f" Timing error (avg): {np.mean(timing_errors):.1f} samples") + print(f" Timing error (max): {np.max(timing_errors):.1f} samples") + +Step 7: Visualize Results +************************** + +.. code-block:: python + + # Process one buffer for detailed visualization + buffer_start = max(0, true_starts[0] - 5000) + buffer_end = min(len(signal), true_starts[0] + 20000) + viz_buffer = signal[buffer_start:buffer_end] + + detections_viz, corr_viz, thresh_viz = detect_packets( + viz_buffer, preamble, cfar_guard, cfar_train, pfa_target + ) + + # Convert to global indices for plotting + detections_viz_global = [d + buffer_start for d in detections_viz] + + # Create visualization + fig, axes = plt.subplots(3, 1, figsize=(14, 10)) + time_axis = (np.arange(len(viz_buffer)) + buffer_start) / sample_rate * 1000 # ms + + # Subplot 1: Received signal power + axes[0].plot(time_axis, np.abs(viz_buffer)**2, 'gray', alpha=0.6, linewidth=0.5) + axes[0].set_ylabel('Power') + axes[0].set_title('Received IQ Signal Power') + axes[0].grid(True, alpha=0.3) + + # Mark true packet locations + for ts in true_starts: + if buffer_start <= ts <= buffer_end: + t_ms = ts / sample_rate * 1000 + axes[0].axvline(t_ms, color='green', linestyle='--', alpha=0.7, + label='True Packet' if ts == true_starts[0] else '') + axes[0].legend() + + # Subplot 2: Correlation output + axes[1].plot(time_axis, corr_viz, 'blue', linewidth=1, label='Correlation') + axes[1].plot(time_axis, thresh_viz, 'red', linestyle='--', linewidth=1.5, + label='CFAR Threshold') + axes[1].set_ylabel('Correlation Power') + axes[1].set_title('Preamble Correlation with Adaptive CFAR Threshold') + axes[1].grid(True, alpha=0.3) + axes[1].legend() + + # Subplot 3: Detections + detection_mask = np.zeros(len(viz_buffer)) + for det in detections_viz: + detection_mask[det] = corr_viz[det] + + axes[2].plot(time_axis, corr_viz, 'blue', alpha=0.4, linewidth=0.8) + axes[2].scatter(time_axis[detection_mask > 0], detection_mask[detection_mask > 0], + color='lime', edgecolors='black', s=100, zorder=5, + label='Detected Packets') + axes[2].set_xlabel('Time (ms)') + axes[2].set_ylabel('Correlation Power') + axes[2].set_title('Detected Packet Locations') + axes[2].grid(True, alpha=0.3) + axes[2].legend() + + plt.tight_layout() + plt.show() + +The visualization should show: + +1. **Top plot**: Raw signal power with true packet locations marked +2. **Middle plot**: Correlation output with adaptive CFAR threshold tracking the noise floor +3. **Bottom plot**: Detected packets highlighted as peaks above threshold + +.. image:: ../_images/detection_realtime.png + :align: center + :scale: 50 % + :alt: Real-time packet detection results + +Practical Considerations and Tuning +#################################### + +Buffer Size Trade-offs +*********************** + +**Larger buffers**, for example 1M samples: + +- ✅ Better CFAR noise estimation (more training cells) +- ✅ Lower computational overhead (fewer processing calls) +- ❌ Higher latency (must wait for buffer to fill) +- ❌ More memory required + +**Smaller buffers**, for example 10k samples: + +- ✅ Lower latency (faster response) +- ✅ Less memory usage +- ❌ CFAR performance degrades (fewer training cells) +- ❌ Higher CPU usage (more frequent processing) + +**Recommendation**: Start with a buffer size of 10x to 100x your preamble length. For a 63-sample preamble at 1 Msps, try 10k to 100k samples. + +CFAR Parameter Tuning +********************** + +The three CFAR parameters control detector behavior: + +**num_guard**: guard cells + +- Prevents signal leakage into the noise estimate +- Too small: signal leaks into the training region, raising the threshold and causing missed detections +- Too large: fewer training cells and a poorer noise estimate +- Rule of thumb: set this to about 0.5 to 1.0x the preamble length + +**num_train**: training cells + +- Estimates the local noise floor +- Too small: noisy threshold and more false alarms or missed detections +- Too large: threshold does not adapt quickly enough to noise changes +- Rule of thumb: set this to about 3 to 5x the preamble length + +**pfa**: probability of false alarm + +- Controls detection sensitivity +- Too high, for example 1e-2: many false alarms +- Too low, for example 1e-10: missed weak packets +- Rule of thumb: start with 1e-5 for per-lag PFA, then adjust based on the system-level false-alarm rate + +Remember the relationship between per-lag and system-level false-alarm rates from earlier in the chapter. + +************** +Rake Receivers +************** + +Imagine you are standing outdoors with a phone, and the tower's signal reaches you by more than one path. Some of the energy arrives straight from the tower, but another copy bounces off a building 150 m away and shows up a little later, and maybe a third copy reflects off a hillside and arrives later still. Each path travels a different distance, so each copy lands at your receiver at a slightly different time and with a different strength and phase. This is multipath, and it is the normal state of affairs in any real wireless environment, not a rare edge case. + +What does multipath look like at the output of a correlator? If you slide your preamble or chip sequence across the received samples, you do not get one clean spike, you get several, you see one peak for the direct path and a smaller peak for each echo. The naive thing to do is grab the tallest peak and throw the rest away. But those smaller peaks are not noise, they are the same data arriving by a different route, and discarding them means discarding signal energy you paid for. + +A rake receiver is the answer to a simple question: instead of throwing the echoes away, why not collect them and add them back together? The name comes from a garden rake, where each finger of the rake reaches out and gathers one row. Here, each "finger" is a separate correlator tuned to one of the multipath delays. Finger one locks onto the direct path, finger two onto the echo from the building, finger three onto the hillside reflection, and so on. Each finger is doing exactly the cross-correlation we have used throughout this chapter, just with its template shifted to a different delay so it tracks one specific copy of the signal. + +Finding the Fingers +############################### + +Before the rake can combine anything, it has to know where the copies are. That job belongs to the correlator output we already have. The set of multipath delays and their relative strengths is called the channel's *power delay profile*, and it is just the magnitude of the correlation peaks plotted against delay. To set up the rake, you scan that profile and pick the strongest few peaks, then assign one finger to each. A receiver might have three or four fingers because allocating a finger to a tiny peak buried in the noise costs more than it gains. + +Because the channel changes as you move, as cars drive by, and as the environment shifts, the fingers cannot be set once and forgotten. The receiver keeps re-scanning the delay profile and reassigning fingers as peaks rise, fade, and drift in delay. A finger that was tracking a strong reflection might find its peak fading away, at which point the receiver reassigns it to a new path that has grown stronger. + +Combining the Fingers +############################### + +Once each finger has locked onto its copy of the signal, the receiver has several independent measurements of the same transmitted symbols. How should it merge them into one decision? You might be tempted to just add them up, but that would be a mistake, because a strong, clean copy and a weak, noisy copy do not deserve an equal vote. The weak finger is mostly noise, and giving it equal weight would drag the combined result down. + +The standard solution is *maximal ratio combining* (MRC), which weights each finger by its own strength before summing. A finger with a strong, high-SNR peak gets a large weight, and a finger that is barely above the noise gets a small one. If we call the complex output of finger :math:`k` at a given symbol :math:`r_k` and the channel gain that finger sees :math:`h_k`, the combined output is: + +.. math:: + + y = \sum_{k} h_k^{*} \, r_k + +I.e., take each finger's output, weight it by the conjugate of that finger's channel gain, and add them all up. The conjugate does two jobs at once; its magnitude :math:`|h_k|` scales each finger by how strong it is, so loud fingers count more, and its phase rotates each finger's contribution so that all the copies line up and add constructively rather than partially canceling. + +The payoff comes in two forms. The first is simply more signal energy; by gathering the echoes instead of discarding them, the rake recovers power that a single-peak detector would have thrown on the floor. The second, and often more important, benefit is *diversity*. The deep fades that wreck a wireless link happen when the paths to a single point momentarily cancel each other, but it is unlikely that several paths with different delays all fade at the same instant. So when the direct path drops into a fade, one of the reflections is probably still strong, and the rake leans on whichever fingers are healthy at that moment. + +Note that rake receivers are only possible for wideband signals, which have sharp auto-correlation, which means multipath copies show up as cleanly separated peaks in the delay profile. Narrowband signals smear those copies together and cannot resolve them, so the rake won't work. diff --git a/content/digital_modulation.rst b/content/digital_modulation.rst index b2959e98..ab09368a 100644 --- a/content/digital_modulation.rst +++ b/content/digital_modulation.rst @@ -236,7 +236,7 @@ Given the difficulty discerning modulation schemes in the time domain, we prefer Frequency Shift Keying (FSK) **************************** -Last on the list is Frequency Shift Keying (FSK). FSK is fairly simple to understand--we just shift between N frequencies where each frequency is one possible symbol. However, because we are modulating a carrier, it's really our carrier frequency +/- these N frequencies. E.g.. we might be at a carrier of 1.2 GHz and shift between these four frequencies: +Last on the list is Frequency Shift Keying (FSK). FSK is fairly simple to understand--we just shift between N frequencies where each frequency is one possible symbol. However, because we are modulating a carrier, it's really our carrier frequency +/- these N frequencies. E.g., we might be at a carrier of 1.2 GHz and shift between these four frequencies: 1. 1.2001 GHz 2. 1.2003 GHz @@ -296,7 +296,7 @@ As an example of encoding, consider transmitting the 10 bits [1, 1, 0, 0, 1, 1, Input: 1 1 0 0 1 1 1 1 1 0 Output: 1 -Next you build the output by comparing the input bit with the previous **output** bit, and apply the XOR operation shown in the table above. The next output bit is therefore a 0, because 1 and 1 match: +Next you build the output by comparing the input bit with the previous **output** bit, and apply the XOR operation. The next output bit is therefore a 0, because 1 and 1 match: .. code-block:: diff --git a/content/doa.rst b/content/doa.rst index 20cc4176..94808090 100644 --- a/content/doa.rst +++ b/content/doa.rst @@ -32,7 +32,7 @@ The following taxonomy attempts to categorize the many areas of beamforming whil Direction-of-Arrival Overview ****************************** -Direction-of-Arrival (DOA) within DSP/SDR refers to the process of using an array of antennas to detect and estimate the directions of arrival of one or more signals received by that array (versus beamforming, which is focused on the process of receiving a signal while rejecting as much noise and interference). Although DOA certainly falls under the beamforming topic umbrella, the two terms can get confusing. Some techniques such as Conventional and MVDR beamforming can apply to both DOA and beamforming, because the same technique used for beamforming is used to perform DOA by sweeping the angle of interest and performing the beamforming operation at each angle, then looking for peaks in the result (each peak is a signal, but we don't know whether it is the signal of interest, an interferer, or even a multipath bounce from the signal of interest). You can think of these DOA techniques as a wrapper around a specific beamformer. Other beamformers are unable to be simply wrapped into a DOA routine, such as due to extra inputs that won't be available within the context of DOA. There are also DOA techniques such as MUSIC and ESPIRT which are strictly for the purpose of DOA and are not beamformers. Because most beamforming techniques assume you know the angle of arrival of the signal of interest, if the target is moving, or the array is moving, you will have to continuously perform DOA as an intermediate step, even if your primary goal is to receive and demodulate the signal of interest. +Direction-of-Arrival (DOA) within DSP/SDR refers to the process of using an array of antennas to detect and estimate the directions of arrival of one or more signals received by that array (versus beamforming, which is focused on the process of receiving a signal while rejecting as much noise and interference). Although DOA certainly falls under the beamforming topic umbrella, the two terms can get confusing. Some techniques such as Conventional and MVDR beamforming can apply to both DOA and beamforming, because the same technique used for beamforming is used to perform DOA by sweeping the angle of interest and performing the beamforming operation at each angle, then looking for peaks in the result (each peak is a signal, but we don't know whether it is the signal of interest, an interferer, or even a multipath bounce from the signal of interest). You can think of these DOA techniques as a wrapper around a specific beamformer. Other beamformers are unable to be simply wrapped into a DOA routine, such as due to extra inputs that won't be available within the context of DOA. There are also DOA techniques such as MUSIC and ESPRIT which are strictly for the purpose of DOA and are not beamformers. Because most beamforming techniques assume you know the angle of arrival of the signal of interest, if the target is moving, or the array is moving, you will have to continuously perform DOA as an intermediate step, even if your primary goal is to receive and demodulate the signal of interest. Phased arrays and beamforming/DOA find use in all sorts of applications, although you will most often see them used in multiple forms of radar, newer WiFi standards, mmWave communication within 5G, satellite communications, and jamming. Generally, any applications that require a high-gain antenna, or require a rapidly moving high-gain antenna, are good candidates for phased arrays. @@ -42,9 +42,9 @@ Types of Arrays Phased arrays can be broken down into three types: -1. **Analog**, a.k.a. passive electronically scanned array (PESA) or traditional phased arrays, where analog phase shifters are used to steer the beam. On the receive side, all elements are summed after phase shifting (and optionally, adjustable gain) and turned into a signal channel which is downconverted and received. On the transmit side the inverse takes place; a single digital signal is outputted from the digital side, and on the analog side phase shifters and gain stages are used to produce the output going to each antenna. These digital phase shifters will have a limited number of bits of resolution, and control latency. -2. **Digital**, a.k.a. active electronically scanned array (AESA), where every single element has its own RF front end, and the beamforming is done entirely in the digital domain. This is the most expensive approach, as RF components are expensive, but it provides much more flexibility and speed than PESAs. Digital arrays are popular with SDRs, although the number of receive or transmit channels of the SDR limits the number of elements in your array. -3. **Hybrid**, where the array consists of many subarrays that individually resemble analog arrays, where each subarray has its own RF front-end just like with digital arrays. This is the most common approach for modern phased arrays, as it provides the best of both worlds. +1. **Analog**, a.k.a. passive electronically scanned array (PESA) or traditional phased arrays, where analog phase shifters are used to steer the beam. On the receive side, all elements are summed after phase shifting (and optionally, adjustable gain) and turned into a single channel which is downconverted and received. On the transmit side the inverse takes place; a single digital signal is outputted from the digital side, and on the analog side phase shifters and gain stages are used to produce the output going to each antenna. These digital phase shifters will have a limited number of bits of resolution, and control latency. A huge advantage of analog beamforming is that strong interferers can be nulled out in the analog domain before the ADC, which can prevent saturating the receiver. +2. **Digital**, a.k.a. active electronically scanned array (AESA), where every single element has its own RF front end, and the beamforming is done entirely in the digital domain. This is the most expensive approach, as RF components are expensive, but it provides much more flexibility and speed than PESAs, and allows for using the adaptive beamforming techniques we will discuss later in this chapter. Digital arrays are popular with SDRs, although the number of receive or transmit channels of the SDR limits the number of elements in your array. +3. **Hybrid**, where the array consists of many subarrays that individually resemble analog arrays, where each subarray has its own RF front-end just like with digital arrays. This is the most common approach for modern phased arrays, as it provides the best of both worlds. A hybrid array allows for adaptive techniques, and can also null out strong interferers in the analog domain before the ADC, which is especially important for radar applications where the target is often much weaker than the interferers, or communications in hostile wireless environments. Note that the terms PESA and AESA are mainly just used in the context of radar, and there is some ambiguity when it comes to exactly what constitutes a PESA or AESA. Therefore, using the terms analog/digital/hybrid array is clearer and can be applied to any type of application. @@ -163,7 +163,7 @@ If you recall SOH CAH TOA, in this case we are interested in the "adjacent" side We must solve for adjacent, as that is what will tell us how far the signal must travel between hitting the first and second element, so it becomes adjacent :math:`= d \cos(90 - \theta)`. Now there is a trig identity that lets us convert this to adjacent :math:`= d \sin(\theta)`. This is just a distance though, we need to convert this to a time, using the speed of light: time elapsed :math:`= d \sin(\theta) / c` seconds. This equation applies between any adjacent elements of our array, although we can multiply the whole thing by an integer to calculate between non-adjacent elements since they are uniformly spaced (we'll do this later). -Now to connect this trig and speed of light math to the signal processing world. Let's denote our transmit signal at baseband :math:`x(t)` and it's being transmitting at some carrier, :math:`f_c` , so the transmit signal is :math:`x(t) e^{2j \pi f_c t}`. We'll use :math:`d_m` to refer to antenna spacing in meters. Lets say this signal hits the first element at time :math:`t = 0`, which means it hits the next element after :math:`d_m \sin(\theta) / c` seconds, like we calculated above. This means the 2nd element receives: +Now to connect this trig and speed of light math to the signal processing world. Let's denote our transmit signal at baseband :math:`x(t)` and it is being transmitted at some carrier, :math:`f_c` , so the transmit signal is :math:`x(t) e^{2j \pi f_c t}`. We'll use :math:`d_m` to refer to antenna spacing in meters. Lets say this signal hits the first element at time :math:`t = 0`, which means it hits the next element after :math:`d_m \sin(\theta) / c` seconds, like we calculated above. This means the 2nd element receives: .. math:: x(t - \Delta t) e^{2j \pi f_c (t - \Delta t)} @@ -173,7 +173,7 @@ Now to connect this trig and speed of light math to the signal processing world. recall that when you have a time shift, it is subtracted from the time argument. -When the receiver or SDR does the downconversion process to receive the signal, its essentially multiplying it by the carrier but in the reverse direction, so after doing downconversion the receiver sees: +When the receiver or SDR does the downconversion process to receive the signal, it's essentially multiplying it by the carrier but in the reverse direction, so after doing downconversion the receiver sees: .. math:: x(t - \Delta t) e^{2j \pi f_c (t - \Delta t)} e^{-2j \pi f_c t} @@ -181,7 +181,7 @@ When the receiver or SDR does the downconversion process to receive the signal, .. math:: = x(t - \Delta t) e^{-2j \pi f_c \Delta t} -Now we can do a little trick to simplify this even further; consider how when we sample a signal it can be modeled by substituting :math:`t` for :math:`nT` where :math:`T` is sample period and :math:`n` is just 0, 1, 2, 3... Substituting this in we get :math:`x(nT - \Delta t) e^{-2j \pi f_c \Delta t}`. Well, :math:`nT` is so much greater than :math:`\Delta t` that we can get rid of the first :math:`\Delta t` term and we are left with :math:`x(nT) e^{-2j \pi f_c \Delta t}`. If the sample rate ever gets fast enough to approach the speed of light over a tiny distance, we can revisit this, but remember that our sample rate only needs to be a bit larger than the signal of interest's bandwidth. +Now we can do a little trick to simplify this even further; consider how when we sample a signal it can be modeled by substituting :math:`t` for :math:`nT` where :math:`T` is sample period and :math:`n` is just 0, 1, 2, 3... Substituting this in we get :math:`x(nT - \Delta t) e^{-2j \pi f_c \Delta t}`. For a narrowband signal, the signal envelope changes slowly enough over the propagation delay :math:`\Delta t` that we can approximate :math:`x(nT - \Delta t) \approx x(nT)`, leaving us with :math:`x(nT) e^{-2j \pi f_c \Delta t}`. If the sample rate ever gets fast enough to approach the speed of light over a tiny distance, we can revisit this, but remember that our sample rate only needs to be a bit larger than the signal of interest's bandwidth. Let's keep going with this math but we'll start representing things in discrete terms so that it will better resemble our Python code. The last equation can be represented as the following, let's plug back in :math:`\Delta t`: @@ -279,7 +279,7 @@ Now let's simulate an array consisting of three omnidirectional antennas in a li s = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta)) # Steering Vector print(s) # note that it's 3 elements long, it's complex, and the first element is 1+0j -To apply the steering vector we have to do a matrix multiplication of :code:`s` and :code:`tx`, so first let's convert both to 2D, using the approach we discussed earlier when we reviewed doing matrix math in Python. We'll start off by making both into row vectors using :code:`ourarray.reshape(-1,1)`. We then perform the matrix multiply, indicated by the :code:`@` symbol. We also have to convert :code:`tx` from a row vector to a column vector using a transpose operation (picture it rotating 90 degrees) so that the matrix multiply inner dimensions match. +To apply the steering vector we have to do a matrix multiplication of :code:`s` and :code:`tx`, so first let's convert both to 2D, using the approach we discussed earlier when we reviewed doing matrix math in Python. We'll start off by making both into column vectors using :code:`ourarray.reshape(-1,1)`. We then perform the matrix multiply, indicated by the :code:`@` symbol. We also have to convert :code:`tx` from a row vector to a column vector using a transpose operation (picture it rotating 90 degrees) so that the matrix multiply inner dimensions match. .. code-block:: python @@ -680,7 +680,7 @@ where: \frac{\partial L}{\partial \mathbf{w}^*} = 2\mathbf{R}\mathbf{w} - \lambda \mathbf{s} = 0 - \mathbf{w} = \lambda \mathbf{s} \mathbf{{R^{-1}}} + \mathbf{w} = \lambda \mathbf{R}^{-1} \mathbf{s} To solve for :math:`\lambda`, apply the constraint :math:`\mathbf{w}^H \mathbf{s} = 1`: @@ -795,7 +795,7 @@ Meaning we don't have to apply the weights at all, this final equation above for .. code-block:: python def power_mvdr(theta, X): - s = np.exp(2j * np.pi * d * np.arange(r.shape[0]) * np.sin(theta)) # steering vector in the desired direction theta_i + s = np.exp(2j * np.pi * d * np.arange(X.shape[0]) * np.sin(theta)) # steering vector in the desired direction theta_i s = s.reshape(-1,1) # make into a column vector (size 3x1) R = (X @ X.conj().T)/X.shape[1] # Calc covariance matrix. gives a Nr x Nr covariance matrix of the samples Rinv = np.linalg.pinv(R) # 3x3. pseudo-inverse tends to work better than a true inverse @@ -1072,9 +1072,9 @@ We get the following beam pattern. You may notice nulls in positions that you d :target: ../_images/null_steering.svg :alt: Example of null steering beamforming -******************* +***** MUSIC -******************* +***** We will now change gears and talk about a different kind of beamformer. All of the previous ones have fallen in the "delay-and-sum" category, but now we will dive into "sub-space" methods. These involve dividing the signal subspace and noise subspace, which means we must estimate how many signals are being received by the array, to get a good result. MUltiple SIgnal Classification (MUSIC) is a very popular sub-space method that involves calculating the eigenvectors of the covariance matrix (which is a computationally intensive operation by the way). We split the eigenvectors into two groups: signal sub-space and noise-subspace, then project steering vectors into the noise sub-space and steer for nulls. That might seem confusing at first, which is part of why MUSIC seems like black magic! @@ -1083,7 +1083,7 @@ The core MUSIC equation is the following: .. math:: \hat{\theta} = \mathrm{argmax}\left(\frac{1}{s^H V_n V^H_n s}\right) -where :math:`V_n` is that list of noise sub-space eigenvectors we mentioned (a 2D matrix). It is found by first calculating the eigenvectors of :math:`R`, which is done simply by :code:`w, v = np.linalg.eig(R)` in Python, and then splitting up the vectors (:code:`w`) based on how many signals we think the array is receiving. There is a trick for estimating the number of signals that we'll talk about later, but it must be between 1 and :code:`Nr - 1`. I.e., if you are designing an array, when you are choosing the number of elements you must have one more than the number of anticipated signals. One thing to note about the equation above is :math:`V_n` does not depend on the steering vector :math:`s`, so we can precalculate it before we start looping through theta. The full MUSIC code is as follows: +where :math:`V_n` is that list of noise sub-space eigenvectors we mentioned (a 2D matrix). It is found by first calculating the eigenvectors of :math:`R`, which is done simply by :code:`w, v = np.linalg.eig(R)` in Python, and then splitting up the eigenvectors (:code:`v`) based on how many signals we think the array is receiving. There is a trick for estimating the number of signals that we'll talk about later, but it must be between 1 and :code:`Nr - 1`. I.e., if you are designing an array, when you are choosing the number of elements you must have one more than the number of anticipated signals. One thing to note about the equation above is :math:`V_n` does not depend on the steering vector :math:`s`, so we can precalculate it before we start looping through theta. The full MUSIC code is as follows: .. code-block:: python @@ -1136,6 +1136,73 @@ Another experiment worth trying with MUSIC is to see how close two signals can a :scale: 100 % :align: center +********** +Root MUSIC +********** + +Every DOA technique we have covered so far, including conventional beamforming, MVDR, and MUSIC itself, works by sweeping through a grid of candidate angles and computing a metric at each one (often in parallel). Root MUSIC eliminates that scan entirely! Instead of searching for peaks in a spectrum, it finds the signal directions analytically by solving for the roots of a polynomial. This gives Root MUSIC potential to be both faster and more precise than spectral MUSIC, since the peak location is no longer limited by the angular resolution of your scan grid. One limitation of Root MUSIC is that it only works for a ULA; for 2D arrays or non-ULA 1D arrays there are variations/extensions of Root MUSIC that can be used, but they are far more complex. We also still need :code:`num_expected_signals` just like in MUSIC, which can be seen as a limitation. + +Root MUSIC takes advantage of the fact that a ULA's steering vector has a clean Vandermonde structure, which is any vector (or matrix) where each row is built by taking successive powers of some base value, e.g. :code:`[1, x, x², x³, ..., x^(n-1)]`. With half-wavelength element spacing the steering vector elements are just consecutive powers of a single complex number :math:`z = e^{j\pi\sin\theta}`, as we saw at the beginning of this chapter. + +To perform Root MUSIC, we form a polynomial from the noise-subspace projection matrix. We use the same MUSIC cost function as in the previous section, but now it takes the form: + +.. math:: + P(z) = z^{N_r-1} \, s^H(z) \, V_n V_n^H \, s(z) + +where :math:`V_n` is the noise-subspace matrix from the eigendecomposition of the covariance matrix :math:`R`, exactly as in MUSIC. Expanding the product yields a polynomial of degree :math:`2(N_r-1)`. Wherever :math:`P(z)` has a root on the unit circle :math:`|z|=1`, the MUSIC cost would be infinite, meaning that point is a signal direction. In practice, with finite samples, the roots don't land exactly on the unit circle but cluster near it, so we look for the :math:`D` roots (where :math:`D` is the number of expected signals) that are closest to the unit circle. + +The polynomial coefficients are built by summing the diagonals of the noise-subspace projection matrix :math:`D = V_n V_n^H`: + +.. math:: + p_k = \sum_{\substack{m,n=0 \\ n-m = k-(N_r-1)}}^{N_r-1} [D]_{m,n}, \quad k = 0, 1, \ldots, 2(N_r-1) + +which is simply the sum along the :math:`(k-(N_r-1))`-th diagonal of :math:`D`. Once we have the polynomial :math:`P(z) = p_0 + p_1 z + \cdots + p_{2(N_r-1)} z^{2(N_r-1)}`, we extract its roots numerically and convert the signal roots back to angles: + +.. math:: + \hat{\theta} = \arcsin\!\left(\frac{\angle z}{2\pi d}\right) + +The full Root MUSIC code, using the same received signal :code:`X` and parameters from the MUSIC example, is: + +.. code-block:: python + + num_expected_signals = 3 + + # Same eigendecomposition as MUSIC + R = np.cov(X) + w, v = np.linalg.eig(R) + eig_val_order = np.argsort(np.abs(w)) + v = v[:, eig_val_order] + V = v[:, :Nr - num_expected_signals] # noise subspace eigenvectors + + # Build the Root MUSIC polynomial from diagonals of noise-subspace projection + D = V @ V.conj().T + p = np.zeros(2*Nr - 1, dtype=np.complex128) + for k in range(2*Nr - 1): + p[k] = np.sum(np.diag(D, k - (Nr - 1))) + + # Find roots, keep those inside the unit circle, pick the num_expected_signals roots closest to the unit circle + roots = np.roots(p[::-1]) # np.roots expects highest-degree coefficient first + roots = roots[np.abs(roots) <= 1.0] # remove the conjugate-reciprocal partners which correspond to the same DOA estimate anyway + roots = roots[np.argsort(-np.abs(roots))] # sort closest-to-unit-circle first + doa_roots = roots[:num_expected_signals] + + # Convert roots to angles in degrees + doas_deg = np.sort(np.arcsin(np.angle(doa_roots) / (2 * np.pi * d)) * 180 / np.pi) + print("Estimated DOAs (degrees):", doas_deg) + +The heavy lifting is done by NumPy's :code:`np.roots()` function, which uses the companion matrix method to find the roots of the polynomial. + +Running this on the same three-signal scenario produces pretty accurate estimated angles, with no sweep, resolution, or peak-finding required: + +.. code-block:: console + + Estimated DOAs (degrees): [-39.98674197 19.99724883 25.00387589] + True DOAs (degrees): [-40. 20. 25.] + +Compare that to spectral MUSIC, which required a thousand-point theta sweep to find those same three peaks. The accuracy you get from Root MUSIC is essentially limited only by the covariance matrix estimate, not by any grid spacing you chose. The computational savings are especially noticeable when :code:`Nr` is large, since building and solving a degree-:math:`2(N_r-1)` polynomial is far cheaper than iterating the MUSIC equation over thousands of steering angles. + +One thing to keep in mind: Root MUSIC inherits the same requirements as MUSIC. You still need to know (or estimate) the number of signals, and you still need enough elements that :math:`N_r > D`. The eigenvalue plot trick described in the MUSIC section works just as well here for estimating the signal count before running Root MUSIC. + *** LMS *** diff --git a/content/filters.rst b/content/filters.rst index b4f17898..beb9518d 100644 --- a/content/filters.rst +++ b/content/filters.rst @@ -27,6 +27,10 @@ You may think we only care about digital filters; this textbook explores DSP, af In DSP, where the input and output are signals, a filter has one input signal and one output signal: +.. raw:: html + +
    + .. tikz:: [font=\sffamily\Large, scale=2] \definecolor{babyblueeyes}{rgb}{0.36, 0.61, 0.83} \node [draw, @@ -36,9 +40,13 @@ In DSP, where the input and output are signals, a filter has one input signal an minimum height=2.4cm ] (filter) {Filter}; \draw[<-, very thick] (filter.west) -- ++(-2,0) node[left,align=center]{Input\\(time domain)} ; - \draw[->, very thick] (filter.east) -- ++(2,0) node[right,align=center]{Output\\(time domain)}; + \draw[->, very thick] (filter.east) -- ++(2,0) node[right,align=center]{Output\\(time domain)}; :libs: positioning - :xscale: 80 + :xscale: 100 + +.. raw:: html + +
    You cannot feed two different signals into a single filter without adding them together first or doing some other operation. Likewise, the output will always be one signal, i.e., a 1D array of numbers. @@ -53,7 +61,7 @@ There are four basic types of filters: low-pass, high-pass, band-pass, and band- .. START OF FILTER TYPES TIKZ .. raw:: html -
    +
    .. This draw the lowpass filter .. tikz:: [font=\sffamily\large] @@ -131,7 +139,7 @@ For most filters we will see (known as FIR, or Finite Impulse Response, type fil Example Use-Case ######################## -To learn how filters are used, let's look an an example where we tune our SDR to a frequency of an existing signal, and we want to isolate it from other signals. Remember that we tell our SDR which frequency to tune to, but the samples that the SDR captures are at baseband, meaning the signal will display as centered around 0 Hz. We will have to keep track of which frequency we told the SDR to tune to. Here is what we might receive: +To learn how filters are used, let's look at an example where we tune our SDR to a frequency of an existing signal, and we want to isolate it from other signals. Remember that we tell our SDR which frequency to tune to, but the samples that the SDR captures are at baseband, meaning the signal will display as centered around 0 Hz. We will have to keep track of which frequency we told the SDR to tune to. Here is what we might receive: .. image:: ../_images/filter_use_case.png :scale: 70 % @@ -255,8 +263,12 @@ Real vs. Complex Filters The filter I showed you had real taps, but taps can also be complex. Whether the taps are real or complex doesn't have to match the signal you put through it, i.e., you can put a complex signal through a filter with real taps and vice versa. When the taps are real, the filter's frequency response will be symmetrical around DC (0 Hz). Typically we use complex taps when we need asymmetry, which does not happen too often. .. draw real vs complex filter -.. tikz:: [font=\sffamily\Large,scale=2] - \definecolor{babyblueeyes}{rgb}{0.36, 0.61, 0.83} +.. raw:: html + +
    + +.. tikz:: [font=\sffamily\Large,scale=2] + \definecolor{babyblueeyes}{rgb}{0.36, 0.61, 0.83} \draw[->, thick] (-5,0) node[below]{$-\frac{f_s}{2}$} -- (5,0) node[below]{$\frac{f_s}{2}$}; \draw[->, thick] (0,-0.5) node[below]{0 Hz} -- (0,1); \draw[babyblueeyes, smooth, line width=3pt] plot[tension=0.1] coordinates{(-5,0) (-1,0) (-0.5,2) (0.5,2) (1,0) (5,0)}; @@ -265,6 +277,11 @@ The filter I showed you had real taps, but taps can also be complex. Whether th \draw[babyblueeyes, smooth, line width=3pt] plot[tension=0] coordinates{(6,0) (11,0) (11,2) (11.5,2) (12,0) (16,0)}; \draw[font=\huge\bfseries] (0,2.5) node[above,align=center]{Example Low-Pass Filter\\with Real Taps}; \draw[font=\huge\bfseries] (11,2.5) node[above,align=center]{Example Low-Pass Filter\\with Complex Taps}; + :xscale: 100 + +.. raw:: html + +
    As an example of complex taps, let's go back to the filtering use-case, except this time we want to receive the other interfering signal (without having to re-tune the radio). That means we want a band-pass filter, but not a symmetrical one. We only want to keep (a.k.a "pass") frequencies between around 7 kHz to 13 kHz (we don't want to also pass -13 kHz to -7 kHz): @@ -387,7 +404,7 @@ Now that we are starting to understand convolution, I will present the mathemati (f * g)(t) = \int f(\tau) g(t - \tau) d\tau -In this above expression, :math:`g(t)` is the signal or input that is flipped and slides across :math:`f(t)`, but :math:`g(t)` and :math:`f(t)` can be swapped and it's still the same expression. Typically, the shorter array will be used as :math:`g(t)`. Convolution is equal to a cross-correlation, defined as :math:`\int f(\tau) g(t+\tau)`, when :math:`g(t)` is symmetrical, i.e., it doesn't change when flipped about the origin. +In this above expression, :math:`g(t)` is the signal or input that is flipped and slides across :math:`f(t)`, but :math:`g(t)` and :math:`f(t)` can be swapped and it's still the same expression. Typically, the shorter array will be used as :math:`g(t)`. Convolution is equal to a cross-correlation, defined as :math:`\int f(\tau) g(t+\tau) d\tau`, when :math:`g(t)` is symmetrical, i.e., it doesn't change when flipped about the origin. ************************* @@ -523,7 +540,7 @@ The above code shows basic usage of these four methods, but you may be wondering :align: center :target: ../_images/convolve_comparison_100000.svg -As you can see, :code:`scipy.signal.convolve` actually switches its method to FFT-based automatically at a certain input size. Either way, :code:`fftconvolve` is the clear winner for these size taps and inputs, which represent fairly typical sizes in RF applications. A lot of the code within PySDR actually uses :code:`np.convolve:` simply because it's one less import and the performance difference is negligible for low data rate or non-real-time applications. +As you can see, :code:`scipy.signal.convolve` actually switches its method to FFT-based automatically at a certain input size. Either way, :code:`fftconvolve` is the clear winner for these size taps and inputs, which represent fairly typical sizes in RF applications. A lot of the code within PySDR actually uses :code:`np.convolve` simply because it's one less import and the performance difference is negligible for low data rate or non-real-time applications. Lastly, we will show the output in the frequency domain, so we can finally check whether the firwin2 method gave us a filter that matched our design parameters. Starting from the code above that gave us :code:`h2`: @@ -661,7 +678,7 @@ We will use these taps shown above as our filter. We know that the impulse resp :scale: 70 % :align: center -See how the frequency response not very straight... it doesn't match our original very well, if you recall the shape that we initially wanted to make a filter for. A big reason is because our impulse response isn't done decaying, i.e., the left and right sides don't reach zero. We have two options that will allow it to decay to zero: +See how the frequency response is not very straight... it doesn't match our original very well, if you recall the shape that we initially wanted to make a filter for. A big reason is because our impulse response isn't done decaying, i.e., the left and right sides don't reach zero. We have two options that will allow it to decay to zero: **Option 1:** We "window" our current impulse response so that it decays to 0 on both sides. It involves multiplying our impulse response with a "windowing function" that starts and ends at zero. @@ -699,7 +716,7 @@ See how the frequency response not very straight... it doesn't match our origina :scale: 50 % :align: center -Both options worked. Which one would you choose? The second method resulted in more taps, but the first method resulted in a frequency response that wasn't very sharp and had a falling edge wasn't very steep. There are numerous ways to design a filter, each with their own trade-offs along the way. Many consider filter design an art. +Both options worked. Which one would you choose? The second method resulted in more taps, but the first method resulted in a frequency response that wasn't very sharp and had a falling edge that wasn't very steep. There are numerous ways to design a filter, each with their own trade-offs along the way. Many consider filter design an art. ************************* Intro to Pulse Shaping @@ -752,6 +769,115 @@ You can see that a lower value of :math:`\beta` reduces the spectrum used (for t You will learn a lot more about pulse shaping, including some special properties that pulse shaping filters must satisfy, in the :ref:`pulse-shaping-chapter` chapter. +******************* +Filtering in Chunks +******************* + +So far we have filtered signals that fit comfortably in memory: we hand the whole array to :code:`np.convolve` and get the whole result back. But what happens when the signal is enormous, say a recording that is tens of gigabytes, or when the signal needs to be processed in real-time? We need a way to filter the signal a piece at a time, while producing the exact same output we would have gotten if we had filtered it all at once. + +At first this sounds trivial, just filter each chunk and stitch the outputs together. But try it and you will see glitches at every chunk boundary. The reason comes straight from how an FIR filter works: to compute one output sample, the filter reaches back across the previous :math:`M-1` input samples, where :math:`M` is the number of taps. Right at the start of a new chunk, those previous samples live in the *previous* chunk, which we already threw away. So the first :math:`M-1` outputs of every chunk are wrong, because the filter had nothing but zeros to reach back into. Put simply, an FIR filter has *memory*, and if we filter chunk by chunk we have to carry that memory across the seams. + +The Simple Way: Carry the State +############################### + +The most direct fix is to keep the last :math:`M-1` samples of each chunk around and glue them onto the front of the next chunk before filtering. Those carried-over samples give the filter the history it needs, so the boundary is no longer starved of context. We then use :code:`mode='valid'` so that only the outputs that don't depend on zero-padding are returned: + +.. code-block:: python + + import numpy as np + + h = np.load('taps.npy') # our FIR filter taps, length M + M = len(h) + + state = np.zeros(M - 1, dtype=np.complex64) # the filter's "memory" + + def process_chunk(x): # x is one chunk from the SDR, length L + global state + x_padded = np.concatenate([state, x]) # prepend last chunk's tail + y = np.convolve(x_padded, h, mode='valid') # length L, all valid outputs + state = x_padded[-(M - 1):] # save tail for next chunk + return y + +Each call returns exactly :code:`len(x)` output samples, and if you concatenate the outputs from every chunk it matches what you would get with filtering the entire signal in one shot. This is really all you need for a lot of real-time work, and SciPy even provides it directly: :code:`scipy.signal.lfilter` accepts an initial-condition array :code:`zi` that holds exactly this state, and hands you back the updated state each call: + +.. code-block:: python + + from scipy.signal import lfilter, lfilter_zi + + zi = np.zeros(len(h) - 1, dtype=np.complex64) # filter state + y1, zi = lfilter(h, 1.0, chunk1, zi=zi) # filter first chunk + y2, zi = lfilter(h, 1.0, chunk2, zi=zi) # state carries over + # ...and so on for every chunk + +So why bother with anything fancier? Direct convolution costs on the order of :math:`M` multiply-adds per output sample. When the filter is long, e.g. a sharp filter with thousands of taps, that gets expensive. For long filters it is much cheaper to do the convolution in the frequency domain using the FFT (recall that convolution in time is multiplication in frequency). But an FFT needs a finite block of samples, so we are right back to the chunking problem, this time with a twist: multiplying two FFTs together and taking the inverse FFT gives you *circular* convolution, which wraps the ends of the block around onto each other, not the *linear* convolution we actually want. Overlap-add and overlap-save are the two classic tricks for getting correct linear convolution out of block-by-block FFTs. + +Overlap-Add +########### + +Overlap-add starts from a simple observation: convolution is linear, so we can chop the input into non-overlapping blocks, filter each block on its own, and sum the results. The catch is that filtering a length-:math:`L` block with a length-:math:`M` filter produces a result of length :math:`L + M - 1`, i.e. it is *longer* than the block we started with. That extra :math:`M-1` samples of "tail" is the filter ringing out past the end of the block, and it spills into the region belonging to the next block. The fix is right there in the name: we let the blocks' outputs overlap and we add the overlapping parts together, as shown below. + +.. image:: ../_images/overlap_add.svg + :align: center + :target: ../_images/overlap_add.svg + +Concretely, we FFT each input block (zero-padded up to :math:`N \ge L + M - 1`), multiply by the FFT of the taps, and inverse-FFT to get that block's full-length output. We emit the first :math:`L` samples and remember the :math:`M-1` sample tail so we can add it into the start of the next block: + +.. code-block:: python + + import numpy as np + + h = np.load('taps.npy') + M = len(h) + L = 1024 # input block size (samples per chunk) + N = L + M - 1 # FFT size (round up to a power of 2 if you like) + H = np.fft.fft(h, N) # precompute the filter's FFT once + + tail = np.zeros(M - 1, dtype=np.complex64) # leftover from previous block + + def process_chunk(x): # x has length L + global tail + conv = np.fft.ifft(np.fft.fft(x, N) * H) # length N, linear conv + y = conv[:L].copy() + y[:M - 1] += tail # add in the tail that rang over from last block + tail = conv[L:] # this block's tail rings into the next one + return y + +Notice that nothing is thrown away here, every sample the filter produces ends up in the output, some of them just get split across two blocks and added back together. + +Overlap-Save +############ + +Overlap-save (sometimes called overlap-discard, which is arguably the clearer name) attacks the same problem from the other direction. Instead of adding overlapping outputs, we overlap the *inputs* and throw away the outputs we know are garbage. Recall the wrap-around from circular convolution corrupts exactly the first :math:`M-1` output samples of a block. So the plan is: feed the filter overlapping input blocks, where each block reuses the last :math:`M-1` samples of the previous one, then simply discard those first :math:`M-1` polluted outputs and keep the rest, as shown below. + +.. image:: ../_images/overlap_save.svg + :align: center + :target: ../_images/overlap_save.svg + +Here we pick an FFT size :math:`N` and consume :math:`N - (M-1)` new samples per block, prepending the :math:`M-1` samples of overlap from last time to fill the block back up to :math:`N`: + +.. code-block:: python + + import numpy as np + + h = np.load('taps.npy') + M = len(h) + N = 2048 # FFT / block size, must be larger than M + step = N - (M - 1) # number of NEW samples consumed per block + H = np.fft.fft(h, N) # precompute the filter's FFT once + + overlap = np.zeros(M - 1, dtype=np.complex64) # carried-over input samples + + def process_chunk(x): # x has length 'step' + global overlap + block = np.concatenate([overlap, x]) # length N + conv = np.fft.ifft(np.fft.fft(block) * H) # circular conv, length N + overlap = block[-(M - 1):] # save tail for next block + return conv[M - 1:] # discard the aliased outputs + +The trade-off between the two is mostly a matter of taste and plumbing. Overlap-add does a little extra work adding the overlapping tails, while overlap-save does a little extra work re-processing the overlapping input samples only to throw the results away. Both produce identical output, and both match plain :code:`np.convolve` over the full signal. + +Note that SciPy's :code:`scipy.signal.oaconvolve` performs overlap-add convolution for you, and internally it calls :code:`scipy.signal.fftconvolve` which will pick an efficient FFT-based approach automatically. The value in understanding overlap-add and overlap-save is that when you are streaming from a live radio, *you* own the block boundaries, and knowing how the filter's memory crosses those boundaries is what lets you filter a never-ending signal without a single glitch at the seams. + diff --git a/content/fpv_video.rst b/content/fpv_video.rst new file mode 100644 index 00000000..adaecfcc --- /dev/null +++ b/content/fpv_video.rst @@ -0,0 +1,152 @@ +.. _fpv-chapter: + +######################## +Analog FPV Video Signals +######################## + +In this chapter we will look at the analog video signals used in most hobby/DIY FPV drones, which consist of FM modulated NTSC or PAL signals. We will analyze the signals and show how to demodulate them to recover the video image. + +**************** +Introduction +**************** + +Analog FPV (First-Person View) signals are a traditional method of transmitting live video from an RC vehicle (most commonly a drone or quadcopter) back to a pilot in real time. Rather than encoding the footage digitally, an analog system broadcasts the camera feed as an NTSC or PAL signal that is FM modulated and transmitted on a carrier, typically in the 5.8 GHz band (though 1.2-1.3 GHz, and 2.4 GHz are also used). It is not a digital signal, and there is no compression or encryption involved. The defining trait of analog FPV is its extremely low latency; because the video isn't compressed or processed, the pilot sees what the camera sees almost instantaneously, which is critical for fast, responsive flying. They also tend to be low-cost; an analog FPV video transmitter can be bought for $10 and an all-in-one unit (that adds a camera and antenna) for $20. Most analog FPV video transmitters are also able to transmit an audio signal that gets added to the video signal. Analog video is typically paired with a separate radio for RC control, such as FrSky, FlySky, Spektrum, and ELRS. + +**************** +Signal Details +**************** + +From the receiver's perspective, after FM demodulating the signal, we are left with the following components: + +.. image:: ../_images/fpv_baseband_spectrum_after_demod.svg + :align: center + :target: ../_images/fpv_baseband_spectrum_after_demod.svg + :alt: Baseband spectrum of the signal after FM demodulation + +One nice perk of FM is that the receiver does not need to be perfectly centered on the signal, as long as it is “in view” of the signal, the FM demod will work just fine. This is because FM demodulation relies on changes in frequency rather than absolute frequency, so as long as the signal is strong enough and within the bandwidth of the receiver, it can be demodulated successfully, although ideally it will be somewhat centered so that excess noise can be filtered out before the FM demod. + +Let's look at an example signal, you can download the example IQ recording of an NTSC signal used in this chapter's code `here `_, note that it is only a few frames worth of signal. + +If we look at the power spectral density of the raw RF signal, we see the FM modulated signal centered at 0 Hz, which corresponds to 5.925 GHz because that is where the SDR was tuned. This is the center frequency of one of the standard FPV channels. The bandwidth of the signal is around 6 MHz. + +.. image:: ../_images/fpv_psd_raw_rf.svg + :align: center + :target: ../_images/fpv_psd_raw_rf.svg + :alt: PSD of raw RF signal + +If we FM demodulate the signal, which can be done with one line of Python, :code:`np.angle(x[1:] * np.conj(x[:-1]))`, we are left with the following power spectral density: + +.. image:: ../_images/fpv_psd_after_fm_demod.svg + :align: center + :target: ../_images/fpv_psd_after_fm_demod.svg + :alt: PSD of signal after FM demod + +In this example there is no audio. We can clearly see the color portion. If we zoom into the low frequencies, we can see harmonics at multiples of 15.734 kHz (for PAL it will be at 15.625 kHz), this corresponds to the horizontal sync signal, which happens once per line of video. + +.. image:: ../_images/fpv_psd_after_fm_demod_harmomics.svg + :align: center + :target: ../_images/fpv_psd_after_fm_demod_harmomics.svg + :alt: PSD of signal after FM demod zooming into the low frequency harmonic + +We can look at the time domain to get a better understanding of the signal, the following shows one line's worth of the video signal (once again, after FM demodulation). The horizontal sync pulse is what we see at the beginning and end, and the color burst is the small oscillation right after the horizontal sync pulse. The color burst is a reference signal that the receiver uses to decode the color information. The rest of the signal is the video information, both black and white and color information. + +.. image:: ../_images/fpv_time_domain_one_line.svg + :align: center + :target: ../_images/fpv_time_domain_one_line.svg + :alt: Time domain representation of the signal, just one line + +If we zoom out in time, we can look at a special synchronization sequence which happens once per frame, called the vertical sync pulse. This is a special sequence of pulses (same every time) that tells the receiver that a new frame is starting, shown below (the first half of what is plotted). Also included are 13 lines worth of signal, similar to what we saw above but zoomed out. + +.. image:: ../_images/fpv_time_domain.svg + :align: center + :target: ../_images/fpv_time_domain.svg + :alt: Time domain representation of the signal including frame sync and a few dozen lines + +******************************** +Demodulating the Video +******************************** + +In order to demodulate the video and recover the image, we will perform the following steps: + +#. Filter out the audio signal +#. Resample luma and chroma to exactly 508 samples per line so that each sample corresponds to one pixel +#. Reshape the 1D array of samples into a 2D image +#. Scale it to 0-255 and display it as a grayscale image + +Note that this process only recovers the black and white portion, the color information is encoded in a different way and is more complicated to recover. + +Below is an entire working example that can be used with the example recording provided `here `_. + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + import scipy.signal as signal + + filename = 'ntsc_remy_10MHz_5925Hz_500ksamples_cf32.iq' + x = np.fromfile(filename, dtype=np.complex64) + sample_rate = 10e6 + color_subcarrier_freq = 3.579545e6 # NTSC. higher than luma carrier, not relative to center freq + # color_subcarrier_freq = 4.43361875e6 # PAL and SECAM + relative_audio_subcarrier_freq = 3.5e6 # the audio might show up at 5.5, 6.0, or 6.5 MHz + + # NTSC constants + samples_per_line = 508 + lines_per_frame = 525 + refresh_Hz = 30.0/1.001 # almost exactly 29.97 # not exactly 30 Hz!! makes difference + + # PAL constants + #samples_per_line = 512 + #lines_per_frame = 625 # (576 visible lines) + #refresh_Hz = 25 + + samples_per_frame = samples_per_line * lines_per_frame // 2 # NTSC's vertical sync repeats every field (half-frame), not every full frame + line_Hz = refresh_Hz * lines_per_frame + + # FM demodulation + x_demod = np.angle(x[1:] * np.conj(x[:-1])) + + # Filter out audio from demodded signal + h = signal.firwin(301, 3e6, fs=sample_rate) # for the 10 Mhz recording + x_demod = np.convolve(x_demod, h, 'same') + + # Resample luma and chroma to exactly L samples per line + resampling_rate = samples_per_line / (sample_rate / line_Hz) + resampling_rate *= 1.00003 # fixes the drift, not 100% sure where it comes from, perhaps sample clock offset + x_demod = signal.resample(x_demod, int(len(x_demod)*resampling_rate)) + print("Resampling rate:", resampling_rate) + + # crop to 1 frames worth of samples (essentially a manual sync) + if False: + manually_tuned_offset = 122250 # for both frame sync and horizontal sync + x_demod = x_demod[manually_tuned_offset:manually_tuned_offset+samples_per_frame] + + # reshape into 2D + x_demod = x_demod[:len(x_demod) - (len(x_demod) % samples_per_line)] # trim to multiple of samples_per_line + frame = x_demod.reshape(-1, samples_per_line) # type: ignore + + # Normalize to 0-255 and convert to uint8 + frame_norm = frame - np.min(frame) + frame_norm = frame_norm / np.max(frame_norm) + frame_uint8 = (frame_norm * 255).astype(np.uint8) + + # Display as single image with fixed scaling + plt.imshow(frame_uint8, cmap='gray', aspect='auto', vmin=0, vmax=255) + plt.axis('off') + plt.show() + +If we run this code as-is, it starts at the beginning of the recording, which represents a random point in time. Without syncing to the horizontal line pulse, it just shifts every line by the same amount so our picture ends up still looking intelligible, it's just shifted horizontally and vertically. We are also looking at multiple frames worth of samples. + +.. image:: ../_images/fpv_image_no_sync.svg + :align: center + :target: ../_images/fpv_image_no_sync.svg + :alt: Demodded image without cropping to a single frame + +Limiting it to one frame's worth of samples is easy, we already calculated :code:`samples_per_frame`, but we need to synchronize to the start of the frame. There are many ways to do it, one way is to correlate for the vertical synchronization sequence, either by reproducing it or using a high-SNR recording of it. It can also be done by plotting the time domain and looking for the sequence. Below shows what the image looks like if you are synchronized, in the code above this is done manually, knowing that sample index 122250 corresponds to where a new frame starts. + +.. image:: ../_images/fpv_image_one_frame.svg + :align: center + :target: ../_images/fpv_image_one_frame.svg + :alt: Demodded image cropping to a single frame + +If anyone wants to contribute a robust Python color demodulator, please reach out, but it must be shown to work on a variety of recordings (e.g. both synthetic and live without manually tuning anything). diff --git a/content/frequency_domain.rst b/content/frequency_domain.rst index ec7988e0..1a3adf98 100644 --- a/content/frequency_domain.rst +++ b/content/frequency_domain.rst @@ -126,7 +126,7 @@ To return to the time domain from frequency is almost the same, aside from a neg .. math:: x(t) = \int X(f) e^{j2\pi ft} df -Note that a lot of textbooks and other resources use :math:`w` in place of the :math:`2\pi f`, where :math:`w` is angular frequency in radians per second, while :math:`f` is in Hz. All you have to know is that +Note that a lot of textbooks and other resources use :math:`\omega` in place of the :math:`2\pi f`, where :math:`\omega` is angular frequency in radians per second, while :math:`f` is in Hz. All you have to know is that .. math:: \omega = 2 \pi f @@ -444,7 +444,7 @@ If you are afraid of choosing the wrong window, don't be. The difference betwee FFT Sizing ******************* -The last thing to note is FFT sizing. The best FFT size is always an order of 2 because of the way the FFT is implemented. You can use a size that is not an order of 2, but it will be slower. Common sizes are between 128 and 4,096, although you can certainly go larger. In practice we may have to process signals that are millions or billions of samples long, so we need to break up the signal and do many FFTs. That means we will get many outputs. We can either average them up or plot them over time (especially when our signal is changing over time). You don't have to put *every* sample of a signal through an FFT to get a good frequency domain representation of that signal. For example you could only FFT 1,024 out of every 100k samples in a signal and it will still probably look fine, as long as the signal is always on. +The last thing to note is FFT sizing. The best FFT size is always a power of 2 because of the way the FFT is implemented. You can use a size that is not an order of 2, but it will be slower. Common sizes are between 128 and 4,096, although you can certainly go larger. In practice we may have to process signals that are millions or billions of samples long, so we need to break up the signal and do many FFTs. That means we will get many outputs. We can either average them up or plot them over time (especially when our signal is changing over time). You don't have to put *every* sample of a signal through an FFT to get a good frequency domain representation of that signal. For example you could only FFT 1,024 out of every 100k samples in a signal and it will still probably look fine, as long as the signal is always on. .. _spectrogram-section: @@ -497,12 +497,13 @@ In Python we can generate a spectrogram as follows: for i in range(num_rows): spectrogram[i,:] = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(x[i*fft_size:(i+1)*fft_size])))**2) - plt.imshow(spectrogram, aspect='auto', extent = [sample_rate/-2/1e6, sample_rate/2/1e6, len(x)/sample_rate, 0]) + # Time starts at the top and goes down, eg sample x[0] will be part of the top row displayed + plt.imshow(spectrogram, aspect='auto', extent = (sample_rate/-2/1e6, sample_rate/2/1e6, len(x)/sample_rate, 0)) plt.xlabel("Frequency [MHz]") plt.ylabel("Time [s]") plt.show() -Which should produce the following, which is not the most interesting spectrogram because there is no time-varying behavior. There are two tones because we simulated a real signal, and real signals always have a negative PSD that matches the positive side. For more interesting examples of spectrograms, checkout https://www.IQEngine.org! +Which should produce the following, which is not the most interesting spectrogram because there is no time-varying behavior. There are two tones because we simulated a real signal, and real signals always have a negative PSD that matches the positive side. Note that with this implementation, the top row corresponds to the beginning of the signal. For more interesting examples of spectrograms, checkout https://www.IQEngine.org! .. image:: ../_images/spectrogram.svg :align: center @@ -528,7 +529,7 @@ or y_1 = x_0 - x_1 w^k_N -where :math:`w^k_N = e^{j2\pi k/N}` are known as twiddle factors (:math:`N` is the size of the sub-FFT and :math:`k` is the index). Note that the input and output is intended to be complex, e.g., :math:`x_0` might be 0.6123 - 0.5213j, and the sums/multiplies are complex. +where :math:`w^k_N = e^{-j2\pi k/N}` are known as twiddle factors (:math:`N` is the size of the sub-FFT and :math:`k` is the index). Note that the input and output is intended to be complex, e.g., :math:`x_0` might be 0.6123 - 0.5213j, and the sums/multiplies are complex. The algorithm is recursive and breaks itself in half until all that is left is a series of butterflies, this is depicted below using a size 8 FFT: @@ -585,4 +586,38 @@ For those who prefer to think in code rather than equations, the following shows :target: ../_images/fft_in_python.svg :alt: python implementation of fft example -For those interested in JavaScript and/or WebAssembly based implementations, check out the `WebFFT `_ library for performing FFTs in web or NodeJS applications, it includes several implementations under the hood, and there is a `benchmarking tool `_ used to compare the performance of each implementation. +If you want to try running the code purely in your browser, it's available as a `web-based jupyter notebook <../jupyterlite/notebooks/index.html?path=frequency_domain.ipynb>`_. + +********************* +Boxcar and Sinc +********************* + +Imagine you switch a signal on, hold it at a constant level for exactly one second, then switch it back off. In time that is about the simplest pulse you can make: a flat-topped rectangle, one second wide. This shape shows up constantly in DSP, so it has a name, the boxcar pulse (also called a rectangular pulse), because it looks like the boxcar of a train sitting on the time axis. A natural question to ask is: if the pulse is so simple in time, what does it look like in the frequency domain? + +You might guess that a simple pulse has a simple spectrum, but it turns out the opposite is true. Take the FFT of a boxcar and you get the shape shown on the right below, a tall central hump surrounded by ripples that fade out as you move away from the center. That shape is called a sinc (pronounced "sink"). The plot below shows the pair side by side, the boxcar in time on the left and its sinc spectrum on the right. + +.. image:: ../_images/boxcar_sinc.svg + :align: center + :target: ../_images/boxcar_sinc.svg + :alt: A boxcar (rectangular) pulse in the time domain and its sinc-shaped spectrum + +Notice that the spectrum does not stop at the first dip, it keeps going with smaller and smaller bumps. Those bumps are the sidelobes, and the tall bump in the middle is the mainlobe. The reason a plain rectangle produces all this structure is the sharp edges: turning the signal on and off instantly requires energy spread across a wide range of frequencies, and the sinc is exactly how that energy is distributed. + +The math backs up the picture. If our boxcar has amplitude :math:`A` and width :math:`T` (in seconds), its Fourier transform is: + +.. math:: + X(f) = A T \, \mathrm{sinc}(f T) + +where the sinc function itself is defined as: + +.. math:: + \mathrm{sinc}(x) = \frac{\sin(\pi x)}{\pi x} + +The spectrum of a rectangle is a sinc, scaled in height by :math:`AT` and stretched in frequency by :math:`T`. The mainlobe crosses zero for the first time when :math:`fT = 1`, i.e., at :math:`f = 1/T`, so the spectrum gets narrower as the pulse gets wider. Just like we saw with the scaling property, a short pulse in time is wide in frequency, and a wide pulse in time is narrow in frequency. The two are inversely linked: you cannot make something compact in both domains at once. If you want a signal that occupies very little bandwidth, you have to let it last a long time, and if you need a very short pulse, you have to accept that it smears out across a lot of frequencies. + +The animation below drives this home. Watch what happens as the boxcar on the left starts out very short and gradually widens. As the pulse fattens up in time, its sinc spectrum on the right squeezes in tighter and tighter toward the center, exactly as :math:`f = 1/T` predicts. + +.. image:: ../_images/boxcar_sinc_animation.gif + :align: center + :target: ../_images/boxcar_sinc_animation.gif + :alt: Animation of a boxcar pulse widening in time while its sinc spectrum narrows in frequency diff --git a/content/hackrf.rst b/content/hackrf.rst index cb2aa09a..3250cc08 100644 --- a/content/hackrf.rst +++ b/content/hackrf.rst @@ -175,7 +175,7 @@ You will likely want the RF amplifier enabled, and then you can adjust the IF ga Receiving IQ Samples within Python with the HackRF ************************************************** -Currently the :code:`python_hackrf` Python package does not include any convenience functions for receiving samples, it is simply a set of Python bindings that map to the HackRF's C++ API. That means in order to receive IQ, we have to use a decent amount of code. The Python package is set up to use a callback function in order to receive more samples, this is a function that we must set up, but it will automatically get called whenever there are more samples ready from the HackRF. This callback function always needs to have three specific arguments, and it needs to return :code:`0` if we want another set of samples. In the code below, within each call to our callback function, we convert the samples to NumPy's complex type, scale them from -1 to +1, and then store them in a larger :code:`samples` array +Currently the :code:`python_hackrf` Python package does not include any convenience functions for receiving samples, it is simply a set of Python bindings that map to the HackRF's C++ API. That means in order to receive IQ, we have to use a decent amount of code. The Python package is set up to use a callback function in order to receive more samples, this is a function that we must set up, but it will automatically get called whenever there are more samples ready from the HackRF. This callback function always needs to have three specific arguments, and it needs to return :code:`0` if we want another set of samples. In the code below, within each call to our callback function, we convert the samples to NumPy's complex type, scale them from -1 to +1, and then store them in a larger :code:`samples` array. After running the code below, if in your time plot, the samples are reaching the ADC limits of -1 and +1, then reduce :code:`lna_gain` by 3 dB until it is clearly not hitting the limits. diff --git a/content/intro.rst b/content/intro.rst index a680fd35..38bde9d6 100644 --- a/content/intro.rst +++ b/content/intro.rst @@ -34,19 +34,28 @@ An example is a Computer Science student interested in a job involving wireless :align: center :alt: The PySDR logo created using a Fourier transform -This textbook is meant to introduce concepts quickly and smoothly, enabling the reader to perform DSP and use SDRs intelligently. It's not meant to be a reference textbook for all DSP/SDR topics; there are plenty of great textbooks already out there, such as `Analog Device's SDR textbook +This textbook is meant to introduce concepts quickly and smoothly, enabling the reader to perform DSP and use SDRs intelligently. It is not meant to be a reference textbook for all DSP/SDR topics; there are plenty of great textbooks already out there, such as `Analog Devices' SDR textbook `_ and `dspguide.com `_. You can always use Google to recall trig identities or the Shannon limit. Think of this textbook like a gateway into the world of DSP and SDR: it's lighter and less of a time and monetary commitment, when compared to more traditional courses and textbooks. To cover foundational DSP theory, an entire semester of "Signals and Systems", a typical course within electrical engineering, is condensed into a few chapters. Once the DSP fundamentals are covered, we launch into SDRs, although DSP and wireless communications concepts continue to come up throughout the textbook. -Code examples are provided in Python. They utilize NumPy, which is Python's standard library for arrays and high-level math. The examples also rely upon Matplotlib, which is a Python plotting library that provides an easy way to visualize signals, arrays, and complex numbers. Note that while Python is "slower" than C++ in general, most math functions within Python/NumPy are implemented in C/C++ and heavily optimized. Likewise, the SDR API we use is simply a set of Python bindings for C/C++ functions/classes. Those who have little Python experience yet a solid foundation in MATLAB, Ruby, or Perl will likely be fine after familiarizing themselves with Python's syntax. +*********** +Why Python? +*********** +Given the name PySDR, you may think Python is a critical part of this resource, but in reality the choice of programming language is not a big deal. In the era of AI, converting code between languages is trivial. In this textbook **we use Python almost as a form of pseudocode**, with the bonus that we can actually run it, see results, plot signals, sweep parameters, etc. Python was chosen as the language simply because it's free, easy to run on all platforms, low boilerplate, lightweight syntax, easily readable, and has a massive ecosystem of libraries and example code in the wild. It also helps that most SDRs have a Python API. -*************** +PySDR purposefully does not include a custom Python library or any wrapper functions, all code is in straight Python, using the standard libraries such as NumPy (standard library for arrays and high-level math), SciPy (more DSP-specific functions such as filter design), and Matplotlib (plotting, allows us to visualize signals). + +Note that while Python is "slower" than C/C++ in general, most functions within Python/NumPy are actually implemented in C/C++ under the hood and heavily optimized, so you might be surprised how fast CPU-based DSP can run in Python. Likewise, the SDR APIs we use (e.g., UHD) are simply a set of Python bindings for C/C++ functions/classes. For fielded RF systems, high-rate signal processing is typically implemented in the FPGA anyway! + +Some PySDR chapters contain example code that can be opened as a web-based Jupyter notebook (using JupyterLite), allowing you to play with and run the Python examples entirely from your browser without installing anything. To check if it works on your browser, try opening `this example <../jupyterlite/notebooks/index.html?path=example.ipynb>`_. + +************ Contributing -*************** +************ -If you got value from PySDR, please share it with colleagues, students, and other lifelong learners who may be interested in the material. You can also donate through the `PySDR Patreon `_ as a way to say thanks and get your name on the left of every page below the chapter list. +If you got value from PySDR, please share it with colleagues, students, and other lifelong learners who may be interested in the material. You can also donate through the `PySDR Patreon `_ as a way to say thanks and get your name on the left of every page below the chapter list. There is also an option to `make a one-time donation `_. If you get through any amount of this textbook and email me at marc@pysdr.org with questions/comments/suggestions, then congratulations, you will have contributed to this textbook! You can also edit the source material directly on the `textbook's GitHub page `_ (your change will start a new pull request). Feel free to submit an issue or even a Pull Request (PR) with fixes or improvements. Those who submit valuable feedback/fixes will be permanently added to the acknowledgments section below. Not good at Git but have changes to suggest? Feel free to email me at marc@pysdr.org. @@ -66,5 +75,6 @@ Thank you to anyone who has read any portion of this textbook and provided feedb - `Yimin Zhao `_ for `translating PySDR to Simplified Chinese `_ - `Eduardo Chancay `_ for `translating PySDR to Spanish `_ - John Marcovici +- `Vishwaksen Reddy Dhareddy `_ for contributing the Detection Chapter section on real-time packet detection As well as all `PySDR Patreon `_ supporters! diff --git a/content/iq_files.rst b/content/iq_files.rst index ae192fc9..3b0b5bb9 100644 --- a/content/iq_files.rst +++ b/content/iq_files.rst @@ -186,7 +186,7 @@ The most simple (and minimal) way to use the SigMF standard to describe a binary "annotations": [] } -Note the :code:`core:cf32_le` indicates your .sigmf-data is of type IQIQIQIQ... with 32-bit floats, i.e., np.complex64 like we used previously. Reference the specifications for other available datatypes, such as if you have real data instead of complex, or are using 16-bit integers instead of floats to save space. +Note the value :code:`cf32_le` for :code:`core:datatype` indicates your .sigmf-data is of type IQIQIQIQ... with 32-bit floats, i.e., np.complex64 like we used previously. Reference the specifications for other available datatypes, such as if you have real data instead of complex, or are using 16-bit integers instead of floats to save space. Aside from datatype, the most important lines to fill out are :code:`core:sample_rate` and :code:`core:frequency`. It is good practice to also enter information about the hardware (:code:`core:hw`) used to capture the recording, such as the SDR type and antenna, as well as a description of what is known about the signal(s) in the recording in :code:`core:description`. The :code:`core:version` is simply the version of the SigMF standard being used at the time the metadata file was created. diff --git a/content/link_budgets.rst b/content/link_budgets.rst index 129b99da..33fdf8aa 100644 --- a/content/link_budgets.rst +++ b/content/link_budgets.rst @@ -82,7 +82,7 @@ As a signal moves through the air (or vacuum), it reduces in strength. Imagine :scale: 80 % :align: center -Free Space Path Loss (FSPL) tells us the path loss when there are no obstacles for a given distance. In its general form, :math:`\mathrm{FSPL} = ( 4\pi d / \lambda )^2`. Google Friis transmission formula for more info. (Fun fact: signals encounter 377 ohms impedance moving through free space.) For generating link budgets, we can use this same equation but converted to dB: +Free Space Path Loss (FSPL) tells us the path loss when there are no obstacles for a given distance. In its general form, :math:`\mathrm{FSPL} = ( 4\pi d / \lambda )^2`. See the Friis transmission formula for more info. (Fun fact: signals encounter 377 ohms impedance moving through free space.) For generating link budgets, we can use this same equation but converted to dB: .. math:: \mathrm{FSPL}_{dB} = 20 \log_{10} d + 20 \log_{10} f - 147.55 \left[ dB \right] @@ -175,11 +175,11 @@ A popular and simple formulation for the noise budget uses the "kTB" approach: .. math:: P_{noise} = kTB -- :math:`k` – Boltzmann’s constant = 1.38 x 10-23 J/K = **-228.6 dBW/K/Hz**. For anyone curious, Boltzmann’s constant is a physical constant relating the average kinetic energy of particles in a gas with the temperature of the gas. +- :math:`k` – Boltzmann’s constant = 1.38 x 10\ :sup:`-23` J/K = **-228.6 dBW/K/Hz**. For anyone curious, Boltzmann’s constant is a physical constant relating the average kinetic energy of particles in a gas with the temperature of the gas. - :math:`T` – System noise temperature in K (cryocoolers anyone?), largely based on our amplifier. This is the term that is most difficult to find, and is usually very approximate. You might pay more for an amplifier with a lower noise temperature. - :math:`B` – Signal bandwidth in Hz, assuming you filter out the noise around your signal. So an LTE downlink signal that is 10 MHz wide will have :math:`B` set to 10 MHz, or 70 dBHz. -Multiplying out (or adding in dB) kTB gives our noise power, i.e., the bottom term of of our SNR equation. +Multiplying out (or adding in dB) kTB gives our noise power, i.e., the bottom term of our SNR equation. ************************* SNR @@ -211,7 +211,7 @@ The Physical (PHY) Layer of ADS-B has the following characteristics: - Signal bandwidth around 2 MHz - PPM modulation - Data rate of 1 Mbit/s, with messages between 56 - 112 microseconds -- Messages carry 15 bytes of data each, so multiple messages are usually needed for the entire aircraft information +- Messages carry around a dozen bytes of data each, so multiple messages are usually needed for the entire aircraft information - Multiple access is achieved by having messages broadcast with a period that ranges randomly between 0.4 and 0.6 seconds. This randomization is designed to prevent aircraft from having all of their transmissions on top of each other (some may still collide but that's fine) - ADS-B antennas are vertically polarized - Transmit power varies, but should be in the ballpark of 100 W (20 dBW) diff --git a/content/multipath_fading.rst b/content/multipath_fading.rst index d8d7ab29..8daf3e37 100644 --- a/content/multipath_fading.rst +++ b/content/multipath_fading.rst @@ -50,7 +50,7 @@ There are two types of fading from a **time** domain perspective: There are also two types of fading from a **frequency** domain perspective: -**Frequency Selective Fading**: The constructive/destructive interference changes within the frequency range of the signal. When we have a wideband signal, we span a large range of frequencies. Recall that wavelength determines whether it's constructive or destructive. Well if our signal spans a wide frequency range, it also spans a wide wavelength range (since wavelength is the inverse of frequency). Consequently we can get different channel qualities in different portions of our signal (in the frequency domain). Hence the name frequency selective fading. +**Frequency Selective Fading**: The constructive/destructive interference changes within the frequency range of the signal. When we have a wideband signal, we span a large range of frequencies. Recall that wavelength determines whether it's constructive or destructive. Well if our signal spans a wide frequency range, it also spans a wide wavelength range (since wavelength is inversely proportional to frequency). Consequently we can get different channel qualities in different portions of our signal (in the frequency domain). Hence the name frequency selective fading. **Flat Fading**: Occurs when the signal's bandwidth is narrow enough that all frequencies experience roughly the same channel. If there is a deep fade then the whole signal will disappear (for the duration of the deep fade). @@ -76,11 +76,11 @@ Rayleigh fading is used to model fading over time, when there is no significant There is a lot of theory that comes out of the Rayleigh fading model, such as expressions for level crossing rate and average fade duration. But the Rayleigh fading model doesn't directly tell us how to actually simulate a channel using the model. To generate Rayleigh fading in simulation we have to use one of many published methods, and in the following Python example we will be using Clarke's "sum-of-sinusoids" method. -To generate a Rayleigh fading channel in Python we need to first specify the max Doppler shift, in Hz, which is based on how fast the transmitter and/or receiver is moving, denoted :math:`\Delta v`. When the velocity is small compared to the speed of light, which will always be the case in wireless communications, the Doppler shift can be calculated as: +To generate a Rayleigh fading channel in Python we need to first specify the max Doppler shift, in Hz, which is based on how fast the transmitter and/or receiver is moving, denoted :math:`v`. When the velocity is small compared to the speed of light, which will always be the case in wireless communications, the Doppler shift can be calculated as: .. math:: - f_D = \frac{\Delta v f_c}{c} + f_D = \frac{v f_c}{c} where :math:`c` is the speed of light, roughly 3e8 m/s, and :math:`f_c` is the carrier frequency being transmitted on. @@ -121,7 +121,7 @@ We also choose how many sinusoids to simulate, and there's no right answer becau plt.axis([0, 1, -15, 5]) plt.show() -If you are intending to use this channel model as part of a larger simulation, you would simply multiply the received signal by the complex number :code:`z`, representing flat fading. The value :code:`z` would then update every time step. This means all frequency components of the signal experience the same channel at any given moment in time, so you would **not** be simulating frequency selective fading, that requires a multi-tap channel impulse response which we will not get into in this chapter. If we look at the magnitude of :code:`z`, we can see the Rayleigh fading over time: +If you are intending to use this channel model as part of a larger simulation, you would simply multiply the received signal by the complex number :code:`z`, representing flat fading. The value :code:`z` would then update every time step. This means all frequency components of the signal experience the same channel at any given moment in time, so you would **not** be simulating frequency selective fading, which requires a multi-tap channel impulse response which we will not get into in this chapter. If we look at the magnitude of :code:`z`, we can see the Rayleigh fading over time: .. image:: ../_images/rayleigh.svg :align: center diff --git a/content/noise.rst b/content/noise.rst index 9d9ea1c4..f4429fed 100644 --- a/content/noise.rst +++ b/content/noise.rst @@ -1,10 +1,10 @@ .. _noise-chapter: -############# -Noise and dB -############# +########################## +Noise and Random Variables +########################## -In this chapter we will discuss noise, including how it is modeled and handled in a wireless communications system. Concepts include AWGN, complex noise, and SNR/SINR. We will also introduce decibels (dB) along the way, as it is widely within wireless communications and SDR. +In this chapter we will discuss noise, including how it is modeled and handled in a wireless communications system. Concepts include AWGN, complex noise, and SNR/SINR. We will also introduce decibels (dB) along the way, as it is widely used within wireless communications and SDR. Lastly, we take a deeper dive into the fundamental concepts of random variables and random processes, which are essential for understanding noise, channel effects, and many signal processing techniques in wireless communications. We'll cover probability distributions, expectation, variance, and how random processes evolve over time. These concepts form the mathematical foundation for analyzing noise and many other topics throughout SDR and DSP. ************************ Gaussian Noise @@ -14,7 +14,8 @@ Most people are aware of the concept of noise: unwanted fluctuations that can ob .. image:: ../_images/noise.png :scale: 70 % - :align: center + :align: center + :target: ../_images/noise.png Note how the average value is zero in the time domain graph. If the average value wasn't zero, then we could subtract the average value, call it a bias, and we would be left with an average of zero. Also note that the individual points in the graph are *not* "uniformly random", i.e., larger values are rarer, most of the points are closer to zero. @@ -52,6 +53,7 @@ To further illustrate the problems of scale we encounter in signal processing, c :scale: 70 % :align: center :alt: Depiction of why it's important to understand dB or decibels, showing a spectrogram using linear vs log scale + :target: ../_images/linear_vs_log.png For a given value x, we can represent x in dB using the following formula: @@ -64,7 +66,7 @@ In Python: x_db = 10.0 * np.log10(x) -You may have seen that :code:`10 *` be a :code:`20 *` in other domains. Whenever you are dealing with a power of some sort, you use 10, and you use 20 if you are dealing with a non-power value like voltage or current. In DSP we tend to deal with a power. In fact there is not a single time in this whole textbook we need to use 20 instead of 10. +You may have seen that :code:`10 *` be a :code:`20 *` in other domains. Whenever you are dealing with a power of some sort, you use 10, and you use 20 if you are dealing with a non-power value like voltage or current. In DSP we tend to deal with a power. We convert from dB back to linear (normal numbers) using: @@ -88,6 +90,7 @@ Some common errors people will run into when new to dB are: .. image:: ../_images/db.png :scale: 80 % :align: center + :target: ../_images/db.png It is also important to understand that dB is not technically a "unit". A value in dB alone is unit-less, like if something is 2x larger, there are no units until I tell you the units. dB is a relative thing. In audio when they say dB, they really mean dBA which is units for sound level (the A is the units). In wireless we typically use watts to refer to an actual power level. Therefore, you may see dBW as a unit, which is relative to 1 W. You may also see dBmW (often written dBm for short) which is relative to 1 mW. For example, someone can say "our transmitter is set to 3 dBW" (so 2 watts). Sometimes we use dB by itself, meaning it is relative and there are no units. One can say, "our signal was received 20 dB above the noise floor". Here's a little tip: 0 dBm = -30 dBW. @@ -133,6 +136,7 @@ In the :ref:`freq-domain-chapter` chapter we tackled "Fourier pairs", i.e., what :scale: 110 % :align: center :alt: AWGN in the time domain is also Gaussian noise in the frequency domain, although it looks like a flat line when you take the magnitude and perform averaging + :target: ../_images/noise_freq.png We can see that it looks roughly the same across all frequencies and is fairly flat. It turns out that Gaussian noise in the time domain is also Gaussian noise in the frequency domain. So why don't the two plots above look the same? It's because the frequency domain plot is showing the magnitude of the FFT, so there will only be positive numbers. Importantly, it's using a log scale, or showing the magnitude in dB. Otherwise these graphs would look the same. We can prove this to ourselves by generating some noise (in the time domain) in Python and then taking the FFT. @@ -157,6 +161,7 @@ Take note that the :code:`randn()` function by default uses mean = 0 and varianc :scale: 100 % :align: center :alt: Example of white noise simulated in Python + :target: ../_images/noise_python.png You can then produce the flat PSD that we had in GNU Radio by taking the log and averaging a bunch together. The signal we generated and took the FFT of was a real signal (versus complex), and the FFT of any real signal will have matching negative and positive portions, so that's why we only saved the positive portion of the FFT output (the 2nd half). But why did we only generate "real" noise, and how do complex signals work into this? @@ -198,6 +203,7 @@ To plot complex noise in the time domain, like any complex signal we need two li :scale: 80 % :align: center :alt: Complex noise simulated in Python + :target: ../_images/noise3.png You can see that the real and imaginary portions are completely independent. @@ -214,6 +220,7 @@ What does complex Gaussian noise look like on an IQ plot? Remember the IQ plot :scale: 60 % :align: center :alt: Complex noise on an IQ or constellation plot, simulated in Python + :target: ../_images/noise_iq.png It looks how we would expect; a random blob centered around 0 + 0j, or the origin. Just for fun, let's try adding noise to a QPSK signal to see what the IQ plot looks like: @@ -221,12 +228,15 @@ It looks how we would expect; a random blob centered around 0 + 0j, or the origi :scale: 60 % :align: center :alt: Noisy QPSK simulated in Python + :target: ../_images/noisey_qpsk.png Now what happens when the noise is stronger? .. image:: ../_images/noisey_qpsk2.png :scale: 50 % :align: center + :alt: Noisy QPSK with stronger noise simulated in Python + :target: ../_images/noisey_qpsk2.png We are starting to get a feel for why transmitting data wirelessly isn't that simple. We want to send as many bits per symbol as we can, but if the noise is too high then we will get erroneous bits on the receiving end. @@ -234,7 +244,7 @@ We are starting to get a feel for why transmitting data wirelessly isn't that si AWGN ************************* -Additive White Gaussian Noise (AWGN) is an abbreviation you will hear a lot in the DSP and SDR world. The GN, Gaussian Noise, we already discussed. Additive just means the noise is being added to our received signal. White, in the frequency domain, means the spectrum is flat across our entire observation band. It will almost always be white in practice,or approximately white. In this textbook we will use AWGN as the only form of noise when dealing with communications links and link budgets and such. Non-AWGN noise tends to be a niche topic. +Additive White Gaussian Noise (AWGN) is an abbreviation you will hear a lot in the DSP and SDR world. The GN, Gaussian Noise, we already discussed. Additive just means the noise is being added to our received signal. White, in the frequency domain, means the spectrum is flat across our entire observation band. It will almost always be white in practice, or approximately white. In this textbook we will use AWGN as the only form of noise when dealing with communications links and link budgets and such. Non-AWGN noise tends to be a niche topic. ************************* SNR and SINR @@ -262,26 +272,360 @@ Signal-to-Interference-plus-Noise Ratio (SINR) is essentially the same as SNR ex What constitutes interference is based on the application/situation, but typically it is another signal that is interfering with the signal of interest (SOI), and is either overlapping with the SOI in frequency, and/or cannot be filtered out for some reason. -************************* -External Resources -************************* +********************************* +Deeper Dive into Random Variables +********************************* + +So far we have avoided getting too mathematical, but now we are going to take a step back and introduce the concept of random variables and how they are used in the context of wireless communications and SDR. A **random variable** is a mathematical concept that maps outcomes of a random experiment to numerical values. Random variables represent quantities whose values are uncertain until they are observed or measured, like our noise samples. Think of rolling a six-sided die. Before you roll it, you don't know what number will appear. We can define a random variable :math:`X` that represents the outcome of the roll. The value of :math:`X` is one of {1, 2, 3, 4, 5, 6}, but we don't know which one until we actually roll the die. + +In the context of wireless communications and SDR, random variables are everywhere: + +* The thermal noise in a receiver is modeled as a random variable at each instant in time +* The amplitude of a received signal affected by multipath fading is random +* The phase offset introduced by a changing channel can be modeled as a random variable between :math:`0` and :math:`2\pi` +* Even the data bits we transmit can be treated as random variables + +**Single Sample vs. Many Samples** + +This is a crucial distinction that often causes confusion: + +* A **single realization** or **single sample** of a random variable is just one number—one outcome of the random experiment +* To characterize a random variable (find its average, spread, etc.), we need **many realizations**—many outcomes + +For example, if you call ``np.random.randn()`` in Python without any arguments, it returns a single random number drawn from a Gaussian distribution. That single number tells you almost nothing about the distribution itself. But if you call ``np.random.randn(10000)`` and generate 10,000 samples, you can now estimate properties of the distribution like its mean and variance. + +.. code-block:: python + + import numpy as np + + # Single sample - just one number + x_single = np.random.randn() + print(x_single) # might be 0.534, -1.23, or any other value + + # Many samples - now we can characterize the distribution + x_many = np.random.randn(10000) + print(np.mean(x_many)) # will be close to 0 + print(np.var(x_many)) # will be close to 1 + +Joint Distributions +#################### + +So far we've focused on single random variables. When dealing with two or more random variables simultaneously, we use a **joint distribution**. + +For continuous variables :math:`X` and :math:`Y`, this is described by the **joint PDF**: + +.. math:: + f_{X,Y}(x,y) + +The joint PDF tells us how likely it is for :math:`X` to take value :math:`x` *and* :math:`Y` to take value :math:`y` at the same time. + +From the joint PDF, we can compute: + +* Marginal PDFs (e.g., :math:`f_X(x)` or :math:`f_Y(y)`) +* Expectations such as :math:`E[XY]` +* Covariance and correlation +* Probabilities involving both variables + +For example, the marginal PDF of :math:`X` is obtained by integrating out :math:`Y`: + +.. math:: + f_X(x) = \int_{-\infty}^{\infty} f_{X,Y}(x,y)\,dy + +Joint distributions are the mathematical foundation for understanding dependence, correlation, and independence between random variables. + + +Probability Distributions +######################### + +A **probability distribution** describes how likely different values of a random variable are. For a continuous random variable, we use a **probability density function (PDF)**, denoted :math:`f_X(x)`. The PDF tells us the relative likelihood of the random variable taking on different values. + +The most important distribution in SDR and communications is the **Gaussian (Normal) distribution**. A Gaussian random variable :math:`X` with mean :math:`\mu` and variance :math:`\sigma^2` has the PDF: + +.. math:: + f_X(x) = \frac{1}{\sqrt{2\pi\sigma^2}} e^{-\frac{(x-\mu)^2}{2\sigma^2}} + +This is the famous "bell curve" you've likely seen before. The distribution is completely characterized by two parameters: + +* **Mean** :math:`\mu`: the center of the distribution +* **Variance** :math:`\sigma^2`: how spread out the distribution is (standard deviation :math:`\sigma` is the square root of variance) + +In Python, ``np.random.randn()`` generates samples from a **standard Gaussian** distribution with :math:`\mu = 0` and :math:`\sigma^2 = 1`. We can visualize this: + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + + # Generate 10,000 samples from standard Gaussian + x = np.random.randn(10000) + + # Create histogram to visualize the distribution + plt.hist(x, bins=50, density=True, alpha=0.7, edgecolor='black') + plt.xlabel('Value') + plt.ylabel('Probability Density') + plt.title('Gaussian Distribution (μ=0, σ²=1)') + plt.grid(True) + plt.show() + +.. image:: ../_images/gaussian_histogram.png + :scale: 80% + :align: center + :alt: Histogram of Gaussian distributed samples + :target: ../_images/gaussian_histogram.png + +Expectation (a.k.a. Mean) +######################### + +The **expectation** or **expected value** of a random variable, denoted :math:`E[X]` or :math:`\mu`, represents its average value over many realizations. For a continuous random variable with PDF :math:`f_X(x)`, the expectation is: + +.. math:: + E[X] = \int_{-\infty}^{\infty} x \cdot f_X(x) \, dx + +In practice, when we have :math:`N` samples :math:`x_1, x_2, \ldots, x_N` drawn from the distribution, we estimate the expectation using the **sample mean**: + +.. math:: + \hat{\mu} = \frac{1}{N} \sum_{n=1}^{N} x_n + +The expectation is a **linear operator**, which means: + +* :math:`E[aX + b] = aE[X] + b` for constants :math:`a` and :math:`b` +* :math:`E[X + Y] = E[X] + E[Y]` for any two random variables + +This linearity is extremely useful in signal processing! + +Variance and Standard Deviation +############################### + +The **variance** of a random variable, denoted :math:`\text{Var}(X)` or :math:`\sigma^2`, measures how spread out its values are around the mean. It's defined as the expected value of the squared deviation from the mean: + +.. math:: + \text{Var}(X) = E[(X - \mu)^2] = E[X^2] - (E[X])^2 + +When we have :math:`N` samples, we estimate variance using: + +.. math:: + \hat{\sigma}^2 = \frac{1}{N} \sum_{n=1}^{N} (x_n - \hat{\mu})^2 + +The **standard deviation** :math:`\sigma` is simply the square root of variance: :math:`\sigma = \sqrt{\sigma^2}`. + +Note the :math:`\enspace \hat{} \enspace` symbol, known as a "hat", in the above equation at :math:`\sigma` and that for sample mean. The hat symbolizes we're estimating the mean/variance. It's not always exactly equal to the true mean/variance, but it gets closer to the true value as we increase the number of samples. + +**Key Property:** If :math:`X` is a random variable with variance :math:`\sigma^2`, then: + +* Scaling: :math:`\text{Var}(aX) = a^2 \text{Var}(X)` +* Shifting: :math:`\text{Var}(X + b) = \text{Var}(X)` (adding a constant doesn't change the spread) + +And consequently for standard deviation :math:`\sigma`: + +* Scaling: :math:`\sigma(aX) = a\sigma(X)` +* Shifting: :math:`\sigma(X+b) = \sigma(X)` + +.. image:: ../_images/gaussian_transformed.png + :scale: 80% + :align: center + :alt: Scaling and shifting the Gaussian Distribution. (notice the scales on x and y axes) + :target: ../_images/gaussian_transformed.png + +Scaling and shifting the Gaussian Distribution. (notice the scales on x and y axes) + +**Variance and Power** -Further resources about AWGN, SNR, and variance: +In signal processing, for a **zero-mean** signal (mean ~ 0), the variance equals the **average power**. This is why we often use the terms interchangeably: -1. https://en.wikipedia.org/wiki/Additive_white_Gaussian_noise -2. https://en.wikipedia.org/wiki/Signal-to-noise_ratio -3. https://en.wikipedia.org/wiki/Variance +.. math:: + P = \text{Var}(X) = E[X^2] \quad \text{(when } E[X] = 0\text{)} + +This relationship is fundamental in analyzing noise power, signal-to-noise ratio (SNR), and link budgets. + +.. code-block:: python + + noise_power = 2.0 + n = np.random.randn(N) * np.sqrt(noise_power) + print(np.var(n)) # will be approximately 2.0 + +Covariance +########## + +The **covariance** between two random variables :math:`X` and :math:`Y` is defined as: + +.. math:: + \text{Cov}(X,Y) = E[(X - E[X])(Y - E[Y])] + +An equivalent and often more convenient form is: + +.. math:: + \text{Cov}(X,Y) = E[XY] - E[X]E[Y] + +Covariance measures how two variables vary together: + +* Positive covariance: they tend to increase and decrease together +* Negative covariance: one tends to increase when the other decreases +* Zero covariance: they are uncorrelated + +If both variables are zero-mean, this simplifies to: + +.. math:: + \text{Cov}(X,Y) = E[XY] + +Covariance has units (it is not normalized), which is why we often use the **correlation coefficient** (or simply correlation) in practice: + +.. math:: + \rho_{XY} = \frac{\text{Cov}(X,Y)}{\sigma_X \sigma_Y} + +This produces a dimensionless value between −1 and +1. + +Variance of a Sum of Variables +############################### + +In signal processing we often deal with sums of random variables, such as a signal plus noise: + +.. math:: + Z = X + Y + +The variance of this sum depends on whether :math:`X` and :math:`Y` are independent (or more generally, correlated). +In full generality: +.. math:: + \text{Var}(X + Y) = \text{Var}(X) + \text{Var}(Y) + 2\,\text{Cov}(X,Y) +where :math:`\text{Cov}(X,Y)` is the **covariance** between :math:`X` and :math:`Y`. +**Independent Case** +If :math:`X` and :math:`Y` are independent (or simply uncorrelated), then the expression simplifies to: + +.. math:: + \text{Var}(X + Y) = \text{Var}(X) + \text{Var}(Y) +This result is extremely important in communications. For example, if a received signal is: +.. math:: + R = S + N + +where :math:`S` is the signal and :math:`N` is independent noise, then the total power is just the sum of signal power and noise power. + +This is why SNR calculations are so straightforward. + +************************ +Complex Random Variables +************************ + +In SDR, we work extensively with **complex-valued signals**, which means we also work with complex random variables. A complex random variable has the form: + +.. math:: + Z = X + jY +where :math:`X` and :math:`Y` are both real-valued random variables representing the in-phase (I) and quadrature (Q) components. +**Complex Gaussian Noise** +The most common complex random variable in wireless communications is **complex Gaussian noise**, where both :math:`X` and :math:`Y` are independent Gaussian random variables with the same variance. +For example, if :math:`X \sim \mathcal{N}(\alpha_1, \sigma_1^2)` and :math:`Y \sim \mathcal{N}(\alpha_2, \sigma_2^2)` are independent, then the complex random variable :math:`Z = X + jY` has: +* Mean: :math:`E[Z] = E[X] + jE[Y] = \alpha_1 + j\alpha_2` +* Variance: :math:`\text{Var}(Z) = \text{Var}(X) + \text{Var}(Y) = \sigma_1^2 + \sigma_2^2` +.. image:: ../_images/gaussian_IQ.png + :scale: 80% + :align: center + :alt: Complex Gaussian noise visualized as two independent Gaussian random variables on the I and Q axes + :target: ../_images/gaussian_IQ.png + +This is why when we create complex Gaussian noise with unit power (variance = 1), we use: + +.. code-block:: python + + N = 10000 + n = (np.random.randn(N) + 1j*np.random.randn(N)) / np.sqrt(2) + print(np.var(n)) # ~ 1 + +The division by :math:`\sqrt{2}` ensures that the total power (sum of I and Q variances) equals 1. + +.. code-block:: python + + # Without normalization: + n_raw = np.random.randn(N) + 1j*np.random.randn(N) + print(np.var(np.real(n_raw))) # ~ 1 + print(np.var(np.imag(n_raw))) # ~ 1 + print(np.var(n_raw)) # ~ 2 (total power) + + # With normalization: + n_norm = n_raw / np.sqrt(2) + print(np.var(n_norm)) # ~ 1 (unit power) + +**************** +Random Processes +**************** + +So far we've discussed random variables—random values at a single point. A **random process** (also called a **stochastic process**) is a collection of random variables indexed by time: + +.. math:: + X(t) \quad \text{or} \quad X[n] \text{ for discrete time} + +At each time :math:`t`, :math:`X(t)` is a random variable. Think of a random process as a signal that evolves randomly over time. + +Examples in wireless communications: + +* Noise at the receiver: :math:`N(t)` or :math:`N[n]` +* A signal experiencing time-varying fading: :math:`H(t)S(t)` +* Samples from an SDR: each batch is a realization of a random process + +**Stationary Processes** + +A random process is **stationary** if its statistical properties don't change over time. In particular, a **wide-sense stationary (WSS)** process has: + +* Constant mean: :math:`E[X(t)] = \mu` for all :math:`t` +* Autocorrelation that depends only on time difference: :math:`E[X(t)X^*(t+\tau)]` depends only on :math:`\tau`, not :math:`t` + +Many noise sources in wireless systems are approximately stationary, which simplifies analysis significantly. + +**White Noise** + +**White noise** is a random process where samples at different times are uncorrelated, and the power spectral density is constant across all frequencies. Additive White Gaussian Noise (AWGN) is both: + +* **White**: uncorrelated in time, flat power spectrum +* **Gaussian**: each sample is Gaussian distributed + +When we generate noise in Python using ``np.random.randn(N)``, each of the :math:`N` samples is an independent Gaussian random variable, creating a white noise process. + + +Independence and Correlation +############################# + +Two random variables :math:`X` and :math:`Y` are **independent** if knowing the value of one tells you nothing about the other. Mathematically, their joint PDF factors: + +.. math:: + f_{X,Y}(x,y) = f_X(x) \cdot f_Y(y) + +Independence is a strong condition. A weaker condition is **uncorrelated**, which means: + +.. math:: + E[XY] = E[X]E[Y] + +For Gaussian random variables, uncorrelated implies independent (this is a special property of Gaussians). + +In complex Gaussian noise, the I and Q components are independent: + +.. code-block:: python + N = 10000 + I = np.random.randn(N) + Q = np.random.randn(N) + + # Check independence via correlation + correlation = np.corrcoef(I, Q)[0, 1] + print(f"Correlation between I and Q: {correlation:.4f}") # ~ 0 + +*************************** +Further Reading +*************************** + +1. Papoulis, A., & Pillai, S. U. (2002). *Probability, Random Variables, and Stochastic Processes*. McGraw-Hill. +2. Kay, S. M. (2006). *Intuitive Probability and Random Processes using MATLAB®*. Springer. +3. https://en.wikipedia.org/wiki/Random_variable +4. https://en.wikipedia.org/wiki/Normal_distribution +5. https://en.wikipedia.org/wiki/Stochastic_process +6. https://en.wikipedia.org/wiki/Additive_white_Gaussian_noise +7. https://en.wikipedia.org/wiki/Signal-to-noise_ratio diff --git a/content/phaser.rst b/content/phaser.rst index 039da2e3..29d1a19e 100644 --- a/content/phaser.rst +++ b/content/phaser.rst @@ -106,7 +106,7 @@ Lastly, we need to calibrate the phased array. This requires holding the HB100 python phaser_examples.py cal -This will create two more pickle files: phase_cal_val.pkl and gain_cal_val.pkl, in the same directory. Each one contains an array of 8 numbers corresponding to the phase and gain tweaks needed to calibrate each channel. These values are unique to each Phaser, as they can very during manufacturing. Subsequent runs of this utility will lead to slightly different values which is normal. +This will create two more pickle files: phase_cal_val.pkl and gain_cal_val.pkl, in the same directory. Each one contains an array of 8 numbers corresponding to the phase and gain tweaks needed to calibrate each channel. These values are unique to each Phaser, as they can vary during manufacturing. Subsequent runs of this utility will lead to slightly different values which is normal. ************************ Pre-built Example App @@ -293,7 +293,7 @@ For each :code:`phase` value (remember, this is the phase between adjacent eleme In this example the HB100 was held slightly to the side of boresight. -If you want a polar plot you can instead using the following: +If you want a polar plot you can instead use the following: .. code-block:: python @@ -386,7 +386,7 @@ Note the lack of sidelobes for Hamming. In fact, every window aside from Rectan Monopulse Tracking ************************ -Up until this point we have been performing individual sweeps in order to find the angle of arrival of a test transmitter (the HB100). But lets say we wish to continuously receive a communications or radar signal, that may be moving an causing the angle of arrival to change over time. We refer to this process as tracking, and it assumes we already have a rough estimate of the angle of arrival (i.e., the initial sweep has identified a signal of interest). We will use monopulse tracking to adaptively update the weights in order to keep the main lobe pointed at the signal over time, although note that there are other methods of tracking besides monopulse. +Up until this point we have been performing individual sweeps in order to find the angle of arrival of a test transmitter (the HB100). But lets say we wish to continuously receive a communications or radar signal, that may be moving and causing the angle of arrival to change over time. We refer to this process as tracking, and it assumes we already have a rough estimate of the angle of arrival (i.e., the initial sweep has identified a signal of interest). We will use monopulse tracking to adaptively update the weights in order to keep the main lobe pointed at the signal over time, although note that there are other methods of tracking besides monopulse. Invented in 1943 by Robert Page at the Naval Research Laboratory (NRL), the basic concept of monopulse tracking is to use two beams, both slightly offset from the current angle of arrival (or at least our estimate of it), but on different sides as shown in the diagram below. @@ -417,7 +417,7 @@ Now jumping into the full Python example, we will start by copying the code we u current_phase = phase_angles[np.argmax(powers)] print("max_phase:", current_phase) -Next we will create two beams, we will start by trying 5 degrees lower and 5 degrees higher than the current estimate, although note that this is in units of phase, we haven't converted to steering angle, although they are similar. The following code is essentially two copies of the code we used earlier to set the phase shifters of each channel, except we use the first 4 elements for the lower beam and last 4 elements for upper beam: +Next we will create two beams, we will start by trying 5 degrees lower and 5 degrees higher than the current estimate, although note that this is in units of phase, we haven't converted to steering angle, though they are similar. The following code is essentially two copies of the code we used earlier to set the phase shifters of each channel, except we use the first 4 elements for the lower beam and last 4 elements for upper beam: .. code-block:: python @@ -526,7 +526,7 @@ Now lets use the error value to update the weights. We will get rid of the prev You can see the error is essentially the derivative of the phase estimate; because we're performing successful tracking, the phase estimate is more or less the actual angle of arrival. It's not clear looking only at these plots, but when there is a sudden movement, it takes the system a small fraction of a second to adjust and catch up. The goal is for the change in angle of arrival to never be so quick that the signal arrives beyond the main lobes of the two beams. -It is a lot easier to visualize the process when the array is only 1D, but practical use-cases of monopulse tracking are almost always 2D (using a 2D/planar array instead of a linear array like the Phaser). For the 2D case, there are four beams created instead of two, and after process there is a single sum beam and four delta beams used to steer in both dimensions. +It is a lot easier to visualize the process when the array is only 1D, but practical use-cases of monopulse tracking are almost always 2D (using a 2D/planar array instead of a linear array like the Phaser). For the 2D case, there are four beams created instead of two, and after processing there is a single sum beam and four delta beams used to steer in both dimensions. ************************ Radar with Phaser diff --git a/content/pluto.rst b/content/pluto.rst index b6a97310..b3a183da 100644 --- a/content/pluto.rst +++ b/content/pluto.rst @@ -15,7 +15,7 @@ In this chapter we learn how to use the Python API for the `PlutoSDR `_ (not Crowd Supply, like the E200). At the time of this writing the E310 is roughly the same price as the E200, so if you don't plan on using "USRP-mode", and value having the extra channels exposed over SMA even if it means a slightly larger form factor, the E310 is a good choice. +In addition to the E200, MicroPhase also makes a model called the AntSDR E310. The AntSDR E310 is very similar to the E200, except it has the 2nd receive and 2nd transmit channel exposed as SMA connectors on the front, and it currently only supports the Pluto/IIO mode (no USRP mode). It uses the same FPGA as the E200. One other difference is that is has an extra USB C port that acts as a USB OTG interface (e.g., to attach a USB drive). The AntSDR E310 is only available on `AliExpress `_ (not Crowd Supply, like the E200). At the time of this writing the E310 is roughly the same price as the E200, so if you don't plan on using "USRP-mode", and value having the extra channels exposed over SMA even if it means a slightly larger form factor, the E310 is a good choice. .. image:: ../_images/AntSDR_E310.png :scale: 80 % diff --git a/content/pulse_shaping.rst b/content/pulse_shaping.rst index d8850323..7d0f21e7 100644 --- a/content/pulse_shaping.rst +++ b/content/pulse_shaping.rst @@ -60,7 +60,7 @@ To split a filter in half you can take the square root of the frequency response .. math:: X(f) = X_H(f) X_H(f) \quad \mathrm{where} \quad X_H(f) = \sqrt{X(f)} -Below shows a simplified diagram of a transmit and receive chain, with a Raised Cosine (RC) filter being split into two Root Raised Cosine (RRC) filters; the one on the transmit side is the pulse shaping filter, and the one on the received side is the matched filter. Together, they cause the pulses at the demodulator to appear as if they had been pulse shaped with a single RRC filter. +Below shows a simplified diagram of a transmit and receive chain, with a Raised Cosine (RC) filter being split into two Root Raised Cosine (RRC) filters; the one on the transmit side is the pulse shaping filter, and the one on the received side is the matched filter. Together, they cause the pulses at the demodulator to appear as if they had been pulse shaped with a single RC filter. .. image:: ../_images/splitting_rc_filter.svg :align: center @@ -185,7 +185,7 @@ At this point our symbols are still 1's and -1's. Don't be caught up in the fac BPSK symbols: [-1, 1, 1, 1, 1, -1, -1, -1, 1, 1] Applying 8 samples per symbol: [-1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, ...] -We will create a raised-cosine filter using a :math:`\beta` of 0.35, and we will make it 101 taps long to give the signal enough time to decay to zero. While the raised cosine equation asks for our symbol period and a time vector :math:`t`, we can assume a **sample** period of 1 second to "normalize" our simulation. It means our symbol period :math:`Ts` is 8 because we have 8 samples per symbol. Our time vector then will be a list of integers. With the way the raised-cosine equation works, we want :math:`t=0` to be in the center. We will generate the 101-length time vector starting at -51 and ending at +51. +We will create a raised-cosine filter using a :math:`\beta` of 0.35, and we will make it 101 taps long to give the signal enough time to decay to zero. While the raised cosine equation asks for our symbol period and a time vector :math:`t`, we can assume a **sample** period of 1 second to "normalize" our simulation. It means our symbol period :math:`Ts` is 8 because we have 8 samples per symbol. Our time vector then will be a list of integers. With the way the raised-cosine equation works, we want :math:`t=0` to be in the center. We will generate the 101-length time vector starting at -50 and ending at +50. .. code-block:: python @@ -259,3 +259,162 @@ Here is another example of a poor sample time, somewhere in between our ideal an :align: center Remember that our Q values are not shown on the time domain plot because they are roughly zero, allowing the IQ plots to spread horizontally only. + +If you want to play around with this concept further, below is an interactive `Potik `_ demonstration that generates a BPSK signal with RRC pulse shaping, adds noise, and lets you adjust the sample timing (by tweaking Symbol Sampler's timing offset parameter) to see how the constellation changes. + +.. raw:: html + + + + + +********************************** +Eye Diagrams +********************************** + +Now that we've built and sampled a pulse-shaped signal, there's a classic tool that lets us see the health of that entire signal at a glance: the eye diagram. The idea is simple, take the pulse-shaped signal we just made, after the receive-side matched filter, and chop it into short chunks that are each a couple symbol periods long, and overlay all of those chunks on top of each other. Because every chunk is aligned to the symbol timing, the pulses stack up and reveal a repeating pattern that, with a little imagination, looks like an eye: + +.. image:: ../_images/eye_diagram.svg + :align: center + :target: ../_images/eye_diagram.svg + :alt: An eye diagram of a BPSK signal with raised-cosine pulse shaping + +What should you notice? The signal converges to tight clusters at :math:`+1` and :math:`-1` right at the symbol instants (the dashed line marks the ideal sample time, which we have purposefully set at x=0), while spreading out and crossing in between the ideal sample time. That open region in the middle is the "eye", and its size tells you how much margin you have for timing error and noise. The *height* of the opening is your amplitude margin, i.e., how much noise the signal can tolerate before samples land on the wrong side of zero. The *width* of the opening is your timing margin, i.e., how far off the receiver's sample clock can drift before ISI starts closing the eye. A wide-open eye means an easy signal to receive; a closed or fuzzy eye means noise, ISI, or timing error is eating into your margin. This is exactly the same timing sensitivity we explored with the constellation plots above, just shown a different way. + +Everything above assumed a real signal (BPSK), where we only have to look at the I component. For complex modulations like QPSK or QAM, the I and Q components each carry their own symbols, so you draw a **separate eye diagram for I and for Q**. You'll usually see them side-by-side, and both eyes need to be open for reliable reception. + +To build intuition, try the interactive explorer below. It generates random symbols, applies raised-cosine pulse shaping, and overlays the results into a live eye diagram. Drag the sliders to add noise (lower the SNR), introduce timing jitter, or change the roll-off factor, and watch the eye open and close. Notice how noise closes the eye vertically (less amplitude margin) while jitter pinches it horizontally (less timing margin), and how switching from BPSK to a 4-level signal (4-ASK, which sends two bits per symbol using four amplitudes) splits it into three smaller, stacked eyes. Note that a lower roll-off factor causes higher time domain values, but it also causes the pulse to span several symbols instead of just one or two, leading to more potential combinations of values when the subsequent pulses are summed. + +.. raw:: html + +
    + + +************* +OQPSK and MSK +************* + +Regular QPSK can contain large amplitude swings, as a result of the I and Q components changing at the same time, which can be a problem for some power amplifiers that work best with a less variable envelope. Below we show an example of QPSK using raised-cosine pulse shaping, on the top shows the time domain baseband I and Q separately, and then the bottom shows the magnitude. Notice the large swings in magnitude due to the near-zero crossings when both I and Q change at the same time. Note the vertical dashed lines, which represent the symbol boundaries, both I and Q are exactly 1 or -1 at those points. Also note how the magnitude gets very close to zero at certain points. + +.. image:: ../_images/qpsk_magnitude.svg + :align: center + :target: ../_images/qpsk_magnitude.svg + :alt: Example of QPSK magnitude showing large swings due to near-zero crossings0 + +**Offset QPSK (OQPSK)** is a small variation on standard QPSK that addresses this issue. It works by delaying the Q component by half a symbol period, so I and Q never change simultaneously. The result is that the signal only makes 90-degree phase transitions at any given moment (instead of potential 180-degree jumps), keeping the envelope much more stable, without changing the shape of the spectrum. Below shows OQPSK this time, we have added vertical dashed lines at intervals offset by half a symbol period to show where the Q component changes (i.e., the center of the symbol). + +.. image:: ../_images/oqpsk_magnitude.svg + :align: center + :target: ../_images/oqpsk_magnitude.svg + :alt: Example of OQPSK magnitude showing much smaller swings due to the offset between I and Q + +The Python code to generate OQPSK with raised-cosine pulse shaping is as follows: + +.. code-block:: python + + # Parameters + num_symbols = 200 + sps = 32 # samples per symbol + beta = 0.35 # roll-off factor + span = 6 # filter span in symbols (each side) + + # Generate QPSK symbols + bits = np.random.randint(0, 4, num_symbols) + symbols = np.exp(1j * (np.pi/4 + bits * np.pi/2)).astype(complex) # points at 45°, 135°, 225°, 315° + + # RC filter + t = np.arange(-span * sps, span * sps + 1) / sps # in symbol periods + h = np.sinc(t) * np.cos(np.pi * beta * t) / (1 - (2 * beta * t)**2 + 1e-20) + + # Delay Q impulses by half a symbol before filtering so the pulse shaping filter handles the ramp-up naturally (no post-filter roll/zero-fill artifact) + half = sps // 2 + I_up = np.zeros(num_symbols * sps) + Q_up = np.zeros(num_symbols * sps) + I_up[::sps] = np.real(symbols) + Q_up[half::sps] = np.imag(symbols) + I_filt = np.convolve(I_up, h, mode='same') + Q_filt = np.convolve(Q_up, h, mode='same') + signal = I_filt + 1j * Q_filt + +We can take this one step further; if we swap out the raised-cosine pulse shaping for a new type of pulse shaping, called half-sine, we can get a perfectly constant envelope! The half-sine pulse shaping filter is defined as :math:`h(t) = \sin\left(\frac{\pi t}{T}\right)`, and its shape smoothly tapers each symbol so that the phase changes continuously and linearly from one symbol to the next. The result is called **Minimum Shift Keying (MSK)** and it's a special case of OQPSK. If we take the previous code, but swap out the raised-cosine filter with the following half-sine filter code, we get MSK: + +.. code-block:: python + + # ... + + # Half-sine pulse shape (insert this in place of the RC Filter lines) + t = np.arange(sps) + h = np.sin(np.pi * t / sps) + + # ... + +.. image:: ../_images/msk_magnitude.svg + :align: center + :target: ../_images/msk_magnitude.svg + :alt: Example of MSK magnitude showing a constant envelope + +The envelope printed above will be essentially constant, which is the hallmark of MSK. + +Note that with OQPSK and MSK, the "symbol period" and "samples per symbol" can potentially be confusing terms because a symbol could either refer to a full I + Q portion of time, or just the length of time between changes in the I or Q component (so half as long). In the above code, we are using the former definition, so a symbol is the full I + Q portion of time, but that may not always be the case, and you may find factors of 2 in equations like the half-sine definition. + +A quick look into the frequency domain (power spectral density) shape of these signals. For QPSK or OQPSK with raised-cosine pulse shaping, the spectrum is the same; it's very compact and rolls off according to the roll-off factor, which is why raised-cosine pulse shaping is so popular. + +.. image:: ../_images/qpsk_psd.svg + :align: center + :target: ../_images/qpsk_psd.svg + :alt: Example of QPSK or OQPSK PSD when an RC filter is used for pulse shaping + +For MSK, the half-sine shape causes the main lobe to be much wider, and the signal has much higher sidelobes. For low SNR signals you won't even see the sidelobes though, because they will be under the noise floor, since they are over 20 dB down. The trade-off is that we get a perfectly constant envelope. + +.. image:: ../_images/msk_psd.svg + :align: center + :target: ../_images/msk_psd.svg + :alt: Example of MSK PSD which uses a raised-sine filter for pulse shaping + +MSK is often used in applications like satellite communications and deep-space communications, where the constant envelope allows for more efficient power amplification, and reducing spectrum occupancy isn't as critical as maximizing power efficiency. Both OQPSK and MSK will require a slightly more complicated receiver, compared to regular QPSK, because of the offset between I and Q. + +Here's a comparison on the same plot, also including rectangular pulse QPSK for reference. Remember, OQPSK and QPSK when using the same pulse shaping filter (e.g., raised cosine) have the same spectrum. + +.. image:: ../_images/msk_vs_qpsk_spectrum.svg + :align: center + :target: ../_images/msk_vs_qpsk_spectrum.svg + :alt: Example of MSK vs QPSK spectrum comparison + +MSK can also be derived from a completely different angle; as a special case of **Continuous-Phase FSK (CPFSK)**. In CPFSK, each symbol is transmitted using one of two frequencies, and crucially the phase is never reset, it continues smoothly from where the previous symbol left off. That continuity is what keeps the envelope constant and the spectrum compact. MSK is CPFSK with a modulation index :math:`h = 0.5`, meaning the two tones are separated by exactly :math:`\Delta f = \frac{1}{2T}` Hz, where :math:`T` is the symbol period. The baseband signal is: + +.. math:: + + s(t) = e^{j 2\pi \frac{h}{2T} \int_{-\infty}^{t} d(\tau)\, d\tau} + +where :math:`d(\tau) \in \{-1, +1\}` is the NRZ data stream. In practice the integral just accumulates phase: each bit rotates the phase by :math:`\pm \frac{\pi}{2}` over one symbol period. The Python code to generate MSK using the CPFSK approach is as follows. Note that :code:`sps` has been divided by 2 everywhere because the symbol period is half as long when we use the CPFSK approach, since each symbol corresponds to a change in either I or Q, not both. + +.. code-block:: python + + bits = np.random.randint(0, 2, num_symbols) + symbols = 2 * bits - 1 # map {0,1} → {-1, +1} + + # Build the instantaneous frequency deviation + mod_index = 0.5 + t = np.arange(num_symbols * sps / 2) / (sps / 2) + freq_dev = np.zeros(num_symbols * sps // 2) + for k, a in enumerate(symbols): + freq_dev[k * sps // 2 : (k + 1) * sps // 2] = a * mod_index / 2.0 + + phase = 2.0 * np.pi * np.cumsum(freq_dev) / (sps / 2) # accumulate phase + signal = np.exp(1j * phase) + +And as you can see, it looks exactly like our MSK from before, but generated using a completely different approach. + +.. image:: ../_images/cpfsk_magnitude.svg + :align: center + :target: ../_images/cpfsk_magnitude.svg + :alt: Example of CPFSK magnitude showing how it matches MSK diff --git a/content/pyqt.rst b/content/pyqt.rst index d980f1ae..24efa0cc 100644 --- a/content/pyqt.rst +++ b/content/pyqt.rst @@ -453,7 +453,7 @@ The slot/callback associated with updating the waterfall data, which goes in :co self.spectrogram_min = mean - 2*sigma # save to window state self.spectrogram_max = mean + 2*sigma -Where spectrogram will be a 2D numpy array of floats. In addition to setting the image data, we will calculate a min and max for the colormap, based on the mean and variance of the data, which we will use later. The last part of the GUI code for the spectrogram is creating the colorbar, which also sets the colormap used: +Where spectrogram will be a 2D numpy array of floats. In addition to setting the image data, we will calculate a min and max for the colormap, based on the mean and standard deviation of the data, which we will use later. The last part of the GUI code for the spectrogram is creating the colorbar, which also sets the colormap used: .. code-block:: python @@ -475,7 +475,7 @@ The second line is important, it is what ultimately connects this colorbar to th Worker Thread *********************** -Recall towards the beginning of this chapter we learned how to create a separate thread, using a class we called SDRWorker with a run() function. This is where we will put all of our SDR and DSP code, with the exception of initialization of the SDR which we will do globally for now. The worker thread will also be responsible for updating the three plots, by emitting signals when new samples are available, to trigger the callback functions we have already created in :code:`MainWindow`, which ultimately updates the plots. The SDRWorker class can be split up into three sections: +Recall towards the beginning of this chapter we learned how to create a separate thread, using a class we called SDRWorker with a run() function. This is where we will put all of our SDR and DSP code, with the exception of initialization of the SDR which we will do globally for now. The worker thread will also be responsible for updating the three plots, by emitting signals when new samples are available, to trigger the callback functions we have already created in :code:`MainWindow`, which ultimately updates the plots. The SDRWorker class can be split up into four sections: #. :code:`init()` - used to initialize any state, such as the spectrogram 2D array #. PyQt Signals - we must define our custom signals that will be emitted diff --git a/content/rds.rst b/content/rds.rst index e15fe627..260d7d8e 100644 --- a/content/rds.rst +++ b/content/rds.rst @@ -1,8 +1,8 @@ .. _rds-chapter: -################## -End-to-End Example -################## +########################### +End-to-End Example with RDS +########################### In this chapter we bring together many of the concepts we previously learned about, and walk through a full example of receiving and decoding a real digital signal. We will be looking at Radio Data System (RDS), which is a communications protocol for embedding small amounts of information in FM radio broadcasts, such as station and song name. We will have to demodulate FM, frequency shift, filter, decimate, resample, synchronize, decode, and parse the bytes. An example IQ file is provided for testing purposes or if you don't have an SDR handy. @@ -56,7 +56,7 @@ The mono and stereo audio signals simply carry the audio signal, in a pattern wh The 19 kHz pilot tone is used to demodulate the stereo audio. If you double the tone it acts as a frequency and phase reference, since the stereo audio signal is centered at 38 kHz. Doubling the tone can be done by simply squaring the samples, recall the frequency shift Fourier property we learned about in the :ref:`freq-domain-chapter` chapter. -DirectBand was a North America wireless datacast network owned and operated by Microsoft, also called "MSN Direct" within consumer markets. DirectBand transmitted information to devices like portable GPS receivers, wristwatches, and home weather stations. It even allowed users to receive short messages from Windows Live Messenger. One of the most successful applications of DirectBand was real-time local traffic data displayed on Garmin GPS receivers, which were used by millions of people before smartphones became ubiquitous. The DirectBand service was shut down on January 2012, which raises the question, why do we see it in our FM signal that was recorded after 2012? My only guess is that most FM transmitters were designed and built way before 2012, and even without any DirectBand "feed" active, it still transmits something, perhaps pilot symbols. +DirectBand was a North America wireless datacast network owned and operated by Microsoft, also called "MSN Direct" within consumer markets. DirectBand transmitted information to devices like portable GPS receivers, wristwatches, and home weather stations. It even allowed users to receive short messages from Windows Live Messenger. One of the most successful applications of DirectBand was real-time local traffic data displayed on Garmin GPS receivers, which were used by millions of people before smartphones became ubiquitous. The DirectBand service was shut down in January 2012, which raises the question, why do we see it in our FM signal that was recorded after 2012? My only guess is that most FM transmitters were designed and built way before 2012, and even without any DirectBand "feed" active, it still transmits something, perhaps pilot symbols. Lastly, we come to RDS, which is the focus of the rest of this chapter. As we can see in our first PSD, RDS is roughly 4 kHz in bandwidth (before it gets FM modulated), and sits in between the stereo audio and DirectBand signal. It is a low data rate digital communications protocol that allows FM stations to include station identification, program information, time, and other miscellaneous information alongside the audio. The RDS standard is published as IEC standard 62106 and can be `found here `_. @@ -309,7 +309,7 @@ The BPSK signal used differential coding when it was created, which means that e RDS Decoding ******************************** -We finally have our bits of information, and we are ready to decode what they mean! The massive block of code provided below is what we will use to decode the 1's and 0's into groups of bytes. This part would make a lot more sense if we first created the transmitter portion of RDS, but for now just know that in RDS, bytes are grouped into groups of 12 bytes, where the first 8 represent the data and the last 4 act as a sync word (called "offset words"). The last 4 bytes are not needed by the next step (the parser) so we don't include them in the output. This block of code takes in the 1's and 0's created above (in the form of a 1D array of uint8's) and outputs a list of lists of bytes (a list of 8 bytes where those 8 bytes are in a list). This makes it convenient for the next step, which will iterate through the list of 8 bytes, one group of 8 at a time. +We finally have our bits of information, and we are ready to decode what they mean! The massive block of code provided below is what we will use to decode the 1's and 0's into groups of bytes. This part would make a lot more sense if we first created the transmitter portion of RDS, but for now just know that in RDS, bytes are grouped into groups of 13 bytes, where the first 8 represent the data and the last 5 act as a sync word (called "offset words"). The last 5 bytes are not needed by the next step (the parser) so we don't include them in the output. This block of code takes in the 1's and 0's created above (in the form of a 1D array of uint8's) and outputs a list of lists of bytes (a list of 8 bytes where those 8 bytes are in a list). This makes it convenient for the next step, which will iterate through the list of 8 bytes, one group of 8 at a time. Most of the actual decoding code below revolves around syncing (at the byte level, not symbol) and error checking. It works in blocks of 104 bits, each block is either received correctly or in error (using CRC to check), and every 50 blocks it checks whether more than 35 of them were received with error, in which case it resets everything and attempts to sync again. The CRC is performed using a 10-bit check, with polynomial :math:`x^{10}+x^8+x^7+x^5+x^4+x^3+1`; this occurs when :code:`reg` is xor'ed with 0x5B9 which is the binary equivalent of that polynomial. In Python, the bitwise operators for [and, or, not, xor] are :code:`& | ~ ^` respectively, exactly the same as C++. A left bit shift is :code:`x << y` (same as multiplying x by 2**y), and a right bit shift is :code:`x >> y` (same as dividing x by 2**y), also like in C++. @@ -631,7 +631,7 @@ Below shows the output of the parsing step for an example FM station. Note how Wrap-Up and Final Code ******************************** -You did it! Below is all of the code above, concatenated, it should work with the `test FM radio recording you can find here `_, although you should be able to feed in your own signal as long as its received at a high enough SNR, simply tune to the station's center frequency and sample at a rate of 250 kHz. If you find you had to make tweaks to get it to work with your own recording or live SDR, let me know what you had to do, you can submit it as a GitHub PR at `the textbook's GitHub page `_. You can also find a version of this code with dozens of debug plotting/printing included, that I originally used to make this chapter, `here `_. +You did it! Below is all of the code above, concatenated, it should work with the `test FM radio recording you can find here `_, although you should be able to feed in your own signal as long as its received at a high enough SNR, simply tune to the station's center frequency and sample at a rate of 250 kHz. If you find you had to make tweaks to get it to work with your own recording or live SDR, let me know what you had to do, you can submit it as a GitHub PR at `the textbook's GitHub page `_. You can also find a version of this code with dozens of debug plotting/printing included, that I originally used to make this chapter, `here `_. Lastly, if you want to try running the code purely in your browser, it's available as a `web-based jupyter notebook <../jupyterlite/notebooks/index.html?path=rds.ipynb>`_, although you'll have to go to View, File Browser, then drag and drop the IQ file into the window for it to work. .. raw:: html diff --git a/content/rtlsdr.rst b/content/rtlsdr.rst index 36c775fa..a0d0d37c 100644 --- a/content/rtlsdr.rst +++ b/content/rtlsdr.rst @@ -19,7 +19,7 @@ The RTL-SDR came into existence around 2010 when folks discovered they could hac The RTL2832U chip includes the analog-to-digital converter (ADC) and USB controller, but it must be paired with an RF tuner. Popular tuner chips include the Rafael Micro R820T, R828D, and Elonics E4000. The tunable frequency range is based on the tuner chip and is usually around 50 - 1700 MHz. The maximum sample rate, on the other hand, is determined by the RTL2832U and your computer's USB bus, and is usually around 2.4 MHz without dropping too many samples. Keep in mind that these tuners are extremely low-cost and have very poor RF sensitivity, so adding a low-noise amplifier (LNA) and bandpass filter is often necessary to receive weak signals. -The RTL2832U always uses 8-bit samples, so the host machine will receive two bytes per IQ sample. Premium RTL-SDRs usually come with a temperature-controlled oscillator (a.k.a. TCXO) in place of the cheaper crystal oscillator, which provides better frequency stability. Another optional feature is a bias tee (a.k.a. bias-T), which is an onboard circuit that provides ~4.5V DC on the SMA connector, used to conveniently power an external LNA or other RF components. This extra DC offset is on the RF side of the SDR so it does not interfere with the basic receiving operation. +The RTL2832U always uses 8-bit samples, so the host machine will receive two bytes per IQ sample. Premium RTL-SDRs usually come with a temperature-controlled oscillator (a.k.a. TCXO) in place of the cheaper crystal oscillator, which provides better frequency stability. Another optional feature is a bias tee (a.k.a. bias-T), which is an onboard circuit that provides ~4.5V DC on the SMA connector, used to conveniently power an external LNA or other RF components. This extra DC voltage is on the RF side of the SDR so it does not interfere with the basic receiving operation. For those interested in direction of arrival (DOA) or other beamforming applications, the `KrakenSDR `_ is a phase-coherent SDR made from five RTL-SDRs that share an oscillator and sample clock. @@ -168,7 +168,7 @@ By setting :code:`sdr.gain = 'auto'` we are enabling automatic gain control (AGC :target: ../_images/rtlsdr-gain.svg :alt: RTL-SDR manual gain example -There are a couple things to note here. The first ~2k samples do not seem to have much signal power in them, because they represent transients. It is recommended to throw away the first 2k samples each script, e.g., using :code:`sdr.read_samples(2048)` and not doing anything with the output. The other thing we notice is that pyrtlsdr is returning the samples to us as floats, in between -1 and +1. Even though it uses an 8-bit ADC and produces integer values, pyrtlsdr is dividing by 127.0 for our convenience. +There are a couple things to note here. The first ~2k samples do not seem to have much signal power in them, because they represent transients. It is recommended to throw away the first 2k samples each script, e.g., using :code:`sdr.read_samples(2048)` and not doing anything with the output. The other thing we notice is that pyrtlsdr is returning the samples to us as floats, in between -1 and +1. Even though it uses an 8-bit ADC and produces integer values, pyrtlsdr is dividing by 127.5 for our convenience. Allowed Sample Rates ##################### diff --git a/content/sampling.rst b/content/sampling.rst index e8a036c3..cca4bf6d 100644 --- a/content/sampling.rst +++ b/content/sampling.rst @@ -32,7 +32,7 @@ For a given signal, the big question often is how fast must we sample? Let's ex .. image:: ../_images/sampling_Fs_0.3.svg :align: center -The red dashed line in the above image reconstructs a different (incorrect) function that could have lead to the same samples being recorded. It indicates that our sample rate was too low because the same samples could have come from two different functions, leading to ambiguity. If we want to accurately reconstruct the original signal, we can't have this ambiguity. +The red dashed line in the above image reconstructs a different (incorrect) function that could have led to the same samples being recorded. It indicates that our sample rate was too low because the same samples could have come from two different functions, leading to ambiguity. If we want to accurately reconstruct the original signal, we can't have this ambiguity. Let's try sampling a little faster, at Fs = 1.2f: @@ -228,7 +228,7 @@ Carrier and Downconversion Until this point we have not discussed frequency, but we saw there was an :math:`f` in the equations involving the cos() and sin(). This frequency is the center frequency of the signal we actually send through the air (the electromagnetic wave's frequency). We refer to it as the "carrier" because it carries our signal on a certain RF frequency. When we tune to a frequency with our SDR and receive samples, our information is stored in I and Q; this carrier does not show up in I and Q. -For reference, radio signals such as FM radio, WiFi, Bluetooth, LTE, GPS, etc., usually use a frequency (i.e., a carrier) between 100 MHz and 6 GHz. These frequencies travel really well through the air, but they don't require super long antennas or a ton of power to transmit or receive. Your microwave cooks food with electromagnetic waves at 2.4 GHz. If there is a leak in the door then your microwave will jam WiFi signals and possibly also burn your skin. Another form of electromagnetic waves is light. Visible light has a frequency of around 500 THz. It's so high that we don't use traditional antennas to transmit light. We use methods like LEDs that are semiconductor devices. They create light when electrons jump in between the atomic orbits of the semiconductor material, and the color depends on how far they jump. Technically, radio frequency (RF) is defined as the range from roughly 20 kHz to 300 GHz. These are the frequencies at which energy from an oscillating electric current can radiate off a conductor (an antenna) and travel through space. The 100 MHz to 6 GHz range are the more useful frequencies, at least for most modern applications. Frequencies above 6 GHz have been used for radar and satellite communications for decades, and are now being used in 5G "mmWave" (24 - 29 GHz) to supplement the lower bands and increase speeds. +For reference, radio signals such as FM radio, WiFi, Bluetooth, LTE, GPS, etc., usually use a frequency (i.e., a carrier) between 100 MHz and 6 GHz. These frequencies travel really well through the air, but they don't require super long antennas or a ton of power to transmit or receive. Your microwave cooks food with electromagnetic waves at 2.4 GHz. If there is a leak in the door then your microwave will jam WiFi signals and possibly also burn your skin. Another form of electromagnetic waves is light. Visible light has a frequency of around 500 THz. It's so high that we don't use traditional antennas to transmit light. We use methods like LEDs that are semiconductor devices. They create light when electrons jump in between the atomic orbits of the semiconductor material, and the color depends on how far they jump. Technically, radio frequency (RF) is defined as the range from roughly 3 kHz to 300 GHz. These are the frequencies at which energy from an oscillating electric current can radiate off a conductor (an antenna) and travel through space. The 100 MHz to 6 GHz range are the more useful frequencies, at least for most modern applications. Frequencies above 6 GHz have been used for radar and satellite communications for decades, and are now being used in 5G "mmWave" (24 - 29 GHz) to supplement the lower bands and increase speeds. When we change our IQ values quickly and transmit our carrier, it's called "modulating" the carrier (with data or whatever we want). When we change I and Q, we change the phase and amplitude of the carrier. Another option is to change the frequency of the carrier, i.e., shift it slightly up or down, which is what FM radio does. It is easy to get confused between the signal we want to transmit (which typically contains many frequency components), and the frequency we transmit it on (our carrier frequency). This will hopefully get cleared up when we cover baseband vs. bandpass signals. @@ -251,7 +251,7 @@ When we are centered around 0 Hz, the maximum frequency is no longer 2.4 GHz but Just to reiterate, the downconversion process is performed by our SDR; as a user of the SDR we don't have to do anything other than tell it which frequency to tune to. Downconversion (and upconversion) is done by a component called a mixer, usually represented in diagrams as a multiplication symbol inside a circle. The mixer takes in a signal, outputs the down/up-converted signal, and has a third port which is used to feed in an oscillator. The frequency of the oscillator determines the frequency shift applied to the signal, and the mixer is essentially just a multiplication function (recall that multiplying by a sinusoid causes a frequency shift). -Lastly, you may be curious how fast signals travel through the air. Recall from high school physics class that radio waves are just electromagnetic waves at low frequencies (between roughly 3 kHz to 80 GHz). Visible light is also electromagnetic waves, at much higher frequencies (400 THz to 700 THz). All electromagnetic waves travel at the speed of light, which is about 3e8 m/s, at least when traveling through air or a vacuum. Now because they always travel at the same speed, the distance the wave travels in one full oscillation (one full cycle of the sine wave) depends on its frequency. We call this distance the wavelength, denoted as :math:`\lambda`. You have probably seen this relationship before: +Lastly, you may be curious how fast signals travel through the air. Recall from high school physics class that radio waves are just electromagnetic waves at low frequencies (between roughly 3 kHz to 300 GHz). Visible light is also electromagnetic waves, at much higher frequencies (400 THz to 700 THz). All electromagnetic waves travel at the speed of light, which is about 3e8 m/s, at least when traveling through air or a vacuum. Now because they always travel at the same speed, the distance the wave travels in one full oscillation (one full cycle of the sine wave) depends on its frequency. We call this distance the wavelength, denoted as :math:`\lambda`. You have probably seen this relationship before: .. math:: f = \frac{c}{\lambda} diff --git a/content/sync.rst b/content/sync.rst index 52c92d54..bebd072d 100644 --- a/content/sync.rst +++ b/content/sync.rst @@ -55,7 +55,7 @@ Let's examine Python code for simulating a non-integer delay and a frequency off h = np.sinc(t/Ts) * np.cos(np.pi*beta*t/Ts) / (1 - (2*beta*t/Ts)**2) # Filter our signal, in order to apply the pulse shaping - samples = np.convolve(pulse_train, h) + samples = np.convolve(pulse_train, h, "same") .. raw:: html @@ -63,11 +63,12 @@ Let's examine Python code for simulating a non-integer delay and a frequency off We will leave out the plotting-related code because by now you have probably learned how to plot any signal you want. Making the plots look pretty, as they often do in this textbook, requires a lot of extra code that is not necessary to understand. +Next, we must simulate the delay a signal experiences as it travels through the wireless channel. We can easily simulate a delay by shifting samples, but it only simulates a delay that is an integer multiple of our sample period. In the real world the delay will be some fraction of a sample period, so to simulate that we need to create a "fractional delay" filter. -Adding a Delay -############## +Fractional Delay Filters +######################## -We can easily simulate a delay by shifting samples, but it only simulates a delay that is an integer multiple of our sample period. In the real world the delay will be some fraction of a sample period. We can simulate the delay of a fraction of a sample by making a "fractional delay" filter, which passes all frequencies but delays the samples by some amount that isn't limited to the sample interval. You can think of it as an all-pass filter that applies the same phase shift to all frequencies. (Recall that a time delay and phase shift are equivalent.) The Python code to create this filter is shown below: +A fractional delay filter is a type of all-pass filter which (ideally) passes all frequencies but delays the samples by some amount, typically between -0.5 and 0.5 of a sample period, because you can perform the integer portion of delay through simple indexing. It applies a constant time delay to the entire signal, which in the frequency domain corresponds to a linear phase shift (phase that increases proportionally with frequency). Every frequency component gets delayed by the same amount of time, so the signal's shape is preserved, it just arrives later. This is in contrast to doing a phase shift which shifts all frequencies by a constant phase; low frequencies get delayed more and high frequencies get delayed less. The Python code to create a fractional delay filter is shown below, using the windowed-sinc method: .. code-block:: python @@ -80,7 +81,7 @@ We can easily simulate a delay by shifting samples, but it only simulates a dela h /= np.sum(h) # normalize to get unity gain, we don't want to change the amplitude/power samples = np.convolve(samples, h) # apply filter -As you can see, we are calculating the filter taps using a sinc() function. A sinc in the time domain is a rectangle in the frequency domain, and our rectangle for this filter spans the entire frequency range of our signal. This filter does not reshape the signal, it just delays it in time. In our example we are delaying by 0.4 of a sample. Keep in mind that applying *any* filter delays a signal by half of the filter taps minus one, due to the act of convolving the signal through the filter. +As you can see, we are calculating the filter taps using a sinc() function. A sinc in the time domain is a rectangle in the frequency domain, and our rectangle for this filter spans the entire frequency range of our signal. This filter does not reshape the signal, it just delays it in time. In our example we are delaying by 0.4 of a sample. Keep in mind that applying a linear-phase FIR filter delays a signal by half of the filter taps minus one, due to the act of convolving the signal through the filter. If we plot the "before" and "after" of filtering a signal, we can observe the fractional delay. In our plot we zoom into only a couple of symbols. Otherwise, the fractional delay is not viewable. @@ -89,7 +90,6 @@ If we plot the "before" and "after" of filtering a signal, we can observe the fr :target: ../_images/fractional-delay-filter.svg - Adding a Frequency Offset ########################## @@ -281,7 +281,7 @@ Let's watch what happens when our QPSK signal has a small phase rotation and mag :scale: 80 % :align: center -It still becomes one cluster, just with a phase shift. The main take-away here is that if you square QPSK twice (and BPSK once), it will merge all four clusters of points into one cluster. Why is that useful? Well by merging the clusters we are essentially removing the modulation! If all points are now in the same cluster, that's like having a bunch of constants in a row. It's as if there is no modulation anymore, and the only thing left is the sinusoid caused by the frequency offset (we also have noise but let's keep ignoring it for now). It turns out that you have to square the signal N times, where N is the order of the modulation scheme used, which means that this trick only works if you know the modulation scheme ahead of time. The equation is really: +It still becomes one cluster, just with a phase shift. The main take-away here is that if you square QPSK twice (and BPSK once), it will merge all four clusters of points into one cluster. Why is that useful? Well by merging the clusters we are essentially removing the modulation! If all points are now in the same cluster, that's like having a bunch of constants in a row. It's as if there is no modulation anymore, and the only thing left is the sinusoid caused by the frequency offset (we also have noise but let's keep ignoring it for now). It turns out that you have to raise the signal to the Nth power, where N is the order of the modulation scheme used, which means that this trick only works if you know the modulation scheme ahead of time. The equation is really: .. math:: @@ -329,7 +329,7 @@ We have to zoom way in to see which frequency the spike is on: You can try increasing the number of symbols simulated (e.g., 1000 symbols) so that we have enough samples to work with. The more samples that go into our FFT, the more accurate our estimation of the frequency offset will be. Just as a reminder, the code above should come *before* the timing synchronizer. -The offset frequency spike shows up at :math:`Nf_o`. We need to divide this bin (26.6 kHz) by 2 to find our final answer, which is very close to the 13 kHz frequency offset we applied at the beginning of the chapter! If you had played with that number and it's no longer 13 kHz, that's fine. Just make sure you are aware of what you set it to. +The offset frequency spike shows up at :math:`Nf_o`. We need to divide this bin (26 kHz) by 2 to find our final answer, which is very close to the 13 kHz frequency offset we applied at the beginning of the chapter! If you had played with that number and it's no longer 13 kHz, that's fine. Just make sure you are aware of what you set it to. Because our sample rate is 1 MHz, the maximum frequencies we can see are -500 kHz to 500 kHz. If we take our signal to the power of N, that means we can only "see" frequency offsets up to :math:`500e3/N`, or in the case of BPSK +/- 250 kHz. If we were receiving a QPSK signal then it would only be +/- 125 kHz, and carrier offset higher or lower than that would be out of our range using this technique. To give you a feel for Doppler shift, if you were transmitting in the 2.4 GHz band and either the transmitter or receiver was traveling at 60 mph (it's the relative speed that matters), it would cause a frequency shift of 214 Hz. The offset due to a low quality oscillator will probably be the main culprit in this situation. @@ -350,7 +350,7 @@ Fine Frequency Synchronization Next we will switch gears to fine frequency sync. The previous trick is more for coarse sync, and it's not a closed-loop (feedback type) operation. But for fine frequency sync we will want a feedback loop that we stream samples through, which once again will be a form of PLL. Our goal is to get the frequency offset to zero and maintain it there, even if the offset changes over time. We have to continuously track the offset. Fine frequency sync techniques work best with a signal that already has been synchronized in time at the symbol level, so the code we discuss in this section will come *after* timing sync. -We will use a technique called a Costas Loop. It is a form of PLL that is specifically designed for carrier frequency offset correction for digital signals like BPSK and QPSK. It was invented by John P. Costas at General Electric in the 1950's, and it had a major impact on modern digital communications. The Costas Loop will remove the frequency offset while also fixing any phase offset. The energy is aligned with the I axis. Frequency is just a change in phase so they can be tracked as one. The Costas Loop is summarized using the following diagram (note that 1/2s have been left out of the equations because they don't functionally matter). +We will use a technique called a Costas Loop. It is a form of PLL that is specifically designed for carrier frequency offset correction for digital signals like BPSK and QPSK. It was invented by John P. Costas at General Electric in the 1950's, and it had a major impact on modern digital communications. The Costas Loop will remove the frequency offset while also fixing any phase offset. For BPSK, the signal energy is aligned with the I axis after correction. Frequency is just a change in phase so they can be tracked as one. The Costas Loop is summarized using the following diagram (note that 1/2s have been left out of the equations because they don't functionally matter). .. image:: ../_images/costas-loop.svg :align: center @@ -391,7 +391,7 @@ Below is the Python code that is our Costas Loop: plt.plot(freq_log,'.-') plt.show() -There is a lot here so let's step through it. Some lines are simple and others are super complicated. :code:`samples` is our input, and :code:`out` is the output samples. :code:`phase` and :code:`frequency` are like the :code:`mu` from the time sync code. They contain the current offset estimates, and each loop iteration we create the output samples by multiplying the input samples by :code:`np.exp(-1j*phase)`. The :code:`error` variable holds the "error" metric, and for a 2nd order Costas Loop it's a very simple equation. We multiply the real part of the sample (I) by the imaginary part (Q), and because Q should be equal to zero for BPSK, the error function is minimized when there is no phase or frequency offset that causes energy to shift from I to Q. For a 4th order Costas Loop, it's still relatively simple but not quite one line, as both I and Q will have energy even when there is no phase or frequency offset, for QPSK. If you are curious what it looks like click below, but we won't be using it in our code for now. The reason this works for QPSK is because when you take the absolute value of I and Q, you will get +1+1j, and if there is no phase or frequency offset then the difference between the absolute value of I and Q should be close to zero. +There is a lot here so let's step through it. Some lines are simple and others are super complicated. :code:`samples` is our input, and :code:`out` is the output samples. :code:`phase` and :code:`frequency` are like the :code:`mu` from the time sync code. They contain the current offset estimates, and each loop iteration we create the output samples by multiplying the input samples by :code:`np.exp(-1j*phase)`. The :code:`error` variable holds the "error" metric, and for a 2nd order Costas Loop it's a very simple equation. We multiply the real part of the sample (I) by the imaginary part (Q), and because Q should be equal to zero for BPSK, the error function is minimized when there is no phase or frequency offset that causes energy to shift from I to Q. For a 4th order Costas Loop, it's still relatively simple but not quite one line, as both I and Q will have energy even when there is no phase or frequency offset, for QPSK. If you are curious what it looks like click below, but we won't be using it in our code for now. The reason this works for QPSK is because when you take the absolute value of I and Q, you will get magnitudes of approximately 1 for both, and if there is no phase or frequency offset then the difference between the absolute value of I and Q should be close to zero. .. raw:: html @@ -449,6 +449,142 @@ Below is an animation of the time sync plus frequency sync running, the time syn :target: ../_images/costas_animation.gif :alt: Costas loop animation +The following (collapsed) code block provides the full Python example of the chapter so far, this was tested to work using Python 3.12.3 and NumPy 1.26.4. It also includes a bit error check at the end, although AWGN is left out for the sake of seeing how tight the BPSK can get through just synchronization alone, you are welcome to add AWGN, e.g., right after adding the fractional delay. Note that the plot of IQ over time is before frequency synchronization, so you can see the BPSK energy slowly shift between I and Q. If you want to try running the code purely in your browser, it's available as a `web-based jupyter notebook <../jupyterlite/notebooks/index.html?path=sync.ipynb>`_. + +.. raw:: html + +
    + Full Python Example + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + from scipy import signal + + # Create BPSK signal + num_symbols = 100 + sps = 8 + bits = np.random.randint(0, 2, num_symbols) # Our data to be transmitted, 1's and 0's + pulse_train = np.array([]) + for bit in bits: + pulse = np.zeros(sps) + pulse[0] = bit*2-1 # set the first value to either a 1 or -1 + pulse_train = np.concatenate((pulse_train, pulse)) # add the 8 samples to the signal + + # Apply pulse shaping to the BPSK + num_taps = 101 + beta = 0.35 + Ts = sps # Assume sample rate is 1 Hz, so sample period is 1, so *symbol* period is 8 + t = np.arange(-51, 52) # remember it's not inclusive of final number + h = np.sinc(t/Ts) * np.cos(np.pi*beta*t/Ts) / (1 - (2*beta*t/Ts)**2) + samples = np.convolve(pulse_train, h, 'same') + + # Create and apply fractional delay filter to emulate a random timing offset + delay = 0.456 # fractional delay, in samples + N = 21 # number of taps, keep this odd + n = np.arange(-(N-1)//2, N//2+1) # -10,-9,...,0,...,9,10 + h = np.sinc(n - delay) # calc filter taps + h *= np.hamming(N) # window the filter to make sure it decays to 0 on both sides + h /= np.sum(h) # normalize to get unity gain, we don't want to change the amplitude/power + samples = np.convolve(samples, h) # apply filter + + # Apply a pretty significant freq offset + fs = 1e6 # assume our sample rate is 1 MHz + fo = 13000 # simulate freq offset THIS REPRESENTS A COARSE OFFSET! + Ts = 1/fs # calc sample period + t = np.arange(0, Ts*len(samples), Ts) # create time vector + samples = samples * np.exp(1j*2*np.pi*fo*t) # perform freq shift + + # Estimate and correct for the coarse freq offset + samples_sq = samples**2 + psd = np.fft.fftshift(np.abs(np.fft.fft(samples_sq, 2048))) + f = np.linspace(-fs/2.0, fs/2.0, len(psd)) + max_freq = f[np.argmax(psd)] / 2.0 + print(f"Estimated freq offset: {max_freq:.2f} Hz") + Ts = 1/fs # calc sample period + t = np.arange(0, Ts*len(samples), Ts) # create time vector + samples = samples * np.exp(-1j*2*np.pi*max_freq*t) + + # At this point there should be less than 1kHz of freq offset in our signal, depending how large an FFT you used above + + # Symbol/Timing Sync + mu = 0 # initial estimate of phase of sample + out = np.zeros(len(samples) // sps + 2, dtype=np.complex64) + out_rail = np.zeros(len(samples) // sps + 2, dtype=np.complex64) # stores values, each iteration we need the previous 2 values plus current value + i_in = 0 # input samples index + i_out = 2 # output index (let first two outputs be 0) + interpolation_factor = 16 + samples_interpolated = signal.resample_poly(samples, interpolation_factor, 1) + while i_out < len(samples) and i_in+16 < len(samples): + out[i_out] = samples_interpolated[i_in*interpolation_factor + int(mu*interpolation_factor)] + out_rail[i_out] = int(np.real(out[i_out]) > 0) + 1j*int(np.imag(out[i_out]) > 0) + x = (out_rail[i_out] - out_rail[i_out-2]) * np.conj(out[i_out-1]) + y = (out[i_out] - out[i_out-2]) * np.conj(out_rail[i_out-1]) + mm_val = np.real(y - x) + mu += sps + 0.3*mm_val + i_in += int(np.floor(mu)) # round down to nearest int since we are using it as an index + mu = mu - np.floor(mu) # remove the integer part of mu + i_out += 1 # increment output index + out = out[3:i_out] # remove the first few due to filter transients, and anything after i_out (that was never filled out) + samples = out + + plt.figure(2) + plt.plot(np.real(samples)) + plt.plot(np.imag(samples)) + plt.xlabel('Sample Index') + plt.ylabel('Sample Value') + plt.legend(['I', 'Q']) + plt.grid() + + N = len(samples) + phase = 0 + freq = 0 + # These next two params is what to adjust, to make the feedback loop faster or slower (which impacts stability) + alpha = 0.132 + beta = 0.00932 + out = np.zeros(N, dtype=np.complex64) + freq_log = [] + for i in range(N): + out[i] = samples[i] * np.exp(-1j*phase) # adjust the input sample by the inverse of the estimated phase offset + error = np.real(out[i]) * np.imag(out[i]) # This is the error formula for 2nd order Costas Loop (e.g. for BPSK) + + # Advance the loop (recalc phase and freq offset) + freq += (beta * error) + freq_log.append(freq * fs / (2*np.pi)) # convert from angular velocity to Hz for logging + phase += freq + (alpha * error) + + # Optional: Adjust phase so its always between 0 and 2pi, recall that phase wraps around every 2pi + while phase >= 2*np.pi: + phase -= 2*np.pi + while phase < 0: + phase += 2*np.pi + + # Calc BER + rx_bits = (np.real(out) > 0).astype(int) + num_bit_errors = np.sum(rx_bits != bits[:len(rx_bits)]) + print(f"Number of bit errors: {num_bit_errors} out of {len(rx_bits)} bits, BER: {num_bit_errors/len(rx_bits):.4f}") + + # Plot freq over time to see how long it takes to hit the right offset + plt.figure(0) + plt.plot(freq_log,'.-') + plt.xlabel('Sample Index') + plt.ylabel('Frequency Offset Estimate (Hz)') + + # Appears to be synced after ~80 samples so lets plot the constellation of the remaining 20 samples + plt.figure(1) + plt.plot(np.real(out[80:]), np.imag(out[80:]), '.') + plt.xlabel('I') + plt.ylabel('Q') + plt.xlim(-1.5, 1.5) + plt.ylim(-1.5, 1.5) + plt.grid() + plt.show() + +.. raw:: html + +
    + *************************** Frame Synchronization *************************** @@ -483,14 +619,3 @@ You can think of it as 11 BPSK symbols. We can look at the autocorrelation of t You can see it's 11 (length of the sequence) in the center, and -1 or 0 for all other delays. It works well for finding the start of a frame because it essentially integrates 11 symbols worth of energy in an attempt to create a 1 bit spike in the output of the cross-correlation. In fact, the hardest part of performing start-of-frame detection is figuring out a good threshold. You don't want frames that aren't actually part of your protocol to trigger it. That means in addition to cross-correlation you also have to do some sort of power normalizing, which we won't consider here. In deciding a threshold, you have to make a trade-off between probability of detection and probability of false alarms. Remember that the frame header itself will have information, so some false alarms are OK; you will quickly find it is not actually a frame when you go to decode the header and the CRC inevitably fails (because it wasn't actually a frame). Yet while some false alarms are OK, missing a frame detection altogether is bad. Another sequence with great autocorrelation properties is Zadoff-Chu sequences, which are used in LTE. They have the benefit of being in sets; you can have multiple different sequences that all have good autocorrelation properties, but they won't trigger each other (i.e., also good cross-correlation properties, when you cross-correlate different sequences in the set). Thanks to that feature, different cell towers will be assigned different sequences so that a phone can not only find the start of the frame but also know which tower it is receiving from. - - - - - - - - - - - diff --git a/content/tdoa.rst b/content/tdoa.rst new file mode 100644 index 00000000..28644990 --- /dev/null +++ b/content/tdoa.rst @@ -0,0 +1,753 @@ +.. _tdoa-chapter: + +#### +TDOA +#### + +Time Difference of Arrival (TDOA) is a technique that can find the position of a transmitter (a.k.a. emitter) using multiple synchronized receivers (a.k.a. sensors), by comparing differences in signal arrival time. This chapter covers the full TDOA pipeline: geometry, GCC-PHAT time-delay estimation, closed-form and maximum-likelihood localization, accuracy bounds (CRLB and GDOP), and challenges like synchronization and multipath. TDOA is commonly used in both RF and acoustic/sonar applications. + +Before diving in, try playing with the interactive demo below to get a quick feel for how TDOA works, which involves the intersection of hyperbolas. + +.. raw:: html + +
    + + +************ +Introduction +************ + +A common problem across RF and acoustics/sonar is the desire to find the position of an emitter, also known as the process of geolocation. The emitter may be cooperative (a cell phone trying to be found) or non-cooperative (a radar emitter that would rather not be), stationary or moving, and the medium may be air, water, or free space. TDOA-based localization appears in cellular emergency-caller location, acoustics with microphone arrays (e.g., gunshot-detection systems mounted on city streetlights), passive sonar, passive (non-emitting) radar, electronic warfare and signals intelligence, and even wildlife tracking. In each case the engineering details differ, but the mathematical skeleton is the same. + +The key behind TDOA is that when the same wavefront hits two sensors, the difference in arrival times depends only on geometry, not on when the emitter transmitted. To see why, consider the propagation time from an emitter to sensor :math:`i`: :math:`t_i = t_0 + r_i / c`, where :math:`t_0` is the (unknown) start of transmission, :math:`r_i` is the emitter-to-sensor distance, and :math:`c` is the propagation speed. If we subtract the arrival times at two sensors, + +.. math:: + + \tau_{ij} = t_i - t_j = \frac{r_i - r_j}{c}, + +the unknown :math:`t_0` vanishes, which is good because we will likely never know :math:`t_0`. The TDOA depends only on the *difference* of ranges, which depends only on emitter and sensor geometry. This single fact is why TDOA dominates for non-cooperative emitters; we never need to know when the emitter transmitted, only that the same wavefront reached our synchronized receivers at measurable relative delays. You still need to isolate the signal so that you're only observing one emitter, so signal detection and classification may be necessary, plus filtering. + +Each pair of sensors yields one TDOA, and each TDOA traces out one hyperbola, so the number of hyperbolas we can draw is just the number of sensor pairs. With :math:`N` sensors that is + +.. math:: + + \binom{N}{2} = \frac{N(N-1)}{2}, + +i.e. 3 sensors give 3 hyperbolas, 4 give 6, 5 give 10, and so on. Not all of these are independent, as we will see below, only :math:`N-1` carry new geometric information, but the full set is still useful for averaging out noise. + +The price we pay is that the receivers must share a precise common time reference, a requirement that, as discussed later, is itself a demanding engineering problem because a timing error of one nanosecond corresponds to about 1 foot or 0.3 meters of range error, at least in RF applications. + +************* +TDOA Geometry +************* + +From Time Difference to Range Difference +=============================================== + +Multiplying a measured time difference by the propagation speed converts it into a *range difference*: + +.. math:: + + \Delta r_{ij} = c\,\tau_{ij} = r_i - r_j . + +For acoustic problems :math:`c \approx 343` m/s in air; for radio problems :math:`c \approx 2.998\times10^8` m/s. Note immediately the consequence for accuracy: in air, a :math:`0.1` ms timing error is only :math:`\sim`\3 cm, whereas in free space the same timing error is 30 km. Radio TDOA therefore demands extraordinarily precise timing, a theme we return to repeatedly. + +The diagram below shows an example of an emitter and three sensors, with a time domain plot of the signal being received by each sensor at different times. + +.. image:: ../_images/tdoa_principle.svg + :align: center + :target: ../_images/tdoa_principle.svg + :alt: An emitter and three sensors, with a time domain plot of the signal being received by each sensor at different times. + +The Hyperbola +=================== + +Now think about what a single range difference actually tells us. Suppose we have two sensors, and we have measured that the emitter is, say, 100 meters closer to one sensor than the other. Where could the emitter be? Not at a single spot, it turns out, but anywhere along a curved line. As you slide along that line, the two distances to the sensors both change, but their *difference* stays fixed at 100 meters the whole way. + +That curve has a name: it is a **hyperbola**, with the two sensors sitting at its two focal points. (In 3D the same idea sweeps out a curved surface called a hyperboloid, but the 2D picture is easier to reason about and everything carries over). If we write the emitter position as :math:`\mathbf{u}` and the two sensor positions as :math:`\mathbf{s}_i` and :math:`\mathbf{s}_j`, the hyperbola is just the set of points obeying + +.. math:: + + |\mathbf{u}-\mathbf{s}_i| - |\mathbf{u}-\mathbf{s}_j| = \Delta r_{ij} = \text{constant}, + +which reads "distance to one sensor minus distance to the other equals our measured range difference". A few practical consequences fall right out of this: + +* **A range difference can't exceed the spacing between the two sensors.** Intuitively, the difference of two distances is largest when the emitter lies directly out beyond one sensor along the line connecting them, and even then it can only equal that sensor-to-sensor spacing (often called the *baseline*). So if you ever measure a range difference bigger than the baseline, something is wrong, most likely noise, multipath, or a timing/synchronization error. +* **The sign tells you which side you're on.** A hyperbola actually has two mirror-image branches, one curving toward each sensor. Whether your range difference came out positive or negative picks the branch nearer the closer sensor, so you don't get confused between the two halves. +* **The shape depends on the measurement.** When the range difference is close to the full baseline, the hyperbola hugs the line between the sensors. When the range difference is near zero (the emitter is roughly equidistant), the curve straightens out into the line that perpendicularly bisects the baseline. Near both of these extremes the geometry becomes "ill-conditioned," meaning small measurement errors push the estimated position around a lot, so positioning there is less reliable. + +A single TDOA thus constrains the emitter's position to a curve, not a point. To fix a position we intersect several such curves. Below we plot two sensors, and several hyperbola branches drawn for :math:`\Delta r < 0`, :math:`\Delta r = 0` (the perpendicular bisector), and :math:`\Delta r > 0`. On each hyperbola, the TDOA between the two sensors is constant. If you calculated the TDOA with just two sensors, you would know it is somewhere on that line, but you would need a third sensor to find where on that line it is (performing geolocation). + +.. image:: ../_images/tdoa_hyperbola.svg + :align: center + :target: ../_images/tdoa_hyperbola.svg + :alt: Two sensors, and several hyperbola branches drawn + +Multilateration +===================== + +With :math:`N` sensors we can form pairs and intersect their hyperbolas; the emitter lies at (or near) their common intersection. This process is **hyperbolic multilateration**. Counting degrees of freedom tells us how many sensors we need: + +* In **2D** the emitter position has 2 unknowns :math:`(x,y)`. Each independent TDOA gives one equation, so we need at least 2 independent TDOAs, which requires **3 sensors**. For example, if we know the emitter is on land and we're not having to take into account curvature of the Earth, this would work. +* In **3D** the emitter position has 3 unknowns :math:`(x,y,z)`, requiring 3 independent TDOAs and therefore **4 sensors**. + +In the noiseless case the hyperbolas meet at a single point (with an occasional geometric ambiguity resolved by branch signs or an extra sensor). With more sensors than the minimum the system is *overdetermined*: noisy hyperbolas no longer share an exact common point, and we must solve a least-squares or maximum-likelihood problem, as described below. + +Reference Sensor and Independent Pairs +============================================= + +From :math:`N` sensors one can form :math:`\binom{N}{2}` pairwise TDOAs, but they are not all independent. Choosing one sensor as a **reference** (say sensor 1) and forming :math:`\tau_{i1}` for :math:`i = 2,\dots,N` yields :math:`N-1` TDOAs from which every other pairwise difference can be reconstructed, since :math:`\tau_{ij} = \tau_{i1} - \tau_{j1}`. These :math:`N-1` are the *independent* measurements that carry all the geometric information. + +The redundant pairs are not worthless, however. Because each measured TDOA carries independent *noise*, using all :math:`\binom{N}{2}` pairs (with a correctly modeled, correlated noise covariance, where the reference sensor's noise is common to every :math:`\tau_{i1}`) can improve the estimate. + +Example: A Three-Sensor 2D Fix +============================== + +Place three sensors at + +.. math:: + + \mathbf{s}_1=(0,0),\quad \mathbf{s}_2=(100,0),\quad \mathbf{s}_3=(0,100)\ \text{(meters)}, + +and suppose the true emitter is at :math:`\mathbf{u}=(40,30)`. The emitter-to-sensor distances are + +.. math:: + + r_1=\sqrt{40^2+30^2}=50,\quad + r_2=\sqrt{60^2+30^2}=\sqrt{4500}\approx 67.08,\quad + r_3=\sqrt{40^2+70^2}=\sqrt{6500}\approx 80.62 . + +Taking sensor 1 as reference, the range-difference measurements are + +.. math:: + + \Delta r_{21}=r_2-r_1\approx 17.08\ \text{m},\qquad + \Delta r_{31}=r_3-r_1\approx 30.62\ \text{m}. + +Each defines a hyperbola with foci :math:`\{\mathbf{s}_2,\mathbf{s}_1\}` and :math:`\{\mathbf{s}_3,\mathbf{s}_1\}` respectively; their intersection is the emitter's position. Solving the two hyperbola equations by hand is awkward, which is precisely the motivation for the algebraic linearization developed below, where we will recover :math:`(40,30)` from exactly these numbers in closed form. + +************************************* +The Signal and Measurement Model +************************************* + +Received-Signal Model +============================ + +Each sensor receives a time-delayed, scaled, noisy copy of whatever the emitter is transmitting. Specifically, let :math:`s(t)` be the transmit waveform. Sensor :math:`i` receives: + +.. math:: + + x_i(t) = a_i \, s(t - t_i) + n_i(t), \qquad i = 1,\dots,N, + +where :math:`a_i` is a real (or complex, for passband signals) gain capturing propagation loss and antenna response, :math:`t_i = t_0 + r_i/c` is the absolute arrival time, and :math:`n_i(t)` is additive noise. This model assumes a single dominant line-of-sight path; multipath and non-line-of-sight effects are deferred to a later section. + +Defining the TDOA +======================== + +The pairwise TDOA is the difference of arrival times, + +.. math:: + + \tau_{ij} = t_i - t_j = \frac{r_i - r_j}{c} = \frac{|\mathbf{u}-\mathbf{s}_i| - |\mathbf{u}-\mathbf{s}_j|}{c}. + +The right-hand side makes explicit that the TDOA is a nonlinear function of the emitter coordinates :math:`\mathbf{u}`. The *measurement* problem is to estimate :math:`\tau_{ij}` from the waveforms :math:`x_i, x_j`; the *localization* problem is to invert the nonlinear map from :math:`\mathbf{u}` to the collection of TDOAs. + +Noise Assumptions +======================== + +We assume each :math:`n_i(t)` is zero-mean, wide-sense stationary, Gaussian, and independent of the transmitted signal and of the noise at other sensors. The per-sensor signal-to-noise ratio is + +.. math:: + + \mathrm{SNR}_i = \frac{a_i^2 \sigma_s^2}{\sigma_{n_i}^2}, + +with :math:`\sigma_s^2` and :math:`\sigma_{n_i}^2` the signal and noise powers. These are idealizations; real noise is often colored and partially correlated across sensors, but they lead to estimators and bounds that perform well in practice, and the framework extends to a general noise covariance when needed. + +The Nonlinear Measurement Equations +========================================== + +Collecting the :math:`N-1` reference-based range differences into a vector :math:`\mathbf{m}` with entries :math:`m_i = c\,\tau_{i1} = r_i - r_1`, the noiseless model is + +.. math:: + + \mathbf{m} = \mathbf{h}(\mathbf{u}), \qquad + h_i(\mathbf{u}) = |\mathbf{u}-\mathbf{s}_i| - |\mathbf{u}-\mathbf{s}_1|, + +and the noisy measurement is :math:`\tilde{\mathbf{m}} = \mathbf{h}(\mathbf{u}) + \boldsymbol{\varepsilon}`, where :math:`\boldsymbol{\varepsilon}` is the range-difference error induced by time-delay estimation errors. The function :math:`\mathbf{h}` is nonlinear because of the Euclidean norms, and this nonlinearity is the source of every algorithmic complication that follows. Two broad strategies address it: algebraically *linearize* by introducing an auxiliary variable (described in the next section), or *iteratively* linearize about a current estimate (described further below). + +************************************************* +Time-Delay Estimation (the Measurement Front End) +************************************************* + +Before any geometry can be exploited we must extract the delays :math:`\tau_{ij}` from the raw waveforms. This is the *time-delay estimation* (TDE) problem, and its accuracy ultimately caps the accuracy of the entire system. + +Cross-Correlation +======================== + +The natural estimator exploits the fact that :math:`x_i` and :math:`x_j` are noisy, shifted copies of the same waveform. Their cross-correlation, + +.. math:: + + R_{x_i x_j}(\tau) = \mathbb{E}\!\left[ x_i(t)\, x_j(t+\tau) \right], + +is maximized when the shift :math:`\tau` aligns the two copies, i.e. at :math:`\tau = \tau_{ij}`. The estimator is therefore + +.. math:: + + \hat{\tau}_{ij} = \arg\max_{\tau} \, \hat{R}_{x_i x_j}(\tau). + +In practice the correlation is usually computed efficiently in the frequency domain via the FFT (just like how large convolutions typically use an FFT), using the cross-power spectral density :math:`G_{x_i x_j}(f) = \mathcal{F}\{R_{x_i x_j}(\tau)\}` and an inverse transform. + +Python Simulation +================== + +Enough math, let's see how this all looks with a simple Python example. First we'll set up the simulation with some high level parameters such as emitter and sensor position, and the simulated sample rate, which is essentially how much spectrum the receivers will "see". + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + from matplotlib.lines import Line2D + from itertools import combinations + from scipy.signal import firwin, lfilter + + sample_rate = 50e6 + c = 3e8 # speed of light [m/s] + snr_db = 10 # SNR of the received signal at each receiver [dB] + tx_len_samples = 1000 # samples to transmit + rx_positions = np.array([ + [65, 229], # Rx0 + [676, 123], # Rx1 + [153, 543], # Rx2 + ]) + num_rx = rx_positions.shape[0] + tx_position = np.array([153, 355]) + pairs = list(combinations(range(num_rx), 2)) # For 3 receivers it's (Rx0,Rx1), (Rx0,Rx2), (Rx1,Rx2) -> 3 pairs + +TDOA is not very dependent on the specific signal the transmitter emits, although the bandwidth of the signal does matter, so to keep this simple we'll have it transmit random noise that is band-limited to a specified bandwidth. If we were to use something like QPSK of the same bandwidth instead, nothing would really change. + +.. code-block:: python + + bandwidth = 20e6 + taps = firwin(numtaps=129, cutoff=bandwidth / 2, fs=sample_rate) + tx_signal = lfilter(taps, 1.0, np.random.randn(tx_len_samples) + 1j * np.random.randn(tx_len_samples)) + +Next we will simulate the receivers receiving the signal at a delay based on their position. We will use a fractional delay filter like we learned about in the :ref:`sync-chapter` Chapter. The rest of the code should look relatively straightforward. We make sure to apply unique AWGN per receiver. + +.. code-block:: python + + # Simulate what each receiver records + true_distances = np.linalg.norm(rx_positions - tx_position, axis=1) + true_delays = true_distances / c + unknown_tx_time = 1.234e-5 # seconds. arbitrary, unknown to receivers and we won't use it in any TDOA calcs + + # Calc the actual TDOAs to act as ground truth + for k, (a, b) in enumerate(pairs): + true_rd = true_distances[b] - true_distances[a] + + # Figure out how many samples we have to simulate + total_delay_samples = (unknown_tx_time + true_delays.max()) * sample_rate + buffer_len = tx_len_samples + int(np.ceil(total_delay_samples)) + 10 + + # Taken from Synchronization chapter + def frac_delay_filter(delay): # delay is in samples, but it can (and will be) not an integer + N = 21 # number of taps, keep this odd + n = np.arange(-(N-1)//2, N//2+1) # -10,-9,...,0,...,9,10 + h = np.sinc(n - delay) # calc filter taps + h *= np.hamming(N) # window the filter to make sure it decays to 0 on both sides + h /= np.sum(h) # normalize to get unity gain, we don't want to change the amplitude/power + return h + + # Simulate the delayed signal being received by each sensor + rx_signals = np.zeros((num_rx, buffer_len), dtype=complex) + for i in range(num_rx): + tau = unknown_tx_time + true_delays[i] # absolute delay at this Rx, in seconds + tau_samples = tau * sample_rate + tau_integer_samps = int(np.round(tau_samples)) + tau_frac_samps = tau_samples - tau_integer_samps + rx = np.zeros(buffer_len, dtype=complex) + rx[tau_integer_samps:tau_integer_samps+tx_len_samples] = tx_signal + frac_delay_i = frac_delay_filter(tau_frac_samps) + rx = np.convolve(rx, frac_delay_i, "same") + + # Each receiver adds its own thermal noise, scaled to hit the SNR set at the top + signal_power = np.mean(np.abs(tx_signal)**2) + noise_power = signal_power / 10**(snr_db / 10) + noise = np.sqrt(noise_power / 2) * (np.random.randn(buffer_len) + 1j * np.random.randn(buffer_len)) + rx_signals[i] = rx + noise + +Everything so far was purely for simulation, the rest represents what you would actually do to calculate the TDOA, typically at a central location or one of the sensors, but it needs access to the samples received at all three sensors. It's not a lot of code, we simply loop through each pair of sensors, calculate the cross-correlation between their received samples, and pull out the peak. Later we will see how to do the subsample version of this for more granularity. + +.. code-block:: python + + # Estimate the TDOAs using a normal cross-correlation + range_diff = np.zeros(len(pairs)) # meters + for k, (a, b) in enumerate(pairs): + xcorr = np.correlate(rx_signals[b], rx_signals[a], mode='full') + peak_lag = np.argmax(np.abs(xcorr)) - (buffer_len - 1) # 'full' puts zero lag at index buffer_len-1 + range_diff[k] = (peak_lag / sample_rate) * c # meters + +Not much to it! This gives us the following results: + +.. image:: ../_images/tdoa_python_integer.svg + :align: center + :target: ../_images/tdoa_python_integer.svg + :alt: Python simulation output when doing integer correlation + +Note that this code doesn't fully "solve" the problem, even though it might seem like it does at first glance because the lines intersect exactly at the position of the emitter, but it's really your brain doing the final "solving" of the position, by looking at the intersection of the hyperbolas. Also, if there was more noise, the hyperbolas would not all intersect at one point. We will dive into automated solutions later in this chapter. + +The full Python code (including the plotting portion) can be found `here `_. + +Resolution and Sub-Sample Estimation +========================================== + +With sampling rate :math:`f_s`, the correlation is computed on a lag grid spaced :math:`1/f_s` apart, so the naive peak resolution is one sample, i.e. :math:`c/f_s` in range. This is usually far too coarse, especially if the sensors (and emitter) are close together, e.g., less than 100 meters. There are two options for sub-sample refinement, one way is to interpolate the signals as part of the cross-correlation, and another is to fit a model to the samples around the discrete peak. For the latter, parabolic interpolation through the peak and its two neighbors is the simplest, while sinc-based interpolation is more accurate because the true correlation of a band-limited signal is a sinc-like function. Good interpolation routinely yields delay estimates one to two orders of magnitude finer than the sample period. Below we show an example of doing the interpolated cross-correlation. + +.. code-block:: python + + U = 16 # correlation upsampling factor + half = (buffer_len + 1) // 2 # number of DC + positive-frequency bins + range_diff = np.zeros(len(pairs)) # meters + for k, (a, b) in enumerate(pairs): + # Cross-correlation in the frequency domain + X = np.conj(np.fft.fft(rx_signals[a])) * np.fft.fft(rx_signals[b]) + + # Insert zeros in the high-frequency MIDDLE: DC + positive freqs at the front, negative freqs at the back, so it stays a valid FFT layout. + X_padded = np.zeros(U * buffer_len, dtype=complex) + X_padded[:half] = X[:half] + X_padded[U * buffer_len - (buffer_len - half):] = X[half:] + + # Now IFFT to finish the crosscorrelation + xcorr = np.abs(np.fft.ifft(X_padded)) * U + + # Peak index -> signed lag; indices past the midpoint are negative lags + peak_idx = np.argmax(xcorr) + if peak_idx > U * buffer_len // 2: + peak_idx -= U * buffer_len + peak_lag = peak_idx / U # sub-sample lag, +ve => Rx_b farther + range_diff[k] = (peak_lag / sample_rate) * c # meters + +When doing the same Python simulation as before, but with subsampling, we get the following results. You would have to zoom in on the left-hand plot to see the accuracy difference. + +.. image:: ../_images/tdoa_python_subsample.svg + :align: center + :target: ../_images/tdoa_python_subsample.svg + :alt: Python simulation output when doing subsample correlation + +Looking at the right-hand plot, we can see how the original integer-only method was off by a decent margin. + +The Generalized Cross-Correlation Framework +================================================== + +Plain cross-correlation is fragile: if the transmitted signal is narrow in bandwidth or the channel contains multipath, the correlation peak is broad and easily shifted by noise. Knapp and Carter's *Generalized Cross-Correlation* (GCC) addresses this by inserting a frequency weighting :math:`\Psi(f)` before transforming back to the lag domain: + +.. math:: + + R^{\mathrm{GCC}}_{x_i x_j}(\tau) = \int_{-\infty}^{\infty} \Psi(f)\, G_{x_i x_j}(f)\, e^{j 2\pi f \tau}\, df . + +The weighting reshapes the spectrum to sharpen and stabilize the peak. Different choices of :math:`\Psi(f)` correspond to different classical estimators, and selecting it well is the heart of robust TDE. Common weightings include: + +* **Cross-correlation** (:math:`\Psi = 1`): the maximum-likelihood choice only in the high-SNR, broadband-flat limit; otherwise suboptimal. +* **Roth** (:math:`\Psi = 1/G_{x_i x_i}(f)`): suppresses frequencies where one sensor is noisy. +* **SCOT** (Smoothed Coherence Transform, :math:`\Psi = 1/\sqrt{G_{x_i x_i}G_{x_j x_j}}`): symmetric whitening of both channels. +* **PHAT** (Phase Transform, :math:`\Psi = 1/|G_{x_i x_j}(f)|`): the most widely used choice in acoustics. + +Diving deeper into the **GCC-PHAT** estimator- by dividing out the magnitude of the cross-spectrum it retains *only the phase*: + +.. math:: + + R^{\mathrm{PHAT}}_{x_i x_j}(\tau) = \int \frac{G_{x_i x_j}(f)}{\bigl|G_{x_i x_j}(f)\bigr|} e^{j2\pi f \tau} df . + +Because the delay between two copies of a signal is encoded entirely in the *linear phase* term :math:`e^{-j2\pi f \tau_{ij}}`, while the magnitude carries the (often unhelpful) spectral shape and reverberant coloring, whitening to unit magnitude weights every frequency equally and produces a sharp, near-impulsive peak at the true delay. This makes PHAT strikingly robust to multipath. Its weakness is that it also whitens noise-dominated frequencies, so at low SNR the equal weighting amplifies noise; SNR-aware variants reintroduce a coherence-based weighting to compensate. In real systems, because most signals are not always on, you typically have to determine the time-frequency bounding box of the target signal before performing TDOA, so unless there is a lot of interference you can estimate the SNR pretty easily. + +Practical Considerations +================================ + +Several effects govern the accuracy of the TDOA results: + +* The **integration window** :math:`T` trades estimator variance (longer is better, since variance falls roughly as :math:`1/T`) against the stationarity assumption and, for moving emitters, against blurring of the delay over the window. Many times this value is determined by the signal itself, e.g. you might perform TDOA on a per-packet basis. +* **Coherence bandwidth** limits which frequencies actually carry usable phase. +* **Signal bandwidth** is decisive: as the Cramér-Rao analysis below shows, delay variance falls as the *square* of the bandwidth, so wideband signals localize far better than narrowband ones, unlike DOA where we didn't care about bandwidth (in fact, many of the DOA concepts used a narrowband assumption). That being said, you don't need to capture the entire signal (from a frequency domain perspective) to perform TDOA, if you are limited by your SDR's maximum sample rate, and you can only receive a portion of the signal bandwidth, you can still do TDOA! + +From a compute perspective, the TDOA computation is dominated by FFTs and is :math:`O(M\log M)` per sensor pair for records of :math:`M` samples, which is what makes large sensor networks tractable. + +GCC-PHAT Python Example +============================================ + +The nice thing about PHAT is that we can fold it into the simulation we already built with almost no new code. Recall that the sub-sample estimator above already worked in the frequency domain: it formed the cross-spectrum :math:`X_a^*(f)\,X_b(f)`, zero-padded it to interpolate, and inverse-FFT to recover the lag-domain correlation. PHAT is just one extra line: before transforming back to the lag domain, we divide the cross-spectrum by its own magnitude, so that every frequency bin contributes with unit weight and only the phase, which is where the delay lives, survives. + +.. code-block:: python + + U = 16 # correlation upsampling factor + half = (buffer_len + 1) // 2 # number of DC + positive-frequency bins + range_diff = np.zeros(len(pairs)) # meters + for k, (a, b) in enumerate(pairs): + # Cross-spectrum, same as the sub-sample example + X = np.conj(np.fft.fft(rx_signals[a])) * np.fft.fft(rx_signals[b]) + + # PHAT weighting: divide out the magnitude so only the phase remains + X = X / (np.abs(X) + 1e-12) # small epsilon avoids divide-by-zero + + # Zero-pad in the high-frequency middle to interpolate, then IFFT + X_padded = np.zeros(U * buffer_len, dtype=complex) + X_padded[:half] = X[:half] + X_padded[U * buffer_len - (buffer_len - half):] = X[half:] + xcorr = np.abs(np.fft.ifft(X_padded)) * U + + # Peak index -> signed lag; indices past the midpoint are negative lags + peak_idx = np.argmax(xcorr) + if peak_idx > U * buffer_len // 2: + peak_idx -= U * buffer_len + peak_lag = peak_idx / U # sub-sample lag, +ve => Rx_b farther + range_diff[k] = (peak_lag / sample_rate) * c # meters + +The only change from the sub-sample code is the single ``X = X / (np.abs(X) + 1e-12)`` line; the small epsilon in the denominator keeps frequency bins that hold almost no energy from blowing up when we divide. With our wideband, high-SNR simulated signal the result barely differs from plain cross-correlation, because PHAT and cross-correlation coincide in exactly that broadband, high-SNR limit. The payoff shows up in harder conditions: when the spectrum is colored or multipath smears the peak, whitening to unit magnitude collapses the correlation back to a sharp, near-impulsive spike at the true delay, which is why PHAT is the default in acoustics. + +************************************* +Closed-Form Localization Algorithms +************************************* + +The measurement equations above are nonlinear and, taken directly, require iterative solution with a good starting point. *Closed-form* (non-iterative) estimators sidestep this by an algebraic trick: introduce an auxiliary variable that absorbs the nonlinearity and renders the system linear. They are fast, need no initial guess, and cannot get stuck in local minima, making them invaluable both on their own and as initializers for the iterative methods described below. + +The Linearization Strategy +================================== + +The trick is to square the range equations and subtract pairs, which cancels the nonlinear :math:`x^2+y^2` term and introduces :math:`r_1`, the range to the reference sensor, as a single auxiliary unknown. Starting with the squared range from the emitter :math:`\mathbf{u}=(x,y)` to sensor :math:`i` at :math:`\mathbf{s}_i=(x_i,y_i)`: + +.. math:: + + r_i^2 = (x-x_i)^2 + (y-y_i)^2 = K_i - 2x_i x - 2y_i y + (x^2+y^2), + \qquad K_i \equiv x_i^2 + y_i^2 . + +The troublesome term is :math:`x^2+y^2`, common to every sensor. Take sensor 1 as reference and subtract its equation from sensor :math:`i`'s: + +.. math:: + + r_i^2 - r_1^2 = (K_i - K_1) - 2(x_i-x_1)x - 2(y_i-y_1)y . + +Now use the measured range difference :math:`r_{i1}\equiv r_i - r_1 = c\,\tau_{i1}`. Since :math:`r_i = r_{i1}+r_1`, we have :math:`r_i^2 = r_{i1}^2 + 2r_{i1}r_1 + r_1^2`, so :math:`r_i^2 - r_1^2 = r_{i1}^2 + 2 r_{i1} r_1`. Substituting and rearranging, + +.. math:: + + \boxed{2(x_i-x_1)\,x + 2(y_i-y_1)\,y + 2 r_{i1} r_1 = K_i - K_1 - r_{i1}^2} + +This equation is **linear** in the unknowns :math:`(x, y, r_1)`, where the range to the reference :math:`r_1` is treated as an auxiliary variable. Stacking it for :math:`i=2,\dots,N` gives a linear system :math:`\mathbf{A}\boldsymbol{\theta} = \mathbf{b}` with :math:`\boldsymbol{\theta}=[x,y,r_1]^\top`, solvable by ordinary or weighted least squares. The nonlinearity has been quarantined into the single extra unknown :math:`r_1`. + +Spherical Interpolation and Spherical Intersection +========================================================= + +The earliest closed-form estimators, Spherical Interpolation (SI) and Spherical Intersection (SX) of Schau and Robinson, exploit exactly this structure. They first solve the linear system for :math:`(x,y)` as a function of :math:`r_1`, then impose the constraint that ties them together, namely :math:`r_1^2 = (x-x_1)^2+(y-y_1)^2`, to pin down :math:`r_1`. SI obtains :math:`r_1` by a least-squares projection; SX substitutes the linear solution into the quadratic constraint and solves the resulting scalar quadratic. They are simple and fast but treat the auxiliary variable somewhat crudely, leaving accuracy on the table at higher noise. + +Fang's Method +==================== + +Fang's algorithm provides an exact algebraic solution for the *minimum* configuration (3 sensors in 2D, 4 in 3D), giving a determined system rather than an overdetermined one. It is elegant and computationally trivial but does not use redundant sensors, so it cannot average down measurement noise and is sensitive to geometry. It is best viewed as the exact-determined special case that the least-squares methods generalize. + +To see how it works, look again at the boxed linear equation above. With three sensors there are exactly two such equations (:math:`i=2,3`) but three unknowns :math:`(x,y,r_1)`. That looks underdetermined, but :math:`r_1` is not free: it is glued to the position by :math:`r_1^2=(x-x_1)^2+(y-y_1)^2`. Fang's trick is to *defer* that constraint, treat :math:`r_1` as a known constant, and solve the two linear equations for :math:`x` and :math:`y`. Because :math:`r_1` enters linearly, inverting the :math:`2\times2` matrix (well-conditioned as long as the sensors are not collinear) gives both coordinates as straight-line functions of the still-unknown range, + +.. math:: + + x = g_x + h_x\,r_1, \qquad y = g_y + h_y\,r_1 , + +with constants :math:`g_x,h_x,g_y,h_y` from the matrix inverse. Now cash in the deferred constraint: substituting these into :math:`r_1^2=(x-x_1)^2+(y-y_1)^2` collapses everything to a single scalar quadratic :math:`a\,r_1^2 + b\,r_1 + c = 0`. Solve it, keep the physical root (a range must be positive; the other root typically lands on the wrong hyperbola branch), and back-substitute to read off :math:`(x,y)`. That is the whole method: one :math:`2\times2` solve and one quadratic, no iteration and no initial guess. The worked example in the next subsection is precisely this procedure carried out with numbers. + +Chan's Method (Two-Step Weighted Least Squares) +====================================================== + +The estimator that became the practical standard is Chan and Ho's two-step weighted least squares (WLS). It is built on the linear system above but treats the statistics correctly and refines the auxiliary variable, achieving accuracy close to the Cramér-Rao bound at small-to-moderate noise. + +**First step.** Treat :math:`\boldsymbol{\theta}=[x,y,r_1]^\top` as if its three components were independent and solve the linear system by weighted least squares, + +.. math:: + + \hat{\boldsymbol{\theta}} = (\mathbf{A}^\top \mathbf{W}\mathbf{A})^{-1}\mathbf{A}^\top \mathbf{W}\,\mathbf{b}, + +with the weight :math:`\mathbf{W}` chosen as the inverse covariance of the equation errors. Because that covariance itself depends on the unknown ranges, in practice one first solves with :math:`\mathbf{W}=\mathbf{I}` (or the raw TDOA noise covariance), then recomputes :math:`\mathbf{W}` from the resulting range estimates and re-solves, a one- or two-pass refinement. + +**Second step.** The first step ignored the known relationship :math:`r_1^2 = (x-x_1)^2+(y-y_1)^2` that couples the auxiliary variable to the position. The second step restores it: form a new small least-squares problem in the squared quantities :math:`[(x-x_1)^2,(y-y_1)^2,r_1^2]`, using the first-step covariance to weight it, and solve for a corrected position. This second WLS removes much of the bias of the naive linear solution and is what brings Chan's estimator close to optimal. + +The method returns a position directly, with computational cost dominated by inverting small :math:`3\times3` matrices, negligible compared with the FFTs of the front end. Its limitations appear at high noise or unfavorable geometry, where the squared-range manipulation amplifies errors and the second step can pick the wrong root; there, the iterative refinement described below, seeded by Chan's output, is the standard remedy. + +Example, Continued: Solving the Three-Sensor Fix in Closed Form +================================================================ + +Let's pick up right where the Python simulation left off. At that point we had the ``range_diff`` array holding one measured range difference per sensor pair, and earlier we let our brain do the final step by eyeballing where the hyperbolas crossed. Now we'll replace that eyeballing with the closed-form algebra developed above, recovering the emitter position directly from ``range_diff`` and ``rx_positions``. Because we have exactly three sensors in 2D, this is Fang's minimum-configuration case: two boxed linear equations and one quadratic, no iteration and no initial guess. + +We take ``Rx0`` as the reference sensor. The pairs were built as ``(0,1)``, ``(0,2)``, ``(1,2)``, and recall that ``range_diff[k]`` for pair ``(a,b)`` is :math:`r_b - r_a`, so the two pairs that include the reference, ``(0,1)`` and ``(0,2)``, hand us exactly the reference-based range differences :math:`r_{i0}=r_i-r_0` that the boxed equation needs. + +.. code-block:: python + + # Solve for the emitter position in closed form (Fang's method, 3 sensors in 2D) + ref = 0 # use Rx0 as the reference sensor + s = rx_positions.astype(float) + K = np.sum(s**2, axis=1) # K_i = x_i^2 + y_i^2 for each sensor + + # Reference-based range differences r_i0 = r_i - r_ref for the two non-reference sensors + others = [i for i in range(num_rx) if i != ref] + r_i0 = np.array([range_diff[pairs.index((ref, i))] for i in others]) # pair (ref,i) holds r_i - r_ref + + # Build the 2x2 linear system that gives (x, y) as a function of the unknown range r_ref + M = 2 * (s[others] - s[ref]) # rows: [2(x_i - x_ref), 2(y_i - y_ref)] + d = K[others] - K[ref] - r_i0**2 # right-hand side constants + Minv = np.linalg.inv(M) # well-conditioned as long as the sensors aren't collinear + g = Minv @ d # part of (x, y) that doesn't depend on r_ref + h = -2 * (Minv @ r_i0) # how (x, y) slide with r_ref: [x, y] = g + h * r_ref + + # Cash in the deferred constraint r_ref^2 = (x - x_ref)^2 + (y - y_ref)^2 -> scalar quadratic in r_ref + p = g - s[ref] # constant part of (x - x_ref, y - y_ref) + a_q = h[0]**2 + h[1]**2 - 1 + b_q = 2 * (p[0]*h[0] + p[1]*h[1]) + c_q = p[0]**2 + p[1]**2 + roots = np.roots([a_q, b_q, c_q]) + + # Keep the physical root (a range must be positive and real), then back-substitute + r_ref = roots[(roots.real > 0) & (np.abs(roots.imag) < 1e-6)].real.max() + emitter_est = g + h * r_ref + + print("Estimated emitter position:", emitter_est) # ~[153, 355] + print("True emitter position: ", tx_position) + +The structure mirrors the math exactly: ``M`` and ``d`` are the two boxed linear equations, ``g`` and ``h`` express :math:`x` and :math:`y` as straight-line functions of the still-unknown reference range :math:`r_1` (called ``r_ref`` here), and substituting those into :math:`r_1^2=(x-x_1)^2+(y-y_1)^2` collapses everything to the scalar quadratic that ``np.roots`` solves. We discard the non-physical (negative or complex) root, keep the positive real one, and back-substitute to read off the position. With our high-SNR, wideband simulation the estimate lands right on top of the true emitter at :math:`(153, 355)`, with no human in the loop reading off a hyperbola intersection. + +With noisier measurements the two linear equations would no longer be perfectly consistent, the quadratic root would be perturbed, and, because three sensors give us no redundancy to average over, the error would pass straight through. That is exactly where the redundant pairs and the weighting and second step of Chan's method earn their keep, governing how gracefully the estimate degrades. + +***************************************** +Iterative and Statistical Estimation +***************************************** + +Closed-form methods are fast but make algebraic approximations that cost accuracy at high noise or poor geometry. When the best possible estimate is required, we solve the nonlinear estimation problem directly, typically initialized by a closed-form result. + +Nonlinear Least Squares +============================== + +Define the residual between measured and predicted range differences and minimize its weighted squared norm: + +.. math:: + + \hat{\mathbf{u}} = \arg\min_{\mathbf{u}} \bigl[\tilde{\mathbf{m}} - \mathbf{h}(\mathbf{u})\bigr]^\top \mathbf{C}^{-1} \bigl[\tilde{\mathbf{m}} - \mathbf{h}(\mathbf{u})\bigr], + +where :math:`\mathbf{C}` is the covariance of the range-difference errors. This cost has no closed-form minimizer because :math:`\mathbf{h}` is nonlinear, so we descend it iteratively. + +Taylor-Series (Gauss-Newton) Method +========================================== + +Foy's classical approach linearizes :math:`\mathbf{h}` about the current estimate :math:`\mathbf{u}^{(k)}` using its Jacobian :math:`\mathbf{J}`, whose row :math:`i` is the gradient of :math:`h_i`: + +.. math:: + + \frac{\partial h_i}{\partial \mathbf{u}} = \frac{\mathbf{u}-\mathbf{s}_i}{|\mathbf{u}-\mathbf{s}_i|} - \frac{\mathbf{u}-\mathbf{s}_1}{|\mathbf{u}-\mathbf{s}_1|} + = \hat{\mathbf{e}}_i - \hat{\mathbf{e}}_1, + +a difference of *unit vectors* pointing from the candidate emitter toward sensor :math:`i` and the reference. The Gauss-Newton update is + +.. math:: + + \mathbf{u}^{(k+1)} = \mathbf{u}^{(k)} + (\mathbf{J}^\top \mathbf{C}^{-1}\mathbf{J})^{-1}\mathbf{J}^\top \mathbf{C}^{-1}\bigl[\tilde{\mathbf{m}}-\mathbf{h}(\mathbf{u}^{(k)})\bigr], + +iterated to convergence. Each step solves a small linear system. The method converges quickly *when started near the solution*, which is exactly why Chan's closed-form estimate is the preferred seed: it places the iteration in the basin of the global minimum and avoids the spurious local minima that plague hyperbolic cost surfaces, especially in poor geometry. + +Maximum-Likelihood Estimation +===================================== + +Under Gaussian noise, the negative log-likelihood is, up to constants, exactly the weighted squared residual above. So **the maximum-likelihood estimator coincides with weighted nonlinear least squares**, the Gauss-Newton iteration is not a heuristic, it is the statistically optimal estimator under the assumed model. This is also the estimator whose covariance the Cramér-Rao bound below predicts. + +Let's put that to work by continuing the Python example one more time. We already have a position from the closed-form solver, ``emitter_est``, and the theory tells us two things: the maximum-likelihood estimate is just the Gauss-Newton iteration above, and the closed-form fix is the ideal seed for it because it drops us right inside the basin of the true minimum. So we'll start at ``emitter_est`` and take a few Gauss-Newton steps, each one re-linearizing the range-difference model at the current guess and solving a tiny least-squares problem for the correction. Unlike Fang's solver, which used only the two pairs touching the reference sensor, this one uses *all three* pairs in ``range_diff``, so the extra pair acts as redundancy that the iteration averages over. + +.. code-block:: python + + # Refine the closed-form fix with Gauss-Newton (= maximum likelihood under Gaussian noise) + u = emitter_est.copy() # seed the iteration with the closed-form estimate + for _ in range(10): + h = np.zeros(len(pairs)) # predicted range differences at the current guess + J = np.zeros((len(pairs), 2)) # Jacobian, one row per pair + for k, (a, b) in enumerate(pairs): + e_a = (u - s[a]) / np.linalg.norm(u - s[a]) # unit vector from Rx_a toward the guess + e_b = (u - s[b]) / np.linalg.norm(u - s[b]) # unit vector from Rx_b toward the guess + h[k] = np.linalg.norm(u - s[b]) - np.linalg.norm(u - s[a]) # predicted r_b - r_a + J[k] = e_b - e_a # row of the Jacobian is a difference of unit bearing vectors + + residual = range_diff - h # measured minus predicted range differences + delta, *_ = np.linalg.lstsq(J, residual, rcond=None) # Gauss-Newton step (J^T J)^-1 J^T residual + u = u + delta + if np.linalg.norm(delta) < 1e-9: # stop once the update stops moving the estimate + break + + emitter_ml = u + print("ML (Gauss-Newton) estimate:", emitter_ml) # ~[153, 355] + print("True emitter position: ", tx_position) + +A couple of details worth pointing out. Because we assumed the range-difference errors are independent with equal variance, the weight :math:`\mathbf{C}^{-1}=\sigma^{-2}\mathbf{I}` is a scalar that cancels out of the update, which is why a plain ``np.linalg.lstsq`` (no weight matrix) computes the step exactly; if the pairs had unequal quality we would fold their inverse variances in here. The Jacobian rows are literally the ``e_b - e_a`` differences of unit bearing vectors from the math above, so you can watch the geometry enter the estimator directly. Starting from the already-good closed-form seed, the iteration converges in just a handful of steps and lands on the true emitter at :math:`(153, 355)`. In our high-SNR simulation it barely moves off the closed-form answer, but with noisier measurements this is where the extra pair and the iterative refinement pay off, and it is this same :math:`\mathbf{J}^\top\mathbf{C}^{-1}\mathbf{J}` that reappears in the Cramér-Rao bound below as the estimator's covariance. + +Robust, Recursive, and Bayesian Extensions +================================================== + +Real measurements contain outliers, a multipath-corrupted TDOA can be wildly wrong while the rest are fine. Plain least squares, which squares residuals, is badly distorted by such outliers. *Robust* estimators replace the squared loss with one that grows more slowly (e.g. Huber's), or explicitly detect and discard inconsistent TDOAs via residual tests or RANSAC-style consensus. + +When the emitter *moves*, we want to fuse measurements over time rather than localize each instant independently. State-space filtering does this by modeling the emitter's position (and velocity) as an evolving state. The **Kalman filter** is optimal for linear-Gaussian dynamics, but the TDOA measurement is nonlinear, so practitioners use the **Extended Kalman Filter** (which linearizes the measurement with the same Jacobian as above), the **Unscented Kalman Filter** (which propagates a deterministic set of sigma points through the nonlinearity, avoiding explicit Jacobians and handling stronger nonlinearity better), or, for multimodal or heavily non-Gaussian problems, the **particle filter** (which represents the posterior by a weighted sample cloud). These trackers also naturally enforce motion continuity, which suppresses the per-snapshot ambiguities of static localization. + +**************************** +Brute-Force Heatmap Approach +**************************** + +Every method so far has been algebraic or iterative: we manipulated equations or descended a gradient. But there is a refreshingly simple alternative that needs neither. Lay a grid over the search area, and at every candidate position ask a single question: *if the emitter were here, what range differences would the sensors see, and how far off are those from what we actually measured?* Squaring and summing those mismatches gives a cost at each grid point, and the emitter is wherever that cost is smallest. The result is a heatmap of the same cost surface the Gauss-Newton iteration was quietly walking down, except now we can see all of it at once. + +Back to the Python example, we can do this with the variables we already have, ``range_diff``, ``rx_positions``, and ``pairs``: + +.. code-block:: python + + # Evaluate the TDOA cost on a grid of candidate emitter positions + gx = np.linspace(0, 700, 400) + gy = np.linspace(0, 700, 400) + GX, GY = np.meshgrid(gx, gy) + + cost = np.zeros_like(GX) + for k, (a, b) in enumerate(pairs): + r_a = np.hypot(GX - rx_positions[a, 0], GY - rx_positions[a, 1]) # range to Rx_a + r_b = np.hypot(GX - rx_positions[b, 0], GY - rx_positions[b, 1]) # range to Rx_b + cost += ((r_b - r_a) - range_diff[k])**2 # squared mismatch for this pair, summed over pairs + + # The best estimate is simply the grid cell with the lowest cost + iy, ix = np.unravel_index(np.argmin(cost), cost.shape) + emitter_grid = np.array([gx[ix], gy[iy]]) + print("Grid estimate:", emitter_grid) # ~[153, 355] + + # Invert the cost into a likelihood-style surface so higher = more likely emitter location + likelihood = -np.log10(cost + 1e-9) + +Plotting ``likelihood`` as an image reveals the geometry directly: the bright ridges trace out the hyperbolas from earlier, and they all funnel into one bright peak at the true emitter. We take the negative log of the cost so that the most likely location is the maximum rather than a minimum, which is easier to read off visually. The trade-offs are exactly what you'd expect. The method is dead simple, needs no initial guess, and cannot diverge or land on the wrong root, so it is a great sanity check and a robust way to *seed* the iterative refiner. It also handles multimodal cost surfaces gracefully, since it sees every minimum, not just the nearest one. The price is resolution and speed: accuracy is limited by the grid spacing, and cost grows with the number of grid cells, so for a fine answer over a large area you would localize coarsely first and then refine, either by zooming the grid or by handing the result to Gauss-Newton. Below shows the heatmap approach applied to our Python example. + +.. image:: ../_images/tdoa_python_heatmap.svg + :align: center + :target: ../_images/tdoa_python_heatmap.svg + :alt: Adding heatmap to the tdoa plot shown earlier + +One nice part about the heatmap approach is if there is a lot of error, or sensors with low SNR without realizing it, there may be multiple hot spots on the heatmap, which your brain can notice. The heatmap can even be overlaid on top of a satellite view of the area! + +This brute-force approach is not very computationally efficient, and it's not really an option at all for 3D TDOA. One alternative to calculating every grid point but still brute-forcing it is to draw all of the hyperbolas in 2D but with "width" applied to each one, e.g. by applying a lobe shaped function along the hyperbola so it tapers off. + +*********************************************** +Performance Analysis and Fundamental Bounds +*********************************************** + +Having estimators in hand, we ask: how accurate *can* a TDOA system be, and what governs that accuracy? Two ideas answer this: the Cramér-Rao bound, which sets a noise floor from the signals, and geometric dilution of precision, which describes how sensor-emitter geometry amplifies that floor. + +Error Propagation +======================== + +System accuracy is a two-stage cascade. First, finite SNR and bandwidth limit how precisely each delay can be measured (TDE error). Second, the geometry maps those range-difference errors into a position error. Writing :math:`\delta\mathbf{u}` for the position error and :math:`\boldsymbol{\varepsilon}` for the range-difference errors, the linearized relation near the solution is :math:`\boldsymbol{\varepsilon}\approx \mathbf{J}\,\delta\mathbf{u}`, so the position-error covariance is + +.. math:: + + \mathrm{Cov}(\hat{\mathbf{u}}) \approx (\mathbf{J}^\top \mathbf{C}^{-1}\mathbf{J})^{-1}. + +This single expression contains both stages: :math:`\mathbf{C}` is the measurement quality (from TDE) and :math:`\mathbf{J}` is the geometry. + +The Time-Delay Estimation Bound +======================================= + +We can bound how well any estimator can measure a single delay. For a signal of RMS bandwidth :math:`\beta` observed over time :math:`T`, the variance of any unbiased delay estimate obeys + +.. math:: + + \mathrm{var}(\hat\tau_{ij}) \gtrsim \frac{1}{8\pi^2 \beta^2 T \gamma}, + +where :math:`\beta` is the *RMS (Gabor) bandwidth* of the signal and :math:`\gamma` is an effective SNR factor combining the two sensors' SNRs. Three design lessons fall straight out: variance improves with **integration time** :math:`T`, with **effective SNR** :math:`\gamma`, and, most strikingly, with the **square of bandwidth** :math:`\beta^2`. Doubling the bandwidth quarters the delay variance. This is why wideband and spread-spectrum waveforms are so prized for ranging, and why narrowband emitters are intrinsically hard to localize by TDOA alone. + +The Localization Cramér-Rao Lower Bound +============================================== + +Combining measurement quality and geometry, the Fisher information matrix for the emitter position is + +.. math:: + + \mathbf{F} = \mathbf{J}^\top \mathbf{C}^{-1} \mathbf{J}, + +and the Cramér-Rao Lower Bound states that *any* unbiased estimator has covariance no smaller than its inverse: + +.. math:: + + \mathrm{Cov}(\hat{\mathbf{u}}) \succeq \mathbf{F}^{-1} = (\mathbf{J}^\top \mathbf{C}^{-1}\mathbf{J})^{-1}. + +The bound is the benchmark against which estimators are judged: a method that attains it is *efficient*. The maximum-likelihood estimator above attains it asymptotically (large :math:`T`, high SNR), and Chan's closed-form method attains it at small noise, which is exactly why both are used. The CRLB also cleanly separates the two influences on accuracy: :math:`\mathbf{C}` (signal-and-noise quality, improvable by more bandwidth, power, or integration) and :math:`\mathbf{J}` (geometry, improvable by sensor placement), studied next. The plot below shows a few example bandwidths and the lower bound over SNR, to give you a feel for how much error you should expect, or at least the floor. The y-axis is the 1-:math:`\mathrm{\sigma}` value (one standard deviation). + +.. image:: ../_images/tdoa_cramer_rao.svg + :align: center + :target: ../_images/tdoa_cramer_rao.svg + :alt: Plot of cramer rao lower bound + + +Geometric Dilution of Precision +======================================= + +Suppose your sensors can measure range differences to about 1 m of accuracy, a respectable number for a well-synchronized radio system. You might expect to then pin down the emitter to roughly 1 m as well. But where is the emitter? Picture it sitting comfortably inside a triangle of three sensors: the hyperbolas from each sensor pair slice across one another at steep, nearly right angles, and where they cross is pinned down tightly, so your 1 m of ranging error turns into maybe 1.5 m of position error. Now slide that same emitter far off to one side, well outside the cluster. The hyperbolas now graze each other at a shallow angle, like two gently curving lines that nearly overlap, and the crossing point smears out along the direction they share. The very same 1 m of ranging error can now balloon into tens of meters of position error. Nothing about your hardware changed, only the geometry did. + +That blow-up factor has a name: **Geometric Dilution of Precision** (GDOP). It captures how much the sensor-emitter layout magnifies measurement error into position error. If the range-difference errors are independent and each has the same standard deviation :math:`\sigma`, so the covariance is :math:`\mathbf{C}=\sigma^2\mathbf{I}` (a diagonal matrix with :math:`\sigma^2` on the diagonal), then + +.. math:: + + \mathrm{GDOP} = \sqrt{\mathrm{tr}\bigl[(\mathbf{J}^\top\mathbf{J})^{-1}\bigr]}, \qquad + \sigma_{\text{position}} = \mathrm{GDOP}\cdot \sigma . + +Your position error is just your ranging error multiplied by GDOP, so GDOP is a unitless number, always :math:`\ge 1`, telling you the factor by which ranging error gets magnified at a given emitter location. + +Where does the magnification come from? It is baked into the Jacobian :math:`\mathbf{J}`, whose rows are differences of unit bearing vectors :math:`\hat{\mathbf{e}}_i - \hat{\mathbf{e}}_1` (the direction to one sensor minus the direction to another). When those directions point all over the place, :math:`\mathbf{J}^\top\mathbf{J}` is *well-conditioned* (far from singular, so its inverse stays small) and GDOP is small. When they nearly line up, :math:`\mathbf{J}^\top\mathbf{J}` becomes nearly singular and GDOP blows up. So an emitter surrounded by the sensors, with bearing vectors well-spread and hyperbolas crossing at large angles, gets a small GDOP (good), while an emitter far outside the cluster, or sensors nearly collinear (almost in a straight line), leaves the bearing vectors nearly parallel and the hyperbolas grazing at shallow angles, giving a huge GDOP (bad). + +This is the same effect we saw when hyperbolas degenerate near the ends of the baseline. The takeaway: a TDOA system can be limited far more by *where its sensors sit* than by *how well it measures time*, all the nanosecond synchronization and wide bandwidth in the world won't save a fix in a high-GDOP region of the map. + +The figure below shows GDOP heat maps over a plane for (left) three sensors at the vertices of an equilateral triangle and (right) three nearly collinear sensors, showing a broad low-GDOP region inside the triangle versus a narrow usable corridor for the collinear array, with GDOP rising sharply outside the convex hull in both cases. + +.. image:: ../_images/tdoa_gdop.svg + :align: center + :target: ../_images/tdoa_gdop.svg + :alt: GDOP heat maps over a plane for (left) three sensors at the vertices of an equilateral triangle and (right) three nearly collinear sensors, showing a broad low-GDOP region inside the triangle versus a narrow usable corridor for the collinear array, with GDOP rising sharply outside the convex hull in both cases. + +Sensor-Placement Optimization +===================================== + +Because geometry is often a *design* variable, we can place sensors to minimize error. Common objectives minimize a scalar derived from :math:`\mathbf{F}^{-1}`, such as its trace (equivalent to GDOP), its determinant (the confidence-ellipse volume), or its largest eigenvalue (worst-case error). The qualitative results are intuitive: spread the sensors widely so long baselines sharpen angular resolution, surround the region of interest so emitters fall inside the convex hull, avoid collinear or coplanar layouts that create ill-conditioned directions, and add sensors where redundancy both lowers variance and guards against outliers. For a moving target or large coverage area, placement is optimized over the whole region, minimizing average or worst-case GDOP, usually by numerical search. + +***************************************** +Practical Challenges in Real Systems +***************************************** + +The model used in this chapter so far omits a few effects that usually dominate the error budget in actual TDOA deployments. Three deserve detailed treatment: + +Receiver Synchronization +================================ + +TDOA's defining advantage, that it needs no synchronized transmitter, comes paired with its defining burden: the *receivers* must share a common time reference, and any error in that reference enters the measurement directly. If sensor :math:`i`'s clock is offset from truth by :math:`\delta t_i`, the measured TDOA is corrupted by :math:`\delta t_i - \delta t_j`, an error multiplied by :math:`c` in range. The scale is unforgiving for radio systems: + +.. math:: + + c \times 1\ \text{ns} = (3\times10^8\,\text{m/s})(10^{-9}\,\text{s}) = 0.30\ \text{m}. + +So a 1 ns synchronization error already costs :math:`\sim`\0.3 m, and 100 ns costs 30 m. Achieving and holding nanosecond-level synchronization across distributed sensors is therefore central to system design. Common mechanisms include GPS-disciplined oscillators (each sensor recovers a :math:`\sim`\10-100 ns timing reference from satellites), the Precision Time Protocol (IEEE 1588, distributing time over a network to sub-microsecond or, with hardware timestamping, sub-100 ns accuracy), and for the most demanding installations White Rabbit, which reaches sub-nanosecond synchronization over fiber. Two further subtleties matter: clocks not only have a static *offset* but *drift* over time, requiring continual discipline; and in acoustic systems, where :math:`c` is a million times smaller, the same absolute timing error is a million times less harmful, which is why microphone-array TDOA is comparatively forgiving while radio TDOA lives or dies by its clocks. + +Off-the-shelf SDRs that can be easily synchronized include any of the Ettus Research USRPs that can take a GPS disciplined oscillator (GPSDO), such as a `B200 `_ with a `TCXO `_ (a type of GPSDO). If the sensors are close enough, they can also be synchronized by sharing a PPS signal over a cable, e.g., generated using an `OctoClock `_, which also generates a 10 MHz signal used to frequency synchronize them. Nearly all of the USRPs have a PPS and 10 MHz input, and most have room for a GPSDO, or come with one. + +Multipath and Non-Line-of-Sight Propagation +=================================================== + +Everything so far has assumed a single line-of-sight path between the emitter and receivers. Real environments add reflections (multipath) and can block the direct path entirely. Multipath superimposes delayed copies of the signal, which distort or split the correlation peak and bias the delay estimate; this is exactly the failure GCC-PHAT was designed to resist, since whitening sharpens the direct-path peak relative to the smeared reflections. When the direct path is entirely obstructed, the *earliest* arriving energy travels an excess distance, so the measured TDOA is biased *long* in a way no amount of averaging removes, because the error is systematic rather than random. Mitigation strategies include identifying these non-line-of-sight links statistically (non-line-of-sight measurements often show larger variance or violate geometric consistency among redundant sensors), down-weighting or discarding them (requires having way more sensors than three), and exploiting redundancy so that a few corrupted links among many can be detected and rejected by the robust estimators described earlier. In dense indoor multipath, which is an extremely difficult environment for TDOA, model-based delay estimation and machine-learning approaches increasingly outperform classical correlation. + +Sensor-Position Uncertainty and Calibration +=================================================== + +The geometry assumed exact knowledge of the sensor coordinates :math:`\mathbf{s}_i`. Errors in those coordinates propagate into the position estimate just as measurement errors do, and for distant emitters can be amplified by the same poor geometry that inflates GDOP. Careful survey of fixed installations, GPS positioning of mobile sensors, and *self-calibration*, jointly estimating sensor positions and emitter locations from emitters of opportunity at known or constrained locations, are the standard responses. A full error budget must include sensor-position uncertainty alongside timing and TDE error; in well-synchronized systems it is often the next-largest term. + +******************* +Advanced Topics +******************* + +Joint TDOA/FDOA Estimation +================================== + +When the emitter, the sensors, or both are *moving*, the relative motion imparts a Doppler shift that differs between sensors, a **Frequency Difference of Arrival** (FDOA). FDOA carries information about the emitter's *velocity* and, crucially, adds an independent geometric constraint that improves position observability, especially for the difficult far-field and few-sensor cases where TDOA alone is poorly conditioned. TDOA and FDOA are estimated jointly by maximizing the **Complex Ambiguity Function** (CAF) over both delay and frequency offset: + +.. math:: + + A(\tau,\nu) = \int_0^T x_i(t)\, x_j^{*}(t-\tau)\, e^{-j2\pi \nu t}\, dt, + +whose two-dimensional peak gives :math:`(\hat\tau_{ij},\hat\nu_{ij})` simultaneously. The CAF generalizes the cross-correlation technique above by adding a frequency-search dimension, at correspondingly higher computational cost. Note that this is not the same CAF introduced in the cyclostationary chapter as the cyclic autocorrelation function. Joint TDOA/FDOA processing is the backbone of satellite and airborne geolocation of radio emitters, where a single pair of moving platforms can localize a stationary emitter from the combined delay and Doppler constraints. diff --git a/content/usrp.rst b/content/usrp.rst index 4b278f45..48cdc9ad 100644 --- a/content/usrp.rst +++ b/content/usrp.rst @@ -263,7 +263,7 @@ If you want to use the TX/RX port instead of RX2 (the default), it's as simple a which essentially just controls an RF switch onboard the USRP, to route from the other SMA connector. -To receive or transmit on two channels at once, instead of using :code:`st_args.channels = [0]` you provide a list, such as :code:`[0,1]`. The receive samples buffer will have to be of size (2, N) in this case, instead of (1,N). Just remember that with most USRPs, both channels share an LO, so you cant tune to different frequencies at once. +To receive or transmit on two channels at once, instead of using :code:`st_args.channels = [0]` you provide a list, such as :code:`[0,1]`. The receive samples buffer will have to be of size (2, N) in this case, instead of (1,N). Just remember that with most USRPs, both channels share an LO, so you can't tune to different frequencies at once. ************************** Syncing to 10 MHz and PPS @@ -323,7 +323,7 @@ For debugging sake, you can verify the 10 MHz signal is showing up to the USRP b Phase Coherent Sync of Multiple B210s for MIMO ********************************************** -In order to perform operations like direction of arrival (DOA) and phased array digital beamforming, you typically need all receive channels to be phase coherent, meaning the relative phases between the receive channels stay constant and can be calibrated out. The B200 and B210 USRPs are based on the AD9361 RFIC, which generates the LO internally, there is no way to feed it an external LO, so even if you feed the USRP a 10 MHz reference signal and PPS, that will only allow multiple USRPs to synchronized in frequency and sample clock, not phase, because every time the device turns on or changes frequency, there is a new random phase offset due to the dividers in the VCO/PLL chains, for more information see `this page `_. One method to achieve phase sync is to add hardware that involves taking a calibration signal (either generated by the USRP, or wideband noise source, or tone), splitting it, and feeding it into all receive ports, and performing a quick calibration each time the USRPs are turned on or retuned. Note that changing the gain will also lead to phase shifts, but as long as the B210's are kept at the same gain the phase difference shouldn't change significantly. The `Techtile project `_ has additional information on this topic, including custom images that may allow multiple B210s to retune together so that they maintain sync, although it likely still requires calibration with external hardware each time the radios turn on. +In order to perform operations like direction of arrival (DOA) and phased array digital beamforming, you typically need all receive channels to be phase coherent, meaning the relative phases between the receive channels stay constant and can be calibrated out. The B200 and B210 USRPs are based on the AD9361 RFIC, which generates the LO internally, there is no way to feed it an external LO, so even if you feed the USRP a 10 MHz reference signal and PPS, that will only allow multiple USRPs to synchronized in frequency and sample clock, not phase, because every time the device turns on or changes frequency, there is a new random phase offset due to the dividers in the VCO/PLL chains, for more information see `this page `_. One method to achieve phase sync is to add hardware that involves taking a calibration signal (either generated by the USRP, or wideband noise source, or tone), splitting it, and feeding it into all receive ports, and performing a quick calibration each time the USRPs are turned on or retuned. Note that changing the gain will also lead to phase shifts, but as long as the B210's are kept at the same gain the phase difference shouldn't change significantly. The `Techtile project `_ has additional information on this topic, including custom images that may allow multiple B210s to re-tune together so that they maintain sync, although it likely still requires calibration with external hardware each time the radios turn on. **** GPIO diff --git a/figure-generating-scripts/2d_array_recording.py b/figure-generating-scripts/2d_array_recording.py index c4d337fc..7eaf3106 100644 --- a/figure-generating-scripts/2d_array_recording.py +++ b/figure-generating-scripts/2d_array_recording.py @@ -107,10 +107,15 @@ def get_unit_vector(theta, phi): # angles are in radians #results[i, j] = np.abs(resp)[0,0] # power in signal, in dB results = 10*np.log10(results) # convert to dB -results[results < -20] = -20 # crop the z axis to some level of dB + +# Crop the z axis +floor = np.percentile(results, 5) # keeps top 95% +print("floor:", floor) +results = np.maximum(results, floor) # 3D az-el DOA results -if False: +# Note that this is not a polar plot, it's using X and Y to represent the azimuth and elevation angles, and Z to represent the power in dB +if True: fig, ax = plt.subplots(subplot_kw={"projection": "3d", "computed_zorder": False}) surf = ax.plot_surface(np.rad2deg(theta_scan[:,None]), # type: ignore np.rad2deg(phi_scan[None,:]), @@ -120,7 +125,7 @@ def get_unit_vector(theta, phi): # angles are in radians ax.set_xlabel('Azimuth (theta)') ax.set_ylabel('Elevation (phi)') ax.set_zlabel('Power [dB]') # type: ignore - #fig.savefig('../_images/2d_array_3d_doa_plot.png', bbox_inches='tight', dpi=300) # increase dpi to 300 + fig.savefig('../_images/2d_array_3d_doa_plot.png', bbox_inches='tight', dpi=300) plt.show() # 2D, az-el heatmap (same as above, but 2D) @@ -132,13 +137,9 @@ def get_unit_vector(theta, phi): # angles are in radians plt.colorbar(label='Power [linear]') plt.xlabel('Theta (azimuth, degrees)') plt.ylabel('Phi (elevation, degrees)') -#plt.savefig('../_images/2d_array_2d_doa_plot.svg', bbox_inches='tight') +plt.savefig('../_images/2d_array_2d_doa_plot.svg', bbox_inches='tight') plt.show() - -exit() - - ''' # Interferometry resolution = 100 # number of points in each direction diff --git a/figure-generating-scripts/GPS_L1_recording_10ms_4MHz_cf32.iq b/figure-generating-scripts/GPS_L1_recording_10ms_4MHz_cf32.iq new file mode 100644 index 00000000..427e88bc Binary files /dev/null and b/figure-generating-scripts/GPS_L1_recording_10ms_4MHz_cf32.iq differ diff --git a/figure-generating-scripts/boxcar_sinc.py b/figure-generating-scripts/boxcar_sinc.py new file mode 100644 index 00000000..e04425ba --- /dev/null +++ b/figure-generating-scripts/boxcar_sinc.py @@ -0,0 +1,51 @@ +import numpy as np +import matplotlib.pyplot as plt + +# A boxcar (rectangular) pulse in time and its sinc-shaped spectrum + +sample_rate = 100.0 # Hz +N = 4096 # number of time samples / FFT size +t = (np.arange(N) - N // 2) / sample_rate # centered time axis, in seconds + +# Boxcar pulse: amplitude A, total width T (seconds), centered at t=0 +A = 1.0 +T = 1.0 +x = np.where(np.abs(t) <= T / 2, A, 0.0) + +# Spectrum via FFT +X = np.fft.fftshift(np.fft.fft(x)) +X_mag = np.abs(X) / sample_rate # scale so height approximates A*T +f = np.fft.fftshift(np.fft.fftfreq(N, d=1 / sample_rate)) + +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4)) +plt.subplots_adjust(wspace=0.3) + +ax1.plot(t, x, '-') +ax1.set_xlabel("Time [s]") +ax1.set_ylabel("Amplitude") +ax1.set_title("Boxcar Pulse in Time") +ax1.set_xlim(-1.5, 1.5) +ax1.set_ylim(-0.2, 1.3) +ax1.grid() + +# Annotate the pulse width T with a double-headed arrow spanning -T/2 to T/2 +y_ann = A + 0.05 +ax1.annotate("", xy=(-T / 2, y_ann), xytext=(T / 2, y_ann), + arrowprops=dict(arrowstyle="<->", color="red")) +ax1.text(0.05, y_ann + 0.03, "T", color="red", ha="center", va="bottom", fontsize=16) + +ax2.plot(f, X_mag, '-') +ax2.set_xlabel("Frequency [Hz]") +ax2.set_ylabel("Magnitude") +ax2.set_title("Sinc-Shaped Spectrum") +ax2.set_xlim(-4, 4) +ax2.grid() + +# Point out the sinc nulls, which occur at integer multiples of 1/T +for n in [1, 2, 3]: + ax2.annotate(rf"$\frac{{{n}}}{{T}}$", xy=(n / T, 0.05), xytext=(n / T + 0.2, 0.25), + color="red", ha="center", fontsize=20, + arrowprops=dict(arrowstyle="->", color="red")) + +fig.savefig('../_images/boxcar_sinc.svg', bbox_inches='tight') +plt.show() diff --git a/figure-generating-scripts/boxcar_sinc_animation.py b/figure-generating-scripts/boxcar_sinc_animation.py new file mode 100644 index 00000000..e14be1bf --- /dev/null +++ b/figure-generating-scripts/boxcar_sinc_animation.py @@ -0,0 +1,56 @@ +import numpy as np +import matplotlib.pyplot as plt +from PIL import Image + +# Animation of a boxcar pulse widening in time, and its sinc spectrum narrowing + +sample_rate = 100.0 # Hz +N = 4096 # number of time samples / FFT size +t = (np.arange(N) - N // 2) / sample_rate # centered time axis, in seconds +f = np.fft.fftshift(np.fft.fftfreq(N, d=1 / sample_rate)) + +A = 1.0 +# Pulse width sweeps from short to wide, in seconds. Fewer frames = smaller gif. +widths = np.linspace(0.2, 3.0, 40) + +filenames = [] +for i, T in enumerate(widths): + x = np.where(np.abs(t) <= T / 2, A, 0.0) + X = np.fft.fftshift(np.fft.fft(x)) + X_mag = np.abs(X) / sample_rate + + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4)) + plt.subplots_adjust(wspace=0.3) + + ax1.plot(t, x, '-') + ax1.set_xlabel("Time [s]") + ax1.set_ylabel("Amplitude") + ax1.set_title("Boxcar Pulse in Time") + ax1.set_xlim(-3, 3) + ax1.set_ylim(-0.2, 1.3) + ax1.grid() + ax1.text(-2.8, 1.05, f"Pulse length = {T:.2f} s", color='r', fontsize=14) + + ax2.plot(f, X_mag, '-') + ax2.set_xlabel("Frequency [Hz]") + ax2.set_ylabel("Magnitude") + ax2.set_title("Sinc-Shaped Spectrum") + ax2.set_xlim(-4, 4) + ax2.set_ylim(-0.3, 3.2) + ax2.grid() + + filename = '/tmp/boxcar_sinc_' + str(i) + '.png' + print(i) + # fixed (non-'tight') bbox so every frame has identical pixel dimensions, + # which is required for subrectangles=True below + fig.savefig(filename, dpi=72) + filenames.append(filename) + plt.close(fig) + +# Create looping animated gif. Quantize each frame to a 64-color palette and let +# Pillow's optimize=True store only the pixels that change between frames (the +# static axes/labels/grid), which shrinks the file a lot. +frames = [Image.open(fn).convert('RGB').quantize(colors=48) for fn in filenames] +frames[0].save('../_images/boxcar_sinc_animation.gif', save_all=True, + append_images=frames[1:], duration=int(1000 / 15), loop=0, + optimize=True, disposal=2) diff --git a/figure-generating-scripts/costas_loop_animation.py b/figure-generating-scripts/costas_loop_animation.py index 87ecbc0c..95988821 100644 --- a/figure-generating-scripts/costas_loop_animation.py +++ b/figure-generating-scripts/costas_loop_animation.py @@ -48,8 +48,8 @@ # Muller muller samples_interpolated = signal.resample_poly(samples, 16, 1) mu = 0 # initial estimate of phase of sample -out = np.zeros(len(samples) + 10, dtype=np.complex) -out_rail = np.zeros(len(samples) + 10, dtype=np.complex) # stores values, each iteration we need the previous 2 values plus current value +out = np.zeros(len(samples) + 10, dtype=np.complex64) +out_rail = np.zeros(len(samples) + 10, dtype=np.complex64) # stores values, each iteration we need the previous 2 values plus current value i_in = 0 # input samples index i_out = 2 # output index (let first two outputs be 0) while i_out < len(samples) and i_in < len(samples): @@ -73,7 +73,7 @@ # These next two params is what to adjust, to make the feedback loop faster or slower (which impacts stability) alpha = 0.005 beta = 0.001 -out = np.zeros(N, dtype=np.complex) +out = np.zeros(N, dtype=np.complex64) freq_log = [] ii = 0 iii = 0 diff --git a/figure-generating-scripts/cyclostationary.py b/figure-generating-scripts/cyclostationary.py index 086ae481..a0f11fbc 100644 --- a/figure-generating-scripts/cyclostationary.py +++ b/figure-generating-scripts/cyclostationary.py @@ -10,7 +10,7 @@ # Simulate Rect BPSK # ###################### -if True: +if False: N = 100000 # number of samples to simulate f_offset = 0.2 # Hz normalized sps = 20 # cyclic freq (alpha) will be 1/sps or 0.05 Hz normalized @@ -153,9 +153,9 @@ def fractional_delay(x, delay): ########################### # Adapted from https://dspillustrations.com/pages/posts/misc/python-ofdm-example.html -if False: +if True: from scipy.signal import resample - N = 100000 # number of samples to simulate + N = 200000 # number of samples to simulate num_subcarriers = 64 cp_len = num_subcarriers // 4 # length of the cyclic prefix in symbols, in this case 25% of the starting OFDM symbol print("CP length in samples", cp_len*2) # remember there is 2x interpolation at the end @@ -203,7 +203,7 @@ def fractional_delay(x, delay): # Direct CAF # ############## -if True: +if False: # CAF only at the correct alpha alpha_of_interest = 1/sps # equates to 0.05 Hz #alpha_of_interest = 0.08 # INCORRECT ALPHA FOR SAKE OF PLOT @@ -254,13 +254,13 @@ def fractional_delay(x, delay): # Freq smoothing -if False: +if True: start_time = time.time() alphas = np.arange(0, 0.3, 0.001) - if False: # For OFDM example - #alphas = np.arange(0, 0.5+0.0001, 0.0001) # enable max pooling for this one - alphas = np.arange(0, 0.02+0.0001, 0.0001) + if True: # For OFDM example + #alphas = np.arange(0, 0.5+0.0001, 0.0001) # zoomed out, enable max pooling for this one + alphas = np.arange(0, 0.02+0.0001, 0.00001) # zoomed in and increased resolution Nw = 256 # window length N = len(samples) # signal length window = np.hanning(Nw) @@ -277,15 +277,16 @@ def fractional_delay(x, delay): SCF = np.abs(SCF) # null out alpha= 0, 1, -1 which is just the PSD of the signal, it throws off the dynamic range - SCF[np.argmin(np.abs(alphas)), :] = 0 + SCF[np.argmin(np.abs(alphas)), :] = 0 + SCF[np.argmin(np.abs(alphas))+1, :] = 0 # PSD bleeds into 2nd row SCF[np.argmin(np.abs(alphas - 1)), :] = 0 SCF[np.argmin(np.abs(alphas - (-1))), :] = 0 print("Time taken:", time.time() - start_time) print("SCF shape", SCF.shape) - # Max pooling in cyclic domain - if False: + # Max pooling in cyclic domain, used for OFDM example and possibly others + if True: import skimage.measure SCF = skimage.measure.block_reduce(SCF, block_size=(16, 1), func=np.max) # type: ignore print("Shape of SCF:", SCF.shape) @@ -296,7 +297,7 @@ def fractional_delay(x, delay): plt.ylabel('Cyclic Frequency [Normalized Hz]') #plt.savefig('../_images/scf_freq_smoothing.svg', bbox_inches='tight') #plt.savefig('../_images/scf_freq_smoothing_ofdm.svg', bbox_inches='tight') # for OFDM example - #plt.savefig('../_images/scf_freq_smoothing_ofdm_zoomed_in.svg', bbox_inches='tight') # for OFDM example 2 + plt.savefig('../_images/scf_freq_smoothing_ofdm_zoomed_in.svg', bbox_inches='tight') # for OFDM example 2 #plt.savefig('../_images/scf_freq_smoothing_pulse_shaped_bpsk.svg', bbox_inches='tight') #plt.savefig('../_images/scf_freq_smoothing_pulse_shaped_bpsk2.svg', bbox_inches='tight') #plt.savefig('../_images/scf_freq_smoothing_pulse_shaped_bpsk3.svg', bbox_inches='tight') diff --git a/figure-generating-scripts/detection_CFAR.py b/figure-generating-scripts/detection_CFAR.py new file mode 100644 index 00000000..d41a440d --- /dev/null +++ b/figure-generating-scripts/detection_CFAR.py @@ -0,0 +1,92 @@ +import numpy as np +import matplotlib.pyplot as plt +from scipy.signal import correlate + +def generate_qpsk_packets(num_packets, sps, preamble): + """Generates repeating QPSK packets with gaps and varying noise.""" + qpsk_map = np.array([1+1j, -1+1j, -1-1j, 1-1j]) / np.sqrt(2) + data_len = 200 + gap_len = 100 + full_signal = [] + + # Pre-calculate preamble upsampled for correlation + upsampled_preamble = np.repeat(preamble, sps) + + for _ in range(num_packets): + data = qpsk_map[np.random.randint(0, 4, data_len)] + packet = np.concatenate([preamble, data]) + full_signal.extend(np.repeat(packet, sps)) + full_signal.extend(np.zeros(gap_len * sps)) + + return np.array(full_signal), upsampled_preamble + +# 1. Setup Parameters +sps = 4 +preamble_syms = np.array([1+1j, 1+1j, -1-1j, -1-1j, 1-1j, -1+1j]) / np.sqrt(2) +tx_signal, ref_preamble = generate_qpsk_packets(5, sps, preamble_syms) + +# 2. Channel: Time-Varying Noise Floor +t = np.arange(len(tx_signal)) +noise_env = 0.05 + 0.3 * np.sin(2 * np.pi * 0.0003 * t)**2 +noise = (np.random.randn(len(tx_signal)) + 1j*np.random.randn(len(tx_signal))) * noise_env +rx_signal = tx_signal + noise + +# 3. Preamble Correlation +# Correlation spike occurs when the reference matches the received segment +corr_out = correlate(rx_signal, ref_preamble, mode='same') +corr_power = np.abs(corr_out)**2 + +# 4. CFAR Detection on Correlator Output +def ca_cfar_adaptive(data, num_train, num_guard, pfa): + num_cells = len(data) + thresholds = np.zeros(num_cells) + alpha = num_train * (pfa**(-1/num_train) - 1) # Scaling factor + + half_window = (num_train + num_guard) // 2 + guard_half = num_guard // 2 + + for i in range(half_window, num_cells - half_window): + # Extract training cells (excluding guard cells and CUT) + lagging_win = data[i - half_window : i - guard_half] + leading_win = data[i + guard_half + 1 : i + half_window + 1] + noise_floor_est = np.mean(np.concatenate([lagging_win, leading_win])) + + thresholds[i] = alpha * noise_floor_est + + return thresholds + +# Detect on correlator power +cfar_thresholds = ca_cfar_adaptive(corr_power, num_train=60, num_guard=20, pfa=1e-5) +detections = np.where(corr_power > cfar_thresholds)[0] +# Filter detections to only include those where threshold is non-zero (avoid edges) +detections = detections[cfar_thresholds[detections] > 0] + +# 5. Visualization +plt.figure(figsize=(14, 8)) + +# Subplot 1: Received Signal and Raw Power +plt.subplot(2, 1, 1) +plt.plot(np.abs(rx_signal)**2, color='gray', alpha=0.4, label='Rx Signal Power ($|r(t)|^2$)') +plt.title("Time-Domain Received Signal") +plt.ylabel("Power") +plt.legend() +plt.grid(True, alpha=0.3) + +# Subplot 2: Correlator Output vs Adaptive Threshold +plt.subplot(2, 1, 2) +plt.plot(corr_power, label='Correlator Output $|r(t) * p^*(-t)|^2$', color='blue') +plt.plot(cfar_thresholds, label='CFAR Adaptive Threshold', color='red', linestyle='--', linewidth=1.5) + +# Overlay detections +if len(detections) > 0: + plt.scatter(detections, corr_power[detections], color='lime', edgecolors='black', + label='Detections (Preamble Found)', zorder=5) + +plt.title("Preamble Correlator Output with Adaptive CFAR Threshold") +plt.xlabel("Sample Index") +plt.ylabel("Correlation Power") +plt.legend() +plt.grid(True, alpha=0.3) +plt.tight_layout() +plt.savefig('../_images/detection_cfar.svg', bbox_inches='tight') +plt.show() diff --git a/figure-generating-scripts/detection_DSSS.py b/figure-generating-scripts/detection_DSSS.py new file mode 100644 index 00000000..1dbe3989 --- /dev/null +++ b/figure-generating-scripts/detection_DSSS.py @@ -0,0 +1,39 @@ +import numpy as np +import matplotlib.pyplot as plt + +# Barker 11 sequence: +1, -1, +1, +1, -1, +1, +1, +1, -1, -1, -1 +barker11 = np.array([1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1]) +samples_per_chip = 100 + +# Upsample the sequence to simulate continuous-ish time +sig = np.repeat(barker11, samples_per_chip) + +offsets = np.linspace(-1.5, 1.5, 500) # Fractional chip offsets +peaks = [] + +for offset in offsets: + # Shift the signal by a fractional number of chips (converted to samples) + shift_samples = int(offset * samples_per_chip) + if shift_samples > 0: + shifted_sig = np.pad(sig, (shift_samples, 0))[:len(sig)] + elif shift_samples < 0: + shifted_sig = np.pad(sig, (0, abs(shift_samples)))[abs(shift_samples):] + else: + shifted_sig = sig + + # Compute normalized correlation at zero lag for this specific offset + correlation = np.vdot(sig, shifted_sig) / np.vdot(sig, sig) + peaks.append(np.abs(correlation)) + +plt.figure(figsize=(10, 5)) +plt.plot(offsets, peaks, label='Normalized Correlation', color='blue', linewidth=2) +plt.axvline(0, color='red', linestyle='--', alpha=0.5, label='Perfect Alignment') +plt.title('DSSS Correlation Peak vs. Fractional Chip Timing Offset') +plt.xlabel('Offset (Fraction of a Chip)') +plt.ylabel('Normalized Correlation Peak Magnitude') +plt.grid(True, which='both', linestyle='--', alpha=0.6) +plt.legend() +plt.savefig('../_images/detection_dsss.svg', bbox_inches='tight') +plt.show() + + diff --git a/figure-generating-scripts/detection_basic.py b/figure-generating-scripts/detection_basic.py new file mode 100644 index 00000000..6ee8950a --- /dev/null +++ b/figure-generating-scripts/detection_basic.py @@ -0,0 +1,41 @@ +import numpy as np +import matplotlib.pyplot as plt + +# Long Zadoff-Chu sequence +N = 839 # Length of Zadoff-Chu sequence +u = 25 # Root of ZC sequence +t = np.arange(N) +zadoff_chu = np.exp(-1j * np.pi * u * t * (t + 1) / N) + +# Create AWGN and stick the ZC sequence in a random spot +signal_length = 10 * N +offset = np.random.randint(N, signal_length - N) +print(f"True offset: {offset}") +snr_db = -15 +noise_power = 1 / (2 * (10**(snr_db / 10))) +signal = np.sqrt(noise_power/2) * (np.random.randn(signal_length) + 1j * np.random.randn(signal_length)) +signal[offset:offset+N] += zadoff_chu + +plt.figure(0) +plt.plot(np.abs(signal)) +plt.xlabel('Sample Index') +plt.ylabel('Signal Magnitude [Linear]') +plt.axvline(float(offset), 0, 1, color='r', linestyle=':') +plt.text(float(offset), -0.5, 'True Offset', color='r', verticalalignment='bottom') +plt.grid() +plt.tight_layout() +plt.savefig('../_images/detection_basic_1.svg', bbox_inches='tight') + +# Correlator +correlation = np.abs(np.correlate(signal, zadoff_chu, mode='valid') / N)**2 + +plt.figure(1) +plt.plot(correlation) +plt.xlabel('Sample Index') +plt.ylabel('Correlation Magnitude [Linear]') +plt.axvline(float(offset), 0, 0.2, color='r', linestyle=':') +plt.text(float(offset), -0.05, 'True Offset', color='r', verticalalignment='bottom') +plt.grid() +plt.tight_layout() +plt.savefig('../_images/detection_basic_2.svg', bbox_inches='tight') +plt.show() diff --git a/figure-generating-scripts/detection_freq_offset.py b/figure-generating-scripts/detection_freq_offset.py new file mode 100644 index 00000000..158f773f --- /dev/null +++ b/figure-generating-scripts/detection_freq_offset.py @@ -0,0 +1,160 @@ +import numpy as np +from scipy.signal import upfirdn +from scipy.special import erfc +import matplotlib.pyplot as plt + +# ============================== +# Helper Functions +# ============================== + +def srrc_pulse(alpha, sps, span): + """Generate SRRC pulse.""" + t = np.arange(-span/2, span/2, 1/sps) + p = np.zeros_like(t) + for i, ti in enumerate(t): + if ti == 0: + p[i] = 1.0 - alpha + 4*alpha/np.pi + elif abs(ti) == 1/(4*alpha): + p[i] = (alpha/np.sqrt(2))*((1+2/np.pi)*np.sin(np.pi/(4*alpha))+(1-2/np.pi)*np.cos(np.pi/(4*alpha))) + else: + p[i] = (np.sin(np.pi*ti*(1-alpha)) + 4*alpha*ti*np.cos(np.pi*ti*(1+alpha))) / (np.pi*ti*(1-(4*alpha*ti)**2)) + return p/np.sqrt(np.sum(p**2)) + +def qpsk_mod(bits): + """Map bits to QPSK symbols.""" + bits = bits.reshape(-1, 2) + mapping = { (0,0): 1+1j, (0,1): -1+1j, (1,1): -1-1j, (1,0): 1-1j } + symbols = np.array([mapping[tuple(b)] for b in bits]) / np.sqrt(2) + return symbols + +def apply_freq_offset(x, Fs, f_offset): + """Apply frequency offset.""" + n = np.arange(len(x)) + return x * np.exp(1j*2*np.pi*f_offset*n/Fs) + +def awgn(x, snr_dB): + """Add AWGN.""" + snr_lin = 10**(snr_dB/10) + P = np.mean(np.abs(x)**2) + N0 = P/snr_lin + noise = np.sqrt(N0/2) * (np.random.randn(len(x)) + 1j*np.random.randn(len(x))) + return x + noise + +def preamble_detector(rx, preamble, Fs, sps, freqs, seg_len, coherent=True): + """Perform frequency search and segmented correlation.""" + corr_vals = [] + preamble_up = upfirdn([1], preamble, sps) + for f in freqs: + rxf = rx * np.exp(-1j*2*np.pi*f*np.arange(len(rx))/Fs) + seg_corrs = [] + for i in range(0, len(preamble_up), seg_len*sps): + segment = preamble_up[i:i+seg_len*sps] + if len(segment) > len(rxf): break + c = np.abs(np.vdot(rxf[:len(segment)], segment)) + if coherent: + seg_corrs.append(np.vdot(rxf[:len(segment)], segment)) + else: + seg_corrs.append(np.abs(np.vdot(rxf[:len(segment)], segment))) + if coherent: + total_corr = np.abs(np.sum(seg_corrs)) + else: + total_corr = np.sum(seg_corrs) + corr_vals.append(total_corr) + return np.array(corr_vals) + + +def determine_freq_spacing(f_max, deg_dB, seg_len, symbol_rate): + """Decide frequency step spacing based on allowed correlation degradation.""" + # degradation = sinc(f_offset * seg_duration) + # want degradation (in dB) < max tolerated + deg_lin = 10**(-deg_dB/20) + seg_dur = seg_len / symbol_rate + f_step = (1 / (2*seg_dur)) * np.sqrt(1 - deg_lin) + freqs = np.arange(-f_max, f_max+f_step, f_step) + return freqs + + + +# Parameters +N_preamble = 64 +N_data = 512 +sps = 8 +rolloff = 0.35 +span = 8 +Fs = 1e6 +symbol_rate = Fs / sps + +f_max = 5e3 +deg_dB = 1 +seg_symb_min = 8 +EbN0_dBs = [0, 5, 10] +num_trials = 200 + +# Generate preamble + data +bits = np.random.randint(0, 2, (N_preamble+N_data)*2) +symbols = qpsk_mod(bits) +preamble = symbols[:N_preamble] +data = symbols[N_preamble:] + +# SRRC shaping +pulse = srrc_pulse(rolloff, sps, span) +tx = upfirdn(pulse, np.concatenate([preamble, data]), sps) +tx = tx / np.sqrt(np.mean(np.abs(tx)**2)) + +# Determine frequency sweep +freqs = determine_freq_spacing(f_max, deg_dB, seg_symb_min, symbol_rate) + +# ====================== +# Sweep: frequency offset +# ====================== +freq_offsets = np.linspace(-f_max, f_max, 15) +results = {snr: [] for snr in EbN0_dBs} + +for snr in EbN0_dBs: + for fo in freq_offsets: + corr_peaks = [] + for _ in range(num_trials): + rx = apply_freq_offset(tx, Fs, fo) + rx = awgn(rx, snr) + corr = preamble_detector(rx, preamble, Fs, sps, freqs, seg_symb_min, coherent=False) + corr_peaks.append(np.max(corr)) + results[snr].append(np.mean(corr_peaks)) + +plt.figure() +for snr in EbN0_dBs: + plt.plot(freq_offsets/1e3, 20*np.log10(results[snr]/np.max(results[snr])), label=f"SNR={snr}dB") +plt.xlabel("Frequency offset (kHz)") +plt.ylabel("Normalized correlation peak (dB)") +plt.legend() +plt.title("Correlation degradation vs frequency offset") +plt.grid(True) +plt.savefig('../_images/detection_freq_offset.svg', bbox_inches='tight') +plt.show() + +# ====================== +# Sweep: SNR vs detection probability +# ====================== +snr_range = np.linspace(-5, 20, 10) +test_offsets = [0, 2e3, 5e3] +threshold = 0.3 # detection threshold +det_prob = {fo: [] for fo in test_offsets} + +for fo in test_offsets: + for snr in snr_range: + detections = 0 + for _ in range(num_trials): + rx = apply_freq_offset(tx, Fs, fo) + rx = awgn(rx, snr) + corr = preamble_detector(rx, preamble, Fs, sps, freqs, seg_symb_min, coherent=False) + if np.max(corr)/np.max(corr) > threshold: + detections += 1 + det_prob[fo].append(detections/num_trials) + plt.plot(snr_range, det_prob[fo], label=f"Offset={fo/1e3:.1f} kHz") + +plt.xlabel("SNR (dB)") +plt.ylabel("Probability of detection") +plt.title("Detection probability vs SNR for various frequency offsets") +plt.legend() +plt.grid(True) +plt.savefig('../_images/detection_freq_offset2.svg', bbox_inches='tight') +plt.show() diff --git a/figure-generating-scripts/detection_gps.py b/figure-generating-scripts/detection_gps.py new file mode 100644 index 00000000..b31ff977 --- /dev/null +++ b/figure-generating-scripts/detection_gps.py @@ -0,0 +1,161 @@ +import numpy as np +import matplotlib.pyplot as plt + +filename = "GPS_L1_recording_10ms_4MHz_cf32.iq" +sample_rate = 4e6 +chip_rate = 1023000 # chips / sec (part of the GPS spec) +num_chips = 1023 # chips per C/A code period +samples_per_code = int(round(sample_rate / chip_rate * num_chips)) # Exact number of samples in one 1 ms code period at 4 MHz +doppler_min_hz = -5e3 # GPS Doppler ≈ ±4 kHz for stationary receiver +doppler_max_hz = 5e3 +doppler_step_hz = 500 # good enough for a coarse search +num_integrations = 10 # non-coherent power integrations (so 10 ms total), determines how much of the IQ recording we read in and process! +detection_thresh_dB = 14.0 # Peak-to-mean ratio (PMR) threshold in dB to declare a detection, GPS C/A signals are typically 14–20 dB PMR above threshold with 10ms of integration +gps_svs = list(range(1, 33)) # 1–32 + +##### C/A Code Generation ##### +# The GPS C/A code is a Gold code formed by XOR-ing two 10-stage maximal-length +# shift registers (G1 and G2). G2 is effectively delayed by a satellite- +# specific number of chips before the XOR +# Reference: IS-GPS-200, Table 3-Ia +G2_DELAY = [ # G2 phase delay (chips) for gps_svs 1–32 + 5, 6, 7, 8, 17, 18, 139, 140, # 1– 8 + 141, 251, 252, 254, 255, 256, 257, 258, # 9–16 + 469, 470, 471, 472, 473, 474, 509, 512, # 17–24 + 513, 514, 515, 516, 859, 860, 861, 862, # 25–32 +] + +"""G1 LFSR: polynomial x^10 + x^3 + 1, all-ones init, output at stage 10.""" +reg = np.ones(10, dtype=np.int8) +G1 = np.empty(num_chips, dtype=np.int8) +for i in range(num_chips): + G1[i] = reg[9] + fb = reg[2] ^ reg[9] # stages 3 and 10 (0-indexed: 2 and 9) + reg = np.roll(reg, 1) + reg[0] = fb + +"""G2 LFSR: polynomial x^10+x^9+x^8+x^6+x^3+x^2+1, all-ones init.""" +reg = np.ones(10, dtype=np.int8) +G2 = np.empty(num_chips, dtype=np.int8) +for i in range(num_chips): + G2[i] = reg[9] + fb = reg[1]^reg[2]^reg[5]^reg[7]^reg[8]^reg[9] # taps 2,3,6,8,9,10 + reg = np.roll(reg, 1) + reg[0] = fb + +# 1023-chip C/A PRN code for SV sv (1-32) as float32, 1's and -1's, so BPSK +def make_prn(sv: int) -> np.ndarray: + g2_delayed = np.roll(G2, G2_DELAY[sv - 1]) + bits = G1 ^ g2_delayed # {0, 1} + return (1 - 2 * bits).astype(np.float32) # BPSK: {+1, −1} + +def upsample_prn(sv: int) -> np.ndarray: + """Nearest-neighbour upsample 1023-chip C/A code → samples_per_code samples.""" + code = make_prn(sv) + idx = (np.arange(samples_per_code) * num_chips / samples_per_code).astype(int) + return code[idx] + +# Pre-compute template signals - conjugate FFTs of all upsampled PRN codes +template_signals = {sv: np.conj(np.fft.fft(upsample_prn(sv))) for sv in gps_svs} + +# Read in IQ file +n_needed = samples_per_code * num_integrations +iq = np.fromfile(filename, dtype=np.complex64, count=n_needed) +# For the full version from IQEngine use the following instead +#iq = np.fromfile(filename, dtype=np.int16, count=n_needed * 2) +#iq = (iq[0::2] + 1j * iq[1::2]).astype(np.complex64) + +# Create a spectrogram to show how the signals are under the noise floor +if False: + fft_size = 512 + num_rows = len(iq) // fft_size # // is an integer division which rounds down + spectrogram = np.zeros((num_rows, fft_size)) + for i in range(num_rows): + spectrogram[i,:] = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(iq[i*fft_size:(i+1)*fft_size])))**2) + plt.figure(2) + plt.imshow(spectrogram, aspect='auto', extent = [sample_rate/-2/1e6, sample_rate/2/1e6, len(iq)/sample_rate, 0]) + plt.xlabel("Frequency [MHz]") + plt.ylabel("Time [s]") + plt.savefig('../_images/detection_gps_spectrogram.svg', bbox_inches='tight') + plt.show() + exit() + +# Loop through satellites performing acquisition +results = [] +detected = [] +print(f" {'SV':>3} {'Doppler (Hz)':>13} {'Phase (chips)':>14}" + f" {'Phase (samp)':>13} {'Delay (µs)':>11} {'PMR (dB)':>9}") +doppler_bins = np.arange(doppler_min_hz, doppler_max_hz + doppler_step_hz, doppler_step_hz) +for sv in gps_svs: + corr_map = np.zeros((len(doppler_bins), samples_per_code)) + n_total = samples_per_code * num_integrations + for di, f_d in enumerate(doppler_bins): + t = np.arange(n_total) / sample_rate # time vector + mixed = iq[:n_total] * np.exp(-2j*np.pi*float(f_d)*t) # freq shift + + # Non-coherent integration: accumulate squared correlation magnitude + for k in range(num_integrations): + blk = mixed[k * samples_per_code:(k + 1) * samples_per_code] + sig_fft = np.fft.fft(blk) + corr = np.fft.ifft(sig_fft * template_signals[sv]) # cross-correlation in freq domain + corr_map[di] += np.abs(corr)**2 + + # Normalize by mean and convert to dB + peak_val = float(np.max(corr_map)) + mean_val = float(np.mean(corr_map)) + pmr_db = 10.0 * np.log10(peak_val / mean_val) + + peak_idx = np.unravel_index(np.argmax(corr_map), corr_map.shape) + best_doppler_hz = float(doppler_bins[peak_idx[0]]) + best_phase_samp = int(peak_idx[1]) + best_phase_chips = best_phase_samp * num_chips / samples_per_code + + r = { + "sv": sv, + "detected": pmr_db >= detection_thresh_dB, + "doppler_hz": best_doppler_hz, + "code_phase_samp": best_phase_samp, # sample offset = "start of packet" + "code_phase_chip": best_phase_chips, + "pmr_db": pmr_db, + "corr_map": corr_map, + "doppler_bins": doppler_bins, + } + results.append(r) + + # Print row + delay_us = r['code_phase_samp'] / sample_rate * 1e6 + flag = " ← DETECTED" if r['detected'] else "" + print(f" {sv:>3} {r['doppler_hz']:>+13.0f} {r['code_phase_chip']:>14.2f}" + f" {r['code_phase_samp']:>13d} {delay_us:>11.3f} {r['pmr_db']:>9.1f}{flag}") + + +# Plotting +sv = 11 # we detected 11, 12, 22, 25, 31, 32 although try looking at one we didnt find as well! +r = results[sv - 1] # print the dict of results for this SV to see what we got +cmap = r['corr_map'] # 2-D array of correlation power vs Doppler and code phase +d_bins = r['doppler_bins'] # Doppler bins corresponding +chips_axis = np.arange(samples_per_code) * num_chips / samples_per_code + +# 2-D Doppler × code-phase map +plt.figure(0, figsize=(10, 6)) +im = plt.pcolormesh(chips_axis, d_bins, cmap, shading='auto', cmap='viridis') +plt.xlabel("Code Phase (chips)") +plt.ylabel("Doppler (Hz)") +plt.title(f"SV {sv} — 2-D Acquisition Map (PMR = {r['pmr_db']:.1f} dB)") +plt.legend(fontsize=8, loc='upper right') +plt.colorbar(im, label="Correlation Power") +plt.savefig('../_images/detection_gps_2d_map.png', bbox_inches='tight', dpi=300) + +# code-phase slice at best Doppler +best_di = int(np.argmin(np.abs(d_bins - r['doppler_hz']))) +plt.figure(1, figsize=(8, 4)) +plt.plot(chips_axis, cmap[best_di], lw=1, color='steelblue') +plt.xlabel("Code Phase (chips)") +plt.ylabel("Correlation Power") +plt.title(f"SV {sv} — Code-Phase Slice (Doppler = {r['doppler_hz']:+.0f} Hz)") +plt.legend(fontsize=8) +plt.grid(True, alpha=0.3) +plt.savefig('../_images/detection_gps_code_phase_slice.svg', bbox_inches='tight') + +plt.show() + diff --git a/figure-generating-scripts/detection_preamble.py b/figure-generating-scripts/detection_preamble.py new file mode 100644 index 00000000..bac18632 --- /dev/null +++ b/figure-generating-scripts/detection_preamble.py @@ -0,0 +1,111 @@ +import numpy as np +import matplotlib.pyplot as plt +from scipy.signal import lfilter + +def get_srrc_pulse(sps, roll_off, span): + """Generates Square Root Raised Cosine (SRRC) pulse coefficients.""" + t = np.arange(-span * sps, span * sps + 1) / sps + with np.errstate(divide='ignore', invalid='ignore'): + pulse = (np.sin(np.pi * t * (1 - roll_off)) + + 4 * roll_off * t * np.cos(np.pi * t * (1 + roll_off))) / \ + (np.pi * t * (1 - (4 * roll_off * t)**2)) + pulse[t == 0] = 1 - roll_off + (4 * roll_off / np.pi) + pulse[np.abs(np.abs(4 * roll_off * t) - 1) < 1e-10] = \ + (roll_off / np.sqrt(2)) * (((1 + 2/np.pi) * np.sin(np.pi / (4 * roll_off))) + \ + ((1 - 2/np.pi) * np.cos(np.pi / (4 * roll_off)))) + return pulse / np.sqrt(np.sum(pulse**2)) + +# Simulation Parameters +N_preamble = 16 # Preamble symbol length +N_data = 1000 # Data symbol length +sps = 4 # Samples per symbol +roll_off = 0.35 # SRRC roll-off factor +snr_db_list = [-20, -15, -10, -5, 0] # SNR values for ROC +mc_trials = 10000 # Monte Carlo trials per SNR + +# 1. Generate QPSK Signal +qpsk_map = np.array([1+1j, -1+1j, -1-1j, 1-1j]) / np.sqrt(2) +preamble = qpsk_map[np.random.randint(0, 4, N_preamble)] +data = qpsk_map[np.random.randint(0, 4, N_data)] +symbols = np.concatenate([preamble, data]) + +# 2. Pulse Shaping +pulse = get_srrc_pulse(sps, roll_off, span=6) +upsampled_symbols = np.zeros(len(symbols) * sps, dtype=complex) +upsampled_symbols[::sps] = symbols +tx_signal = np.convolve(upsampled_symbols, pulse, mode='same') + +# 3. Monte Carlo Simulation for ROC Curves +plt.figure(figsize=(12, 5)) +thresholds = np.linspace(0, 2, 200) + +for snr_db in snr_db_list: + print(f"Simulating for SNR={snr_db}dB...") + pd_curve = [] + pfa_curve = [] + + # Noise power calculation + snr_linear = 10**(snr_db / 10) + noise_std = np.sqrt(1 / (2 * snr_linear)) + + for thresh in thresholds: + detections = 0 + false_alarms = 0 + + for _ in range(mc_trials): + # Trial under H1 (Signal + Noise) + noise = noise_std * (np.random.randn(len(tx_signal)) + 1j*np.random.randn(len(tx_signal))) + rx_h1 = tx_signal + noise + # Test statistic: Correlation with preamble + corr = np.abs(np.sum(np.conj(tx_signal[:N_preamble*sps]) * rx_h1[:N_preamble*sps])) / (N_preamble*sps) + if corr > thresh: detections += 1 + + # Trial under H0 (Noise only) + rx_h0 = noise_std * (np.random.randn(len(tx_signal)) + 1j*np.random.randn(len(tx_signal))) + corr_h0 = np.abs(np.sum(np.conj(tx_signal[:N_preamble*sps]) * rx_h0[:N_preamble*sps])) / (N_preamble*sps) + if corr_h0 > thresh: false_alarms += 1 + + pd_curve.append(detections / mc_trials) + pfa_curve.append(false_alarms / mc_trials) + + print(f"thres={thresh} | SNR={snr_db}") + + plt.subplot(1, 2, 1) + plt.plot(pfa_curve, pd_curve, label=f'SNR={snr_db}dB') + +plt.subplot(1, 2, 1) +plt.title("ROC Curves") +plt.xlabel("Pfa") +plt.ylabel("Pd") +plt.legend() +plt.grid(True) + +# 4. Pd vs SNR Curve (Fixed Pfa) +target_pfa = 0.01 +snr_range = np.arange(-10, 15, 2) +pd_vs_snr = [] + +for snr_db in snr_range: + snr_linear = 10**(snr_db / 10) + noise_std = np.sqrt(1 / (2 * snr_linear)) + # Determine threshold for target Pfa under H0 + noise_trials = [np.abs(np.sum(np.conj(tx_signal[:N_preamble*sps]) * (noise_std*(np.random.randn(N_preamble*sps)+1j*np.random.randn(N_preamble*sps))))) / (N_preamble*sps) for _ in range(1000)] + thresh = np.percentile(noise_trials, 100 * (1 - target_pfa)) + + # Calculate Pd + detections = 0 + for _ in range(mc_trials): + rx = tx_signal + noise_std * (np.random.randn(len(tx_signal)) + 1j*np.random.randn(len(tx_signal))) + if np.abs(np.sum(np.conj(tx_signal[:N_preamble*sps]) * rx[:N_preamble*sps])) / (N_preamble*sps) > thresh: + detections += 1 + pd_vs_snr.append(detections / mc_trials) + +plt.subplot(1, 2, 2) +plt.plot(snr_range, pd_vs_snr, 'o-') +plt.title(f"Pd vs SNR (Pfa={target_pfa})") +plt.xlabel("SNR (dB)") +plt.ylabel("Pd") +plt.grid(True) +plt.tight_layout() +plt.savefig('../_images/detection_pd_vs_snr.svg', bbox_inches='tight') +plt.show() diff --git a/figure-generating-scripts/detection_realtime.py b/figure-generating-scripts/detection_realtime.py new file mode 100644 index 00000000..f90adabb --- /dev/null +++ b/figure-generating-scripts/detection_realtime.py @@ -0,0 +1,154 @@ +""" +Generate visualization for real-time packet detection section. +""" +import numpy as np +import matplotlib.pyplot as plt +from scipy.signal import correlate + +def ca_cfar_1d(signal, num_train, num_guard, pfa): + """Cell-Averaging CFAR detector.""" + n = len(signal) + threshold = np.zeros(n) + alpha = num_train * (pfa**(-1/num_train) - 1) + + for i in range(n): + train_start_left = max(0, i - num_guard - num_train) + train_end_left = max(0, i - num_guard) + train_start_right = min(n, i + num_guard + 1) + train_end_right = min(n, i + num_guard + num_train + 1) + + train_cells = np.concatenate([ + signal[train_start_left:train_end_left], + signal[train_start_right:train_end_right] + ]) + + if len(train_cells) > 0: + threshold[i] = alpha * np.mean(train_cells) + + return threshold + +def detect_packets(buffer, preamble, cfar_guard, cfar_train, pfa): + """Detect packets in IQ buffer.""" + corr = correlate(buffer, preamble, mode='same') + corr_power = np.abs(corr)**2 + threshold = ca_cfar_1d(corr_power, cfar_train, cfar_guard, pfa) + + detections_raw = np.where(corr_power > threshold)[0] + half_preamble = len(preamble) // 2 + detections_raw = detections_raw - half_preamble + detections_raw = detections_raw[ + (detections_raw > half_preamble) & + (detections_raw < len(buffer) - half_preamble) + ] + + detections = [] + if len(detections_raw) > 0: + detections.append(detections_raw[0]) + for det in detections_raw[1:]: + if det - detections[-1] > len(preamble): + detections.append(det) + + return detections, corr_power, threshold + +def generate_packet_stream(preamble, packet_length, num_packets, sample_rate, snr_db): + """Generate simulated IQ stream with packets.""" + signal_power = 1.0 + noise_power = signal_power / (10**(snr_db/10)) + noise_std = np.sqrt(noise_power / 2) + + qpsk_map = np.array([1+1j, -1+1j, -1-1j, 1-1j]) / np.sqrt(2) + avg_gap = int(sample_rate / 1) # 1 packet per second + + signal = [] + true_starts = [] + + for i in range(num_packets): + if i == 0: + gap_length = np.random.randint(avg_gap//2, avg_gap) + else: + gap_length = np.random.randint(int(avg_gap*0.8), int(avg_gap*1.2)) + + noise = noise_std * (np.random.randn(gap_length) + 1j*np.random.randn(gap_length)) + signal.extend(noise) + + true_starts.append(len(signal)) + + data_length = packet_length - len(preamble) + data = qpsk_map[np.random.randint(0, 4, data_length)] + packet = np.concatenate([preamble, data]) + packet_noisy = packet + noise_std * (np.random.randn(len(packet)) + + 1j*np.random.randn(len(packet))) + signal.extend(packet_noisy) + + gap_length = np.random.randint(avg_gap//2, avg_gap) + noise = noise_std * (np.random.randn(gap_length) + 1j*np.random.randn(gap_length)) + signal.extend(noise) + + return np.array(signal), true_starts + +# Generate test signal +np.random.seed(42) +N_zc, u = 63, 5 +t = np.arange(N_zc) +preamble = np.exp(-1j * np.pi * u * t * (t + 1) / N_zc) + +sample_rate = 1e6 +packet_length = 500 +snr_db = -5 + +signal, true_starts = generate_packet_stream( + preamble, packet_length, num_packets=5, + sample_rate=sample_rate, snr_db=snr_db +) + +# Process one buffer for visualization +buffer_start = max(0, true_starts[0] - 5000) +buffer_end = min(len(signal), true_starts[2] + 10000) +viz_buffer = signal[buffer_start:buffer_end] + +detections_viz, corr_viz, thresh_viz = detect_packets( + viz_buffer, preamble, cfar_guard=10, cfar_train=50, pfa=1e-5 +) + +# Create visualization +fig, axes = plt.subplots(3, 1, figsize=(14, 10)) +time_axis = (np.arange(len(viz_buffer)) + buffer_start) / sample_rate * 1000 + +# Subplot 1: Received signal power +axes[0].plot(time_axis, np.abs(viz_buffer)**2, 'gray', alpha=0.6, linewidth=0.5) +axes[0].set_ylabel('Power', fontsize=11) +axes[0].set_title('Received IQ Signal Power', fontsize=12, fontweight='bold') +axes[0].grid(True, alpha=0.3) +for i, ts in enumerate(true_starts): + if buffer_start <= ts <= buffer_end: + t_ms = ts / sample_rate * 1000 + axes[0].axvline(t_ms, color='green', linestyle='--', alpha=0.7, linewidth=1.5, + label='True Packet' if i == 0 else '') +axes[0].legend(fontsize=10) + +# Subplot 2: Correlation output +axes[1].plot(time_axis, corr_viz, 'blue', linewidth=1, label='Correlation') +axes[1].plot(time_axis, thresh_viz, 'red', linestyle='--', linewidth=1.5, label='CFAR Threshold') +axes[1].set_ylabel('Correlation Power', fontsize=11) +axes[1].set_title('Preamble Correlation with Adaptive CFAR Threshold', fontsize=12, fontweight='bold') +axes[1].grid(True, alpha=0.3) +axes[1].legend(fontsize=10) + +# Subplot 3: Detections +detection_mask = np.zeros(len(viz_buffer)) +for det in detections_viz: + detection_mask[det] = corr_viz[det] + +axes[2].plot(time_axis, corr_viz, 'blue', alpha=0.4, linewidth=0.8) +axes[2].scatter(time_axis[detection_mask > 0], detection_mask[detection_mask > 0], + color='lime', edgecolors='black', s=100, zorder=5, label='Detected Packets') +axes[2].set_xlabel('Time (ms)', fontsize=11) +axes[2].set_ylabel('Correlation Power', fontsize=11) +axes[2].set_title('Detected Packet Locations', fontsize=12, fontweight='bold') +axes[2].grid(True, alpha=0.3) +axes[2].legend(fontsize=10) + +plt.tight_layout() +plt.savefig('../_images/detection_realtime.png', bbox_inches='tight', dpi=150) +print("Figure saved to ../_images/detection_realtime.png") +plt.show() \ No newline at end of file diff --git a/figure-generating-scripts/doa_2d.py b/figure-generating-scripts/doa_2d.py index bd486447..011406dc 100644 --- a/figure-generating-scripts/doa_2d.py +++ b/figure-generating-scripts/doa_2d.py @@ -198,36 +198,6 @@ def get_unit_vector(theta, phi): # angles are in radians exit() -# Visualize beam pattern when using these weights, but this time we need a 3D surface plot -# Note that this is not a polar plot, it's using X and Y to represent the azimuth and elevation angles, and Z to represent the power in dB -if False: - resolution = 100 # number of points in each direction - theta_scan = np.linspace(-np.pi/2, np.pi/2, resolution) # azimuth angles - phi_scan = np.linspace(-np.pi/4, np.pi/4, resolution) # elevation angles - results = np.zeros((resolution, resolution)) # 2D array to store results - for i, theta_i in enumerate(theta_scan): - for j, phi_i in enumerate(phi_scan): - dir_i = get_unit_vector(theta_i, phi_i) - a = steering_vector(pos, dir_i) # array factor - resp = w.conj().T @ a # scalar - results[i, j] = 10*np.log10(np.abs(resp)[0,0]) # power in signal, in dB - # plot_surface needs x,y,z form - results = 10*np.log10(results) # convert to dB - #results[results < -10] = -10 # crop the z axis to some level of dB - fig, ax = plt.subplots(subplot_kw={"projection": "3d", "computed_zorder": False}) - surf = ax.plot_surface(np.rad2deg(theta_scan[:,None]), # type: ignore - np.rad2deg(phi_scan[None,:]), - results, - cmap='viridis') - #ax.set_zlim(-10, results[max_idx]) - ax.set_xlabel('Azimuth (theta)') - ax.set_ylabel('Elevation (phi)') - ax.set_zlabel('Power [dB]') # type: ignore - fig.savefig('../_images/2d_beamforming_3dplot.svg', bbox_inches='tight') - plt.show() - exit() - - # Let's simulate some actual samples now, we'll add two tone jammers coming it from different directions. Same 4x4 array, same element positions (pos variable) N = 10000 # number of samples to simulate diff --git a/figure-generating-scripts/doa_root_music.py b/figure-generating-scripts/doa_root_music.py new file mode 100644 index 00000000..50f2ba85 --- /dev/null +++ b/figure-generating-scripts/doa_root_music.py @@ -0,0 +1,49 @@ +import numpy as np + +sample_rate = 1e6 +N = 10000 # number of samples to simulate +d = 0.5 # half wavelength spacing +Nr = 8 # number of array elements +t = np.arange(N) / sample_rate + +# Simulate three signals at 20, 25, and -40 degrees (same scenario as MUSIC section) +theta1 = 20 / 180 * np.pi +theta2 = 25 / 180 * np.pi +theta3 = -40 / 180 * np.pi +s1 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta1)).reshape(-1, 1) +s2 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta2)).reshape(-1, 1) +s3 = np.exp(2j * np.pi * d * np.arange(Nr) * np.sin(theta3)).reshape(-1, 1) +tone1 = np.exp(2j * np.pi * 0.01e6 * t).reshape(1, -1) +tone2 = np.exp(2j * np.pi * 0.02e6 * t).reshape(1, -1) +tone3 = np.exp(2j * np.pi * 0.03e6 * t).reshape(1, -1) +X = s1 @ tone1 + s2 @ tone2 + 0.1 * s3 @ tone3 +n = np.random.randn(Nr, N) + 1j * np.random.randn(Nr, N) +X = X + 0.05 * n # 8xN + +num_expected_signals = 3 + +# Same eigendecomposition as MUSIC +R = np.cov(X) +w, v = np.linalg.eig(R) +eig_val_order = np.argsort(np.abs(w)) +v = v[:, eig_val_order] +V = v[:, :Nr - num_expected_signals] # noise subspace eigenvectors + +# Build the Root MUSIC polynomial from diagonals of noise-subspace projection +D = V @ V.conj().T +p = np.zeros(2*Nr - 1, dtype=np.complex128) +for k in range(2*Nr - 1): + p[k] = np.sum(np.diag(D, k - (Nr - 1))) + +# Find roots, keep those inside the unit circle, pick the num_expected_signals roots closest to the unit circle +roots = np.roots(p[::-1]) # np.roots expects highest-degree coefficient first +roots = roots[np.abs(roots) <= 1.0] +roots = roots[np.argsort(-np.abs(roots))] # sort closest-to-unit-circle first +doa_roots = roots[:num_expected_signals] + +# Convert roots to angles in degrees +doas_deg = np.sort(np.arcsin(np.angle(doa_roots) / (2 * np.pi * d)) * 180 / np.pi) + +# Print results +print("Estimated DOAs (degrees):", doas_deg) +print("True DOAs (degrees): [-40. 20. 25.]") \ No newline at end of file diff --git a/figure-generating-scripts/eye_diagram.py b/figure-generating-scripts/eye_diagram.py new file mode 100644 index 00000000..51352677 --- /dev/null +++ b/figure-generating-scripts/eye_diagram.py @@ -0,0 +1,50 @@ +import matplotlib.pyplot as plt +import numpy as np + +np.random.seed(5) + +# BPSK + RRC pulse shaping, same style of setup as the chapter's Python exercise +num_symbols = 400 +sps = 32 +beta = 0.35 +span = 8 # filter span in symbols (each side) + +# Random BPSK symbols +symbols = np.random.randint(0, 2, num_symbols) * 2 - 1 + +# Upsample (impulses spaced by sps) +x = np.zeros(num_symbols * sps) +x[::sps] = symbols + +# Raised-cosine filter (Tx + Rx combined for this illustration) +t = np.arange(-span * sps, span * sps + 1) / sps +h = np.sinc(t) * np.cos(np.pi * beta * t) / (1 - (2 * beta * t) ** 2 + 1e-20) +h /= np.max(np.convolve(np.ones(1), h)) # keep peaks near +/-1 + +y = np.convolve(x, h, mode='same') + +# Build the eye diagram: chop the signal into 2-symbol-wide slices and overlay +span_samps = 2 * sps +n_traces = 250 +fig, ax = plt.subplots(1, 1, figsize=(8, 4)) +start = span * sps # skip filter transient +for i in range(n_traces): + s = start + i * sps + seg = y[s:s + span_samps] + if len(seg) < span_samps: + break + ax.plot(np.arange(span_samps) / sps - 1, seg, color='#1f77b4', alpha=0.15, linewidth=1, rasterized=True) + +# Mark the ideal sampling instant (center of the eye) +ax.axvline(0, color='k', linestyle='--', linewidth=1) +ax.text(0.02, 1.35, 'ideal sample time', fontsize=11) + +ax.set_xlabel('Time (symbol periods)', fontsize=12) +ax.set_ylabel('Amplitude', fontsize=12) +ax.set_xlim(-1, 1) +ax.set_ylim(-1.6, 1.6) +ax.grid(True, alpha=0.3) + +plt.tight_layout() +plt.show() +fig.savefig('../_images/eye_diagram.svg', bbox_inches='tight', dpi=100) diff --git a/figure-generating-scripts/gps_L1.py b/figure-generating-scripts/gps_L1.py deleted file mode 100644 index 5c521ec5..00000000 --- a/figure-generating-scripts/gps_L1.py +++ /dev/null @@ -1,249 +0,0 @@ -import numpy as np -from scipy.signal import resample -import matplotlib.pyplot as plt - -''' -1. Acquisition - Detect the presence of satellites https://gnss-sdr.org/docs/sp-blocks/acquisition/ -2. For each satellite determine frequency shift and delay -3. Tracking - Track carrier phase and code delay over time. see state machine here https://gnss-sdr.org/docs/sp-blocks/tracking/ -4. Decode the navigation (aka telemetry) message https://gnss-sdr.org/docs/sp-blocks/telemetry-decoder/ - -https://github.com/JasonNg91/GNSS-SDR-Python/blob/master/acquire-gps-l1.py -https://github.com/psas/gps -''' - -g1tap = [2,9] -g2tap = [1,2,5,7,8,9] -sats = [(1, 5), (2, 6), (3, 7), (4, 8), (0, 8), (1, 9), (0, 7), (1, 8), (2, 9), (1, 2), - (2, 3), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9), (0, 3), (1, 4), (2, 5), (3, 6), - (4, 7), (5, 8), (0, 2), (3, 5), (4, 6), (5, 7), (6, 8), (7, 9), (0, 5), (1, 6), - (2, 7), (3, 8), (4, 9), (3, 9), (0, 6), (1, 7), (3, 9)] - -# Test file from IQEngine, was taken on 2022-03-27T11:32:04.2147593125 -samples_to_read = 10e6 -samples_offset = 1e6 -x = np.fromfile('/mnt/c/Users/marclichtman/Downloads/GPS-L1.sigmf-data', dtype=np.int16, count=int(samples_to_read), offset=int(samples_offset)) -x = x.astype(np.complex64) / 32768.0 -x = x[::2] + 1j*x[1::2] -sample_rate = 4e6 -center_freq = 1575.42e6 - -# Resample to 4092 MHz because it's an integer multiple of the chip rate 1023M chips/sec -resampling_rate = 4.092e6/sample_rate -x = resample(x, int(resampling_rate*len(x))) -sample_rate = 4.092e6 - - -def gold_code(prn): # Returns a list of bits that form the Gold Code PRN of the designated satellite - g1 = np.ones(10) - g2 = np.ones(10) - g = np.empty(1023) - for i in range(1023): - val = (g1[9] + g2[prn[0]] + g2[prn[1]]) % 2 - g[i] = val - - # shift g1 - g1[9] = sum([g1[i] for i in g1tap]) % 2 - g1 = np.roll(g1, 1) - - # shift g2 - g2[9] = sum([g2[i] for i in g2tap]) % 2 - g2 = np.roll(g2, 1) - - # Convert to BPSK by changing 0 to -1 - g = g * 2 - 1 - return np.repeat(g, 4) # repeat each chip 4x to match our sample rate which is 4x the chip rate - - -def _GetSecondLargest(arr): # Returns the second largest value in an array. It will also ignore any value that is close to the second largest value - ScaledLargest = 0.95 * np.amax(arr) # Reduce value by a percent to prevent near-identical values from being selected - SecondLargest = 0 - for ind, val in enumerate(arr): - if val < ScaledLargest: - if val > SecondLargest: # Ignore adjacent bins to Largest - if np.abs(np.argmax(arr) - ind) > 100: - SecondLargest = val - return SecondLargest - - -def findSat(samples, code, bins, block_size_ms=10, tracking = False): - samples_slice = samples[0:(4092*block_size_ms)] - NsamplesBlock = 4092 * block_size_ms - - peakToSecondList = np.zeros(len(bins)) - codePhaseList = np.zeros(len(bins)) - SNRList = np.zeros(len(bins)) - - codefft = np.fft.fft(code, len(samples_slice)) - GCConj = np.conjugate(codefft) - - N = len(bins) - freqInd = 0 - # Loop through all frequencies - for n, curFreq in enumerate(bins): - - # Shift frequency to baseband using complex exponential - t = np.arange(len(samples_slice))/sample_rate - samples_slice = samples_slice * np.exp(-2j * np.pi * curFreq * t) - - # Mix code fft and take inverse, then square - result = np.fft.ifft(GCConj * np.fft.fft(samples_slice)) - result_squared = np.real(result * np.conjugate(result)) # imag part will always be near zero - - #rmsPowerdB = 10*np.log10(np.mean(result_squared)) - #resultdB = 10*np.log10(result_squared) - - codePhaseInSamples = np.argmax(result_squared[0:4092]) - - # Search for secondlargest value in 1 ms worth of data - secondLargestValue = _GetSecondLargest(result_squared[0:int(sample_rate * 0.001)]) - - # Pseudo SNR - firstPeak = np.amax(result_squared[0:4092]) - peakToSecond = 10*np.log10(firstPeak / secondLargestValue) - - #if tracking is True: - peakToSecondList[n] = peakToSecond - codePhaseList[n] = codePhaseInSamples - SNRList[n] = 10*np.log10( firstPeak/np.mean(result_squared) ) - - # Don't print data when correlation is probably not happening - SNR_THRESHOLD = 3.4 - if peakToSecond > SNR_THRESHOLD: - print("Possible acquisition: Freq: %8.4f, Peak2Second: %8.4f, Code Phase (samples): %8.4f" - %(curFreq, peakToSecond, codePhaseInSamples)) - - freqInd = freqInd + 1 - - # Percentage Output - print("%02d%%"%((n/N)*100), end="\r") - - #print(SNRList[np.argmax(peakToSecondList)]) - #print(bins[np.argmax(peakToSecondList)]) # doppler - #print(codePhaseList[np.argmax(peakToSecondList)]) # CodePhaseSamples - #print(1023 - (1.023e6) / (4.092e6) * codePhaseList[np.argmax(peakToSecondList)]) # CodePhaseChips - - if True: - plt.ion() - plt.plot(bin_list, peakToSecondList) - plt.ylim((0, 20)) - plt.xlabel('Doppler Shift (Hz)') - plt.ylabel('Peak-to-SecondLargest ratio (dB)') - plt.title("Sat %d - PeakToSecondLargest"%curSat) - plt.draw() - plt.pause(0.001) - plt.clf() - - Acquired = np.amax(peakToSecondList) >= SNR_THRESHOLD # Check if Acquisition was successful for this satellite - - # Get fine-frequency (If acquired): - if Acquired == True: - # Already have a CA code that is at least 1 ms in length - CACode = code[0:4092] # store first ms - - # Repeat entire array 5 times for 5 ms - code5ms = np.tile(CACode, int(5)) - - #GetFineFrequency(data,curSatInfo,code5ms) - - return - - -''' -def GetFineFrequency(data, SatInfo, code5ms): # now passed in data class - # Performs fine-frequency estimation. In this case, data will be a slice - # of data (probably same length of data that was used in the circular - # cross-correlation) - - - Ts = 1/sample_rate - - # Medium-frequency estimation data length (1ms in book, but may need to used - # the data length from acquisition) - numMSmf = 1 # num ms for medium-frequency estimation - Nmf = int(np.ceil(numMSmf*0.001*sample_rate)) # num of samples to use for medium-frequency estimation (and DFT) - - dataMF = data.CData[0:(4092*numMSmf)] - - # Create list of the three frequencies to test for medium-frequency estimation. - k = [] - k.append(SatInfo.DopplerHz - 400*10**3) - k.append(SatInfo.DopplerHz) - k.append(SatInfo.DopplerHz + 400*10**3) - - # Create sampled time array for DFT - nTs = np.linspace(0,Ts*(Nmf + 1),Nmf,endpoint=False) - - # Perform DFT at each of the three frequencies. - X = [] - X.append(np.abs(sum(dataMF*np.exp(-2*np.pi*1j*k[0]*nTs)))**2) - X.append(np.abs(sum(dataMF*np.exp(-2*np.pi*1j*k[1]*nTs)))**2) - X.append(np.abs(sum(dataMF*np.exp(-2*np.pi*1j*k[2]*nTs)))**2) - - # Store the frequency value that has the largest power - kLargest = k[np.argmax(X)] - print("Largest of three frequencies: %f"%kLargest) # Will remove. Temporarily for debugging purposes. - - # Get 5 ms of consecutive data, starting at beginning of CA Code - CACodeBeginning = int(SatInfo.CodePhaseSamples) - data5ms = data.CData[CACodeBeginning:int(5*4092) + CACodeBeginning] - - # Get 5 ms of CA Code, with no rotation performed. - # passed in from function (code5ms) - - # Multiply data with ca code to get cw signal - dataCW = data5ms*code5ms - - # Perform DFT on each of the ms of data (5 total), at kLargest frequency. - # Uses variables from medium-frequency, so if they change, may need to re-create below. - X = [] - PhaseAngle = [] - for i in range(0,5): - X.append(sum(dataCW[i*4092:(i+1)*4092]*np.exp(-2*np.pi*1j*kLargest*nTs))) - PhaseAngle.append(np.arctan(np.imag(X[i])/np.real(X[i]))) - print("Magnitude: %f" %X[i]) - print("Phase Angle: %f" %PhaseAngle[i]) - - # Get difference angles - PhaseDiff = [] - for i in range(1,5): - PhaseDiff.append(PhaseAngle[i]-PhaseAngle[i-1]) - print("Phase difference %d, is: %f"%((i-1),PhaseDiff[i-1])) - - # Adjust phases so magnitude not greater than 2.3*pi/5 - # WIP - PhaseThreshold = (2.3*np.pi)/5 - for (i,curPhaseDiff) in enumerate(PhaseDiff): - if np.abs(curPhaseDiff) > PhaseThreshold: - curPhaseDiff = PhaseDiff[i] - 2*np.pi - if np.abs(curPhaseDiff) > PhaseThreshold: - curPhaseDiff = PhaseDiff[i] + 2*np.pi - if np.abs(curPhaseDiff) > (2.2*np.pi)/5: - curPhaseDiff = PhaseDiff[i] - np.pi - if np.abs(curPhaseDiff) > PhaseThreshold: - curPhaseDiff = PhaseDiff[i] - 3*np.pi - if np.abs(curPhaseDiff) > PhaseThreshold: - curPhaseDiff = PhaseDiff[i] + np.pi - PhaseDiff[i] = curPhaseDiff - fList = (np.array(PhaseDiff)/(2*np.pi*0.001)) - print(fList) - print(np.mean(fList)) - - FineFrequencyEst = 0 # Just a placeholder. - return FineFrequencyEst -''' - -bin_list=range(-10000,10000, 100) -sat_list=range(1, 33) -block_size_ms=10 - -# Create array to store max values, freq ranges, per satellite -satInd = 0 -# Loop through selected satellites -for curSat in sat_list: - print("Searching for SV " + str(curSat) + "...") - CACode = gold_code(sats[curSat-1]) # Grab a CA Code - CACodeSampled = np.tile(CACode, int(len(x)/sample_rate*1000)) # Repeat entire array for each ms of data sampled - findSat(x, CACodeSampled, bin_list, block_size_ms) - satInd += 1 - diff --git a/figure-generating-scripts/msk.py b/figure-generating-scripts/msk.py new file mode 100644 index 00000000..086b814f --- /dev/null +++ b/figure-generating-scripts/msk.py @@ -0,0 +1,98 @@ +import numpy as np +import matplotlib.pyplot as plt + +# Parameters +num_symbols = 20000 +sps = 32 # use 32 for time domain parts, 8 for PSD +span = 6 # filter span in symbols (each side) +mode = 'OQPSK' # 'QPSK' or 'OQPSK' + +# Generate QPSK symbols +bits = np.random.randint(0, 4, num_symbols) +symbols = np.exp(1j * (np.pi/4 + bits * np.pi/2)).astype(complex) # points at 45°, 135°, 225°, 315° + +if False: + # RC filter + beta = 0.35 # roll-off factor + t = np.arange(-span * sps, span * sps + 1) / sps # in symbol periods + h = np.sinc(t) * np.cos(np.pi * beta * t) / (1 - (2 * beta * t)**2 + 1e-20) +else: + # Half-sine pulse shape + t = np.arange(sps) + h = np.sin(np.pi * t / sps) + output_file = '../_images/msk_magnitude.svg' + +if mode == 'QPSK': + upsampled = np.zeros(num_symbols * sps, dtype=complex) + upsampled[::sps] = symbols + signal = np.convolve(upsampled, h, mode='same') + output_file = '../_images/qpsk_magnitude.svg' + +elif mode == 'OQPSK': + # Delay Q impulses by half a symbol before filtering so the pulse shaping filter handles the ramp-up naturally (no post-filter roll/zero-fill artifact) + # half = sps // 2 + # I_up = np.zeros(num_symbols * sps) + # Q_up = np.zeros(num_symbols * sps) + # I_up[::sps] = np.real(symbols) + # Q_up[half::sps] = np.imag(symbols) + # I_filt = np.convolve(I_up, h, mode='same') + # Q_filt = np.convolve(Q_up, h, mode='same') + # signal = I_filt + 1j * Q_filt + #output_file = '../_images/oqpsk_magnitude.svg' + #mode = "MSK" # TEMPORARY + + bits = np.random.randint(0, 2, num_symbols) + symbols = 2 * bits - 1 # map {0,1} → {-1, +1} + + # Build the instantaneous frequency deviation + mod_index = 0.5 + t = np.arange(num_symbols * sps / 2) / (sps / 2) + freq_dev = np.zeros(num_symbols * sps // 2) + for k, a in enumerate(symbols): + freq_dev[k * sps // 2 : (k + 1) * sps // 2] = a * mod_index / 2.0 + + phase = 2.0 * np.pi * np.cumsum(freq_dev) / (sps / 2) # accumulate phase + signal = np.exp(1j * phase) + + mode = "CPFSK" + output_file = '../_images/cpfsk_magnitude.svg' + +#signal *= np.sqrt(2) + +# Plot +N = 10 +fig, axes = plt.subplots(2, 1, figsize=(7, 4), tight_layout=True) +axes[0].plot(signal.real[:N*sps], label='I') +axes[0].plot(signal.imag[:N*sps], label='Q', alpha=0.7) +axes[0].axhline(1, color='gray', linestyle='--', linewidth=1) +axes[0].axhline(-1, color='gray', linestyle='--', linewidth=1) +# NOTE THE -1 IS ONLY FOR CPFSK TO ALIGN THINGS +for x in range(-1, N * sps, sps): + axes[0].axvline(x, color='gray', linestyle='--', linewidth=1) +if mode == 'OQPSK' or mode == 'MSK' or mode == 'CPFSK': + for x in range(sps // 2 - 1, N * sps, sps): + axes[0].axvline(x, color='blue', linestyle='--', linewidth=1, alpha=0.5) +axes[0].set_title(mode) +axes[0].legend() +axes[1].plot(np.abs(signal[:N*sps])) +axes[1].set_ylabel('Magnitude') +axes[1].set_xlabel('Sample Index (Time)') +axes[1].set_ylim(bottom=0, top=1.2) +axes[1].grid(True) +plt.savefig(output_file, bbox_inches='tight') +plt.show() + +# Plot the PSD +# psd = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(signal)))**2) +# psd -= np.max(psd) # Normalize to 0 dB max +# f = np.linspace(-0.5, 0.5, len(psd)) +# plt.figure(figsize=(7, 4), tight_layout=True) +# plt.plot(f, psd) +# plt.ylim(bottom=-80, top=5) +# #plt.title(f'{mode}') +# plt.title('QPSK or OQPSK with RC Pulse Shaping') +# plt.xlabel('Normalized Frequency (cycles/sample)') +# plt.ylabel('PSD [dB]') +# plt.grid(True) +# plt.savefig('../_images/qpsk_psd.svg', bbox_inches='tight') +# plt.show() diff --git a/figure-generating-scripts/msk_qpsk_psd.py b/figure-generating-scripts/msk_qpsk_psd.py new file mode 100644 index 00000000..61f59379 --- /dev/null +++ b/figure-generating-scripts/msk_qpsk_psd.py @@ -0,0 +1,91 @@ +""" +Power Spectral Density comparison: MSK vs QPSK with Raised Cosine (α=0.35) pulse shaping. + +MSK uses a half-sinusoidal pulse shape, giving a naturally compact spectrum. +QPSK with raised-cosine filtering is shown for comparison. +""" + +import numpy as np +import matplotlib.pyplot as plt + +# ── Parameters ────────────────────────────────────────────────────── +Rb = 1.0 # Bit rate (normalised to 1) +Tb = 1.0 / Rb # Bit period +Ts = 2 * Tb # Symbol period (2 bits per QPSK symbol) +alpha = 0.35 # Roll-off factor for raised-cosine filter +N = 8192 # FFT length for smooth curves +fmax = 3.0 # Max normalised frequency (f·Tb) to display + +f = np.linspace(-fmax, fmax, N) +# Avoid exact zeros that cause division issues +f_safe = np.where(f == 0, 1e-30, f) + +# ── 1. MSK Power Spectral Density (closed-form) ─────────────────── +# MSK PSD: S(f) = (16·Tb / π²) · [ cos(2π·f·Tb) / (1 - 16·f²·Tb²) ]² +# Normalised so that Eb = Tb (energy per bit = bit period for unit power) +numerator = np.cos(2 * np.pi * f_safe * Tb) +denominator = 1.0 - 16.0 * (f_safe * Tb) ** 2 + +# Handle the removable singularities at f·Tb = ±0.25 +psd_msk = np.where( + np.abs(np.abs(f * Tb) - 0.25) < 1e-8, + (16.0 * Tb / np.pi**2) * (np.pi / 8.0) ** 2, # L'Hôpital limit + (16.0 * Tb / np.pi**2) * (numerator / denominator) ** 2, +) + +# ── 2. QPSK with Raised-Cosine filter PSD ───────────────────────── +# The raised-cosine spectrum (frequency domain) for roll-off α: +# H(f) = { Ts, |f| <= (1-α)/(2Ts) +# { Ts/2 · [1 + cos(π·Ts/α·(|f| - (1-α)/(2Ts)))], passband edge +# { 0, |f| > (1+α)/(2Ts) } +# PSD of QPSK = Es · |H(f)|² (Es = symbol energy, set to 2·Tb for fair comparison) + +f1 = (1 - alpha) / (2 * Ts) # passband edge +f2 = (1 + alpha) / (2 * Ts) # stopband edge + +H_rc = np.zeros_like(f) +abs_f = np.abs(f) + +# Flat region +mask_flat = abs_f <= f1 +H_rc[mask_flat] = Ts + +# Roll-off region +mask_roll = (abs_f > f1) & (abs_f <= f2) +H_rc[mask_roll] = (Ts / 2.0) * ( + 1.0 + np.cos((np.pi * Ts / alpha) * (abs_f[mask_roll] - f1)) +) + +# PSD of shaped QPSK (energy per symbol Es = 2·Eb = 2·Tb) +Es = 2 * Tb +psd_qpsk_rc = Es * (H_rc / Ts) ** 2 # normalise H so peak PSD matches + +# ── 3. Unfiltered QPSK (rectangular pulse) for reference ────────── +# S(f) = 2·Tb · sinc²(f·Ts) +psd_qpsk_rect = 2 * Tb * np.sinc(f * Ts) ** 2 + +# ── Normalise all to 0 dB peak ───────────────────────────────────── +psd_msk_dB = 10 * np.log10(psd_msk / psd_msk.max() + 1e-30) +psd_qpsk_rc_dB = 10 * np.log10(psd_qpsk_rc / psd_qpsk_rc.max() + 1e-30) +psd_qpsk_rect_dB = 10 * np.log10(psd_qpsk_rect / psd_qpsk_rect.max() + 1e-30) + +# ── Plot ──────────────────────────────────────────────────────────── +fig, ax = plt.subplots(figsize=(10, 6)) + +ax.plot(f, psd_msk_dB, linewidth=2.2, label="MSK", color="#E63946") +ax.plot(f, psd_qpsk_rc_dB, linewidth=2.2, label=f"QPSK (RC α = {alpha})", color="#457B9D") +ax.plot(f, psd_qpsk_rect_dB, linewidth=1.4, label="QPSK (rectangular)", color="#457B9D", + linestyle="--", alpha=0.55) + +ax.set_xlim(-fmax, fmax) +ax.set_ylim(-50, 3) +ax.set_xlabel("Normalized Frequency, fTₛ", fontsize=13) +ax.set_ylabel("Power Spectral Density [dB]", fontsize=13) +ax.set_title("MSK vs QPSK - Spectral Comparison", fontsize=14, fontweight="bold") +ax.legend(fontsize=12, loc="upper right") +ax.grid(True, alpha=0.3, linewidth=0.6) + +plt.tight_layout() +plt.savefig('../_images/msk_vs_qpsk_spectrum.svg', dpi=150) +plt.show() +print("Plot saved to msk_vs_qpsk_spectrum.svg") \ No newline at end of file diff --git a/figure-generating-scripts/ntcs_pal_color.py b/figure-generating-scripts/ntcs_pal_color.py new file mode 100644 index 00000000..5ee2b994 --- /dev/null +++ b/figure-generating-scripts/ntcs_pal_color.py @@ -0,0 +1,151 @@ +import numpy as np +import matplotlib.pyplot as plt +import scipy.signal as sp_signal + +ntsc_filepath = '/mnt/c/Users/marclichtman/Downloads/never_the_same_color.sigmf-data' # cf32, 8M sample rate +num_samples = 10000000 +sig = np.fromfile(ntsc_filepath, dtype=np.complex64, count=num_samples) +fs = 8e6 + +print("=== NTSC Color Decoder ===") +print(f"Sample rate: {fs/1e6} MHz") + +# NTSC parameters +color_carrier_freq = 3.579545e6 # color subcarrier relative to luma carrier +samples_per_line = 508 # samples per line after resampling +total_lines = 525 +frame_rate = 29.97 +line_rate = frame_rate * total_lines # ~15734.25 Hz + +# Find luma carrier (peak in lower half of spectrum) +power_spectrum = 10 * np.log10(np.abs(np.fft.fftshift(np.fft.fft(sig))) ** 2) +freq_axis = np.linspace(-fs / 2, fs / 2, len(power_spectrum)) +luma_carrier_freq = freq_axis[np.argmax(power_spectrum[0:len(power_spectrum) // 2])] +print(f"Luma carrier at: {luma_carrier_freq / 1e6:.3f} MHz") + +# Center on luma carrier +sig = sig * np.exp(-2j * np.pi * luma_carrier_freq * np.arange(len(sig)) / fs) + +# Find line sync positions using falling edges of |sig|, filtered for line spacing +sync_threshold = 0.65 +neg_edges = np.where(np.diff((np.abs(sig) > sync_threshold).astype(int)) == -1)[0] +sync_positions = [neg_edges[0]] +for k in range(1, len(neg_edges)): + if neg_edges[k] - sync_positions[-1] > 400: + sync_positions.append(neg_edges[k]) +sync_positions = np.array(sync_positions) +# Skip first edge if it has abnormal gap (partial line at start) +if len(sync_positions) > 1 and (sync_positions[1] - sync_positions[0]) > 600: + sync_positions = sync_positions[1:] +print(f"Lines found: {len(sync_positions)}") +active_video_offset = 70 # samples from sync edge to start of active video + +# Extract chroma: shift by color subcarrier, lowpass +chroma_sig = sig * np.exp(-2j * np.pi * color_carrier_freq * np.arange(len(sig)) / fs) +chroma_sig = np.convolve(chroma_sig, sp_signal.firwin(301, 1e6, fs=fs), 'same') + +# Extract luma: lowpass and take magnitude (AM demod) +luma_sig = np.convolve(sig, sp_signal.firwin(301, 3e6, fs=fs), 'same') +luma_sig = np.abs(luma_sig) + +# Extract color burst info from each line +burst_delay = 6 +burst_length = 22 +color_freq_offsets = [] +for j in sync_positions: + burst_segment = chroma_sig[j + burst_delay:j + burst_delay + burst_length] + if len(burst_segment) < burst_length: + color_freq_offsets.append(0.0) + continue + burst_spectrum = 10 * np.log10(np.abs(np.fft.fftshift(np.fft.fft(burst_segment, 1024))) ** 2) + burst_freq_axis = np.linspace(-fs / 2, fs / 2, 1024) + color_freq_offsets.append(burst_freq_axis[np.argmax(burst_spectrum)]) + +# Find burst phases and filter out bad bursts +burst_angles = [] +good_sync_positions = [] +good_freq_offsets = [] +for k in range(len(sync_positions)): + burst_chunk = chroma_sig[sync_positions[k] + 12:sync_positions[k] + burst_length] + if len(burst_chunk) == 0: + continue + burst_chunk = burst_chunk * np.exp(-2j * np.pi * color_freq_offsets[k] * np.arange(len(burst_chunk)) / fs) + if np.max(np.abs(burst_chunk)) > 0.02: + if np.var(burst_chunk) < 1e-4: + burst_angles.append(np.mean(np.angle(burst_chunk))) + good_sync_positions.append(sync_positions[k]) + good_freq_offsets.append(color_freq_offsets[k]) +sync_positions = good_sync_positions +color_freq_offsets = good_freq_offsets + +# Determine line parity from burst phase (robust to filtered-out lines) +line_parities = [] +for k in range(len(burst_angles)): + angle_deg = (burst_angles[k] * 180 / np.pi) % 360 + dist_225 = min(abs(angle_deg - 225), 360 - abs(angle_deg - 225)) + dist_135 = min(abs(angle_deg - 135), 360 - abs(angle_deg - 135)) + line_parities.append(0 if dist_225 < dist_135 else 1) + +# Compute per-line phase correction based on detected parity +phase_corrections = [] +for k in range(len(burst_angles)): + if line_parities[k] == 0: + adjusted = burst_angles[k] - 225 / 180 * np.pi + else: + adjusted = burst_angles[k] - 135 / 180 * np.pi + phase_corrections.append(adjusted % (2 * np.pi)) + +# Decode each line into RGB frame +active_start = 32 +active_end = 6 +rgb_frame = np.zeros((total_lines // 2, samples_per_line, 3)) +line_idx = 0 + +for ln in range(len(sync_positions)): + pos = sync_positions[ln] + if pos + samples_per_line + active_end >= len(luma_sig): + break + + ref_level = luma_sig[pos + 20] + if ref_level < 0.01: + ref_level = 1.0 + luma = np.array(luma_sig[pos + active_start:pos + samples_per_line + active_end]) + luma = luma / ref_level + + chroma_segment = chroma_sig[pos + active_start:pos + samples_per_line + active_end] + chroma_segment = chroma_segment * np.exp(-2j * np.pi * color_freq_offsets[ln] * np.arange(len(chroma_segment)) / fs) + chroma_segment = chroma_segment * np.exp(1j * phase_corrections[ln]) + i_signal = chroma_segment.real + q_signal = chroma_segment.imag + if line_parities[ln] == 0: + q_signal *= -1 + + i_signal *= 4.5 + q_signal *= 5.5 + + blue = luma + 2.029 * i_signal + red = luma + 1.14 * q_signal + green = luma - 0.396 * i_signal - 0.581 * q_signal + + if line_idx < total_lines // 2: + count = min(len(luma), samples_per_line) + rgb_frame[line_idx, 0:count, 0] = 1 - red[:count] + rgb_frame[line_idx, 0:count, 1] = 1 - green[:count] + rgb_frame[line_idx, 0:count, 2] = 1 - blue[:count] + + line_idx += 1 + if line_idx == total_lines - 18: + break # one frame decoded + +rgb_frame = np.clip(rgb_frame, 0, 1) +print(f"Decoded {line_idx} lines") +print(f"RGB max: R={rgb_frame[:,:,0].max():.2f} G={rgb_frame[:,:,1].max():.2f} B={rgb_frame[:,:,2].max():.2f}") + +plt.figure(figsize=(10, 7)) +plt.imshow(rgb_frame, aspect=0.6) +plt.title('Decoded NTSC Color Frame') +plt.axis('off') +plt.tight_layout() +#plt.savefig('/home/marc/PySDR/figure-generating-scripts/ntsc_color_frame.png', dpi=150) +print("Saved to ntsc_color_frame.png") +plt.show() diff --git a/figure-generating-scripts/ntsc_pal.py b/figure-generating-scripts/ntsc_pal.py index 6adccafa..ebc75ce8 100644 --- a/figure-generating-scripts/ntsc_pal.py +++ b/figure-generating-scripts/ntsc_pal.py @@ -20,6 +20,14 @@ - They use VSB and not SSB because they have a DC component and SSB would filter that out - remember that hacktv can also produce fm modulated pal, as well as the different variants of pal - http://martin.hinner.info/vga/pal.html + +Create example color recording using hacktv: +sudo apt install hacktv +download https://minibaud.com/pscroll.php?b=1&d=7&fn=6985 +hacktv -o file:/tmp/pal_color_hacktv.fc32 -t float -m i /mnt/c/Users/marclichtman/Downloads/Free_Test_Data_1.21MB_MKV.mkv -s 16000000 --filter +or +hacktv -o file:/tmp/pal_color_hacktv.fc32 -t float -m i -s 16000000 --filter test:colourbars +(2nd one needs to be manually stopped) ''' import numpy as np @@ -43,7 +51,7 @@ # ATSC recording from 2022 GNU Radio Conference CTF- # https://ctf-2022.gnuradio.org/files/5d51c1bb8774333af7e87ecf19f8b664/never_the_same_color.sigmf-meta # https://ctf-2022.gnuradio.org/files/bccb3de9c758a0760146aa86e610fa02/never_the_same_color.sigmf-data - ntsc_example = '/mnt/d/never_the_same_color.sigmf-data' # cf32, 8M sample rate + ntsc_example = '/mnt/c/Users/marclichtman/Downloads/never_the_same_color.sigmf-data' # cf32, 8M sample rate samples_to_process = 10000000 x = np.fromfile(ntsc_example, dtype=np.complex64, count=samples_to_process) sample_rate = 8e6 @@ -55,19 +63,25 @@ color_subcarrier_freq = 3.579545e6 # higher than luma carrier, not relative to center freq relative_audio_subcarrier_freq = 3.5e6 else: - samples_to_process = 10000000 format_type = 'pal' - #pal_example = '/mnt/d/SDRSharp_20170122_171736Z_179100000Hz_IQ.wav' # used in this SIGIDWIKI entry https://www.sigidwiki.com/wiki/PAL_Broadcast#google_vignette - #x = read(pal_example) - #sample_rate = x[0] - #print("Sample Rate:", sample_rate) - #fc = 179.1e6 # taken from filename - #sample_offset = 200 + 512*55 # in samples. specific to recording - #pal_example2 = '/mnt/d/pal_color_hacktv.fc32' # ./hacktv -o file:/mnt/d/pal_color_hacktv.fc32 -t float -m i /mnt/c/Users/marclichtman/Downloads/Free_Test_Data_1.21MB_MKV.mkv -s 16000000 --filter - pal_example2 = '/mnt/d/pal_color_hacktv_colourbars.fc32' # same as above but used test:colourbars instead of mkv file + + ''' + samples_to_process = 10000000 + pal_example = '/mnt/c/Users/marclichtman/Downloads/SDRSharp_20170122_171736Z_179100000Hz_IQ.wav' # used in this SIGIDWIKI entry https://www.sigidwiki.com/wiki/PAL_Broadcast#google_vignette + x = read(pal_example) + sample_rate = x[0] + print("Sample Rate:", sample_rate) + fc = 179.1e6 # taken from filename + sample_offset = 200 + 512*55 # in samples. specific to recording + ''' + + samples_to_process = 10000000 + pal_example2 = '/tmp/pal_color_hacktv.fc32' # ./hacktv -o file:/mnt/d/pal_color_hacktv.fc32 -t float -m i /mnt/c/Users/marclichtman/Downloads/Free_Test_Data_1.21MB_MKV.mkv -s 16000000 --filter + #pal_example2 = '/mnt/d/pal_color_hacktv_colourbars.fc32' # same as above but used test:colourbars instead of mkv file sample_rate = 16e6 x = np.fromfile(pal_example2, dtype=np.complex64, count=samples_to_process) sample_offset = 15 + 0*55 # in samples. specific to recording + color_subcarrier_freq = 4.43361875e6 # higher than luma carrier, not relative to center freq relative_audio_subcarrier_freq = 3.5e6 # relative to luma carrier, leave positive even if its negative @@ -121,8 +135,10 @@ # Find start of frame TODO: currently assumes recording starts during the transition period gap_between_lines = 1024 # samples threshold = 0.65 # can be same as other threshold -burst_indxs = np.where(np.diff((np.abs(x) > threshold).astype(int)) == 1)[0] # indx of rising edges -start_of_frame = burst_indxs[np.where(np.diff(burst_indxs) == gap_between_lines)[0][0] + 1] +x_env = np.convolve(np.abs(x), np.ones(100)/100, 'same') # smooth out chroma oscillations to get envelope +burst_indxs = np.where(np.diff((x_env > threshold).astype(int)) == 1)[0] # indx of rising edges +diffs = np.diff(burst_indxs) +start_of_frame = burst_indxs[np.where(np.abs(diffs - gap_between_lines) < 10)[0][0] + 1] print("Start of frame:", start_of_frame) x = x[start_of_frame:] # cut off end of prev frame if False: @@ -162,7 +178,7 @@ # Using a manually tuned threshold, find the start of each burst, using the combined luma+chroma (last time it needs to be used) threshold = 0.65 -burst_indxs = np.where(np.diff((np.abs(x) > threshold).astype(int)) == -1)[0] # need to use abs() of original signal that includes luma and chroma for detection of each pixel start +burst_indxs = np.where(np.diff((x_env > threshold).astype(int)) == -1)[0] # need to use envelope for detection of each pixel start if False: # look at a single line and the threshold offset = 100000 length = 2000 @@ -201,7 +217,9 @@ # Extract just the chroma bursts, and store freq offsets of each burst delay_till_burst = 6 # samples between thresh and start of burst FIXME CONVERT TO SECONDS AND CALC BASED ON SAMPLE RATE burst_len = 22 # samples FIXME CONVERT TO SECONDS AND CALC BASED ON SAMPLE RATE -x_chroma_burst = np.zeros_like(x) +x_chroma_burst = np.zeros_like(x_chroma) +# Filter out burst indices that would go out of bounds after resampling +burst_indxs = [i for i in burst_indxs if i + delay_till_burst + burst_len <= len(x_chroma)] chroma_freq_offsets = [] # corresponds to burst_indxs for i in burst_indxs: burst_slice = x_chroma[i+delay_till_burst:i+delay_till_burst+burst_len] diff --git a/figure-generating-scripts/ntsc_pal_bw.py b/figure-generating-scripts/ntsc_pal_bw.py new file mode 100644 index 00000000..e732b2c1 --- /dev/null +++ b/figure-generating-scripts/ntsc_pal_bw.py @@ -0,0 +1,205 @@ +import numpy as np +import matplotlib.pyplot as plt +import scipy.signal as signal +from PIL import Image + +# Spikes after FM demod +# 3.579545e6 Color NTSC +# 4.43361875e6 Color PAL and SECAM +# 6.5025e6 audio carrier (I think the audio is transmitted separately but this is where it would show up after FM demodding the whole thing) +# apparently the audio might show up at 5.5, 6.0, or 6.5 MHz + +if True: + format_type = 'ntsc' + samples_to_process = 500000 + + # ATSC recording from 2022 GNU Radio Conference CTF- + # https://ctf-2022.gnuradio.org/files/5d51c1bb8774333af7e87ecf19f8b664/never_the_same_color.sigmf-meta + # https://ctf-2022.gnuradio.org/files/bccb3de9c758a0760146aa86e610fa02/never_the_same_color.sigmf-data + #ntsc_example = '/mnt/c/Users/marclichtman/Downloads/never_the_same_color.sigmf-data' # cf32, 8M sample rate + + # ntsc_example = '/mnt/c/Users/marclichtman/Downloads/signal_recordings/RunCamNightEagle3V2_rushfpv.sigmf-data' #ci16, 40M. NO COLOR! + # offset = 66200 # to manually sync to the horizontal pulse, so lines all start on the left + # x = np.fromfile(ntsc_example, dtype=np.int16, count=samples_to_process, offset=offset) + # x = x.astype(np.float32) / 32768.0 + # x = x[::2] + 1j*x[1::2] + + # ntsc_example = '/mnt/c/Users/marclichtman/Downloads/signal_recordings/color.sigmf-data' # 40M sample rate, cf32 + ntsc_example = '/mnt/c/Users/marcl/Downloads/ntsc_remy_10MHz_5925Hz_cf32.iq' + sample_rate = 10e6 + x = np.fromfile(ntsc_example, dtype=np.complex64, count=samples_to_process) + + #sample_rate = 40e6 + #fc = 441e6 # taken from metadata file + color_subcarrier_freq = 3.579545e6 # higher than luma carrier, not relative to center freq + relative_audio_subcarrier_freq = 3.5e6 +else: + format_type = 'pal' + samples_to_process = 100000000 + + ''' + pal_example = '/mnt/c/Users/marclichtman/Downloads/SDRSharp_20170122_171736Z_179100000Hz_IQ.wav' # used in this SIGIDWIKI entry https://www.sigidwiki.com/wiki/PAL_Broadcast#google_vignette + x = read(pal_example) + sample_rate = x[0] + print("Sample Rate:", sample_rate) + fc = 179.1e6 # taken from filename + sample_offset = 200 + 512*55 # in samples. specific to recording + ''' + + #pal_example = '/mnt/c/Users/marclichtman/Downloads/signal_recordings/foxeer_rushfpv.sigmf-data' #ci16, 40M. PAL Color + # pal_example = '/mnt/c/Users/marclichtman/Downloads/signal_recordings/3390MHz_40MS_10m_cable_4000m_distance+LNA30.sigmf-data' + # x = np.fromfile(pal_example, dtype=np.int16, count=samples_to_process) + # x = x.astype(np.float32) + # x = x[::2] + 1j*x[1::2] + # x /= np.max(np.abs(x)) + # sample_rate = 40e6 + + #pal_example = '/tmp/pal_color_hacktv.fc32' # ./hacktv -o file:/mnt/d/pal_color_hacktv.fc32 -t float -m i /mnt/c/Users/marclichtman/Downloads/Free_Test_Data_1.21MB_MKV.mkv -s 16000000 --filter + #pal_example = '/mnt/d/pal_color_hacktv_colourbars.fc32' # same as above but used test:colourbars instead of mkv file + #sample_rate = 16e6 + + x = np.fromfile(pal_example, dtype=np.complex64, count=samples_to_process) + + sample_offset = 15 + 0*55 # in samples. specific to recording + + color_subcarrier_freq = 4.43361875e6 # higher than luma carrier, not relative to center freq + relative_audio_subcarrier_freq = 3.5e6 # relative to luma carrier, leave positive even if its negative + + # if plotting R-Y and B-Y on complex plane, phase is the hue of the color, and its magnitude is the saturation + # the tx inserts a snippet of the subcarrier just after the horizontal sync pulse, known as the color burst + # in PAL, the phase of the R-Y component is inverted on alternate lines, hence "Phase Alternating Line" + # i.e., the imaginary part (R-Y) will be negative every other line. it also lets the rx know whether its receiving an even or odd line at any given time + # the phase of the colour burst alternates between 135º and -135º relative to B-Y + +if format_type == 'ntsc': + samples_per_line = 508 + lines_per_frame = 525 + refresh_Hz = 30.0/1.001 # almost exactly 29.97 # not exactly 30 Hz!! makes difference +else: # PAL + samples_per_line = 512 + lines_per_frame = 625 # (576 visible lines) + refresh_Hz = 25 + +samples_per_frame = samples_per_line * lines_per_frame // 2 # samples per frame. WHY DO I NEED THE /2? +print("Samples per frame:", samples_per_frame) +line_Hz = refresh_Hz * lines_per_frame + +# PSD of raw RF +if False: + PSD = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(x)))**2 / (len(x)*sample_rate)) + f = np.linspace(sample_rate/-2, sample_rate/2, len(PSD)) + plt.plot(f / 1e6, PSD) + plt.xlim(-4, 4) + plt.ylim(-100, -50) + plt.xlabel("Frequency [MHz]") + plt.ylabel("PSD [dB]") + plt.show() + +x_demod = np.angle(x[1:] * np.conj(x[:-1])) # FM demodulation + +# PSD of FM demodulated signal +if False: + PSD = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(x_demod)))**2 / (len(x_demod)*sample_rate)) + f = np.linspace(sample_rate/-2, sample_rate/2, len(PSD)) + plt.plot(f / 1e6, PSD) + plt.xlim(0, 7) + plt.ylim(-110, -35) + plt.xlabel("Frequency [MHz]") + plt.ylabel("PSD [dB]") + plt.show() + exit() + +# Spectrogram of FM demodded signal +if False: + fft_size = 1024 + num_rows = len(x_demod) // fft_size # // is an integer division which rounds down + spectrogram = np.zeros((num_rows, fft_size)) + for i in range(num_rows): + spectrogram[i,:] = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(x_demod[i*fft_size:(i+1)*fft_size])))**2) + plt.imshow(spectrogram, aspect='auto', extent = [sample_rate/-2/1e6, sample_rate/2/1e6, len(x)/sample_rate, 0]) + plt.xlabel("Frequency [MHz]") + plt.ylabel("Time [s]") + plt.show() + +# Filter out audio from demodded signal +#h = signal.firwin(301, 6e6, fs=sample_rate) # LPF up to 6 MHz, audio is centered at 6.5 MHz but is pretty narrow +h = signal.firwin(301, 3e6, fs=sample_rate) # for the 10 Mhz recording +x_demod = np.convolve(x_demod, h, 'same') + +if False: # nice shot of a single line using foxeer_rushfpv + offset = 2515 + length = 4000 + plt.plot(x_demod[offset:offset+length]) + plt.xlabel("Sample") + plt.show() + exit() + +# h = signal.firwin(301, 3e6, fs=sample_rate) # LPF +# x_demod = np.convolve(x_demod, h, 'same') + +# Resample luma and chroma to exactly L samples per line +resampling_rate = samples_per_line / (sample_rate / line_Hz) +resampling_rate *= 1.00003 # fixes the drift, not 100% sure where it comes from, perhaps sample clock offset +x_demod = signal.resample(x_demod, int(len(x_demod)*resampling_rate)) +print("Resampling rate:", resampling_rate) + +# Optionally, crop to 1 frames worth of samples +if False: + manually_tuned_offset = 122250 # for both frame sync and horizontal sync + x_demod = x_demod[manually_tuned_offset:manually_tuned_offset+samples_per_frame] + +# Time domain plot +if False: + plt.plot(x_demod) + plt.xlabel("Sample") + plt.show() + +# Save the vertical sync signal as a template to correlate with later +if False: + v_sync_template = np.asarray(x_demod[117386:121712]) + print(type(v_sync_template[0])) # np.float64 + v_sync_template.tofile("/tmp/vertical_sync_template.iq") + plt.plot(x_demod[117386:121712]) + plt.xlabel("Sample") + plt.show() + +# Correlate entire signal against the v-sync template, then sync to frame +if False: + template = np.fromfile("/tmp/vertical_sync_template.iq", dtype=np.float64) + correlation = np.abs(np.correlate(x_demod, template, mode='full'))**2 + # plt.plot(correlation) + # plt.xlabel("Sample") + # plt.ylabel("Correlation") + # plt.show() + + # Sync to the start of frame we detected + frame_start = np.argmax(correlation[:150000]) # try to get one of the first ones + frame_start += 20 + print("Argmax in first 150000 samples at:", frame_start) + x_demod = x_demod[frame_start:frame_start+samples_per_frame] + +# Autocorrelation, to try to file spikes at certain lags (254 for vertical sync, 508 samples per line) +if False: + n_autocorr = 650 + autocorr = np.array([np.dot(x_demod[:len(x_demod)-lag], x_demod[lag:]) for lag in range(n_autocorr)]) + plt.plot(np.arange(n_autocorr), np.abs(autocorr)) + plt.xlabel("Lag") + plt.ylabel("Autocorrelation") + plt.show() + exit() + + +# reshape into 2D +x_demod = x_demod[:len(x_demod) - (len(x_demod) % samples_per_line)] # trim to multiple of samples_per_line +frame = x_demod.reshape(-1, samples_per_line) # type: ignore + +# Normalize to 0-255 and convert to uint8 +frame_norm = frame - np.min(frame) +frame_norm = frame_norm / np.max(frame_norm) +frame_uint8 = (frame_norm * 255).astype(np.uint8) + +# Display as single image with fixed scaling +plt.imshow(frame_uint8, cmap='gray', aspect='auto', vmin=0, vmax=255) +plt.axis('off') +plt.title(f'{format_type.upper()} B&W') +plt.show() diff --git a/figure-generating-scripts/ntsc_pal_bw_minimal.py b/figure-generating-scripts/ntsc_pal_bw_minimal.py new file mode 100644 index 00000000..94a3d862 --- /dev/null +++ b/figure-generating-scripts/ntsc_pal_bw_minimal.py @@ -0,0 +1,128 @@ +import numpy as np +import matplotlib.pyplot as plt +import scipy.signal as signal + +filename = 'ntsc_remy_10MHz_5925Hz_500ksamples_cf32.iq' +x = np.fromfile(filename, dtype=np.complex64) +sample_rate = 10e6 +color_subcarrier_freq = 3.579545e6 # NTSC. higher than luma carrier, not relative to center freq +# color_subcarrier_freq = 4.43361875e6 # PAL and SECAM +relative_audio_subcarrier_freq = 3.5e6 # the audio might show up at 5.5, 6.0, or 6.5 MHz + +# NTSC constants +samples_per_line = 508 +lines_per_frame = 525 +refresh_Hz = 30.0/1.001 # almost exactly 29.97 # not exactly 30 Hz!! makes difference + +# PAL constants +#samples_per_line = 512 +#lines_per_frame = 625 # (576 visible lines) +#refresh_Hz = 25 + +samples_per_frame = samples_per_line * lines_per_frame // 2 # NTSC's vertical sync repeats every field (half-frame), not every full frame +print("Samples per frame:", samples_per_frame) +line_Hz = refresh_Hz * lines_per_frame + +# PSD of raw RF +if False: + plt.rcParams['svg.fonttype'] = 'none' + PSD = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(x)))**2 / (len(x)*sample_rate)) + f = np.linspace(sample_rate/-2, sample_rate/2, len(PSD)) + n = 4096 + step = len(PSD) // n + PSD_plot = PSD[:step*n].reshape(n, step).mean(axis=1) + f_plot = f[:step*n].reshape(n, step).mean(axis=1) + plt.plot(f_plot / 1e6, PSD_plot) + plt.grid() + plt.xlim(-4, 4) + plt.ylim(-30, 15) + plt.xlabel("Frequency [MHz]") + plt.ylabel("PSD [dB]") + plt.savefig('../_images/fpv_psd_raw_rf.svg', bbox_inches='tight') + exit() + +x_demod = np.angle(x[1:] * np.conj(x[:-1])) # FM demodulation + +# PSD of FM demodulated signal +if False: + plt.rcParams['svg.fonttype'] = 'none' + PSD = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(x_demod)))**2 / (len(x_demod)*sample_rate)) + f = np.linspace(sample_rate/-2, sample_rate/2, len(PSD)) + n = 2**14 + step = len(PSD) // n + PSD_plot = PSD[:step*n].reshape(n, step).mean(axis=1) + f_plot = f[:step*n].reshape(n, step).mean(axis=1) + plt.plot(f_plot / 1e6, PSD_plot) + plt.grid() + plt.xlim(0, 4.7) + plt.ylim(-110, -30) + plt.xlabel("Frequency [MHz]") + plt.ylabel("PSD [dB]") + plt.savefig('../_images/fpv_psd_after_fm_demod.svg', bbox_inches='tight') + plt.show() + exit() + +# PSD of FM demodulated signal, zooming into the low freq harmonics +if False: + PSD = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(x_demod)))**2 / (len(x_demod)*sample_rate)) + f = np.linspace(sample_rate/-2, sample_rate/2, len(PSD)) + plt.plot(f / 1e6, PSD) + plt.grid() + plt.xlim(0, 0.1) + plt.ylim(-70, -20) + plt.xlabel("Frequency [MHz]") + plt.ylabel("PSD [dB]") + plt.savefig('../_images/fpv_psd_after_fm_demod_harmomics.svg', bbox_inches='tight') + plt.show() + + +if False: # nice shot of the start of a frame and several lines + offset = 146880 + length = 20000 + plt.figure(figsize=(12, 3)) + plt.plot(x_demod[offset:offset+length]) + plt.xlabel("Sample") + plt.ylabel("Amplitude") + plt.savefig('../_images/fpv_time_domain.svg', bbox_inches='tight') + plt.show() + +if False: # zoomed into 1 line + offset = 400 + length = samples_per_line + 150 + plt.figure(figsize=(12, 3)) + plt.plot(x_demod[offset:offset+length]) + plt.xlabel("Sample") + plt.ylabel("Amplitude") + plt.savefig('../_images/fpv_time_domain_one_line.svg', bbox_inches='tight') + plt.show() + +# Filter out audio from demodded signal +h = signal.firwin(301, 3e6, fs=sample_rate) # for the 10 Mhz recording +x_demod = np.convolve(x_demod, h, 'same') + +# Resample luma and chroma to exactly L samples per line +resampling_rate = samples_per_line / (sample_rate / line_Hz) +resampling_rate *= 1.00003 # fixes the drift, not 100% sure where it comes from, perhaps sample clock offset +x_demod = signal.resample(x_demod, int(len(x_demod)*resampling_rate)) +print("Resampling rate:", resampling_rate) + +# crop to 1 frames worth of samples +if True: + manually_tuned_offset = 122250 # for both frame sync and horizontal sync + x_demod = x_demod[manually_tuned_offset:manually_tuned_offset+samples_per_frame] + +# reshape into 2D +x_demod = x_demod[:len(x_demod) - (len(x_demod) % samples_per_line)] # trim to multiple of samples_per_line +frame = x_demod.reshape(-1, samples_per_line) # type: ignore + +# Normalize to 0-255 and convert to uint8 +frame_norm = frame - np.min(frame) +frame_norm = frame_norm / np.max(frame_norm) +frame_uint8 = (frame_norm * 255).astype(np.uint8) + +# Display as single image with fixed scaling +plt.imshow(frame_uint8, cmap='gray', aspect='auto', vmin=0, vmax=255) +plt.axis('off') +#plt.savefig('../_images/fpv_image_no_sync.svg', bbox_inches='tight') +#plt.savefig('../_images/fpv_image_one_frame.svg', bbox_inches='tight') +plt.show() diff --git a/figure-generating-scripts/ntsc_remy_10MHz_5925Hz_500ksamples_cf32.iq b/figure-generating-scripts/ntsc_remy_10MHz_5925Hz_500ksamples_cf32.iq new file mode 100644 index 00000000..eda235a2 Binary files /dev/null and b/figure-generating-scripts/ntsc_remy_10MHz_5925Hz_500ksamples_cf32.iq differ diff --git a/figure-generating-scripts/pluto.py b/figure-generating-scripts/pluto.py new file mode 100644 index 00000000..a48b962c --- /dev/null +++ b/figure-generating-scripts/pluto.py @@ -0,0 +1,46 @@ +import numpy as np +import adi +import matplotlib.pyplot as plt + +sample_rate = 56e6 # Hz +center_freq = 5.78e9 # Hz +num_samps = int(10e6) # number of samples returned per call to rx() + +sdr = adi.Pluto('ip:192.168.20.1') +sdr.gain_control_mode_chan0 = 'manual' +sdr.rx_hardwaregain_chan0 = 20.0 # dB +#sdr.gain_control_mode_chan0 = "fast_attack" +sdr.rx_lo = int(center_freq) +sdr.sample_rate = int(sample_rate) +sdr.rx_rf_bandwidth = int(sample_rate) # filter width, just set it to the same as sample rate for now +sdr.rx_buffer_size = num_samps + +x = sdr.rx() # receive samples off Pluto +x = np.asarray(x) # purely for type hinting and linting +print(np.max(x)) + +# Spectrogram +if True: + fft_size = 1024 + num_rows = len(x) // fft_size # // is an integer division which rounds down + spectrogram = np.zeros((num_rows, fft_size)) + for i in range(num_rows): + spectrogram[i,:] = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(x[i*fft_size:(i+1)*fft_size])))**2) + # Time starts at the top and goes down, eg sample x[0] will be part of the top row displayed + plt.imshow(spectrogram, aspect='auto', extent = [sample_rate/-2/1e6 + center_freq/1e6, sample_rate/2/1e6 + center_freq/1e6, len(x)/sample_rate, 0]) # type: ignore + plt.xlabel("Frequency [MHz]") + plt.ylabel("Time [s]") + plt.show() + +# PSD +if False: + psd = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(x[0:10000])))**2) + plt.plot(np.linspace(-sample_rate/2, sample_rate/2, len(psd))/1e6, psd) + plt.xlabel("Frequency [MHz]") + plt.ylabel("Power [dB]") + plt.show() + +# Save to file +if False: + x = np.asarray(x, dtype=np.complex64) + x.tofile("/tmp/pluto_samples.iq") \ No newline at end of file diff --git a/figure-generating-scripts/random_variables.py b/figure-generating-scripts/random_variables.py new file mode 100644 index 00000000..7f458918 --- /dev/null +++ b/figure-generating-scripts/random_variables.py @@ -0,0 +1,69 @@ +import numpy as np +import matplotlib.pyplot as plt + +# Generate 10,000 samples from standard Gaussian +x = np.random.randn(10000) + +# Create histogram to visualize the distribution +plt.hist(x, bins=50, density=True, alpha=0.7, edgecolor='black') +plt.xlabel('Value') +plt.ylabel('Probability Density') +plt.title('Gaussian Distribution (μ=0, σ²=1)') +plt.grid(True) +plt.show() + +# Simulation parameters +N = 10000 + +# Generate standard Gaussian random variables (mean=0, var=1) +x = np.random.randn(N) + +# Create different random variables by scaling and shifting +y1 = x # mean=0, var=1 +y2 = 2 * x # mean=0, var=4 +y3 = x + 3 # mean=3, var=1 +y4 = 0.5 * x - 1 # mean=-1, var=0.25 + +# Verify properties +signals = [y1, y2, y3, y4] +labels = ['y1: x', 'y2: 2x', 'y3: x+3', 'y4: 0.5x-1'] + +for i, (sig, label) in enumerate(zip(signals, labels)): + print(f"{label}") + print(f" Sample mean: {np.mean(sig):.3f}") + print(f" Sample variance: {np.var(sig):.3f}") + print() + +# Plot histograms +fig, axes = plt.subplots(2, 2, figsize=(10, 8)) +axes = axes.flatten() + +for i, (sig, label, ax) in enumerate(zip(signals, labels, axes)): + ax.hist(sig, bins=50, density=True, alpha=0.7, edgecolor='black') + ax.set_title(label) + ax.set_xlabel('Value') + ax.set_ylabel('Density') + ax.grid(True) + +plt.tight_layout() +plt.show() + +# Complex Gaussian noise demonstration +n_complex = (np.random.randn(N) + 1j*np.random.randn(N)) / np.sqrt(2) + +print("Complex Gaussian Noise (unit power):") +print(f" Real part variance: {np.var(np.real(n_complex)):.3f}") +print(f" Imag part variance: {np.var(np.imag(n_complex)):.3f}") +print(f" Total variance: {np.var(n_complex):.3f}") + +# Plot on IQ plane +plt.figure(figsize=(6, 6)) +plt.plot(np.real(n_complex[:1000]), np.imag(n_complex[:1000]), '.', alpha=0.3) +plt.xlabel('In-phase (I)') +plt.ylabel('Quadrature (Q)') +plt.title('Complex Gaussian Noise on IQ Plane') +plt.grid(True) +plt.axis('equal') +plt.xlim([-3, 3]) +plt.ylim([-3, 3]) +plt.show() \ No newline at end of file diff --git a/figure-generating-scripts/rds_demo.py b/figure-generating-scripts/rds_demo.py index d84a8db3..c42bb064 100644 --- a/figure-generating-scripts/rds_demo.py +++ b/figure-generating-scripts/rds_demo.py @@ -1,12 +1,12 @@ import matplotlib.pyplot as plt import numpy as np -from gnuradio.filter import firdes +#from gnuradio.filter import firdes from scipy.signal import resample_poly, firwin from matplotlib.animation import FuncAnimation #samples = np.fromfile('/home/marc/Downloads/fm_clip_for_rds.iq', dtype=np.complex64) # med SNR #samples = np.fromfile('/home/marc/Downloads/fm_rds_250k.iq', dtype=np.complex64) # high SNR -samples = np.fromfile('fm_rds_250k_1Msamples.iq', dtype=np.complex64) # high SNR, shorter +samples = np.fromfile('/home/marc/fm_rds_250k_1Msamples.iq', dtype=np.complex64) # high SNR, shorter # MAKE MY OWN RECORDING OF A COOLER STATION, JUST MAKE SURE ITS HIGH SNR AND SCALE IT TO THE SAME SIGNAL LEVEL AS THIS WORKING ONE @@ -35,17 +35,19 @@ x = 0.5 * np.angle(samples[0:-1] * np.conj(samples[1:])) # see https://wiki.gnuradio.org/index.php/Quadrature_Demod # PSD -if False: - PSD = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(x)))**2) - PSD = PSD[::100] +if True: + print(len(x)) + PSD = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(x)))**2 / len(x) / sample_rate) + PSD = PSD[::10] PSD = PSD[len(PSD)//2:] PSD = PSD - np.max(PSD) f = np.linspace(0, sample_rate/2, len(PSD))/1e3 plt.plot(f, PSD) - plt.axis([0, 125, -55, 1]) + plt.axis([0, 80, -70, 0]) plt.xlabel("Frequency [kHz]") plt.ylabel("PSD After FM Demod [dB]") plt.show() + exit() # Spectrogram (once i get a higher SNR better looking recording I can include spectrogram towards the start if False: diff --git a/figure-generating-scripts/spectrogram.py b/figure-generating-scripts/spectrogram.py index db5080f4..de75ca83 100644 --- a/figure-generating-scripts/spectrogram.py +++ b/figure-generating-scripts/spectrogram.py @@ -21,8 +21,9 @@ for i in range(num_rows): spectrogram[i,:] = np.log10(np.abs(np.fft.fftshift(np.fft.fft(x[i*fft_size:(i+1)*fft_size])))**2) -plt.imshow(spectrogram, aspect='auto', extent = [sample_rate/-2/1e6, sample_rate/2/1e6, 0, len(x)/sample_rate]) +# Time starts at the top and goes down, eg x[0] will be in the top row displayed +plt.imshow(spectrogram, aspect='auto', extent = [sample_rate/-2/1e6, sample_rate/2/1e6, len(x)/sample_rate, 0]) plt.xlabel("Frequency [MHz]") plt.ylabel("Time [s]") -#plt.show() plt.savefig('../_images/spectrogram.svg', bbox_inches='tight') +#plt.show() diff --git a/figure-generating-scripts/sync_chapter.py b/figure-generating-scripts/sync_chapter.py index c2b20ac4..814b3150 100644 --- a/figure-generating-scripts/sync_chapter.py +++ b/figure-generating-scripts/sync_chapter.py @@ -41,7 +41,7 @@ # Filter our signal, in order to apply the pulse shaping -samples = np.convolve(pulse_train, h) +samples = np.convolve(pulse_train, h, "same") fig, ax = plt.subplots(1, figsize=(7, 3)) # 7 is nearly full width symbols_to_plot = 10 plt.plot(samples[0:symbols_to_plot * sps + (num_taps - 1) // 2], '.-') @@ -146,34 +146,6 @@ def rail(x): ax2.set_title('After Interpolation') #fig.savefig('/tmp/time-sync-interpolated-samples.svg', bbox_inches='tight') -''' REAL VERSION -mu = 0 # initial estimate of phase of sample -i_in = 0 # input index -i_out = 0 # output index -last_sample = 0 # initial condition -out = np.zeros(num_symbols + 30, dtype=np.complex) # output will be 1 sample per symbol, we add extra room at the end for good measure -while i_out < len(samples) and i_in < len(samples): - out[i_out] = samples_interpolated[i_in*16 + int(mu*16)] # grab what we think is the "best" sample - last_sample = out[i_out] - mm_val = rail(last_sample) * out[i_out] - rail(out[i_out]) * last_sample - mu += sps + 0.3*mm_val # the multiplier can be tweaked to change how fast it reacts, higher value will make it work faster - i_in += int(np.floor(mu)) # round down to nearest int since we are using it as an index - mu = mu - np.floor(mu) # remove the integer part of mu - i_out += 1 # increment output index - print(i_out) -''' - -# COMPLEX VERSION -''' (made into one-liner) -def rail_complex(x): # takes in a complex sample - I = 0.0 - Q = 0.0 - if(np.real(x) > 0): - I = 1.0 - if(np.imag(x) > 0): - Q = 1.0 - return I + 1j*Q -''' mu = 0 # initial estimate of phase of sample out = np.zeros(len(samples) + 10, dtype=np.complex64) diff --git a/figure-generating-scripts/sync_chapter_only_full_example.py b/figure-generating-scripts/sync_chapter_only_full_example.py new file mode 100644 index 00000000..56079944 --- /dev/null +++ b/figure-generating-scripts/sync_chapter_only_full_example.py @@ -0,0 +1,122 @@ +import numpy as np +import matplotlib.pyplot as plt +from scipy import signal + +# Create BPSK signal +num_symbols = 100 +sps = 8 +bits = np.random.randint(0, 2, num_symbols) # Our data to be transmitted, 1's and 0's +pulse_train = np.array([]) +for bit in bits: + pulse = np.zeros(sps) + pulse[0] = bit*2-1 # set the first value to either a 1 or -1 + pulse_train = np.concatenate((pulse_train, pulse)) # add the 8 samples to the signal + +# Apply pulse shaping to the BPSK +num_taps = 101 +beta = 0.35 +Ts = sps # Assume sample rate is 1 Hz, so sample period is 1, so *symbol* period is 8 +t = np.arange(-51, 52) # remember it's not inclusive of final number +h = np.sinc(t/Ts) * np.cos(np.pi*beta*t/Ts) / (1 - (2*beta*t/Ts)**2) +samples = np.convolve(pulse_train, h, 'same') + +# Create and apply fractional delay filter to emulate a random timing offset +delay = 0.456 # fractional delay, in samples +N = 21 # number of taps, keep this odd +n = np.arange(-(N-1)//2, N//2+1) # -10,-9,...,0,...,9,10 +h = np.sinc(n - delay) # calc filter taps +h *= np.hamming(N) # window the filter to make sure it decays to 0 on both sides +h /= np.sum(h) # normalize to get unity gain, we don't want to change the amplitude/power +samples = np.convolve(samples, h) # apply filter + +# Apply a pretty significant freq offset +fs = 1e6 # assume our sample rate is 1 MHz +fo = 13000 # simulate freq offset THIS REPRESENTS A COARSE OFFSET! +Ts = 1/fs # calc sample period +t = np.arange(0, Ts*len(samples), Ts) # create time vector +samples = samples * np.exp(1j*2*np.pi*fo*t) # perform freq shift + +# Estimate and correct for the coarse freq offset +samples_sq = samples**2 +psd = np.fft.fftshift(np.abs(np.fft.fft(samples_sq, 2048))) +f = np.linspace(-fs/2.0, fs/2.0, len(psd)) +max_freq = f[np.argmax(psd)] / 2.0 +print(f"Estimated freq offset: {max_freq:.2f} Hz") +Ts = 1/fs # calc sample period +t = np.arange(0, Ts*len(samples), Ts) # create time vector +samples = samples * np.exp(-1j*2*np.pi*max_freq*t) + +# At this point there should be less than 1kHz of freq offset in our signal, depending how large an FFT you used above + +# Symbol/Timing Sync +mu = 0 # initial estimate of phase of sample +out = np.zeros(len(samples) // sps + 2, dtype=np.complex64) +out_rail = np.zeros(len(samples) // sps + 2, dtype=np.complex64) # stores values, each iteration we need the previous 2 values plus current value +i_in = 0 # input samples index +i_out = 2 # output index (let first two outputs be 0) +interpolation_factor = 16 +samples_interpolated = signal.resample_poly(samples, interpolation_factor, 1) +while i_out < len(samples) and i_in+16 < len(samples): + out[i_out] = samples_interpolated[i_in*interpolation_factor + int(mu*interpolation_factor)] + out_rail[i_out] = int(np.real(out[i_out]) > 0) + 1j*int(np.imag(out[i_out]) > 0) + x = (out_rail[i_out] - out_rail[i_out-2]) * np.conj(out[i_out-1]) + y = (out[i_out] - out[i_out-2]) * np.conj(out_rail[i_out-1]) + mm_val = np.real(y - x) + mu += sps + 0.3*mm_val + i_in += int(np.floor(mu)) # round down to nearest int since we are using it as an index + mu = mu - np.floor(mu) # remove the integer part of mu + i_out += 1 # increment output index +out = out[3:i_out] # remove the first few due to filter transients, and anything after i_out (that was never filled out) +samples = out + +plt.figure(2) +plt.plot(np.real(samples)) +plt.plot(np.imag(samples)) +plt.xlabel('Sample Index') +plt.ylabel('Sample Value') +plt.legend(['I', 'Q']) +plt.grid() + +N = len(samples) +phase = 0 +freq = 0 +# These next two params is what to adjust, to make the feedback loop faster or slower (which impacts stability) +alpha = 0.132 +beta = 0.00932 +out = np.zeros(N, dtype=np.complex64) +freq_log = [] +for i in range(N): + out[i] = samples[i] * np.exp(-1j*phase) # adjust the input sample by the inverse of the estimated phase offset + error = np.real(out[i]) * np.imag(out[i]) # This is the error formula for 2nd order Costas Loop (e.g. for BPSK) + + # Advance the loop (recalc phase and freq offset) + freq += (beta * error) + freq_log.append(freq * fs / (2*np.pi)) # convert from angular velocity to Hz for logging + phase += freq + (alpha * error) + + # Optional: Adjust phase so its always between 0 and 2pi, recall that phase wraps around every 2pi + while phase >= 2*np.pi: + phase -= 2*np.pi + while phase < 0: + phase += 2*np.pi + +# Calc BER +rx_bits = (np.real(out) > 0).astype(int) +num_bit_errors = np.sum(rx_bits != bits[:len(rx_bits)]) +print(f"Number of bit errors: {num_bit_errors} out of {len(rx_bits)} bits, BER: {num_bit_errors/len(rx_bits):.4f}") + +# Plot freq over time to see how long it takes to hit the right offset +plt.figure(0) +plt.plot(freq_log,'.-') +plt.xlabel('Sample Index') +plt.ylabel('Frequency Offset Estimate (Hz)') + +# Appears to be synced after ~80 samples so lets plot the constellation of the remaining 20 samples +plt.figure(1) +plt.plot(np.real(out[80:]), np.imag(out[80:]), '.') +plt.xlabel('I') +plt.ylabel('Q') +plt.xlim(-1.5, 1.5) +plt.ylim(-1.5, 1.5) +plt.grid() +plt.show() diff --git a/figure-generating-scripts/tdoa.py b/figure-generating-scripts/tdoa.py new file mode 100644 index 00000000..47012146 --- /dev/null +++ b/figure-generating-scripts/tdoa.py @@ -0,0 +1,231 @@ +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.lines import Line2D +from itertools import combinations +from scipy.signal import firwin, lfilter + +sample_rate = 50e6 +c = 3e8 # speed of light [m/s] +snr_db = 10 # SNR of the received signal at each receiver [dB] +tx_len_samples = 1000 # samples to transmit +rx_positions = np.array([ + [65, 229], # Rx0 + [676, 123], # Rx1 + [153, 543], # Rx2 +]) +num_rx = rx_positions.shape[0] +tx_position = np.array([153, 355]) +pairs = list(combinations(range(num_rx), 2)) # For 3 receivers it's (Rx0,Rx1), (Rx0,Rx2), (Rx1,Rx2) -> 3 pairs + +# For the tx signal itself it's arbitrary, although bandwidth matters, we'll transmit band-limited noise +bandwidth = 20e6 +taps = firwin(numtaps=129, cutoff=bandwidth / 2, fs=sample_rate) +tx_signal = lfilter(taps, 1.0, np.random.randn(tx_len_samples) + 1j * np.random.randn(tx_len_samples)) + +# Simulate what each receiver records +true_distances = np.linalg.norm(rx_positions - tx_position, axis=1) +true_delays = true_distances / c +unknown_tx_time = 1.234e-5 # seconds. arbitray, unknown to receivers and we wont use it in any TDOA calcs + +# Calc the actual TDOAs to act as ground truth +for k, (a, b) in enumerate(pairs): + true_rd = true_distances[b] - true_distances[a] + +# Figure out how many samples we have to simulate +total_delay_samples = (unknown_tx_time + true_delays.max()) * sample_rate +buffer_len = tx_len_samples + int(np.ceil(total_delay_samples)) + 10 + +# Taken from Synchronization chapter +def frac_delay_filter(delay): # delay is in samples, but it can (and will be) not an integer + N = 21 # number of taps, keep this odd + n = np.arange(-(N-1)//2, N//2+1) # -10,-9,...,0,...,9,10 + h = np.sinc(n - delay) # calc filter taps + h *= np.hamming(N) # window the filter to make sure it decays to 0 on both sides + h /= np.sum(h) # normalize to get unity gain, we don't want to change the amplitude/power + return h + +# Simulate the delayed signal being received by each sensor +rx_signals = np.zeros((num_rx, buffer_len), dtype=complex) +for i in range(num_rx): + tau = unknown_tx_time + true_delays[i] # absolute delay at this Rx, in seconds + tau_samples = tau * sample_rate + tau_integer_samps = int(np.round(tau_samples)) + tau_frac_samps = tau_samples - tau_integer_samps + rx = np.zeros(buffer_len, dtype=complex) + rx[tau_integer_samps:tau_integer_samps+tx_len_samples] = tx_signal + frac_delay_i = frac_delay_filter(tau_frac_samps) + rx = np.convolve(rx, frac_delay_i, "same") + + # Each receiver adds its own thermal noise, scaled to hit the SNR set at the top + signal_power = np.mean(np.abs(tx_signal)**2) + noise_power = signal_power / 10**(snr_db / 10) + noise = np.sqrt(noise_power / 2) * (np.random.randn(buffer_len) + 1j * np.random.randn(buffer_len)) + rx_signals[i] = rx + noise + +# Estimate the TDOAs using a normal cross-correlation +range_diff = np.zeros(len(pairs)) # meters +for k, (a, b) in enumerate(pairs): + xcorr = np.correlate(rx_signals[b], rx_signals[a], mode='full') + peak_lag = np.argmax(np.abs(xcorr)) - (buffer_len - 1) # 'full' puts zero lag at index buffer_len-1 + range_diff[k] = (peak_lag / sample_rate) * c # meters + +# FIGURE 1: the integer-only result. +# Precompute the distance from each receiver to every grid point, this will get used in the contour plot +grid_x = np.linspace(-200, 800, 400) +grid_y = np.linspace(-200, 800, 400) +GX, GY = np.meshgrid(grid_x, grid_y) +rx_dist = [] +for i in range(num_rx): + rx_dist.append(np.sqrt((GX - rx_positions[i, 0])**2 + (GY - rx_positions[i, 1])**2)) +fig1, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6)) +# Left: the hyperbolas, which all cross at the transmitter. +hyperbola_handles = [] +pair_colors = ['tab:blue', 'tab:orange', 'tab:green'] +for k, (a, b) in enumerate(pairs): + # the next line is what calculates the hyperbola, note levels=[0] means we're making a contour map but only one level, specifically the level where the difference is zero + ax1.contour(GX, GY, (rx_dist[b] - rx_dist[a]) - range_diff[k], levels=[0], colors=pair_colors[k], linestyles='--') + hyperbola_handles.append(Line2D([0], [0], color=pair_colors[k], linestyle='--', label=f'Rx{a}-Rx{b}')) +ax1.scatter(rx_positions[:, 0], rx_positions[:, 1], c='tab:blue', marker='^', s=120, edgecolors='k', label='Receivers', zorder=5) +for i in range(num_rx): + ax1.annotate(f'Rx{i}', rx_positions[i], textcoords='offset points', xytext=(8, 8), fontweight='bold', zorder=6) +ax1.scatter(*tx_position, c='red', marker='*', s=300, edgecolors='k', label='True Tx', zorder=5) +ax1.set_xlim(grid_x[0], grid_x[-1]); ax1.set_ylim(grid_y[0], grid_y[-1]) +ax1.set_xlabel('x [m]'); ax1.set_ylabel('y [m]') +ax1.set_title('TDOA hyperbolas') +ax1.legend(handles=ax1.get_legend_handles_labels()[0] + hyperbola_handles, loc='upper right') +ax1.set_aspect('equal') +# Cross-correlation of one pair, integer only +a, b = pairs[1] # the (Rx0, Rx2) pair +xcorr = np.abs(np.correlate(rx_signals[b], rx_signals[a], mode='full')) +lags = np.arange(xcorr.size) - (buffer_len - 1) +peak = lags[np.argmax(xcorr)] +ax2.plot(lags, xcorr, 'o-', markersize=5, label='correlation samples') +ax2.axvline(peak, color='red', linestyle='--', label=f'integer peak = {peak} samples') +ax2.set_xlim(peak - 6, peak + 6) +ax2.set_xlabel('lag [samples]'); ax2.set_ylabel('|cross-correlation|') +ax2.set_title(f'Cross-correlation of Rx{b} vs Rx{a}') +ax2.legend() +ax2.grid() +#fig1.savefig('../_images/tdoa_python_integer.svg', bbox_inches='tight') +fig1.tight_layout() + +# Subsample TDOA calc using a freq domain cross-correlation that was padded as a way to interpolate +U = 16 # correlation upsampling factor +half = (buffer_len + 1) // 2 # number of DC + positive-frequency bins +range_diff = np.zeros(len(pairs)) # meters +for k, (a, b) in enumerate(pairs): + # Cross-correlation in the frequency domain + X = np.conj(np.fft.fft(rx_signals[a])) * np.fft.fft(rx_signals[b]) + + # Insert zeros in the high-frequency MIDDLE: DC + positive freqs at the front, negative freqs at the back, so it stays a valid FFT layout. + X_padded = np.zeros(U * buffer_len, dtype=complex) + X_padded[:half] = X[:half] + X_padded[U * buffer_len - (buffer_len - half):] = X[half:] + + # Now IFFT to finish the crosscorrelation + xcorr = np.abs(np.fft.ifft(X_padded)) * U + + # Peak index -> signed lag; indices past the midpoint are negative lags + peak_idx = np.argmax(xcorr) + if peak_idx > U * buffer_len // 2: + peak_idx -= U * buffer_len + peak_lag = peak_idx / U # sub-sample lag, +ve => Rx_b farther + range_diff[k] = (peak_lag / sample_rate) * c # meters + +print("METHOD 2 (sub-sample, zero-padded FFT)") +print(" Pair | true range diff [m] | measured range diff [m]") +for k, (a, b) in enumerate(pairs): + true_rd = true_distances[b] - true_distances[a] + print(f"Rx{b}-Rx{a} | {true_rd:9.1f} | {range_diff[k]:9.1f}") + +# 8. FIGURE 2: the sub-sample result, same layout as Figure 1. +fig2, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6)) + +# Left: the hyperbolas from the refined range differences. +hyperbola_handles = [] +for k, (a, b) in enumerate(pairs): + ax1.contour(GX, GY, (rx_dist[b] - rx_dist[a]) - range_diff[k], levels=[0], + colors=pair_colors[k], linewidths=1.5, linestyles='--') + hyperbola_handles.append(Line2D([0], [0], color=pair_colors[k], + linestyle='--', label=f'Rx{a}-Rx{b}')) +ax1.scatter(rx_positions[:, 0], rx_positions[:, 1], c='tab:blue', marker='^', + s=120, edgecolors='k', label='Receivers', zorder=5) +for i in range(num_rx): + ax1.annotate(f'Rx{i}', rx_positions[i], textcoords='offset points', + xytext=(8, 8), fontweight='bold', zorder=6) +ax1.scatter(*tx_position, c='red', marker='*', s=300, edgecolors='k', + label='True Tx', zorder=5) +ax1.set_xlim(grid_x[0], grid_x[-1]); ax1.set_ylim(grid_y[0], grid_y[-1]) +ax1.set_xlabel('x [m]'); ax1.set_ylabel('y [m]') +ax1.set_title('TDOA hyperbolas') +ax1.legend(handles=ax1.get_legend_handles_labels()[0] + hyperbola_handles, loc='upper right') +ax1.set_aspect('equal') + +# Right: coarse (1 sample/lag) correlation as dots vs the U-times upsampled +# correlation as a smooth curve, so the sub-sample shift is visible. +a, b = pairs[1] # the (Rx0, Rx2) pair +X = np.conj(np.fft.fft(rx_signals[a])) * np.fft.fft(rx_signals[b]) +cc_coarse = np.abs(np.fft.ifft(X)) +X_padded = np.zeros(U * buffer_len, dtype=complex) +X_padded[:half] = X[:half] +X_padded[U * buffer_len - (buffer_len - half):] = X[half:] +cc_fine = np.abs(np.fft.ifft(X_padded)) * U +lags_coarse = np.where(np.arange(buffer_len) <= buffer_len // 2, np.arange(buffer_len), np.arange(buffer_len) - buffer_len) +lags_fine = np.arange(U * buffer_len) / U +lags_fine = np.where(lags_fine <= buffer_len / 2, lags_fine, lags_fine - buffer_len) +peak = lags_coarse[np.argmax(cc_coarse)] +subsample_peak = lags_fine[np.argmax(cc_fine)] +# The lag axes wrap from + back to - partway through, so sort before plotting, +# otherwise the connecting line jumps across the figure. +order_c = np.argsort(lags_coarse) +order_f = np.argsort(lags_fine) +ax2.plot(lags_coarse[order_c], cc_coarse[order_c], 'o', markersize=6, label='coarse (1 sample/lag)') +ax2.plot(lags_fine[order_f], cc_fine[order_f], '.-', label=f'{U}x interpolation') +ax2.axvline(subsample_peak, color='red', linestyle='--', + label=f'sub-sample peak = {subsample_peak:.3f}') +ax2.set_xlim(peak - 6, peak + 6) +ax2.set_xlabel('lag [samples]'); ax2.set_ylabel('|cross-correlation|') +ax2.set_title(f'Cross-correlation of Rx{b} vs Rx{a}') +ax2.legend() +ax2.grid() +fig2.tight_layout() +#fig2.savefig('../_images/tdoa_python_subsample.svg', bbox_inches='tight') + + +# Heatmap portion: evaluate the TDOA cost on the grid and display it under the ax1 map +cost = np.zeros_like(GX) +for k, (a, b) in enumerate(pairs): + cost += ((rx_dist[b] - rx_dist[a]) - range_diff[k])**2 # squared mismatch for this pair, summed over pairs + +# The best estimate is simply the grid cell with the lowest cost +iy, ix = np.unravel_index(np.argmin(cost), cost.shape) +emitter_grid = np.array([grid_x[ix], grid_y[iy]]) +print("Grid estimate:", emitter_grid) # ~[153, 355] + +fig3, ax1 = plt.subplots(1, 1, figsize=(7, 6)) +# Invert the cost into a likelihood-style surface so higher (brighter) = more likely emitter location +likelihood = -np.log10(cost + 1e-9) +# Cap the colormap a bit below the peak so the bright region around the emitter spreads out and is easier to see +vmax = likelihood.min() + 0.5 * (likelihood.max() - likelihood.min()) # 0.5 was adjusted manually to look good +im = ax1.imshow(likelihood, origin='lower', cmap='viridis', vmax=vmax, + extent=[grid_x[0], grid_x[-1], grid_y[0], grid_y[-1]]) +fig3.colorbar(im, ax=ax1, label='likelihood (higher = more likely)') +# Overlay the hyperbolas, receivers, true Tx, and the grid-search estimate +hyperbola_handles = [] +for k, (a, b) in enumerate(pairs): + ax1.contour(GX, GY, (rx_dist[b] - rx_dist[a]) - range_diff[k], levels=[0], + colors=pair_colors[k], linewidths=1.5, linestyles='--') + hyperbola_handles.append(Line2D([0], [0], color=pair_colors[k], linestyle='--', label=f'Rx{a}-Rx{b}')) +ax1.scatter(rx_positions[:, 0], rx_positions[:, 1], c='tab:cyan', marker='^', s=120, edgecolors='k', label='Receivers', zorder=5) +for i in range(num_rx): + ax1.annotate(f'Rx{i}', rx_positions[i], textcoords='offset points', xytext=(8, 8), color='w', fontweight='bold', zorder=6) +ax1.scatter(*tx_position, c='red', marker='*', s=300, edgecolors='k', label='True Tx', zorder=5) +#ax1.scatter(*emitter_grid, c='white', marker='x', s=120, linewidths=2, label='Grid estimate', zorder=6) +ax1.set_xlim(grid_x[0], grid_x[-1]); ax1.set_ylim(grid_y[0], grid_y[-1]) +ax1.set_xlabel('x [m]'); ax1.set_ylabel('y [m]') +ax1.legend(handles=ax1.get_legend_handles_labels()[0] + hyperbola_handles, loc='upper right') +ax1.set_aspect('equal') +fig3.tight_layout() +fig3.savefig('../_images/tdoa_python_heatmap.svg', bbox_inches='tight') + +plt.show() diff --git a/figure-generating-scripts/tdoa_cramer_rao.py b/figure-generating-scripts/tdoa_cramer_rao.py new file mode 100644 index 00000000..3f2390a6 --- /dev/null +++ b/figure-generating-scripts/tdoa_cramer_rao.py @@ -0,0 +1,38 @@ +import numpy as np +import matplotlib.pyplot as plt + +# This script generates a figure showing the Cramer-Rao Lower Bound (CRLB) on +# time-delay estimation accuracy as a function of SNR, for three different +# signal bandwidths. The bound on the variance of any unbiased delay estimate is +# +# var(tau_hat) >= 1 / (8 * pi^2 * beta^2 * T * gamma) +# +# where beta is the RMS (Gabor) bandwidth of the signal, T is the integration +# time, and gamma is an effective SNR factor. We convert the resulting delay +# standard deviation into a ranging error in meters (multiplying by the speed of +# light) since that is the more intuitive quantity for localization. + +c = 3e8 # speed of light [m/s] +T = 100e-6 # integration time [s] + +snr_db = np.linspace(0, 30, 200) # SNR sweep [dB] +gamma = 10 ** (snr_db / 10) # effective SNR factor (linear) + +# For band-limited noise that is flat from -B/2 to +B/2, the RMS bandwidth is +# beta = B / sqrt(12). We show three signal bandwidths. +bandwidths = [1e6, 10e6, 50e6] # signal bandwidths [Hz] + +fig, ax = plt.subplots(figsize=(8, 5)) +for B in bandwidths: + beta = B / np.sqrt(12) # RMS bandwidth [Hz] + var_tau = 1.0 / (8 * np.pi**2 * beta**2 * T * gamma) # delay variance [s^2] + range_std = c * np.sqrt(var_tau) # ranging error [m] + ax.semilogy(snr_db, range_std, label=f'{B/1e6:.0f} MHz bandwidth') + +ax.set_xlabel('SNR [dB]') +ax.set_ylabel('Ranging error (CRLB) [m]') +ax.grid(True, which='both', alpha=0.4) +ax.legend() +ax.set_xlim(snr_db[0], snr_db[-1]) +fig.savefig('../_images/tdoa_cramer_rao.svg', bbox_inches='tight') +plt.show() diff --git a/index-fr.rst b/index-fr.rst index 4e2f2c93..4ca1018d 100644 --- a/index-fr.rst +++ b/index-fr.rst @@ -12,6 +12,7 @@ by :ref:`Dr. Marc Lichtman` content-fr/frequency_domain content-fr/sampling content-fr/digital_modulation + content-fr/hackrf content-fr/pluto content-fr/usrp content-fr/noise @@ -23,4 +24,6 @@ by :ref:`Dr. Marc Lichtman` content-fr/pulse_shaping content-fr/sync content-fr/rds + content-fr/doa + content-fr/pyqt content-fr/about_author diff --git a/index-nl.rst b/index-nl.rst index 27ab7fc7..9c7adbad 100644 --- a/index-nl.rst +++ b/index-nl.rst @@ -26,5 +26,13 @@ content-nl/sync content-nl/rds content-nl/doa - content-nl/phaser + content-nl/2d_beamforming + content-nl/phaser + content-nl/cyclostationary + content-nl/pyqt + content-nl/detection content-nl/about_author + +.. raw:: html + + \ No newline at end of file diff --git a/index-zh.rst b/index-zh.rst index 80c5a042..c54ee84f 100644 --- a/index-zh.rst +++ b/index-zh.rst @@ -14,11 +14,16 @@ content-zh/frequency_domain content-zh/sampling content-zh/digital_modulation + content-zh/pluto content-zh/usrp + content-zh/bladerf + content-zh/rtlsdr + content-zh/hackrf content-zh/noise content-zh/filters content-zh/link_budgets content-zh/channel_coding content-zh/iq_files content-zh/multipath_fading + content-zh/pulse_shaping content-zh/about_author diff --git a/index.rst b/index.rst index 17cd501c..ebe6c0f9 100644 --- a/index.rst +++ b/index.rst @@ -33,6 +33,9 @@ content/phaser content/cyclostationary content/pyqt + content/detection + content/fpv_video + content/tdoa content/about_author .. raw:: html diff --git a/jupyter-lite.json b/jupyter-lite.json new file mode 100644 index 00000000..dec6be69 --- /dev/null +++ b/jupyter-lite.json @@ -0,0 +1,7 @@ +{ + "jupyter-lite-schema-version": 0, + "jupyter-config-data": { + "appName": "PySDR", + "faviconUrl": "/_static/myicon.png" + } +} diff --git a/jupyterlite/example.ipynb b/jupyterlite/example.ipynb new file mode 100644 index 00000000..397b4830 --- /dev/null +++ b/jupyterlite/example.ipynb @@ -0,0 +1,27 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "example-cell", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "print(np.arange(10))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python (Pyodide)", + "language": "python", + "name": "python" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/jupyterlite/frequency_domain.ipynb b/jupyterlite/frequency_domain.ipynb new file mode 100644 index 00000000..35ced517 --- /dev/null +++ b/jupyterlite/frequency_domain.ipynb @@ -0,0 +1,331 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d4128b0f", + "metadata": {}, + "source": [ + "# Frequency Domain\n", + "\n", + "This notebook contains the runnable Python examples from the [Frequency Domain chapter](https://pysdr.org/content/frequency_domain.html) of PySDR.\n", + "\n", + "It covers:\n", + "\n", + "1. Computing an FFT with NumPy and plotting the magnitude and phase\n", + "2. Applying a window function before the FFT\n", + "3. Building a spectrogram (waterfall)\n", + "4. A from-scratch recursive FFT implementation\n" + ] + }, + { + "cell_type": "markdown", + "id": "4bfa7e2b", + "metadata": {}, + "source": [ + "## FFT in Python\n", + "\n", + "First we create a signal in the time domain. To keep things simple, we make a sine wave at 0.15 Hz,\n", + "using a sample rate of 1 Hz (so we sample at t = 0, 1, 2, 3 seconds, etc.).\n", + "\n", + "We then take the FFT, apply an `fftshift` so that 0 Hz (DC) is in the center with negative\n", + "frequencies to the left, and plot the magnitude and phase with a proper frequency x-axis.\n", + "Because our sample rate is 1 Hz, the x-axis spans -0.5 Hz to 0.5 Hz.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "d76eb6bd", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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j7e2turtt98O/JrBwcHA15f7/8JWE3mvc33961/XggUL8sIfsk3kvX755Ze1fft2vfHGGyG0cPqg8hGShx9+WLFYrOhHub8ocv3rv/6rXnjhBT3++ONT2+hpyuR77TcyMqK7775bN910k775zW9OvuFAFWzbtk27d+/W3r171djYWO3mRMro6Ki+8pWv6KmnntK8efOq3ZyaQuUjJH/8x3+sr371q0Vf88lPflJtbW15E5eSyaQ+/PDDgrdTXnjhBb377rtqaWnJery7u1t33HGHDhw4MImWTz8m32vX6Oio7rrrLs2ePVt79+7VjBkzJtvsSJk3b54SiYSGhoayHh8aGir43ra1tVX0elw2kffa9eijj2rbtm36j//4Dy1evNhkMyOh0vf63Xff1Xvvvad77rnHeyydTku6XGU9fvy4fumXfslso2tVtSedIJs7CfLVV1/1Hnv++eeLToI8ffq0c+zYsawPSc63v/1t57//+7/Davq0M5H32nEcZ3h42Fm+fLnzxS9+0Tl//nwYTZ2Wli5d6jzwwAPe56lUyrnmmmuKTjj9zd/8zazHOjs7mXBahkrfa8dxnG9961tOU1OT09/fH0YTI6OS9/rjjz/O+928evVqZ8WKFc6xY8ecsbGxMJteUwgfNeiuu+5yPvvZzzqHDx92Xn75ZedTn/qUs27dOu/5n//8584NN9zgHD58uOD3EKtdylLpez08POwsW7bMueWWW5x33nnHOX36tPeRTCar9deoSbt373YaGhqcnTt3Om+99ZZz//33Oy0tLc7g4KDjOI7zla98xXn44Ye91//nf/6nU1dX5zz66KPOf/3Xfzlbt251ZsyY4Rw7dqxaf4Vpo9L3etu2bU59fb3z/e9/P6sPj46OVuuvMG1U+l7nYrXLZYSPGvSLX/zCWbdunTNr1iynqanJ+drXvpb1S+HEiROOJOfFF18s+D0IH+Wp9L1+8cUXHUmBHydOnKjOX6KGffe733U6Ojqc+vp6Z+nSpc6hQ4e85774xS8669evz3r9M88843z605926uvrnc985jPOv/3bv4Xc4umrkvf62muvDezDW7duDb/h01Cl/dqP8HFZzHEcJ+xbPQAAwF6sdgEAAKEifAAAgFARPgAAQKgIHwAAIFSEDwAAECrCBwAACBXhAwAAhIrwAQAAQkX4AAAAoSJ8AACAUBE+AABAqAgfAAAgVP8fCfkj1pYTNzIAAAAASUVORK5CYII=", + "text/plain": [ + "
    " + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
    " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "Fs = 1 # Hz\n", + "N = 100 # number of points to simulate, and our FFT size\n", + "\n", + "t = np.arange(N) # because our sample rate is 1 Hz\n", + "s = np.sin(0.15*2*np.pi*t)\n", + "S = np.fft.fftshift(np.fft.fft(s))\n", + "S_mag = np.abs(S)\n", + "S_phase = np.angle(S)\n", + "f = np.arange(Fs/-2, Fs/2, Fs/N)\n", + "plt.figure(0)\n", + "plt.plot(f, S_mag,'.-')\n", + "plt.figure(1)\n", + "plt.plot(f, S_phase,'.-')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "9aa2efba", + "metadata": {}, + "source": [ + "We see our spike at 0.15 Hz, which is the frequency we used when creating the sine wave, so the FFT\n", + "worked! The reason we also see a spike at -0.15 Hz is because it was a real signal (not complex)." + ] + }, + { + "cell_type": "markdown", + "id": "01c05f28", + "metadata": {}, + "source": [ + "## Windowing\n", + "\n", + "When we use an FFT, it assumes the slice of signal we give it is one period of a periodic signal, so\n", + "we want to avoid sudden transitions between the first and last sample. We fix this by \"windowing\":\n", + "multiplying the slice by a function that tapers to zero on both ends, such as a Hamming window.\n", + "\n", + "Here we apply a Hamming window to the same sine wave before taking the FFT." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "7e49f723", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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f9ct9cREUewLAAA8iyADAAA8iyDjM6WlpZoxY4ZKS0vz3RTj8V13HL7rjsN33XH4rtNjfLEvAAAwFz0yAADAswgyAADAswgyAADAswgyAADAswgyPrBnzx5dffXV6tatm7p3764pU6Zo//79ab3WsiyNGTNGgUBAL730Uvs21ACZftd79uzRzTffrEGDBqlTp07q16+fbrnlFtXV1XVgq71h9uzZGjBggMrKylRTU6O33367xf3/9Kc/afDgwSorK9PQoUP1P//zPx3UUu/L5Lt+4oknNHz4cB1xxBE64ogjNHLkyFb/bRCT6XEdNX/+fAUCAY0bN659G+gBBBkfuPrqq/WPf/xDS5Ys0cKFC7Vq1SrdeOONab121qxZLO2QgUy/6+3bt2v79u167LHHtGHDBs2bN0+LFi3SlClTOrDV7vf888/r9ttv14wZM/T+++/r1FNP1ahRo/Tll18m3f/NN9/UxIkTNWXKFK1du1bjxo3TuHHjtGHDhg5uufdk+l2vWLFCEydO1PLly7V69WpVV1fr0ksv1RdffNHBLfeeTL/rqK1bt+qOO+7Q8OHDO6ilLmfBaB9++KElyXrnnXfsbX/961+tQCBgffHFFy2+du3atdZRRx1l1dbWWpKsBQsWtHNrva0t37XTCy+8YJWUlFiNjY3t0UxPOvvss62pU6faj0OhkNW3b19r5syZSfe/4oorrG9+85tx22pqaqx//dd/bdd2miDT7zrR4cOHrfLycuupp55qryYaI5vv+vDhw9awYcOsP/zhD9akSZOssWPHdkBL3Y0eGcOtXr1a3bt315lnnmlvGzlypAoKCrRmzZqUrzt48KCuuuoqzZ49W1VVVR3RVM/L9rtOVFdXp27duqmoyPil0NISDAb13nvvaeTIkfa2goICjRw5UqtXr076mtWrV8ftL0mjRo1KuT8isvmuEx08eFCNjY3q0aNHezXTCNl+1/fff7969epFr60DvykNt2PHDvXq1StuW1FRkXr06KEdO3akfN1tt92mYcOGaezYse3dRGNk+1077dq1Sw888EDaQ39+sGvXLoVCIfXu3Ttue+/evfXxxx8nfc2OHTuS7p/uv4NfZfNdJ7rrrrvUt2/fZkES8bL5rl9//XU9+eSTWrduXQe00DvokfGou+++W4FAoMWfdH/xJPqv//ovLVu2TLNmzcptoz2qPb9rp/r6en3zm9/USSedpPvuu6/tDQc62EMPPaT58+drwYIFKisry3dzjLJv3z5dc801euKJJ1RZWZnv5rgKPTIe9aMf/UiTJ09ucZ9jjz1WVVVVzQrHDh8+rD179qQcMlq2bJk2b96s7t27x22fMGGChg8frhUrVrSh5d7Tnt911L59+zR69GiVl5drwYIFKi4ubmuzjVFZWanCwkLt3LkzbvvOnTtTfq9VVVUZ7Y+IbL7rqMcee0wPPfSQli5dqlNOOaU9m2mETL/rzZs3a+vWrbrsssvsbeFwWFKk53fjxo067rjj2rfRbpXvIh20r2gB6rvvvmtvW7x4cYsFqLW1tdb69evjfiRZv/rVr6xPP/20o5ruOdl815ZlWXV1ddY555xjXXjhhdaBAwc6oqmec/bZZ1vTpk2zH4dCIeuoo45qsdj3W9/6Vty2c889l2LfNGT6XVuWZT388MNWt27drNWrV3dEE42RyXf91VdfNfu9PHbsWOviiy+21q9fbzU0NHRk012FIOMDo0ePtk4//XRrzZo11uuvv24NHDjQmjhxov38559/bg0aNMhas2ZNyvcQdy2lJdPvuq6uzqqpqbGGDh1qbdq0yaqtrbV/Dh8+nK+/huvMnz/fKi0ttebNm2d9+OGH1o033mh1797d2rFjh2VZlnXNNddYd999t73/G2+8YRUVFVmPPfaY9dFHH1kzZsywiouLrfXr1+frr+AZmX7XDz30kFVSUmL9+c9/jjt+9+3bl6+/gmdk+l0n4q6lCIKMD+zevduaOHGi1bVrV6tbt27WddddF/dLZsuWLZYka/ny5SnfgyCTnky/6+XLl1uSkv5s2bIlP38Jl/rNb35j9evXzyopKbHOPvts66233rKfu/DCC61JkybF7f/CCy9YJ5xwglVSUmKdfPLJ1n//9393cIu9K5Pvun///kmP3xkzZnR8wz0o0+PaiSATEbAsy+ro4SwAAIBc4K4lAADgWQQZAADgWQQZAADgWQQZAADgWQQZAADgWQQZAADgWQQZAADgWQQZAADgWQQZAGjB5MmT7VXOX3rppZy+94oVK+z3HjduXE7fG/ALggzgM84Ts/Nn06ZN+W6aa40ePVq1tbUaM2aMvS1VsJk8eXLaoWTYsGGqra3VFVdckaOWAv5TlO8GAOh4o0eP1ty5c+O2HXnkkc32CwaDKikp6ahmuVZpaamqqqpy/r4lJSWqqqpSp06d1NDQkPP3B/yAHhnAh6InZudPYWGhRowYoWnTpunWW29VZWWlRo0aJUnasGGDxowZo65du6p379665pprtGvXLvv9Dhw4oGuvvVZdu3ZVnz599POf/1wjRozQrbfeau+TrAeje/fumjdvnv1427ZtuuKKK9S9e3f16NFDY8eO1datW+3no70djz32mPr06aOePXtq6tSpamxstPdpaGjQXXfdperqapWWlur444/Xk08+KcuydPzxx+uxxx6La8O6devarUdq69atSXu/RowYkfPPAvyKIAMgzlNPPaWSkhK98cYb+u1vf6u9e/fq4osv1umnn653331XixYt0s6dO+OGQ3784x9r5cqVevnll/W3v/1NK1as0Pvvv5/R5zY2NmrUqFEqLy/Xa6+9pjfeeENdu3bV6NGjFQwG7f2WL1+uzZs3a/ny5Xrqqac0b968uDB07bXX6rnnntOvf/1rffTRR/rd736nrl27KhAI6Prrr2/WEzV37lxdcMEFOv7447P7wlpQXV2t2tpa+2ft2rXq2bOnLrjggpx/FuBbeV59G0AHmzRpklVYWGh16dLF/vnud79rWZZlXXjhhdbpp58et/8DDzxgXXrppXHbtm3bZkmyNm7caO3bt88qKSmxXnjhBfv53bt3W506dbJ++MMf2tskWQsWLIh7n4qKCmvu3LmWZVnWf/7nf1qDBg2ywuGw/XxDQ4PVqVMna/HixXbb+/fvbx0+fNje5/LLL7euvPJKy7Isa+PGjZYka8mSJUn/7l988YVVWFhorVmzxrIsywoGg1ZlZaU1b968Fr+vsWPHNtsuySorK4v7Hrt06WIVFRUl3f+rr76yampqrG9961tWKBRK6zMAtI4aGcCHLrroIs2ZM8d+3KVLF/vPZ5xxRty+f//737V8+XJ17dq12fts3rxZX331lYLBoGpqauztPXr00KBBgzJq09///ndt2rRJ5eXlcdsPHTqkzZs3249PPvlkFRYW2o/79Omj9evXS4oMExUWFurCCy9M+hl9+/bVN7/5Tf3xj3/U2WefrVdeeUUNDQ26/PLLM2pr1C9/+UuNHDkybttdd92lUCjUbN/rr79e+/bt05IlS1RQQGc4kCsEGcCHunTpknIoxRlqJGn//v267LLL9PDDDzfbt0+fPmnXlgQCAVmWFbfNWduyf/9+nXHGGXrmmWeavdZZiFxcXNzsfcPhsCSpU6dOrbbj+9//vq655hr98pe/1Ny5c3XllVeqc+fOaf0dElVVVTX7HsvLy7V37964bQ8++KAWL16st99+u1lQA9A2BBkALfra176mv/zlLxowYICKipr/yjjuuONUXFysNWvWqF+/fpKk//u//9Mnn3wS1zNy5JFHqra21n78z3/+UwcPHoz7nOeff169evVSt27dsmrr0KFDFQ6HtXLlymY9JVHf+MY31KVLF82ZM0eLFi3SqlWrsvqsdP3lL3/R/fffr7/+9a867rjj2vWzAD+ifxNAi6ZOnao9e/Zo4sSJeuedd7R582YtXrxY1113nUKhkLp27aopU6boxz/+sZYtW6YNGzZo8uTJzYZPLr74Yj3++ONau3at3n33Xf3gBz+I6125+uqrVVlZqbFjx+q1117Tli1btGLFCt1yyy36/PPP02rrgAEDNGnSJF1//fV66aWX7Pd44YUX7H0KCws1efJkTZ8+XQMHDtS5556bmy8qiQ0bNujaa6/VXXfdpZNPPlk7duzQjh07tGfPnnb7TMBvCDIAWtS3b1+98cYbCoVCuvTSSzV06FDdeuut6t69ux1WHn30UQ0fPlyXXXaZRo4cqfPPP79Zrc3Pf/5zVVdXa/jw4brqqqt0xx13xA3pdO7cWatWrVK/fv00fvx4nXjiiZoyZYoOHTqUUQ/NnDlz9N3vflc33XSTBg8erBtuuEEHDhyI22fKlCkKBoO67rrr2vDNtO7dd9/VwYMH9eCDD6pPnz72z/jx49v1cwE/CViJg9YAkAMjRozQaaedplmzZuW7Kc289tpruuSSS7Rt2zb17t27xX0nT56svXv35nx5go7+DMBU9MgA8I2GhgZ9/vnnuu+++3T55Ze3GmKiFi5cqK5du2rhwoU5bc9rr72mrl27Ji1wBpAein0B+MZzzz2nKVOm6LTTTtPTTz+d1mseeeQR3XPPPZIid2nl0plnnql169ZJUtLb2wG0jqElAADgWQwtAQAAzyLIAAAAzyLIAAAAzyLIAAAAzyLIAAAAzyLIAAAAzyLIAAAAzyLIAAAAz/r/AVEtvAs0IfwaAAAAAElFTkSuQmCC", + "text/plain": [ + "
    " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "Fs = 1 # Hz\n", + "N = 100 # number of points to simulate, and our FFT size\n", + "\n", + "t = np.arange(N)\n", + "s = np.sin(0.15*2*np.pi*t)\n", + "s = s * np.hamming(N) # apply the window right before the FFT\n", + "S = np.fft.fftshift(np.fft.fft(s))\n", + "S_mag = np.abs(S)\n", + "f = np.arange(Fs/-2, Fs/2, Fs/N)\n", + "plt.plot(f, S_mag,'.-')\n", + "plt.xlabel(\"Frequency [Hz]\")\n", + "plt.ylabel(\"Magnitude\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "90dfd128", + "metadata": {}, + "source": [ + "## Spectrogram / Waterfall\n", + "\n", + "A spectrogram is simply a bunch of FFTs stacked together, showing frequency over time. Let's create\n", + "an example signal that is a tone at 50 kHz in white noise, sampled at 1 MHz." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "575ccbc0", + "metadata": {}, + "outputs": [], + "source": [ + "sample_rate = 1e6\n", + "\n", + "# Generate tone plus noise\n", + "t = np.arange(1024*1000)/sample_rate # time vector\n", + "f = 50e3 # freq of tone\n", + "x = np.sin(2*np.pi*f*t) + 0.2*np.random.randn(len(t))" + ] + }, + { + "cell_type": "markdown", + "id": "701d328a", + "metadata": {}, + "source": [ + "Here is what the signal looks like in the time domain (first 200 samples):" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "8a8de7db", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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Ojs7kUqlsGHDBgDAggULUFNTAwBYtGgRVq9ejY997GMYHh7GDTfcgI9//ONoa2vD1q1b8fWvfx0LFizA6aefXvS/29HRgZ07d6K2thaapln2+wwODmLmzJnYuXMn6urqLPu5KkG/o/uZ7L8fQL/jZGCy/34A/Y7loOs6hoaG0NHRMe77XBMIXXvttbjnnnv4348++mgAwFNPPYVTTjkFALB582YMDAwAALxeLzZu3Ih77rkH/f396OjowGmnnYZvfetbJfUS8ng8OOigg6z7RXKoq6ubtCc1g35H9zPZfz+AfsfJwGT//QD6HUtlPCWI4ZpA6O67756wh5CYBwyHw3j00Uclr4ogCIIgCDczqcvnCYIgCIIgxoMCIYcIBoO47rrrJvXID/od3c9k//0A+h0nA5P99wPod5SJpk9UV0YQBEEQBDFJIUWIIAiCIIgpCwVCBEEQBEFMWSgQIgiCIAhiykKBEEEQBEEQUxYKhBzitttuw5w5cxAKhbB06VK89NJLTi+pLFavXo33vOc9qK2tRUtLC8455xxs3rw56z2nnHLKmGG6l156qUMrLp3rr79+zPoXLVrEvx6NRnH55Zdj+vTpqKmpwcc//nH09PQ4uOLSmTNnTt6hx5dffjkA932GzzzzDM4880x0dHRA0zQ88MADWV/XdR3XXnst2tvbEQ6HsXz5crzzzjtZ7+nr68P555+Puro6NDQ04POf/zyGh4dt/C3GZ7zfMZFI4JprrsERRxyB6upqdHR04IILLsCePXuyfka+z/273/2uzb9JYSb6HC+66KIx61+xYkXWe1T+HCf6/QoNI//BD37A36PyZ1jM/lDM/bOzsxMf+chHUFVVhZaWFnzta19DMpm0bJ0UCDnAH/7wB6xcuRLXXXcd1q9fjyVLluD000/H3r17nV5ayTz99NO4/PLL8cILL+Cxxx5DIpHAaaedhpGRkaz3XXLJJejq6uJ/vv/97zu04vI4/PDDs9b/7LPP8q999atfxd/+9jf86U9/wtNPP409e/bg3/7t3xxcbem8/PLLWb/fY489BgA499xz+Xvc9BmOjIxgyZIluO222/J+/fvf/z5uvfVW3H777XjxxRdRXV2N008/HdFolL/n/PPPxxtvvIHHHnsMDz74IJ555hl88YtftOtXmJDxfsdIJIL169fjm9/8JtavX4/77rsPmzdvxllnnTXmvTfeeGPW5/rlL3/ZjuUXxUSfIwCsWLEia/333ntv1tdV/hwn+v3E36urqwt33XUXNE3Dxz/+8az3qfoZFrM/THT/TKVS+MhHPoJ4PI7nn38e99xzD+6++25ce+211i1UJ2zn+OOP1y+//HL+91QqpXd0dOirV692cFXWsHfvXh2A/vTTT/PXTj75ZP0rX/mKc4uqkOuuu05fsmRJ3q/19/frfr9f/9Of/sRfe+utt3QA+tq1a21aofV85Stf0efPn6+n02ld1939GQLQ77//fv73dDqtt7W16T/4wQ/4a/39/XowGNTvvfdeXdd1/c0339QB6C+//DJ/z9///ndd0zR99+7dtq29WHJ/x3y89NJLOgB9x44d/LXZs2frN998s9zFWUS+3/HCCy/Uzz777ILf46bPsZjP8Oyzz9Y/+MEPZr3mps8wd38o5v758MMP6x6PR+/u7ubv+elPf6rX1dXpsVjMknWRImQz8Xgc69atw/Lly/lrHo8Hy5cvx9q1ax1cmTWwWW+NjY1Zr//2t79FU1MTFi9ejFWrViESiTixvLJ555130NHRgXnz5uH8889HZ2cnAGDdunVIJBJZn+eiRYswa9Ys136e8Xgcv/nNb/C5z30ua9Cw2z9DxrZt29Dd3Z31mdXX12Pp0qX8M1u7di0aGhpw3HHH8fcsX74cHo8HL774ou1rtoKBgQFomoaGhoas17/73e9i+vTpOProo/GDH/zA0pSDHaxZswYtLS1YuHAhLrvsMvT29vKvTabPsaenBw899BA+//nPj/maWz7D3P2hmPvn2rVrccQRR6C1tZW/5/TTT8fg4CDeeOMNS9blmlljk4X9+/cjlUplfagA0Nraik2bNjm0KmtIp9O46qqr8L73vQ+LFy/mr3/mM5/B7Nmz0dHRgY0bN+Kaa67B5s2bcd999zm42uJZunQp7r77bixcuBBdXV244YYb8P73vx+vv/46uru7EQgExmwura2t6O7udmbBFfLAAw+gv78fF110EX/N7Z+hCPtc8l2D7Gvd3d1oaWnJ+rrP50NjY6MrP9doNIprrrkG5513XtYwyyuvvBLHHHMMGhsb8fzzz2PVqlXo6urCj370IwdXWzwrVqzAv/3bv2Hu3LnYunUr/t//+38444wzsHbtWni93kn1Od5zzz2ora0dk3Z3y2eYb38o5v7Z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hH/84x9YvXo1brrpJnz5y18u+98lCMKAAiGCIJTimGOOwZ///GfMmTMHPl9ltyifz4fly5dj+fLluO6669DQ0IAnn3wSJ598MjZv3oyf//zneP/73w8AePbZZ61YPgBD1RodHUU4HAYAvPDCC6ipqcHMmTPHvPfoo49GKpXC3r17+VryMXPmTFx66aW49NJLsWrVKvz85z+nQIggLIBSYwRBKMXll1+Ovr4+nHfeeXj55ZexdetWPProo7j44ouRSqWK/jkPPvggbr31VmzYsAE7duzAr371K6TTaSxcuBDTpk3D9OnTcccdd2DLli148sknsXLlSst+h3g8js9//vN488038fDDD+O6667DFVdcAY9n7C33kEMOwfnnn48LLrgA9913H7Zt24aXXnoJq1evxkMPPQQAuOqqq/Doo49i27ZtWL9+PZ566ikceuihlq2XIKYypAgRBKEUHR0deO6553DNNdfgtNNOQywWw+zZs7FixYq8gUQhGhoacN999+H6669HNBrFwQcfjHvvvReHH344AOD3v/89rrzySixevBgLFy7ErbfeilNOOcWS3+HUU0/FwQcfjJNOOgmxWAznnXcerr/++oLv/+Uvf4lvf/vbuPrqq7F79240NTXhve99Lz760Y8CAFKpFC6//HLs2rULdXV1WLFiBW6++WZL1koQUx1N1x1qA0sQBGERd999N6666ir09/c7vRRcdNFF6O/vxwMPPGDrv3v99dfjgQcewIYNG2z9dwnC7VBqjCCIScHAwABqampwzTXXOL0UW+ns7ERNTQ3++7//2+mlEIQrodQYQRCu5+Mf/zhOPPFEAEZKbCrR0dHBVaBgMOjsYgjChVBqjCAIgiCIKQulxgiCIAiCmLJQIEQQBEEQxJSFAiGCIAiCIKYsFAgRBEEQBDFloUCIIAiCIIgpCwVCBEEQBEFMWSgQIgiCIAhiykKBEEEQBEEQU5b/H8RhOwzulwHFAAAAAElFTkSuQmCC", + "text/plain": [ + "
    " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(x[0:200])\n", + "plt.xlabel(\"Time [samples]\")\n", + "plt.ylabel(\"Amplitude\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "e3d0e3f5", + "metadata": {}, + "source": [ + "Now we slice the signal into chunks of our FFT size, take the FFT of each, convert to dB, and stack\n", + "them into a 2D array that we display with `imshow`. Time starts at the top and goes down." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c40c6803", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
    " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fft_size = 1024\n", + "num_rows = len(x) // fft_size # // is an integer division which rounds down\n", + "spectrogram = np.zeros((num_rows, fft_size))\n", + "for i in range(num_rows):\n", + " spectrogram[i,:] = 10*np.log10(np.abs(np.fft.fftshift(np.fft.fft(x[i*fft_size:(i+1)*fft_size])))**2)\n", + "\n", + "# Time starts at the top and goes down, eg sample x[0] will be part of the top row displayed\n", + "plt.imshow(spectrogram, aspect='auto', extent = (sample_rate/-2/1e6, sample_rate/2/1e6, len(x)/sample_rate, 0))\n", + "plt.xlabel(\"Frequency [MHz]\")\n", + "plt.ylabel(\"Time [s]\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "b4f280a8", + "metadata": {}, + "source": [ + "There are two tones because we simulated a real signal, and real signals always have a negative side\n", + "of the spectrum that mirrors the positive side." + ] + }, + { + "cell_type": "markdown", + "id": "4e1c92a1", + "metadata": {}, + "source": [ + "## FFT Implementation\n", + "\n", + "Even though NumPy already implements the FFT for us, it's nice to see how it works under the hood.\n", + "Below is a simple recursive implementation of the Cooley-Tukey FFT, along with an example signal\n", + "consisting of a complex tone plus noise (0 dB SNR)." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "1f91c8ff", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
    " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def fft(x):\n", + " N = len(x)\n", + " if N == 1:\n", + " return x\n", + " twiddle_factors = np.exp(-2j * np.pi * np.arange(N//2) / N)\n", + " x_even = fft(x[::2]) # yay recursion!\n", + " x_odd = fft(x[1::2])\n", + " return np.concatenate([x_even + twiddle_factors * x_odd,\n", + " x_even - twiddle_factors * x_odd])\n", + "\n", + "# Simulate a tone + noise\n", + "sample_rate = 1e6\n", + "f_offset = 0.2e6 # 200 kHz offset from carrier\n", + "N = 1024\n", + "t = np.arange(N)/sample_rate\n", + "s = np.exp(2j*np.pi*f_offset*t)\n", + "n = (np.random.randn(N) + 1j*np.random.randn(N))/np.sqrt(2) # unity complex noise\n", + "r = s + n # 0 dB SNR\n", + "\n", + "# Perform fft, fftshift, convert to dB\n", + "X = fft(r)\n", + "X_shifted = np.roll(X, N//2) # equivalent to np.fft.fftshift\n", + "X_mag = 10*np.log10(np.abs(X_shifted)**2)\n", + "\n", + "# Plot results\n", + "f = np.linspace(sample_rate/-2, sample_rate/2, N)/1e6 # plt in MHz\n", + "plt.plot(f, X_mag)\n", + "plt.plot(f[np.argmax(X_mag)], np.max(X_mag), 'rx') # show max\n", + "plt.grid()\n", + "plt.xlabel('Frequency [MHz]')\n", + "plt.ylabel('Magnitude [dB]')\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/jupyterlite/inject_branding.py b/jupyterlite/inject_branding.py new file mode 100644 index 00000000..5a6ea6b9 --- /dev/null +++ b/jupyterlite/inject_branding.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +"""Inject PySDR branding into a built JupyterLite site. + +Run AFTER `jupyter lite build`. JupyterLab 4 / Notebook 7 render the top-left +logo from JavaScript and offer no user-CSS hook, so we inline a small stylesheet +(pysdr-brand.css) into every generated app page. It hides the built-in Jupyter +mark (#jp-NotebookLogo for the Notebook apps, #jp-MainLogo for Lab) and paints +the PySDR logo from /_static/logo.svg instead. + +Usage: python jupyterlite/inject_branding.py [output_dir] + (output_dir defaults to _build/jupyterlite) + +Exits non-zero if it patches nothing, so CI fails loudly if a JupyterLite +upgrade changes the build layout out from under us. +""" +from __future__ import annotations + +import sys +from pathlib import Path + +HERE = Path(__file__).resolve().parent +MARKER = "pysdr-branding" + + +def main() -> int: + out = Path(sys.argv[1] if len(sys.argv) > 1 else "_build/jupyterlite") + if not out.is_dir(): + print(f"[inject_branding] output dir not found: {out}", file=sys.stderr) + return 1 + + css = (HERE / "pysdr-brand.css").read_text(encoding="utf-8") + block = f'' + + patched = 0 + for html in out.rglob("*.html"): + text = html.read_text(encoding="utf-8") + if MARKER in text or "" not in text: + continue + html.write_text(text.replace("", block + "\n", 1), encoding="utf-8") + patched += 1 + + print(f"[inject_branding] patched {patched} page(s) under {out}") + return 0 if patched else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/jupyterlite/pysdr-brand.css b/jupyterlite/pysdr-brand.css new file mode 100644 index 00000000..16cdde10 --- /dev/null +++ b/jupyterlite/pysdr-brand.css @@ -0,0 +1,31 @@ +/* PySDR branding for the self-hosted JupyterLite deployment. + * + * JupyterLab 4 / Notebook 7 build the top-left logo in JavaScript and expose no + * user-CSS hook, so inject_branding.py inlines this file into every generated + * app page after `jupyter lite build`. We hide the built-in Jupyter mark and + * paint the PySDR logo (served at /_static/logo.svg on the deployed site) + * instead. logo.svg is ~1983x1192 (=1.66:1); at 28px tall that is ~47px wide. */ + +/* Notebook 7 apps: notebooks/, tree/, edit/, consoles/ (this is what opens) */ +#jp-NotebookLogo { + background-image: url(/_static/logo.svg); + background-repeat: no-repeat; + background-position: left center; + background-size: contain; + width: 48px; +} +#jp-NotebookLogo svg { + visibility: hidden; +} + +/* JupyterLab app: lab/ */ +#jp-MainLogo { + background-image: url(/_static/logo.svg); + background-repeat: no-repeat; + background-position: center; + background-size: contain; + width: 48px; +} +#jp-MainLogo svg { + visibility: hidden; +} diff --git a/jupyterlite/rds.ipynb b/jupyterlite/rds.ipynb new file mode 100644 index 00000000..3ad0273d --- /dev/null +++ b/jupyterlite/rds.ipynb @@ -0,0 +1,526 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7e2a6dd7", + "metadata": {}, + "source": [ + "# RDS Decoding\n", + "\n", + "This notebook walks through demodulating and decoding the Radio Data System (RDS) signal\n", + "embedded within an FM broadcast, from raw IQ samples all the way to the decoded\n", + "RadioText and program information.\n", + "\n", + "The steps are:\n", + "\n", + "1. FM (quadrature) demodulation\n", + "2. Frequency shift the 57 kHz RDS subcarrier down to baseband\n", + "3. Low-pass filter and decimate\n", + "4. Resample to a convenient rate\n", + "5. Symbol (timing) synchronization\n", + "6. Fine frequency synchronization with a Costas loop\n", + "7. BPSK demodulation and differential decoding\n", + "8. RDS block decoding\n", + "9. RDS group parsing\n" + ] + }, + { + "cell_type": "markdown", + "id": "27796d5c", + "metadata": {}, + "source": [ + "## Setup and read in the signal" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5539e502", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "from scipy.signal import resample_poly, firwin, bilinear, lfilter\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# Read in signal\n", + "x = np.fromfile('fm_rds_250k_1Msamples.iq', dtype=np.complex64)\n", + "sample_rate = 250e3\n", + "center_freq = 99.5e6" + ] + }, + { + "cell_type": "markdown", + "id": "98fbf5a5", + "metadata": {}, + "source": [ + "## Quadrature demod\n", + "\n", + "FM demodulate the signal to recover the composite baseband (which contains the RDS subcarrier)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78cd59dd", + "metadata": {}, + "outputs": [], + "source": [ + "# Quadrature Demod\n", + "x = 0.5 * np.angle(x[0:-1] * np.conj(x[1:])) # see https://wiki.gnuradio.org/index.php/Quadrature_Demod" + ] + }, + { + "cell_type": "markdown", + "id": "cede7bb1", + "metadata": {}, + "source": [ + "## Frequency shift\n", + "\n", + "The RDS subcarrier sits at 57 kHz, so we shift it down to 0 Hz." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ebbd81d1", + "metadata": {}, + "outputs": [], + "source": [ + "# Freq shift\n", + "N = len(x)\n", + "f_o = -57e3 # amount we need to shift by\n", + "t = np.arange(N)/sample_rate # time vector\n", + "x = x * np.exp(2j*np.pi*f_o*t) # down shift" + ] + }, + { + "cell_type": "markdown", + "id": "2b80bc29", + "metadata": {}, + "source": [ + "## Low-pass filter and decimate" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c01edca9", + "metadata": {}, + "outputs": [], + "source": [ + "# Low-Pass Filter\n", + "taps = firwin(numtaps=101, cutoff=7.5e3, fs=sample_rate)\n", + "x = np.convolve(x, taps, 'valid')\n", + "\n", + "# Decimate by 10, now that we filtered and there wont be aliasing\n", + "x = x[::10]\n", + "sample_rate = 25e3" + ] + }, + { + "cell_type": "markdown", + "id": "dc666583", + "metadata": {}, + "source": [ + "## Resample to 19 kHz" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3e0cbed", + "metadata": {}, + "outputs": [], + "source": [ + "# Resample to 19kHz\n", + "x = resample_poly(x, 19, 25) # up, down\n", + "sample_rate = 19e3" + ] + }, + { + "cell_type": "markdown", + "id": "6e717a4c", + "metadata": {}, + "source": [ + "## Symbol synchronization\n", + "\n", + "Using the Mueller and Muller clock recovery technique from the synchronization chapter." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70e8e59d", + "metadata": {}, + "outputs": [], + "source": [ + "# Symbol sync, using what we did in sync chapter\n", + "samples = x # for the sake of matching the sync chapter\n", + "samples_interpolated = resample_poly(samples, 32, 1) # we'll use 32 as the interpolation factor, arbitrarily chosen\n", + "sps = 16\n", + "mu = 0.01 # initial estimate of phase of sample\n", + "out = np.zeros(len(samples) + 10, dtype=np.complex64)\n", + "out_rail = np.zeros(len(samples) + 10, dtype=np.complex64) # stores values, each iteration we need the previous 2 values plus current value\n", + "i_in = 0 # input samples index\n", + "i_out = 2 # output index (let first two outputs be 0)\n", + "while i_out < len(samples) and i_in+32 < len(samples):\n", + " out[i_out] = samples_interpolated[i_in*32 + int(mu*32)] # grab what we think is the \"best\" sample\n", + " out_rail[i_out] = int(np.real(out[i_out]) > 0) + 1j*int(np.imag(out[i_out]) > 0)\n", + " x = (out_rail[i_out] - out_rail[i_out-2]) * np.conj(out[i_out-1])\n", + " y = (out[i_out] - out[i_out-2]) * np.conj(out_rail[i_out-1])\n", + " mm_val = np.real(y - x)\n", + " mu += sps + 0.01*mm_val\n", + " i_in += int(np.floor(mu)) # round down to nearest int since we are using it as an index\n", + " mu = mu - np.floor(mu) # remove the integer part of mu\n", + " i_out += 1 # increment output index\n", + "x = out[2:i_out] # remove the first two, and anything after i_out (that was never filled out)\n", + "\n", + "# new sample_rate should be 1187.5\n", + "sample_rate /= 16" + ] + }, + { + "cell_type": "markdown", + "id": "2f355481", + "metadata": {}, + "source": [ + "## Fine frequency synchronization\n", + "\n", + "A 2nd-order Costas loop removes any residual frequency and phase offset on the BPSK signal." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d52bbe48", + "metadata": {}, + "outputs": [], + "source": [ + "# Fine freq sync\n", + "samples = x # for the sake of matching the sync chapter\n", + "N = len(samples)\n", + "phase = 0\n", + "freq = 0\n", + "# These next two params is what to adjust, to make the feedback loop faster or slower (which impacts stability)\n", + "alpha = 8.0\n", + "beta = 0.02\n", + "out = np.zeros(N, dtype=np.complex64)\n", + "freq_log = []\n", + "for i in range(N):\n", + " out[i] = samples[i] * np.exp(-1j*phase) # adjust the input sample by the inverse of the estimated phase offset\n", + " error = np.real(out[i]) * np.imag(out[i]) # This is the error formula for 2nd order Costas Loop (e.g. for BPSK)\n", + "\n", + " # Advance the loop (recalc phase and freq offset)\n", + " freq += (beta * error)\n", + " freq_log.append(freq * sample_rate / (2*np.pi)) # convert from angular velocity to Hz for logging\n", + " phase += freq + (alpha * error)\n", + "\n", + " # Optional: Adjust phase so its always between 0 and 2pi, recall that phase wraps around every 2pi\n", + " while phase >= 2*np.pi:\n", + " phase -= 2*np.pi\n", + " while phase < 0:\n", + " phase += 2*np.pi\n", + "x = out" + ] + }, + { + "cell_type": "markdown", + "id": "4484d87c", + "metadata": {}, + "source": [ + "## Demod BPSK and differential decoding" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "018947e6", + "metadata": {}, + "outputs": [], + "source": [ + "# Demod BPSK\n", + "bits = (np.real(x) > 0).astype(int) # 1's and 0's\n", + "\n", + "# Differential decoding, so that it doesn't matter whether our BPSK was 180 degrees rotated without us realizing it\n", + "bits = (bits[1:] - bits[0:-1]) % 2\n", + "bits = bits.astype(np.uint8) # for decoder" + ] + }, + { + "cell_type": "markdown", + "id": "27429bbb", + "metadata": {}, + "source": [ + "## Decoder\n", + "\n", + "Synchronize to the RDS block structure and check each block's CRC. See Annex B, C of the RDS/RBDS standard." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3f796d99", + "metadata": {}, + "outputs": [], + "source": [ + "# Constants\n", + "syndrome = [383, 14, 303, 663, 748]\n", + "offset_pos = [0, 1, 2, 3, 2]\n", + "offset_word = [252, 408, 360, 436, 848]\n", + "\n", + "# see Annex B, page 64 of the standard\n", + "def calc_syndrome(x, mlen):\n", + " reg = 0\n", + " plen = 10\n", + " for ii in range(mlen, 0, -1):\n", + " reg = (reg << 1) | ((x >> (ii-1)) & 0x01)\n", + " if (reg & (1 << plen)):\n", + " reg = reg ^ 0x5B9\n", + " for ii in range(plen, 0, -1):\n", + " reg = reg << 1\n", + " if (reg & (1 << plen)):\n", + " reg = reg ^ 0x5B9\n", + " return reg & ((1 << plen) - 1) # select the bottom plen bits of reg\n", + "\n", + "# Initialize all the working vars we'll need during the loop\n", + "synced = False\n", + "presync = False\n", + "\n", + "wrong_blocks_counter = 0\n", + "blocks_counter = 0\n", + "group_good_blocks_counter = 0\n", + "\n", + "reg = np.uint32(0) # was unsigned long in C++ (64 bits) but numpy doesn't support bitwise ops of uint64, I don't think it gets that high anyway\n", + "lastseen_offset_counter = 0\n", + "lastseen_offset = 0\n", + "\n", + "# the synchronization process is described in Annex C, page 66 of the standard */\n", + "bytes_out = []\n", + "for i in range(len(bits)):\n", + " # in C++ reg doesn't get init so it will be random at first, for ours its 0s\n", + " # It was also an unsigned long but never seemed to get anywhere near the max value\n", + " # bits are either 0 or 1\n", + " reg = np.bitwise_or(np.left_shift(reg, 1), bits[i]) # reg contains the last 26 rds bits. these are both bitwise ops\n", + " if not synced:\n", + " reg_syndrome = calc_syndrome(reg, 26)\n", + " for j in range(5):\n", + " if reg_syndrome == syndrome[j]:\n", + " if not presync:\n", + " lastseen_offset = j\n", + " lastseen_offset_counter = i\n", + " presync = True\n", + " else:\n", + " if offset_pos[lastseen_offset] >= offset_pos[j]:\n", + " block_distance = offset_pos[j] + 4 - offset_pos[lastseen_offset]\n", + " else:\n", + " block_distance = offset_pos[j] - offset_pos[lastseen_offset]\n", + " if (block_distance*26) != (i - lastseen_offset_counter):\n", + " presync = False\n", + " else:\n", + " print('Sync State Detected')\n", + " wrong_blocks_counter = 0\n", + " blocks_counter = 0\n", + " block_bit_counter = 0\n", + " block_number = (j + 1) % 4\n", + " group_assembly_started = False\n", + " synced = True\n", + " break # syndrome found, no more cycles\n", + "\n", + " else: # SYNCED\n", + " # wait until 26 bits enter the buffer */\n", + " if block_bit_counter < 25:\n", + " block_bit_counter += 1\n", + " else:\n", + " good_block = False\n", + " dataword = (reg >> 10) & 0xffff\n", + " block_calculated_crc = calc_syndrome(dataword, 16)\n", + " checkword = reg & 0x3ff\n", + " if block_number == 2: # manage special case of C or C' offset word\n", + " block_received_crc = checkword ^ offset_word[block_number]\n", + " if (block_received_crc == block_calculated_crc):\n", + " good_block = True\n", + " else:\n", + " block_received_crc = checkword ^ offset_word[4]\n", + " if (block_received_crc == block_calculated_crc):\n", + " good_block = True\n", + " else:\n", + " wrong_blocks_counter += 1\n", + " good_block = False\n", + " else:\n", + " block_received_crc = checkword ^ offset_word[block_number] # bitwise xor\n", + " if block_received_crc == block_calculated_crc:\n", + " good_block = True\n", + " else:\n", + " wrong_blocks_counter += 1\n", + " good_block = False\n", + "\n", + " # Done checking CRC\n", + " if block_number == 0 and good_block:\n", + " group_assembly_started = True\n", + " group_good_blocks_counter = 1\n", + " group = bytearray(8) # 8 bytes filled with 0s\n", + " if group_assembly_started:\n", + " if not good_block:\n", + " group_assembly_started = False\n", + " else:\n", + " # raw data bytes, as received from RDS. 8 info bytes, followed by 4 RDS offset chars: ABCD/ABcD/EEEE (in US) which we leave out here\n", + " # RDS information words\n", + " # block_number is either 0,1,2,3 so this is how we fill out the 8 bytes\n", + " group[block_number*2] = (dataword >> 8) & 255\n", + " group[block_number*2+1] = dataword & 255\n", + " group_good_blocks_counter += 1\n", + " #print('group_good_blocks_counter:', group_good_blocks_counter)\n", + " if group_good_blocks_counter == 5:\n", + " #print(group)\n", + " bytes_out.append(group) # list of len-8 lists of bytes\n", + " block_bit_counter = 0\n", + " block_number = (block_number + 1) % 4\n", + " blocks_counter += 1\n", + " if blocks_counter == 50:\n", + " if wrong_blocks_counter > 35: # This many wrong blocks must mean we lost sync\n", + " print(\"Lost Sync (Got \", wrong_blocks_counter, \" bad blocks on \", blocks_counter, \" total)\")\n", + " synced = False\n", + " presync = False\n", + " else:\n", + " print(\"Still Sync-ed (Got \", wrong_blocks_counter, \" bad blocks on \", blocks_counter, \" total)\")\n", + " blocks_counter = 0\n", + " wrong_blocks_counter = 0" + ] + }, + { + "cell_type": "markdown", + "id": "c1ac9192", + "metadata": {}, + "source": [ + "## Parser\n", + "\n", + "Parse the assembled RDS groups to extract the program info and RadioText. See Annex D, F of the standard." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "02948ff5", + "metadata": {}, + "outputs": [], + "source": [ + "# Annex F of RBDS Standard Table F.1 (North America) and Table F.2 (Europe)\n", + "# Europe North America\n", + "pty_table = [[\"Undefined\", \"Undefined\"],\n", + " [\"News\", \"News\"],\n", + " [\"Current Affairs\", \"Information\"],\n", + " [\"Information\", \"Sports\"],\n", + " [\"Sport\", \"Talk\"],\n", + " [\"Education\", \"Rock\"],\n", + " [\"Drama\", \"Classic Rock\"],\n", + " [\"Culture\", \"Adult Hits\"],\n", + " [\"Science\", \"Soft Rock\"],\n", + " [\"Varied\", \"Top 40\"],\n", + " [\"Pop Music\", \"Country\"],\n", + " [\"Rock Music\", \"Oldies\"],\n", + " [\"Easy Listening\", \"Soft\"],\n", + " [\"Light Classical\", \"Nostalgia\"],\n", + " [\"Serious Classical\", \"Jazz\"],\n", + " [\"Other Music\", \"Classical\"],\n", + " [\"Weather\", \"Rhythm & Blues\"],\n", + " [\"Finance\", \"Soft Rhythm & Blues\"],\n", + " [\"Children\\u2019s Programmes\", \"Language\"],\n", + " [\"Social Affairs\", \"Religious Music\"],\n", + " [\"Religion\", \"Religious Talk\"],\n", + " [\"Phone-In\", \"Personality\"],\n", + " [\"Travel\", \"Public\"],\n", + " [\"Leisure\", \"College\"],\n", + " [\"Jazz Music\", \"Spanish Talk\"],\n", + " [\"Country Music\", \"Spanish Music\"],\n", + " [\"National Music\", \"Hip Hop\"],\n", + " [\"Oldies Music\", \"Unassigned\"],\n", + " [\"Folk Music\", \"Unassigned\"],\n", + " [\"Documentary\", \"Weather\"],\n", + " [\"Alarm Test\", \"Emergency Test\"],\n", + " [\"Alarm\", \"Emergency\"]]\n", + "pty_locale = 1 # set to 0 for Europe which will use first column instead\n", + "\n", + "# page 72, Annex D, table D.2 in the standard\n", + "coverage_area_codes = [\"Local\",\n", + " \"International\",\n", + " \"National\",\n", + " \"Supra-regional\",\n", + " \"Regional 1\",\n", + " \"Regional 2\",\n", + " \"Regional 3\",\n", + " \"Regional 4\",\n", + " \"Regional 5\",\n", + " \"Regional 6\",\n", + " \"Regional 7\",\n", + " \"Regional 8\",\n", + " \"Regional 9\",\n", + " \"Regional 10\",\n", + " \"Regional 11\",\n", + " \"Regional 12\"]\n", + "\n", + "radiotext_AB_flag = 0\n", + "radiotext = [' ']*65\n", + "first_time = True\n", + "for group in bytes_out:\n", + " group_0 = group[1] | (group[0] << 8)\n", + " group_1 = group[3] | (group[2] << 8)\n", + " group_2 = group[5] | (group[4] << 8)\n", + " group_3 = group[7] | (group[6] << 8)\n", + "\n", + " group_type = (group_1 >> 12) & 0xf # here is what each one means, e.g. RT is radiotext which is the only one we decode here: [\"BASIC\", \"PIN/SL\", \"RT\", \"AID\", \"CT\", \"TDC\", \"IH\", \"RP\", \"TMC\", \"EWS\", \"___\", \"___\", \"___\", \"___\", \"EON\", \"___\"]\n", + " AB = (group_1 >> 11 ) & 0x1 # b if 1, a if 0\n", + "\n", + " #print(\"group_type:\", group_type) # this is essentially message type, i only see type 0 and 2 in my recording\n", + " #print(\"AB:\", AB)\n", + "\n", + " program_identification = group_0 # \"PI\"\n", + "\n", + " program_type = (group_1 >> 5) & 0x1f # \"PTY\"\n", + " pty = pty_table[program_type][pty_locale]\n", + "\n", + " pi_area_coverage = (program_identification >> 8) & 0xf\n", + " coverage_area = coverage_area_codes[pi_area_coverage]\n", + "\n", + " pi_program_reference_number = program_identification & 0xff # just an int\n", + "\n", + " if first_time:\n", + " print(\"PTY:\", pty)\n", + " print(\"program:\", pi_program_reference_number)\n", + " print(\"coverage_area:\", coverage_area)\n", + " first_time = False\n", + "\n", + " if group_type == 2:\n", + " # when the A/B flag is toggled, flush your current radiotext\n", + " if radiotext_AB_flag != ((group_1 >> 4) & 0x01):\n", + " radiotext = [' ']*65\n", + " radiotext_AB_flag = (group_1 >> 4) & 0x01\n", + " text_segment_address_code = group_1 & 0x0f\n", + " if AB:\n", + " radiotext[text_segment_address_code * 2 ] = chr((group_3 >> 8) & 0xff)\n", + " radiotext[text_segment_address_code * 2 + 1] = chr(group_3 & 0xff)\n", + " else:\n", + " radiotext[text_segment_address_code *4 ] = chr((group_2 >> 8) & 0xff)\n", + " radiotext[text_segment_address_code * 4 + 1] = chr(group_2 & 0xff)\n", + " radiotext[text_segment_address_code * 4 + 2] = chr((group_3 >> 8) & 0xff)\n", + " radiotext[text_segment_address_code * 4 + 3] = chr(group_3 & 0xff)\n", + " print(''.join(radiotext))\n", + " else:\n", + " pass\n", + " #print(\"unsupported group_type:\", group_type)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python (Pyodide)", + "language": "python", + "name": "python" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/jupyterlite/sync.ipynb b/jupyterlite/sync.ipynb new file mode 100644 index 00000000..f8c3ff9c --- /dev/null +++ b/jupyterlite/sync.ipynb @@ -0,0 +1,349 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3d4cb9e2", + "metadata": {}, + "source": [ + "# Synchronization\n", + "\n", + "This notebook walks through the full receiver-side synchronization chain for a BPSK signal,\n", + "following the PySDR *Synchronization* chapter. We start by simulating a transmitted signal\n", + "with realistic impairments (a fractional timing offset and a frequency offset), then recover\n", + "it step by step:\n", + "\n", + "1. Generate a pulse-shaped BPSK signal\n", + "2. Add a fractional-sample timing offset\n", + "3. Add a coarse frequency offset\n", + "4. Estimate and correct the coarse frequency offset (squaring method)\n", + "5. Symbol timing recovery (Mueller and Muller)\n", + "6. Fine frequency/phase sync (Costas loop) and BER check\n" + ] + }, + { + "cell_type": "markdown", + "id": "3f520421", + "metadata": {}, + "source": [ + "## Create the BPSK signal\n", + "\n", + "We generate random bits, map them to +1/-1, and space them out by `sps` samples per symbol\n", + "to form a pulse train (an impulse at the start of each symbol period)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "26737a53", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from scipy import signal\n", + "\n", + "# Create BPSK signal\n", + "num_symbols = 100\n", + "sps = 8\n", + "bits = np.random.randint(0, 2, num_symbols) # Our data to be transmitted, 1's and 0's\n", + "pulse_train = np.array([])\n", + "for bit in bits:\n", + " pulse = np.zeros(sps)\n", + " pulse[0] = bit*2-1 # set the first value to either a 1 or -1\n", + " pulse_train = np.concatenate((pulse_train, pulse)) # add the 8 samples to the signal" + ] + }, + { + "cell_type": "markdown", + "id": "0ec4f885", + "metadata": {}, + "source": [ + "## Pulse shaping\n", + "\n", + "We convolve the pulse train with a raised-cosine filter to limit the signal's bandwidth." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "a880dd10", + "metadata": {}, + "outputs": [], + "source": [ + "# Apply pulse shaping to the BPSK\n", + "num_taps = 101\n", + "beta = 0.35\n", + "Ts = sps # Assume sample rate is 1 Hz, so sample period is 1, so *symbol* period is 8\n", + "t = np.arange(-51, 52) # remember it's not inclusive of final number\n", + "h = np.sinc(t/Ts) * np.cos(np.pi*beta*t/Ts) / (1 - (2*beta*t/Ts)**2)\n", + "samples = np.convolve(pulse_train, h, 'same')" + ] + }, + { + "cell_type": "markdown", + "id": "7e701728", + "metadata": {}, + "source": [ + "## Add a fractional timing offset\n", + "\n", + "A real receiver never samples exactly at the symbol boundaries. We emulate that by applying a\n", + "fractional-delay filter, shifting the signal by a non-integer number of samples." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "e1d8346a", + "metadata": {}, + "outputs": [], + "source": [ + "# Create and apply fractional delay filter to emulate a random timing offset\n", + "delay = 0.456 # fractional delay, in samples\n", + "N = 21 # number of taps, keep this odd\n", + "n = np.arange(-(N-1)//2, N//2+1) # -10,-9,...,0,...,9,10\n", + "h = np.sinc(n - delay) # calc filter taps\n", + "h *= np.hamming(N) # window the filter to make sure it decays to 0 on both sides\n", + "h /= np.sum(h) # normalize to get unity gain, we don't want to change the amplitude/power\n", + "samples = np.convolve(samples, h) # apply filter" + ] + }, + { + "cell_type": "markdown", + "id": "28fb8f50", + "metadata": {}, + "source": [ + "## Add a coarse frequency offset\n", + "\n", + "Transmitter and receiver oscillators are never perfectly aligned, which shows up as a frequency\n", + "offset. Here we deliberately add a large one (13 kHz) to be corrected later." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "1b56a043", + "metadata": {}, + "outputs": [], + "source": [ + "# Apply a pretty significant freq offset\n", + "fs = 1e6 # assume our sample rate is 1 MHz\n", + "fo = 13000 # simulate freq offset THIS REPRESENTS A COARSE OFFSET!\n", + "Ts = 1/fs # calc sample period\n", + "t = np.arange(0, Ts*len(samples), Ts) # create time vector\n", + "samples = samples * np.exp(1j*2*np.pi*fo*t) # perform freq shift" + ] + }, + { + "cell_type": "markdown", + "id": "2183e8e3", + "metadata": {}, + "source": [ + "## Coarse frequency correction\n", + "\n", + "Squaring a BPSK signal removes the data modulation and produces a tone at twice the frequency\n", + "offset. We find that tone's location in the FFT, halve it, and de-rotate the signal." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "23a87587", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Estimated freq offset: 13067.90 Hz\n" + ] + } + ], + "source": [ + "# Estimate and correct for the coarse freq offset\n", + "samples_sq = samples**2\n", + "psd = np.fft.fftshift(np.abs(np.fft.fft(samples_sq, 2048)))\n", + "f = np.linspace(-fs/2.0, fs/2.0, len(psd))\n", + "max_freq = f[np.argmax(psd)] / 2.0\n", + "print(f\"Estimated freq offset: {max_freq:.2f} Hz\")\n", + "Ts = 1/fs # calc sample period\n", + "t = np.arange(0, Ts*len(samples), Ts) # create time vector\n", + "samples = samples * np.exp(-1j*2*np.pi*max_freq*t)\n", + "\n", + "# At this point there should be less than 1kHz of freq offset in our signal, depending how large an FFT you used above" + ] + }, + { + "cell_type": "markdown", + "id": "c0d6f178", + "metadata": {}, + "source": [ + "## Symbol timing recovery\n", + "\n", + "We use the Mueller and Muller timing-error detector. An interpolating resampler lets us pick a\n", + "sub-sample-accurate point within each symbol, and the loop adjusts the sampling instant `mu`\n", + "to lock onto the symbol timing." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "48f53c9d", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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JKxZsybVQyEIwkMCqR4AQRDNgyuuuAL19fWYNWsWevbsidLSUsyfPx9lZWWpHhpBEIQl5BEiCMI15eXlWLx4MZ5//nmce+656N69O0aNGoWHHnoIl1xyibbctGnTMHjwYLRu3RqFhYW48847UVVVpX0/c+ZM5Obm4rPPPkPfvn2RmZmJK6+8EtXV1Zg1axaKiorQtm1b3HPPPQiHw9p6RUVFePLJJ3HttdeidevW6NKlC15++WXmmPft24err74aubm5yMvLw8SJE7F7927uY164cCEkScL8+fMxcuRIZGZm4owzzsCWLVsMyz333HPIz89HdnY2br31VtTW1sZt64033kD//v2RkZGBfv364c9//rP23S233IIhQ4agrq4OAFBfX4/hw4fjhhtu4B4rQRDWkCFEEIRrsrKykJWVhY8++kh7YJvh8/kwffp0bNy4EbNmzcKXX36JBx54wLBMdXU1pk+fjnfeeQdffPEFFi5ciMsuuwxz5szBnDlz8Oabb+K1117DP//5T8N6v/3tbzF06FCsXr0aDz74ICZPnoy5c+eajiMUCmHChAnIzs7G4sWLsWTJEmRlZeHCCy9EfX290LE//PDDePHFF7Fy5UoEAgHccsst2nfvvfceHnvsMTzzzDNYuXIlOnXqZDByAGD27Nl45JFH8PTTT2Pz5s145plnMHXqVMyaNQsAMH36dJw4cQIPPvigtr/y8nL86U9/EhonQRAWuO5fTxAEIcvyP//5T7lt27ZyRkaGfMYZZ8gPPfSQvHbtWuY677//vtyuXTvt7xkzZsgA5O3bt2uf/exnP5MzMzPlyspK7bMJEybIP/vZz7S/u3fvLl944YWGbf/4xz+WL7roIu1vAPKHH34oy7Isv/nmm3Lfvn3lSCSifV9XVye3atVK/s9//mM61l27dskA5NWrV8uyLMsLFiyQAcjz5s3Tlvn8889lAHJNTY0sy7I8ZswY+c477zRsZ/To0fLQoUO1v3v16iW//fbbhmWefPJJecyYMdrf//vf/+RgMChPnTpVDgQC8uLFi03HSBCEOOQRIgjCE6644gocPHgQn3zyCS688EIsXLgQp556KmbOnKktM2/ePIwbNw5dunRBdnY2rr/+epSVlaG6ulpbJjMzE7169dL+zs/PR1FREbKysgyfHT582LD/MWPGxP29efNm07GuXbsW27dvR3Z2tubNysvLQ21tLXbs2CF03EOGDNH+3alTJwDQxrZ582aMHj3acpwnTpzAjh07cOutt2rjyMrKwlNPPWUYx5gxY/DLX/4STz75JO6//36MHTtWaIwEQVhDYmmCIDwjIyMD48ePx/jx4zF16lT89Kc/xaOPPoqbbroJu3fvxo9+9CPccccdePrpp5GXl4evv/4at956K+rr65GZmQkACAaDhm1KkmT6WSQScTzOqqoqjBgxArNnz477rkOHDkLb0o9NkiQA4B6bqo96/fXX4wwmv9+v/TsSiWDJkiXw+/3Yvn270PgIgmBDHiGCIBLGgAEDcOLECQDAqlWrEIlE8OKLL+L000/HKaecgoMHD3q2r2+++Sbu7/79+5sue+qpp2Lbtm3o2LEjevfubfivTZs2no2pf//+WLZsmeU48/Pz0blzZ+zcuTNuHD169NCW++1vf4vvvvsOixYtwhdffIEZM2Z4NkaCaOmQIUQQhGvKyspw3nnn4a233sK6deuwa9cuvP/++3jhhRcwceJEAEDv3r0RCoXw0ksvYefOnXjzzTfx6quvejaGJUuW4IUXXsDWrVvx8ssv4/3338fkyZNNl500aRLat2+PiRMnYvHixdi1axcWLlyIe+65B/v37/dsTJMnT8bf/vY3zJgxA1u3bsWjjz6KjRs3GpZ5/PHH8eyzz2L69OnYunUr1q9fjxkzZmDatGkAgNWrV+ORRx7BG2+8gTPPPBPTpk3D5MmTsXPnTs/GSRAtGTKECIJwTVZWFkaPHo3f//73OOusszBo0CBMnToVt912m5bdNHToUEybNg3PP/88Bg0ahNmzZ+PZZ5/1bAz3338/Vq5cieHDh+Opp57CtGnTMGHCBNNlMzMz8dVXX6Fbt264/PLL0b9/fy21PScnx7Mx/fjHP8bUqVPxwAMPYMSIEdizZw/uuOMOwzI//elP8cYbb2DGjBkYPHgwzj77bMycORM9evRAbW0trrvuOtx00024+OKLAQC33347zj33XFx//fWGEgIEQThDkmVZTvUgCIIg3FBUVIQpU6ZgypQpqR4KQRBNDPIIEQRBEATRYiFDiCAIgiCIFguFxgiCIAiCaLGQR4ggCIIgiBYLGUIEQRAEQbRYyBAiCIIgCKLFQoYQQRAEQRAtFjKECIIgCIJosZAhRBAEQRBEi4UMIYIgCIIgWixkCBEEQRAE0WL5fx36+NplywKAAAAAAElFTkSuQmCC", + "text/plain": [ + "
    " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Symbol/Timing Sync\n", + "mu = 0 # initial estimate of phase of sample\n", + "out = np.zeros(len(samples) // sps + 2, dtype=np.complex64)\n", + "out_rail = np.zeros(len(samples) // sps + 2, dtype=np.complex64) # stores values, each iteration we need the previous 2 values plus current value\n", + "i_in = 0 # input samples index\n", + "i_out = 2 # output index (let first two outputs be 0)\n", + "interpolation_factor = 16\n", + "samples_interpolated = signal.resample_poly(samples, interpolation_factor, 1)\n", + "while i_out < len(samples) and i_in+16 < len(samples):\n", + " out[i_out] = samples_interpolated[i_in*interpolation_factor + int(mu*interpolation_factor)]\n", + " out_rail[i_out] = int(np.real(out[i_out]) > 0) + 1j*int(np.imag(out[i_out]) > 0)\n", + " x = (out_rail[i_out] - out_rail[i_out-2]) * np.conj(out[i_out-1])\n", + " y = (out[i_out] - out[i_out-2]) * np.conj(out_rail[i_out-1])\n", + " mm_val = np.real(y - x)\n", + " mu += sps + 0.3*mm_val\n", + " i_in += int(np.floor(mu)) # round down to nearest int since we are using it as an index\n", + " mu = mu - np.floor(mu) # remove the integer part of mu\n", + " i_out += 1 # increment output index\n", + "out = out[3:i_out] # remove the first few due to filter transients, and anything after i_out (that was never filled out)\n", + "samples = out\n", + "\n", + "plt.figure(2)\n", + "plt.plot(np.real(samples))\n", + "plt.plot(np.imag(samples))\n", + "plt.xlabel('Sample Index')\n", + "plt.ylabel('Sample Value')\n", + "plt.legend(['I', 'Q'])\n", + "plt.grid()" + ] + }, + { + "cell_type": "markdown", + "id": "d334f1aa", + "metadata": {}, + "source": [ + "## Fine frequency and phase sync (Costas loop)\n", + "\n", + "The coarse correction leaves a small residual frequency/phase offset. A Costas loop tracks and\n", + "removes it. After it converges, we slice the bits, compute the bit error rate, and plot the\n", + "frequency estimate over time along with the recovered constellation." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "47f7667d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of bit errors: 0 out of 100 bits, BER: 0.0000\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
    " + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
    " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "N = len(samples)\n", + "phase = 0\n", + "freq = 0\n", + "# These next two params is what to adjust, to make the feedback loop faster or slower (which impacts stability)\n", + "alpha = 0.132\n", + "beta = 0.00932\n", + "out = np.zeros(N, dtype=np.complex64)\n", + "freq_log = []\n", + "for i in range(N):\n", + " out[i] = samples[i] * np.exp(-1j*phase) # adjust the input sample by the inverse of the estimated phase offset\n", + " error = np.real(out[i]) * np.imag(out[i]) # This is the error formula for 2nd order Costas Loop (e.g. for BPSK)\n", + "\n", + " # Advance the loop (recalc phase and freq offset)\n", + " freq += (beta * error)\n", + " freq_log.append(freq * fs / (2*np.pi)) # convert from angular velocity to Hz for logging\n", + " phase += freq + (alpha * error)\n", + "\n", + " # Optional: Adjust phase so its always between 0 and 2pi, recall that phase wraps around every 2pi\n", + " while phase >= 2*np.pi:\n", + " phase -= 2*np.pi\n", + " while phase < 0:\n", + " phase += 2*np.pi\n", + "\n", + "# Calc BER\n", + "rx_bits = (np.real(out) > 0).astype(int)\n", + "num_bit_errors = np.sum(rx_bits != bits[:len(rx_bits)])\n", + "print(f\"Number of bit errors: {num_bit_errors} out of {len(rx_bits)} bits, BER: {num_bit_errors/len(rx_bits):.4f}\")\n", + "\n", + "# Plot freq over time to see how long it takes to hit the right offset\n", + "plt.figure(0)\n", + "plt.plot(freq_log,'.-')\n", + "plt.xlabel('Sample Index')\n", + "plt.ylabel('Frequency Offset Estimate (Hz)')\n", + "\n", + "# Appears to be synced after ~80 samples so lets plot the constellation of the remaining 20 samples\n", + "plt.figure(1)\n", + "plt.plot(np.real(out[80:]), np.imag(out[80:]), '.')\n", + "plt.xlabel('I')\n", + "plt.ylabel('Q')\n", + "plt.xlim(-1.5, 1.5)\n", + "plt.ylim(-1.5, 1.5)\n", + "plt.grid()\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/requirements-jupyterlite.txt b/requirements-jupyterlite.txt new file mode 100644 index 00000000..201c1c31 --- /dev/null +++ b/requirements-jupyterlite.txt @@ -0,0 +1,5 @@ +# Used only to build the self-hosted JupyterLite environment deployed at /jupyterlite/ +# Kept separate from requirements.txt so it can't disturb the (older) Sphinx pins. +jupyterlite-core==0.8.1 +jupyterlite-pyodide-kernel==0.8.1 +jupyter-server==2.20.0 # required for `jupyter lite build --contents` to bundle the notebook(s) in jupyterlite/ diff --git a/requirements.txt b/requirements.txt index f2c9865e..3aaddcc4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,12 +1,14 @@ sphinx==4.4.0 sphinxcontrib-tikz==0.4.20 sphinxcontrib-spelling==8.0.0 -docutils==0.17.1 -patreon==0.5.0 -imageio==2.11.0 sphinxcontrib-applehelp==1.0.2 sphinxcontrib-devhelp==1.0.2 sphinxcontrib-htmlhelp==2.0.0 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 -sphinxcontrib-serializinghtml==1.1.5 \ No newline at end of file +sphinxcontrib-serializinghtml==1.1.5 +sphinxcontrib-mermaid==2.0.0 +docutils==0.17.1 +patreon==0.5.0 +setuptools<72 # until patreon fixes their stuff, this is needed +imageio==2.11.0 \ No newline at end of file diff --git a/scrape_patreon.py b/scrape_patreon.py index 179e00ff..fbc3c56a 100644 --- a/scrape_patreon.py +++ b/scrape_patreon.py @@ -34,6 +34,7 @@ def scrape_patreon(): names.append(f'{full_name} ') continue names.append(full_name) # there's also 'first_name' which might be better for a public display name + names.append('Dan Boschen') # Patreon Supporters html_string = '' html_string += '
    A big thanks to all PySDR
    Patreon supporters:
    ' diff --git a/spelling_wordlist.txt b/spelling_wordlist.txt index 2953551a..b122dae5 100644 --- a/spelling_wordlist.txt +++ b/spelling_wordlist.txt @@ -12,6 +12,8 @@ sc np NumPy numpy +Jupyter +JupyterLite Arg frontend dBm @@ -298,3 +300,70 @@ dBi Marcovici Techtile retuned +Wi +Fi +Kasami +correlator +correlators +decorrelate +decorrelates +Weibull +Xilinx +Neyman +detections +amidst +IoT +Papoulis +Pillai +Springer +Napolitano +trilaterate +Estévez +trilateration +bursty +demod +grayscale +SNR +luma +quadcopter +Spektrum +DIY +chroma +Vandermonde +eigendecomposition +ULA +geolocation +observability +timestamping +coplanar +collinear +GDOP +Cramér +Rao +nonlinearity +Jacobians +linearizes +Foy +iteratively +minimizer +Jacobian +linearized +multimodal +overdetermined +Schau +Linearization +initializers +stationarity +reverberant +suboptimal +linearize +foci +Multilateration +subsample +subsampling +linearization +hyperboloid +underdetermined +unitless +linearizing +prepending