├── .gitattributes ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── documentation-request.md │ ├── feature_request.md │ └── submit-question.md ├── PULL_REQUEST_TEMPLATE.md ├── copy-pr-bot.yaml ├── labeler.yml ├── ops-bot.yaml └── workflows │ ├── build.yaml │ ├── labeler.yml │ ├── new-issues-to-triage-projects.yml │ ├── pr.yaml │ └── test.yaml ├── .gitignore ├── .pre-commit-config.yaml ├── CHANGELOG.md ├── CITATION.cff ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── benchmarks └── __init__.py ├── build.sh ├── ci ├── build_docs.sh ├── build_python.sh ├── check_style.sh ├── release │ └── update-version.sh ├── test_notebooks.sh ├── test_python.sh └── utils │ ├── nbtest.sh │ └── nbtestlog2junitxml.py ├── conda ├── environments │ ├── all_cuda-118_arch-x86_64.yaml │ ├── cusignal_airt.yml │ ├── cusignal_base.yml │ ├── cusignal_full.yml │ └── cusignal_jetson_base.yml └── recipes │ └── cusignal │ ├── build.sh │ ├── conda_build_config.yaml │ └── meta.yaml ├── cpp ├── .clang_format ├── scripts │ └── run-clang-format.py └── src │ ├── convolution │ └── _convolution.cu │ ├── filtering │ ├── _channelizer.cu │ ├── _sosfilt.cu │ └── _upfirdn.cu │ ├── io │ ├── _reader.cu │ └── _writer.cu │ ├── peak_finding │ └── _peak_finding.cu │ └── spectral_analysis │ └── _spectral.cu ├── dependencies.yaml ├── docker └── Dockerfile ├── docs ├── Makefile ├── README.md ├── make.bat ├── requirement.txt └── source │ ├── _static │ ├── EMPTY │ └── RAPIDS-logo-purple.png │ ├── api.rst │ ├── conf.py │ └── index.rst ├── notebooks ├── E2E_Example.ipynb ├── api_guide │ ├── acoustics_examples.ipynb │ ├── bspline_examples.ipynb │ ├── convolution_examples.ipynb │ ├── estimation_examples.ipynb │ ├── filter_design_examples.ipynb │ ├── filtering_examples.ipynb │ ├── io_examples.ipynb │ ├── peak_finding_examples.ipynb │ ├── radar_examples.ipynb │ ├── spectral_examples.ipynb │ ├── waveform_examples.ipynb │ ├── wavelets_examples.ipynb │ └── windows_examples.ipynb ├── sdr │ ├── online_signal_processing_tools.ipynb │ ├── rtlsdr_offline_demod_to_transcript.ipynb │ └── sdr_wfm_demod.ipynb └── visualization │ └── scope.ipynb ├── print_env.sh └── python ├── .coveragerc ├── MANIFEST.in ├── cusignal ├── __init__.py ├── _version.py ├── acoustics │ ├── __init__.py │ └── cepstrum.py ├── bsplines │ ├── __init__.py │ └── bsplines.py ├── convolution │ ├── __init__.py │ ├── _convolution_cuda.py │ ├── convolution_utils.py │ ├── convolve.py │ └── correlate.py ├── demod │ ├── __init__.py │ └── demod.py ├── estimation │ ├── __init__.py │ ├── _filters_cuda.py │ └── filters.py ├── filter_design │ ├── __init__.py │ ├── filter_design_utils.py │ └── fir_filter_design.py ├── filtering │ ├── __init__.py │ ├── _channelizer_cuda.py │ ├── _sosfilt_cuda.py │ ├── _upfirdn_cuda.py │ ├── filtering.py │ └── resample.py ├── io │ ├── __init__.py │ ├── _reader_cuda.py │ ├── _writer_cuda.py │ ├── reader.py │ └── writer.py ├── peak_finding │ ├── __init__.py │ ├── _peak_finding_cuda.py │ └── peak_finding.py ├── radartools │ ├── __init__.py │ ├── beamformers.py │ └── radartools.py ├── spectral_analysis │ ├── __init__.py │ ├── _spectral_cuda.py │ └── spectral.py ├── test │ ├── conftest.py │ ├── io │ │ ├── test_bin.py │ │ └── test_sigmf.py │ ├── test_acoustics.py │ ├── test_arraytools.py │ ├── test_bsplines.py │ ├── test_convolution.py │ ├── test_filter_design.py │ ├── test_filtering.py │ ├── test_filters.py │ ├── test_peak_finding.py │ ├── test_radartools.py │ ├── test_spectral_analysis.py │ ├── test_waveforms.py │ ├── test_wavelets.py │ └── test_windows.py ├── testing │ ├── __init__.py │ └── utils.py ├── utils │ ├── __init__.py │ ├── _caches.py │ ├── arraytools.py │ ├── fftpack_helper.py │ └── helper_tools.py ├── waveforms │ ├── __init__.py │ └── waveforms.py ├── wavelets │ ├── __init__.py │ └── wavelets.py └── windows │ ├── __init__.py │ └── windows.py ├── setup.cfg ├── setup.py └── versioneer.py /.gitattributes: -------------------------------------------------------------------------------- 1 | notebooks/api_guide/*.ipynb linguist-vendored 2 | notebooks/*.ipynb linguist-vendored 3 | notebooks/sdr/*.ipynb linguist-vendored 4 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # python code owners 2 | python/ @rapidsai/cusignal-python-codeowners 3 | 4 | # build/ops code owners 5 | .github/ @rapidsai/ops-codeowners 6 | ci/ @rapidsai/ops-codeowners 7 | conda/ @rapidsai/ops-codeowners 8 | **/Dockerfile @rapidsai/ops-codeowners 9 | **/.dockerignore @rapidsai/ops-codeowners 10 | dependencies.yaml @rapidsai/ops-codeowners 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a bug report to help us improve cuSignal 4 | title: "[BUG]" 5 | labels: "? - Needs Triage, bug" 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Steps/Code to reproduce bug** 14 | Follow this guide http://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports to craft a minimal bug report. This helps us reproduce the issue you're having and resolve the issue more quickly. 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Environment details (please complete the following information):** 20 | - Environment location: [Bare-metal, Docker, Cloud(specify cloud provider)] 21 | - Method of cuSignal install: [conda, Docker, or from source] 22 | - If method of install is [Docker], provide `docker pull` & `docker run` commands used 23 | 24 | 25 | **Additional context** 26 | Add any other context about the problem here. 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Documentation request 3 | about: Report incorrect or needed documentation 4 | title: "[DOC]" 5 | labels: "? - Needs Triage, doc" 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Report incorrect documentation 11 | 12 | **Location of incorrect documentation** 13 | Provide links and line numbers if applicable. 14 | 15 | **Describe the problems or issues found in the documentation** 16 | A clear and concise description of what you found to be incorrect. 17 | 18 | **Steps taken to verify documentation is incorrect** 19 | List any steps you have taken: 20 | 21 | **Suggested fix for documentation** 22 | Detail proposed changes to fix the documentation if you have any. 23 | 24 | --- 25 | 26 | ## Report needed documentation 27 | 28 | **Report needed documentation** 29 | A clear and concise description of what documentation you believe it is needed and why. 30 | 31 | **Describe the documentation you'd like** 32 | A clear and concise description of what you want to happen. 33 | 34 | **Steps taken to search for needed documentation** 35 | List any steps you have taken: 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for cuSignal 4 | title: "[FEA]" 5 | labels: "? - Needs Triage, feature request" 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I wish I could use cuSignal to do [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context, code examples, or references to existing implementations about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/submit-question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Submit question 3 | about: Ask a general question about cuSignal 4 | title: "[QST]" 5 | labels: "? - Needs Triage, question" 6 | assignees: '' 7 | 8 | --- 9 | 10 | **What is your question?** 11 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 45 | -------------------------------------------------------------------------------- /.github/copy-pr-bot.yaml: -------------------------------------------------------------------------------- 1 | # Configuration file for `copy-pr-bot` GitHub App 2 | # https://docs.gha-runners.nvidia.com/apps/copy-pr-bot/ 3 | 4 | enabled: true 5 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/actions/labeler#common-examples 2 | # Adapted from https://github.com/rapidsai/cudf/blob/main/.github/CODEOWNERS 3 | # Labels culled from https://github.com/rapidsai/cusignal/labels 4 | 5 | Python: 6 | - python/** 7 | - notebooks/** 8 | 9 | cpp: 10 | - cpp/** 11 | 12 | CMake: 13 | - '**/CMakeLists.txt' 14 | - '**/cmake/**' 15 | 16 | ci: 17 | - /ci/** 18 | 19 | conda: 20 | - conda/** 21 | -------------------------------------------------------------------------------- /.github/ops-bot.yaml: -------------------------------------------------------------------------------- 1 | # This file controls which features from the `ops-bot` repository below are enabled. 2 | # - https://github.com/rapidsai/ops-bot 3 | 4 | auto_merger: true 5 | branch_checker: true 6 | label_checker: true 7 | release_drafter: true 8 | external_contributors: false 9 | recently_updated: true 10 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: 6 | - "branch-*" 7 | tags: 8 | - v[0-9][0-9].[0-9][0-9].[0-9][0-9] 9 | workflow_dispatch: 10 | inputs: 11 | branch: 12 | required: true 13 | type: string 14 | date: 15 | required: true 16 | type: string 17 | sha: 18 | required: true 19 | type: string 20 | build_type: 21 | type: string 22 | default: nightly 23 | 24 | concurrency: 25 | group: ${{ github.workflow }}-${{ github.ref }} 26 | cancel-in-progress: true 27 | 28 | jobs: 29 | python-build: 30 | secrets: inherit 31 | uses: rapidsai/shared-action-workflows/.github/workflows/conda-python-build.yaml@branch-23.10 32 | with: 33 | matrix_filter: map(select(.CUDA_VER | startswith("11"))) 34 | build_type: ${{ inputs.build_type || 'branch' }} 35 | branch: ${{ inputs.branch }} 36 | date: ${{ inputs.date }} 37 | sha: ${{ inputs.sha }} 38 | upload-conda: 39 | needs: [python-build] 40 | secrets: inherit 41 | uses: rapidsai/shared-action-workflows/.github/workflows/conda-upload-packages.yaml@branch-23.10 42 | with: 43 | build_type: ${{ inputs.build_type || 'branch' }} 44 | branch: ${{ inputs.branch }} 45 | date: ${{ inputs.date }} 46 | sha: ${{ inputs.sha }} 47 | docs-build: 48 | if: github.ref_type == 'branch' 49 | needs: python-build 50 | secrets: inherit 51 | uses: rapidsai/shared-action-workflows/.github/workflows/custom-job.yaml@branch-23.10 52 | with: 53 | arch: "amd64" 54 | branch: ${{ inputs.branch }} 55 | build_type: ${{ inputs.build_type || 'branch' }} 56 | container_image: "rapidsai/ci-conda:latest" 57 | date: ${{ inputs.date }} 58 | node_type: "gpu-v100-latest-1" 59 | run_script: "ci/build_docs.sh" 60 | sha: ${{ inputs.sha }} 61 | -------------------------------------------------------------------------------- /.github/workflows/labeler.yml: -------------------------------------------------------------------------------- 1 | name: "Pull Request Labeler" 2 | on: 3 | - pull_request_target 4 | 5 | jobs: 6 | triage: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/labeler@main 10 | with: 11 | repo-token: "${{ secrets.GITHUB_TOKEN }}" 12 | -------------------------------------------------------------------------------- /.github/workflows/new-issues-to-triage-projects.yml: -------------------------------------------------------------------------------- 1 | name: Auto Assign New Issues to Triage Project 2 | 3 | on: 4 | issues: 5 | types: [opened] 6 | 7 | env: 8 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 9 | 10 | jobs: 11 | assign_one_project: 12 | runs-on: ubuntu-latest 13 | name: Assign to New Issues to Triage Project 14 | steps: 15 | - name: Process bug issues 16 | uses: docker://takanabe/github-actions-automate-projects:v0.0.1 17 | if: contains(github.event.issue.labels.*.name, 'bug') && contains(github.event.issue.labels.*.name, '? - Needs Triage') 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | GITHUB_PROJECT_URL: https://github.com/rapidsai/cusignal/projects/4 21 | GITHUB_PROJECT_COLUMN_NAME: 'Needs prioritizing' 22 | - name: Process feature issues 23 | uses: docker://takanabe/github-actions-automate-projects:v0.0.1 24 | if: contains(github.event.issue.labels.*.name, 'feature request') && contains(github.event.issue.labels.*.name, '? - Needs Triage') 25 | env: 26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 27 | GITHUB_PROJECT_URL: https://github.com/rapidsai/cusignal/projects/5 28 | GITHUB_PROJECT_COLUMN_NAME: 'Needs prioritizing' 29 | - name: Process other issues 30 | uses: docker://takanabe/github-actions-automate-projects:v0.0.1 31 | if: contains(github.event.issue.labels.*.name, '? - Needs Triage') && (!contains(github.event.issue.labels.*.name, 'bug') && !contains(github.event.issue.labels.*.name, 'feature request')) 32 | env: 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 34 | GITHUB_PROJECT_URL: https://github.com/rapidsai/cusignal/projects/6 35 | GITHUB_PROJECT_COLUMN_NAME: 'Needs prioritizing' 36 | -------------------------------------------------------------------------------- /.github/workflows/pr.yaml: -------------------------------------------------------------------------------- 1 | name: pr 2 | 3 | on: 4 | push: 5 | branches: 6 | - "pull-request/[0-9]+" 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.ref }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | pr-builder: 14 | needs: 15 | - checks 16 | - conda-python-build 17 | - conda-python-tests 18 | - conda-notebook-tests 19 | - docs-build 20 | secrets: inherit 21 | uses: rapidsai/shared-action-workflows/.github/workflows/pr-builder.yaml@branch-23.10 22 | checks: 23 | secrets: inherit 24 | uses: rapidsai/shared-action-workflows/.github/workflows/checks.yaml@branch-23.10 25 | conda-python-build: 26 | needs: checks 27 | secrets: inherit 28 | uses: rapidsai/shared-action-workflows/.github/workflows/conda-python-build.yaml@branch-23.10 29 | with: 30 | matrix_filter: map(select(.CUDA_VER | startswith("11"))) 31 | build_type: pull-request 32 | conda-python-tests: 33 | needs: conda-python-build 34 | secrets: inherit 35 | uses: rapidsai/shared-action-workflows/.github/workflows/conda-python-tests.yaml@branch-23.10 36 | with: 37 | matrix_filter: map(select(.CUDA_VER | startswith("11"))) 38 | build_type: pull-request 39 | conda-notebook-tests: 40 | needs: conda-python-build 41 | secrets: inherit 42 | uses: rapidsai/shared-action-workflows/.github/workflows/custom-job.yaml@branch-23.10 43 | with: 44 | build_type: pull-request 45 | node_type: "gpu-v100-latest-1" 46 | arch: "amd64" 47 | container_image: "rapidsai/ci-conda:cuda11.8.0-ubuntu22.04-py3.10" 48 | run_script: "ci/test_notebooks.sh" 49 | docs-build: 50 | needs: conda-python-build 51 | secrets: inherit 52 | uses: rapidsai/shared-action-workflows/.github/workflows/custom-job.yaml@branch-23.10 53 | with: 54 | build_type: pull-request 55 | node_type: "gpu-v100-latest-1" 56 | arch: "amd64" 57 | container_image: "rapidsai/ci-conda:cuda11.8.0-ubuntu22.04-py3.9" 58 | run_script: "ci/build_docs.sh" 59 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | branch: 7 | required: true 8 | type: string 9 | date: 10 | required: true 11 | type: string 12 | sha: 13 | required: true 14 | type: string 15 | 16 | jobs: 17 | conda-python-tests: 18 | secrets: inherit 19 | uses: rapidsai/shared-action-workflows/.github/workflows/conda-python-tests.yaml@branch-23.10 20 | with: 21 | matrix_filter: map(select(.CUDA_VER | startswith("11"))) 22 | build_type: nightly 23 | branch: ${{ inputs.branch }} 24 | date: ${{ inputs.date }} 25 | sha: ${{ inputs.sha }} 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | dist 3 | eggs 4 | lib 5 | lib64 6 | *.pyo 7 | *.pyc 8 | *.egg-info 9 | *.fatbin 10 | docs/build 11 | *.ipynb_checkpoints 12 | docs/_html 13 | docs/_text 14 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/PyCQA/isort 3 | rev: 5.12.0 4 | hooks: 5 | - id: isort 6 | args: ["--settings-path=python/setup.cfg"] 7 | files: python/.* 8 | - repo: https://github.com/psf/black 9 | rev: 22.12.0 10 | hooks: 11 | - id: black 12 | files: python/.* 13 | - repo: https://github.com/PyCQA/flake8 14 | rev: 6.0.0 15 | hooks: 16 | - id: flake8 17 | args: ["--config=python/setup.cfg"] 18 | files: python/.* 19 | default_language_version: 20 | python: python3 21 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | message: "Thank you for using cuSignal. Please cite it in your work as described below." 3 | authors: 4 | - family-names: "Thompson" 5 | given-names: "Adam" 6 | orcid: "https://orcid.org/0000-0001-9690-6357" 7 | - family-names: "Nicely" 8 | given-names: "Matthew" 9 | orcid: "https://orcid.org/0000-0003-3702-1684" 10 | title: "cuSignal: The GPU-Accelerated Signal Processing Library" 11 | version: 21.08 12 | date-released: 2021-08-06 13 | url: "https://github.com/rapidsai/cusignal" -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to cuSignal 2 | 3 | If you are interested in contributing to cuSignal, your contributions will fall 4 | into three categories: 5 | 1. You want to report a bug, feature request, or documentation issue 6 | - File an [issue](https://github.com/rapidsai/cusignal/issues/new/choose) 7 | describing what you encountered or what you want to see changed. 8 | - The RAPIDS team will evaluate the issues and triage them, scheduling 9 | them for a release. If you believe the issue needs priority attention 10 | comment on the issue to notify the team. 11 | 2. You want to propose a new Feature and implement it 12 | - Post about your intended feature, and we shall discuss the design and 13 | implementation. 14 | - Once we agree that the plan looks good, go ahead and implement it, using 15 | the [code contributions](#code-contributions) guide below. 16 | 3. You want to implement a feature or bug-fix for an outstanding issue 17 | - Follow the [code contributions](#code-contributions) guide below. 18 | - If you need more context on a particular issue, please ask and we shall 19 | provide. 20 | 21 | ## Code contributions 22 | 23 | ### Your first issue 24 | 25 | 1. Read the project's [README.md](https://github.com/rapidsai/cusignal/blob/main/README.md) 26 | to learn how to setup the development environment 27 | 2. Find an issue to work on. The best way is to look for the [good first issue](https://github.com/rapidsai/cusignal/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) 28 | or [help wanted](https://github.com/rapidsai/cusignal/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) labels 29 | 3. Comment on the issue saying you are going to work on it 30 | 4. Code! Make sure to update unit tests! 31 | 5. When done, [create your pull request](https://github.com/rapidsai/cusignal/compare) 32 | 6. Verify that CI passes all [status checks](https://help.github.com/articles/about-status-checks/). Fix if needed 33 | 7. Wait for other developers to review your code and update code as needed 34 | 8. Once reviewed and approved, a RAPIDS developer will merge your pull request 35 | 36 | Remember, if you are unsure about anything, don't hesitate to comment on issues 37 | and ask for clarifications! 38 | 39 | ### Seasoned developers 40 | 41 | Once you have gotten your feet wet and are more comfortable with the code, you 42 | can look at the prioritized issues of our next release in our [project boards](https://github.com/rapidsai/cusignal/projects). 43 | 44 | > **Pro Tip:** Always look at the release board with the highest number for 45 | issues to work on. This is where RAPIDS developers also focus their efforts. 46 | 47 | Look at the unassigned issues, and find an issue you are comfortable with 48 | contributing to. Start with _Step 3_ from above, commenting on the issue to let 49 | others know you are working on it. If you have any questions related to the 50 | implementation of the issue, ask them in the issue instead of the PR. 51 | 52 | ## Attribution 53 | Portions adopted from https://github.com/pytorch/pytorch/blob/master/CONTRIBUTING.md 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a 4 | copy of this software and associated documentation files (the "Software"), 5 | to deal in the Software without restriction, including without limitation 6 | and/or sell copies of the Software, and to permit persons to whom the 7 | Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 15 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 18 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /benchmarks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rapidsai/cusignal/136453a3c8ef381f502a1edd51ca741f6c159f4a/benchmarks/__init__.py -------------------------------------------------------------------------------- /ci/build_docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, NVIDIA CORPORATION. 3 | 4 | set -euo pipefail 5 | 6 | rapids-logger "Create test conda environment" 7 | . /opt/conda/etc/profile.d/conda.sh 8 | 9 | rapids-dependency-file-generator \ 10 | --output conda \ 11 | --file_key docs \ 12 | --matrix "cuda=${RAPIDS_CUDA_VERSION%.*};arch=$(arch);py=${RAPIDS_PY_VERSION}" | tee env.yaml 13 | 14 | rapids-mamba-retry env create --force -f env.yaml -n docs 15 | conda activate docs 16 | 17 | rapids-print-env 18 | 19 | rapids-logger "Downloading artifacts from previous jobs" 20 | PYTHON_CHANNEL=$(rapids-download-conda-from-s3 python) 21 | 22 | rapids-mamba-retry install \ 23 | --channel "${PYTHON_CHANNEL}" \ 24 | cusignal 25 | 26 | export RAPIDS_VERSION_NUMBER="23.10" 27 | export RAPIDS_DOCS_DIR="$(mktemp -d)" 28 | 29 | rapids-logger "Build Python docs" 30 | pushd docs 31 | sphinx-build -b dirhtml source _html 32 | sphinx-build -b text source _text 33 | mkdir -p "${RAPIDS_DOCS_DIR}/cusignal/"{html,txt} 34 | mv _html/* "${RAPIDS_DOCS_DIR}/cusignal/html" 35 | mv _text/* "${RAPIDS_DOCS_DIR}/cusignal/txt" 36 | popd 37 | 38 | rapids-upload-docs 39 | -------------------------------------------------------------------------------- /ci/build_python.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2022, NVIDIA CORPORATION. 3 | 4 | set -euo pipefail 5 | 6 | source rapids-env-update 7 | 8 | rapids-print-env 9 | 10 | rapids-logger "Begin py build" 11 | 12 | # TODO: Remove `--no-test` flag once importing on a CPU 13 | # node works correctly 14 | rapids-mamba-retry mambabuild \ 15 | --no-test \ 16 | conda/recipes/cusignal 17 | 18 | rapids-upload-conda-to-s3 python 19 | -------------------------------------------------------------------------------- /ci/check_style.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2020-2022, NVIDIA CORPORATION. 3 | 4 | set -euo pipefail 5 | 6 | rapids-logger "Create checks conda environment" 7 | . /opt/conda/etc/profile.d/conda.sh 8 | 9 | rapids-dependency-file-generator \ 10 | --output conda \ 11 | --file_key checks \ 12 | --matrix "cuda=${RAPIDS_CUDA_VERSION%.*};arch=$(arch);py=${RAPIDS_PY_VERSION}" | tee env.yaml 13 | 14 | rapids-mamba-retry env create --force -f env.yaml -n checks 15 | conda activate checks 16 | 17 | # Run pre-commit checks 18 | pre-commit run --hook-stage manual --all-files --show-diff-on-failure 19 | -------------------------------------------------------------------------------- /ci/release/update-version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2020, NVIDIA CORPORATION. 3 | ######################## 4 | # cuML Version Updater # 5 | ######################## 6 | 7 | ## Usage 8 | # bash update-version.sh 9 | 10 | 11 | # Format is YY.MM.PP - no leading 'v' or trailing 'a' 12 | NEXT_FULL_TAG=$1 13 | 14 | # Get current version 15 | CURRENT_TAG=$(git tag --merged HEAD | grep -xE '^v.*' | sort --version-sort | tail -n 1 | tr -d 'v') 16 | CURRENT_MAJOR=$(echo $CURRENT_TAG | awk '{split($0, a, "."); print a[1]}') 17 | CURRENT_MINOR=$(echo $CURRENT_TAG | awk '{split($0, a, "."); print a[2]}') 18 | CURRENT_PATCH=$(echo $CURRENT_TAG | awk '{split($0, a, "."); print a[3]}') 19 | CURRENT_SHORT_TAG=${CURRENT_MAJOR}.${CURRENT_MINOR} 20 | 21 | #Get . for next version 22 | NEXT_MAJOR=$(echo $NEXT_FULL_TAG | awk '{split($0, a, "."); print a[1]}') 23 | NEXT_MINOR=$(echo $NEXT_FULL_TAG | awk '{split($0, a, "."); print a[2]}') 24 | NEXT_SHORT_TAG=${NEXT_MAJOR}.${NEXT_MINOR} 25 | 26 | echo "Preparing release $CURRENT_TAG => $NEXT_FULL_TAG" 27 | 28 | # Inplace sed replace; workaround for Linux and Mac 29 | function sed_runner() { 30 | sed -i.bak ''"$1"'' $2 && rm -f ${2}.bak 31 | } 32 | 33 | # RTD update 34 | sed_runner 's/version = .*/version = '"'${NEXT_SHORT_TAG}'"'/g' docs/source/conf.py 35 | sed_runner 's/release = .*/release = '"'${NEXT_FULL_TAG}'"'/g' docs/source/conf.py 36 | for FILE in .github/workflows/*.yaml; do 37 | sed_runner "/shared-action-workflows/ s/@.*/@branch-${NEXT_SHORT_TAG}/g" "${FILE}" 38 | done 39 | sed_runner "s/RAPIDS_VERSION_NUMBER=\".*/RAPIDS_VERSION_NUMBER=\"${NEXT_SHORT_TAG}\"/g" ci/build_docs.sh 40 | -------------------------------------------------------------------------------- /ci/test_notebooks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2020-2023, NVIDIA CORPORATION. 3 | 4 | set -euo pipefail 5 | 6 | . /opt/conda/etc/profile.d/conda.sh 7 | 8 | rapids-logger "Generate notebook testing dependencies" 9 | rapids-dependency-file-generator \ 10 | --output conda \ 11 | --file_key test_notebooks \ 12 | --matrix "cuda=${RAPIDS_CUDA_VERSION%.*};arch=$(arch);py=${RAPIDS_PY_VERSION}" | tee env.yaml 13 | 14 | rapids-mamba-retry env create --force -f env.yaml -n test 15 | 16 | # Temporarily allow unbound variables for conda activation. 17 | set +u 18 | conda activate test 19 | set -u 20 | 21 | rapids-print-env 22 | 23 | rapids-logger "Downloading artifacts from previous jobs" 24 | PYTHON_CHANNEL=$(rapids-download-conda-from-s3 python) 25 | 26 | rapids-mamba-retry install \ 27 | --channel "${PYTHON_CHANNEL}" \ 28 | cusignal 29 | 30 | NBTEST="$(realpath "$(dirname "$0")/utils/nbtest.sh")" 31 | pushd notebooks 32 | 33 | # Add notebooks that should be skipped here 34 | # (space-separated list of filenames without paths) 35 | SKIPNBS="sdr_wfm_demod.ipynb io_examples.ipynb rtlsdr_offline_demod_to_transcript.ipynb" 36 | 37 | EXITCODE=0 38 | trap "EXITCODE=1" ERR 39 | set +e 40 | for nb in $(find . -name "*.ipynb"); do 41 | nbBasename=$(basename ${nb}) 42 | # Skip all notebooks that use dask (in the code or even in their name) 43 | if ((echo ${nb} | grep -qi dask) || \ 44 | (grep -q dask ${nb})); then 45 | echo "--------------------------------------------------------------------------------" 46 | echo "SKIPPING: ${nb} (suspected Dask usage, not currently automatable)" 47 | echo "--------------------------------------------------------------------------------" 48 | elif (echo " ${SKIPNBS} " | grep -q " ${nbBasename} "); then 49 | echo "--------------------------------------------------------------------------------" 50 | echo "SKIPPING: ${nb} (listed in skip list)" 51 | echo "--------------------------------------------------------------------------------" 52 | else 53 | # All notebooks are run from the directory in which they are contained. 54 | # This makes operations that assume relative paths easiest to understand 55 | # and maintain, since most users assume relative paths are relative to 56 | # the location of the notebook itself. After a run, the CWD must be 57 | # returned to NOTEBOOKS_DIR, since the find operation returned paths 58 | # relative to that dir. 59 | pushd $(dirname ${nb}) 60 | nvidia-smi 61 | ${NBTEST} ${nbBasename} 62 | popd 63 | fi 64 | done 65 | 66 | rapids-logger "Notebooks test script exiting with value: $EXITCODE" 67 | exit ${EXITCODE} 68 | -------------------------------------------------------------------------------- /ci/test_python.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2022-2023, NVIDIA CORPORATION. 3 | 4 | set -euo pipefail 5 | 6 | . /opt/conda/etc/profile.d/conda.sh 7 | 8 | rapids-logger "Generate Python testing dependencies" 9 | rapids-dependency-file-generator \ 10 | --output conda \ 11 | --file_key test_python \ 12 | --matrix "cuda=${RAPIDS_CUDA_VERSION%.*};arch=$(arch);py=${RAPIDS_PY_VERSION}" | tee env.yaml 13 | 14 | rapids-mamba-retry env create --force -f env.yaml -n test 15 | 16 | # Temporarily allow unbound variables for conda activation. 17 | set +u 18 | conda activate test 19 | set -u 20 | 21 | rapids-logger "Downloading artifacts from previous jobs" 22 | PYTHON_CHANNEL=$(rapids-download-conda-from-s3 python) 23 | 24 | RAPIDS_TESTS_DIR=${RAPIDS_TESTS_DIR:-"${PWD}/test-results"} 25 | RAPIDS_COVERAGE_DIR=${RAPIDS_COVERAGE_DIR:-"${PWD}/coverage-results"} 26 | mkdir -p "${RAPIDS_TESTS_DIR}" "${RAPIDS_COVERAGE_DIR}" 27 | 28 | rapids-print-env 29 | 30 | rapids-mamba-retry install \ 31 | --channel "${PYTHON_CHANNEL}" \ 32 | cusignal 33 | 34 | rapids-logger "Check GPU usage" 35 | nvidia-smi 36 | 37 | EXITCODE=0 38 | trap "EXITCODE=1" ERR 39 | set +e 40 | 41 | rapids-logger "pytest cusignal" 42 | pushd python/cusignal 43 | pytest \ 44 | --cache-clear \ 45 | --junitxml="${RAPIDS_TESTS_DIR}/junit-cusignal.xml" \ 46 | --numprocesses=8 \ 47 | --dist=loadscope \ 48 | --cov-config=../.coveragerc \ 49 | --cov=cusignal \ 50 | --cov-report=xml:"${RAPIDS_COVERAGE_DIR}/cusignal-coverage.xml" \ 51 | --cov-report=term \ 52 | test 53 | popd 54 | 55 | rapids-logger "Test script exiting with value: $EXITCODE" 56 | exit ${EXITCODE} 57 | -------------------------------------------------------------------------------- /ci/utils/nbtest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | MAGIC_OVERRIDE_CODE=" 4 | def my_run_line_magic(*args, **kwargs): 5 | g=globals() 6 | l={} 7 | for a in args: 8 | try: 9 | exec(str(a),g,l) 10 | except Exception as e: 11 | print('WARNING: %s\n While executing this magic function code:\n%s\n continuing...\n' % (e, a)) 12 | else: 13 | g.update(l) 14 | def my_run_cell_magic(*args, **kwargs): 15 | my_run_line_magic(*args, **kwargs) 16 | get_ipython().run_line_magic=my_run_line_magic 17 | get_ipython().run_cell_magic=my_run_cell_magic 18 | " 19 | 20 | NO_COLORS=--colors=NoColor 21 | EXITCODE=0 22 | NBTMPDIR="$WORKSPACE/tmp" 23 | mkdir -p ${NBTMPDIR} 24 | 25 | for nb in $*; do 26 | NBFILENAME=$1 27 | NBNAME=${NBFILENAME%.*} 28 | NBNAME=${NBNAME##*/} 29 | NBTESTSCRIPT=${NBTMPDIR}/${NBNAME}-test.py 30 | shift 31 | 32 | echo -------------------------------------------------------------------------------- 33 | echo STARTING: ${NBNAME} 34 | echo -------------------------------------------------------------------------------- 35 | jupyter nbconvert --to script ${NBFILENAME} --output ${NBTMPDIR}/${NBNAME}-test 36 | echo "${MAGIC_OVERRIDE_CODE}" > ${NBTMPDIR}/tmpfile 37 | cat ${NBTESTSCRIPT} >> ${NBTMPDIR}/tmpfile 38 | mv ${NBTMPDIR}/tmpfile ${NBTESTSCRIPT} 39 | 40 | echo "Running \"ipython ${NO_COLORS} ${NBTESTSCRIPT}\" on $(date)" 41 | echo 42 | time bash -c "ipython ${NO_COLORS} ${NBTESTSCRIPT}; EC=\$?; echo -------------------------------------------------------------------------------- ; echo DONE: ${NBNAME}; exit \$EC" 43 | NBEXITCODE=$? 44 | echo EXIT CODE: ${NBEXITCODE} 45 | echo 46 | EXITCODE=$((EXITCODE | ${NBEXITCODE})) 47 | done 48 | 49 | exit ${EXITCODE} 50 | -------------------------------------------------------------------------------- /ci/utils/nbtestlog2junitxml.py: -------------------------------------------------------------------------------- 1 | # Generate a junit-xml file from parsing a nbtest log 2 | 3 | import re 4 | from xml.etree.ElementTree import Element, ElementTree 5 | from os import path 6 | import string 7 | from enum import Enum 8 | 9 | 10 | startingPatt = re.compile("^STARTING: ([\w\.\-]+)$") 11 | skippingPatt = re.compile("^SKIPPING: ([\w\.\-]+)\s*(\(([\w\.\-\ \,]+)\))?\s*$") 12 | exitCodePatt = re.compile("^EXIT CODE: (\d+)$") 13 | folderPatt = re.compile("^FOLDER: ([\w\.\-]+)$") 14 | timePatt = re.compile("^real\s+([\d\.ms]+)$") 15 | linePatt = re.compile("^" + ("-" * 80) + "$") 16 | 17 | 18 | def getFileBaseName(filePathName): 19 | return path.splitext(path.basename(filePathName))[0] 20 | 21 | 22 | def makeTestCaseElement(attrDict): 23 | return Element("testcase", attrib=attrDict) 24 | 25 | 26 | def makeSystemOutElement(outputLines): 27 | e = Element("system-out") 28 | e.text = "".join(filter(lambda c: c in string.printable, outputLines)) 29 | return e 30 | 31 | 32 | def makeFailureElement(outputLines): 33 | e = Element("failure", message="failed") 34 | e.text = "".join(filter(lambda c: c in string.printable, outputLines)) 35 | return e 36 | 37 | 38 | def setFileNameAttr(attrDict, fileName): 39 | attrDict.update(file=fileName, 40 | classname="", 41 | line="", 42 | name="", 43 | time="" 44 | ) 45 | 46 | def setClassNameAttr(attrDict, className): 47 | attrDict["classname"] = className 48 | 49 | 50 | def setTestNameAttr(attrDict, testName): 51 | attrDict["name"] = testName 52 | 53 | 54 | def setTimeAttr(attrDict, timeVal): 55 | (mins, seconds) = timeVal.split("m") 56 | seconds = float(seconds.strip("s")) + (60 * int(mins)) 57 | attrDict["time"] = str(seconds) 58 | 59 | 60 | def incrNumAttr(element, attr): 61 | newVal = int(element.attrib.get(attr)) + 1 62 | element.attrib[attr] = str(newVal) 63 | 64 | 65 | def parseLog(logFile, testSuiteElement): 66 | # Example attrs: 67 | # errors="0" failures="0" hostname="a437d6835edf" name="pytest" skipped="2" tests="6" time="6.174" timestamp="2019-11-18T19:49:47.946307" 68 | 69 | with open(logFile) as lf: 70 | testSuiteElement.attrib["tests"] = "0" 71 | testSuiteElement.attrib["errors"] = "0" 72 | testSuiteElement.attrib["failures"] = "0" 73 | testSuiteElement.attrib["skipped"] = "0" 74 | testSuiteElement.attrib["time"] = "0" 75 | testSuiteElement.attrib["timestamp"] = "" 76 | 77 | attrDict = {} 78 | #setFileNameAttr(attrDict, logFile) 79 | setFileNameAttr(attrDict, "nbtest") 80 | 81 | parserStateEnum = Enum("parserStateEnum", 82 | "newTest startingLine finishLine exitCode") 83 | parserState = parserStateEnum.newTest 84 | 85 | testOutput = "" 86 | 87 | for line in lf.readlines(): 88 | if parserState == parserStateEnum.newTest: 89 | m = folderPatt.match(line) 90 | if m: 91 | setClassNameAttr(attrDict, m.group(1)) 92 | continue 93 | 94 | m = skippingPatt.match(line) 95 | if m: 96 | setTestNameAttr(attrDict, getFileBaseName(m.group(1))) 97 | setTimeAttr(attrDict, "0m0s") 98 | skippedElement = makeTestCaseElement(attrDict) 99 | message = m.group(3) or "" 100 | skippedElement.append(Element("skipped", message=message, type="")) 101 | testSuiteElement.append(skippedElement) 102 | incrNumAttr(testSuiteElement, "skipped") 103 | incrNumAttr(testSuiteElement, "tests") 104 | continue 105 | 106 | m = startingPatt.match(line) 107 | if m: 108 | parserState = parserStateEnum.startingLine 109 | testOutput = "" 110 | setTestNameAttr(attrDict, m.group(1)) 111 | setTimeAttr(attrDict, "0m0s") 112 | continue 113 | 114 | continue 115 | 116 | elif parserState == parserStateEnum.startingLine: 117 | if linePatt.match(line): 118 | parserState = parserStateEnum.finishLine 119 | testOutput = "" 120 | continue 121 | 122 | elif parserState == parserStateEnum.finishLine: 123 | if linePatt.match(line): 124 | parserState = parserStateEnum.exitCode 125 | else: 126 | testOutput += line 127 | continue 128 | 129 | elif parserState == parserStateEnum.exitCode: 130 | m = exitCodePatt.match(line) 131 | if m: 132 | testCaseElement = makeTestCaseElement(attrDict) 133 | if m.group(1) != "0": 134 | failureElement = makeFailureElement(testOutput) 135 | testCaseElement.append(failureElement) 136 | incrNumAttr(testSuiteElement, "failures") 137 | else: 138 | systemOutElement = makeSystemOutElement(testOutput) 139 | testCaseElement.append(systemOutElement) 140 | 141 | testSuiteElement.append(testCaseElement) 142 | parserState = parserStateEnum.newTest 143 | testOutput = "" 144 | incrNumAttr(testSuiteElement, "tests") 145 | continue 146 | 147 | m = timePatt.match(line) 148 | if m: 149 | setTimeAttr(attrDict, m.group(1)) 150 | continue 151 | 152 | continue 153 | 154 | 155 | if __name__ == "__main__": 156 | import sys 157 | 158 | testSuitesElement = Element("testsuites") 159 | testSuiteElement = Element("testsuite", name="nbtest", hostname="") 160 | parseLog(sys.argv[1], testSuiteElement) 161 | testSuitesElement.append(testSuiteElement) 162 | ElementTree(testSuitesElement).write(sys.argv[1]+".xml", xml_declaration=True) 163 | -------------------------------------------------------------------------------- /conda/environments/all_cuda-118_arch-x86_64.yaml: -------------------------------------------------------------------------------- 1 | # This file is generated by `rapids-dependency-file-generator`. 2 | # To make changes, edit ../../dependencies.yaml and run `rapids-dependency-file-generator`. 3 | channels: 4 | - rapidsai 5 | - rapidsai-nightly 6 | - conda-forge 7 | - nvidia 8 | dependencies: 9 | - cudatoolkit=11.8 10 | - cupy >=12.0.0 11 | - ipython 12 | - matplotlib-base 13 | - notebook 14 | - numba >=0.57.0 15 | - numpy >=1.21 16 | - numpydoc 17 | - pre-commit 18 | - pydata-sphinx-theme 19 | - pytest 20 | - pytest-benchmark 21 | - pytest-cov 22 | - pytest-xdist 23 | - python>=3.9,<3.11 24 | - pytorch <=1.12.1 25 | - scipy >=1.6.0 26 | - sphinx-copybutton 27 | - sphinx<6 28 | name: all_cuda-118_arch-x86_64 29 | -------------------------------------------------------------------------------- /conda/environments/cusignal_airt.yml: -------------------------------------------------------------------------------- 1 | name: cusignal 2 | channels: 3 | - conda-forge 4 | - nvidia 5 | - numba 6 | dependencies: 7 | - python=3.6.9 8 | - scipy>=1.5.0 9 | - numpy 10 | - matplotlib 11 | - numba>=0.49 12 | - pytest 13 | - pytest-benchmark 14 | - sphinx 15 | - pydata-sphinx-theme 16 | - sphinx-copybutton 17 | - numpydoc 18 | - ipython 19 | - pip 20 | - pip: 21 | - cupy>=9.0.0 22 | -------------------------------------------------------------------------------- /conda/environments/cusignal_base.yml: -------------------------------------------------------------------------------- 1 | name: cusignal-dev 2 | channels: 3 | - conda-forge 4 | - nvidia 5 | - numba 6 | dependencies: 7 | - scipy>=1.5.0 8 | - numpy 9 | - cudatoolkit>=11.0,<=11.2 10 | - matplotlib 11 | - numba>=0.49 12 | - pytest 13 | - pytest-benchmark 14 | - cupy>=9.0.0 15 | - sphinx 16 | - pydata-sphinx-theme 17 | - sphinx-copybutton 18 | - numpydoc 19 | - ipython 20 | -------------------------------------------------------------------------------- /conda/environments/cusignal_full.yml: -------------------------------------------------------------------------------- 1 | name: cusignal-dev 2 | channels: 3 | - conda-forge 4 | - nvidia 5 | - rapidsai 6 | - pytorch 7 | - numba 8 | dependencies: 9 | - scipy>=1.5.0 10 | - numpy 11 | - cudatoolkit>=9.2,<=11.2 12 | - matplotlib 13 | - numba>=0.49 14 | - pytest 15 | - pytest-benchmark 16 | - cupy>=9.0.0 17 | - pytorch 18 | - cudf 19 | - cuml 20 | - cugraph 21 | - pandas 22 | - sphinx 23 | - pydata-sphinx-theme 24 | - sphinx-copybutton 25 | - numpydoc 26 | - ipython 27 | -------------------------------------------------------------------------------- /conda/environments/cusignal_jetson_base.yml: -------------------------------------------------------------------------------- 1 | name: cusignal-dev 2 | channels: 3 | - conda-forge 4 | - nvidia 5 | - numba 6 | - c4aarch64 7 | dependencies: 8 | - scipy>=1.5.0 9 | - numpy 10 | - matplotlib 11 | - numba>=0.49 12 | - pytest 13 | - pytest-benchmark 14 | - sphinx 15 | - pydata-sphinx-theme 16 | - sphinx-copybutton 17 | - numpydoc 18 | - ipython 19 | - pip 20 | - pip: 21 | - cupy>=9.0.0 22 | -------------------------------------------------------------------------------- /conda/recipes/cusignal/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./build.sh cusignal -c --allgpuarch 4 | -------------------------------------------------------------------------------- /conda/recipes/cusignal/conda_build_config.yaml: -------------------------------------------------------------------------------- 1 | c_compiler_version: 2 | - 11 3 | 4 | cxx_compiler_version: 5 | - 11 6 | 7 | cuda_compiler: 8 | - nvcc 9 | 10 | sysroot_version: 11 | - "2.17" 12 | -------------------------------------------------------------------------------- /conda/recipes/cusignal/meta.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, NVIDIA CORPORATION. 2 | 3 | {% set version = environ.get('GIT_DESCRIBE_TAG', '0.0.0.dev').lstrip('v') %} 4 | {% set minor_version = version.split('.')[0] + '.' + version.split('.')[1] %} 5 | {% set py_version = environ['CONDA_PY'] %} 6 | {% set cuda_version = '.'.join(environ['RAPIDS_CUDA_VERSION'].split('.')[:2]) %} 7 | {% set date_string = environ['RAPIDS_DATE_STRING'] %} 8 | 9 | package: 10 | name: cusignal 11 | version: {{ version }} 12 | 13 | source: 14 | git_url: ../../.. 15 | 16 | build: 17 | number: {{ GIT_DESCRIBE_NUMBER }} 18 | string: py{{ py_version }}_{{ date_string }}_{{ GIT_DESCRIBE_HASH }}_{{ GIT_DESCRIBE_NUMBER }} 19 | noarch: python 20 | 21 | requirements: 22 | build: 23 | - {{ compiler('c') }} 24 | - {{ compiler('cxx') }} 25 | - {{ compiler('cuda') }} {{ cuda_version }} 26 | host: 27 | - python 28 | - setuptools 29 | run: 30 | - cupy >=12.0.0 31 | - numba >=0.57.0 32 | - numpy >=1.21 33 | - python 34 | - scipy >=1.6.0 35 | 36 | test: 37 | requires: 38 | - cudatoolkit ={{ cuda_version }} 39 | imports: 40 | - cusignal 41 | 42 | about: 43 | home: https://rapids.ai/ 44 | license: MIT 45 | license_family: MIT 46 | license_file: ../../../LICENSE 47 | summary: cuSignal core library 48 | dev_url: https://github.com/rapidsai/cusignal 49 | -------------------------------------------------------------------------------- /cpp/.clang_format: -------------------------------------------------------------------------------- 1 | --- 2 | # Refer to the following link for the explanation of each params: 3 | # http://releases.llvm.org/8.0.0/tools/clang/docs/ClangFormatStyleOptions.html 4 | Language: Cpp 5 | # BasedOnStyle: Google 6 | AccessModifierOffset: -1 7 | AlignAfterOpenBracket: Align 8 | AlignConsecutiveAssignments: true 9 | AlignConsecutiveDeclarations: false 10 | AlignEscapedNewlines: Left 11 | AlignOperands: true 12 | AlignTrailingComments: true 13 | AllowAllParametersOfDeclarationOnNextLine: true 14 | AllowShortBlocksOnASingleLine: true 15 | AllowShortCaseLabelsOnASingleLine: true 16 | AllowShortFunctionsOnASingleLine: All 17 | AllowShortIfStatementsOnASingleLine: true 18 | AllowShortLoopsOnASingleLine: true 19 | # This is deprecated 20 | AlwaysBreakAfterDefinitionReturnType: None 21 | AlwaysBreakAfterReturnType: None 22 | AlwaysBreakBeforeMultilineStrings: true 23 | AlwaysBreakTemplateDeclarations: Yes 24 | BinPackArguments: false 25 | BinPackParameters: false 26 | BraceWrapping: 27 | AfterClass: false 28 | AfterControlStatement: false 29 | AfterEnum: false 30 | AfterFunction: false 31 | AfterNamespace: false 32 | AfterObjCDeclaration: false 33 | AfterStruct: false 34 | AfterUnion: false 35 | AfterExternBlock: false 36 | BeforeCatch: false 37 | BeforeElse: false 38 | IndentBraces: false 39 | # disabling the below splits, else, they'll just add to the vertical length of source files! 40 | SplitEmptyFunction: false 41 | SplitEmptyRecord: false 42 | SplitEmptyNamespace: false 43 | BreakBeforeBinaryOperators: None 44 | BreakBeforeBraces: WebKit 45 | BreakBeforeInheritanceComma: false 46 | BreakInheritanceList: BeforeColon 47 | BreakBeforeTernaryOperators: true 48 | BreakConstructorInitializersBeforeComma: false 49 | BreakConstructorInitializers: BeforeColon 50 | BreakAfterJavaFieldAnnotations: false 51 | BreakStringLiterals: true 52 | ColumnLimit: 100 53 | CommentPragmas: '^ IWYU pragma:' 54 | CompactNamespaces: false 55 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 56 | # Kept the below 2 to be the same as `IndentWidth` to keep everything uniform 57 | ConstructorInitializerIndentWidth: 2 58 | ContinuationIndentWidth: 2 59 | Cpp11BracedListStyle: true 60 | DerivePointerAlignment: true 61 | DisableFormat: false 62 | ExperimentalAutoDetectBinPacking: false 63 | FixNamespaceComments: true 64 | ForEachMacros: 65 | - foreach 66 | - Q_FOREACH 67 | - BOOST_FOREACH 68 | IncludeBlocks: Preserve 69 | IncludeCategories: 70 | - Regex: '^' 71 | Priority: 2 72 | - Regex: '^<.*\.h>' 73 | Priority: 1 74 | - Regex: '^<.*' 75 | Priority: 2 76 | - Regex: '.*' 77 | Priority: 3 78 | IncludeIsMainRegex: '([-_](test|unittest))?$' 79 | IndentCaseLabels: true 80 | IndentPPDirectives: None 81 | IndentWidth: 2 82 | IndentWrappedFunctionNames: false 83 | JavaScriptQuotes: Leave 84 | JavaScriptWrapImports: true 85 | KeepEmptyLinesAtTheStartOfBlocks: false 86 | MacroBlockBegin: '' 87 | MacroBlockEnd: '' 88 | MaxEmptyLinesToKeep: 1 89 | NamespaceIndentation: None 90 | ObjCBinPackProtocolList: Never 91 | ObjCBlockIndentWidth: 2 92 | ObjCSpaceAfterProperty: false 93 | ObjCSpaceBeforeProtocolList: true 94 | PenaltyBreakAssignment: 2 95 | PenaltyBreakBeforeFirstCallParameter: 1 96 | PenaltyBreakComment: 300 97 | PenaltyBreakFirstLessLess: 120 98 | PenaltyBreakString: 1000 99 | PenaltyBreakTemplateDeclaration: 10 100 | PenaltyExcessCharacter: 1000000 101 | PenaltyReturnTypeOnItsOwnLine: 200 102 | PointerAlignment: Left 103 | RawStringFormats: 104 | - Language: Cpp 105 | Delimiters: 106 | - cc 107 | - CC 108 | - cpp 109 | - Cpp 110 | - CPP 111 | - 'c++' 112 | - 'C++' 113 | CanonicalDelimiter: '' 114 | - Language: TextProto 115 | Delimiters: 116 | - pb 117 | - PB 118 | - proto 119 | - PROTO 120 | EnclosingFunctions: 121 | - EqualsProto 122 | - EquivToProto 123 | - PARSE_PARTIAL_TEXT_PROTO 124 | - PARSE_TEST_PROTO 125 | - PARSE_TEXT_PROTO 126 | - ParseTextOrDie 127 | - ParseTextProtoOrDie 128 | CanonicalDelimiter: '' 129 | BasedOnStyle: google 130 | # Enabling comment reflow causes doxygen comments to be messed up in their formats! 131 | ReflowComments: true 132 | SortIncludes: true 133 | SortUsingDeclarations: true 134 | SpaceAfterCStyleCast: false 135 | SpaceAfterTemplateKeyword: true 136 | SpaceBeforeAssignmentOperators: true 137 | SpaceBeforeCpp11BracedList: false 138 | SpaceBeforeCtorInitializerColon: true 139 | SpaceBeforeInheritanceColon: true 140 | SpaceBeforeParens: ControlStatements 141 | SpaceBeforeRangeBasedForLoopColon: true 142 | SpaceInEmptyParentheses: false 143 | SpacesBeforeTrailingComments: 2 144 | SpacesInAngles: false 145 | SpacesInContainerLiterals: true 146 | SpacesInCStyleCastParentheses: false 147 | SpacesInParentheses: false 148 | SpacesInSquareBrackets: false 149 | Standard: Cpp11 150 | StatementMacros: 151 | - Q_UNUSED 152 | - QT_REQUIRE_VERSION 153 | # Be consistent with indent-width, even for people who use tab for indentation! 154 | TabWidth: 2 155 | UseTab: Never 156 | -------------------------------------------------------------------------------- /cpp/src/io/_writer.cu: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | /////////////////////////////////////////////////////////////////////////////// 26 | // WRITER // 27 | /////////////////////////////////////////////////////////////////////////////// 28 | 29 | template 30 | __device__ void _cupy_pack( const size_t N, T *__restrict__ input, unsigned char *__restrict__ output ) { 31 | 32 | const int tx { static_cast( blockIdx.x * blockDim.x + threadIdx.x ) }; 33 | const int stride { static_cast( blockDim.x * gridDim.x ) }; 34 | 35 | for ( int tid = tx; tid < N; tid += stride ) { 36 | output[tid] = reinterpret_cast( input )[tid]; 37 | } 38 | } 39 | 40 | extern "C" __global__ void __launch_bounds__( 512 ) 41 | _cupy_pack_int8( const size_t N, char *__restrict__ input, unsigned char *__restrict__ output ) { 42 | _cupy_pack( N, input, output ); 43 | } 44 | 45 | extern "C" __global__ void __launch_bounds__( 512 ) 46 | _cupy_pack_uint8( const size_t N, unsigned char *__restrict__ input, unsigned char *__restrict__ output ) { 47 | _cupy_pack( N, input, output ); 48 | } 49 | 50 | extern "C" __global__ void __launch_bounds__( 512 ) 51 | _cupy_pack_int16( const size_t N, short *__restrict__ input, unsigned char *__restrict__ output ) { 52 | _cupy_pack( N, input, output ); 53 | } 54 | 55 | extern "C" __global__ void __launch_bounds__( 512 ) 56 | _cupy_pack_uint16( const size_t N, unsigned short *__restrict__ input, unsigned char *__restrict__ output ) { 57 | _cupy_pack( N, input, output ); 58 | } 59 | 60 | extern "C" __global__ void __launch_bounds__( 512 ) 61 | _cupy_pack_int32( const size_t N, int *__restrict__ input, unsigned char *__restrict__ output ) { 62 | _cupy_pack( N, input, output ); 63 | } 64 | 65 | extern "C" __global__ void __launch_bounds__( 512 ) 66 | _cupy_pack_uint32( const size_t N, unsigned int *__restrict__ input, unsigned char *__restrict__ output ) { 67 | _cupy_pack( N, input, output ); 68 | } 69 | 70 | extern "C" __global__ void __launch_bounds__( 512 ) 71 | _cupy_pack_float32( const size_t N, float *__restrict__ input, unsigned char *__restrict__ output ) { 72 | _cupy_pack( N, input, output ); 73 | } 74 | 75 | extern "C" __global__ void __launch_bounds__( 512 ) 76 | _cupy_pack_float64( const size_t N, double *__restrict__ input, unsigned char *__restrict__ output ) { 77 | _cupy_pack( N, input, output ); 78 | } 79 | 80 | extern "C" __global__ void __launch_bounds__( 512 ) _cupy_pack_complex64( const size_t N, 81 | thrust::complex *__restrict__ input, 82 | unsigned char *__restrict__ output ) { 83 | _cupy_pack>( N, input, output ); 84 | } 85 | 86 | extern "C" __global__ void __launch_bounds__( 512 ) _cupy_pack_complex128( const size_t N, 87 | thrust::complex *__restrict__ input, 88 | unsigned char *__restrict__ output ) { 89 | _cupy_pack>( N, input, output ); 90 | } 91 | -------------------------------------------------------------------------------- /dependencies.yaml: -------------------------------------------------------------------------------- 1 | # Dependency list for https://github.com/rapidsai/dependency-file-generator 2 | files: 3 | all: 4 | output: conda 5 | matrix: 6 | cuda: ["11.8"] 7 | arch: [x86_64] 8 | includes: 9 | - checks 10 | - cudatoolkit 11 | - docs 12 | - py_version 13 | - run 14 | - test_notebooks 15 | - test_python 16 | test_notebooks: 17 | output: none 18 | includes: 19 | - cudatoolkit 20 | - py_version 21 | - test_notebooks 22 | test_python: 23 | output: none 24 | includes: 25 | - cudatoolkit 26 | - py_version 27 | - test_python 28 | checks: 29 | output: none 30 | includes: 31 | - checks 32 | - py_version 33 | docs: 34 | output: none 35 | includes: 36 | - cudatoolkit 37 | - docs 38 | - py_version 39 | channels: 40 | - rapidsai 41 | - rapidsai-nightly 42 | - conda-forge 43 | - nvidia 44 | dependencies: 45 | cudatoolkit: 46 | specific: 47 | - output_types: conda 48 | matrices: 49 | - matrix: 50 | cuda: "11.2" 51 | packages: 52 | - cudatoolkit=11.2 53 | - matrix: 54 | cuda: "11.4" 55 | packages: 56 | - cudatoolkit=11.4 57 | - matrix: 58 | cuda: "11.5" 59 | packages: 60 | - cudatoolkit=11.5 61 | - matrix: 62 | cuda: "11.8" 63 | packages: 64 | - cudatoolkit=11.8 65 | checks: 66 | common: 67 | - output_types: [conda, requirements] 68 | packages: 69 | - pre-commit 70 | docs: 71 | common: 72 | - output_types: [conda, requirements] 73 | packages: 74 | - ipython 75 | - numpydoc 76 | - pydata-sphinx-theme 77 | - sphinx<6 78 | - sphinx-copybutton 79 | py_version: 80 | specific: 81 | - output_types: conda 82 | matrices: 83 | - matrix: 84 | py: "3.9" 85 | packages: 86 | - python=3.9 87 | - matrix: 88 | py: "3.10" 89 | packages: 90 | - python=3.10 91 | - matrix: 92 | packages: 93 | - python>=3.9,<3.11 94 | run: 95 | common: 96 | - output_types: [conda, requirements] 97 | packages: 98 | - cupy >=12.0.0 99 | - numba >=0.57.0 100 | - numpy >=1.21 101 | - scipy >=1.6.0 102 | test_notebooks: 103 | common: 104 | - output_types: [conda, requirements] 105 | packages: 106 | - ipython 107 | - matplotlib-base 108 | - notebook 109 | specific: 110 | - output_types: conda 111 | matrices: 112 | - matrix: 113 | arch: x86_64 114 | packages: 115 | - pytorch <=1.12.1 116 | - matrix: 117 | packages: 118 | test_python: 119 | common: 120 | - output_types: [conda, requirements] 121 | packages: 122 | - pytest 123 | - pytest-benchmark 124 | - pytest-cov 125 | - pytest-xdist 126 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nvidia/cuda:11.2.2-devel-ubuntu20.04 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y --no-install-recommends \ 5 | python3-dev \ 6 | python3-pip \ 7 | python3-wheel \ 8 | python3-setuptools \ 9 | git && \ 10 | rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* 11 | 12 | RUN pip3 install --no-cache-dir -U install setuptools pip 13 | RUN pip3 install --no-cache-dir "cupy-cuda112==8.6.0" \ 14 | numba numpy scipy 15 | 16 | RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 10 17 | 18 | RUN git clone https://github.com/rapidsai/cusignal.git && \ 19 | cd cusignal && \ 20 | ./build.sh 21 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = cuSignal 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Building Documentation 2 | 3 | A basic python environment with packages listed in `./requirement.txt` is 4 | enough to build the docs. 5 | 6 | ## Get additional dependency 7 | 8 | ```bash 9 | pip install -r requirement.txt 10 | ``` 11 | 12 | ## Run makefile: 13 | 14 | ```bash 15 | make html 16 | ``` 17 | 18 | Outputs to `build/html/index.html` 19 | 20 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | set SPHINXPROJ=cuSignal 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs/requirement.txt: -------------------------------------------------------------------------------- 1 | sphinx 2 | pydata-sphinx-theme 3 | sphinx-copybutton 4 | numpydoc 5 | ipython 6 | -------------------------------------------------------------------------------- /docs/source/_static/EMPTY: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rapidsai/cusignal/136453a3c8ef381f502a1edd51ca741f6c159f4a/docs/source/_static/EMPTY -------------------------------------------------------------------------------- /docs/source/_static/RAPIDS-logo-purple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rapidsai/cusignal/136453a3c8ef381f502a1edd51ca741f6c159f4a/docs/source/_static/RAPIDS-logo-purple.png -------------------------------------------------------------------------------- /docs/source/api.rst: -------------------------------------------------------------------------------- 1 | ~~~~~~~~~~~~~~~~~~~~~~ 2 | cuSignal API Reference 3 | ~~~~~~~~~~~~~~~~~~~~~~ 4 | 5 | 6 | Convolution 7 | =========== 8 | 9 | Convolve 10 | -------- 11 | 12 | .. automodule:: cusignal.convolution.convolve 13 | :members: 14 | :undoc-members: 15 | 16 | Correlate 17 | --------- 18 | .. automodule:: cusignal.convolution.correlate 19 | :members: 20 | :undoc-members: 21 | 22 | 23 | Modulation/Demodulation 24 | ======================= 25 | 26 | Demodulation 27 | ------------ 28 | 29 | .. automodule:: cusignal.demod.demod 30 | :members: 31 | :undoc-members: 32 | 33 | Estimation 34 | ========== 35 | 36 | Kalman Filter 37 | ------------- 38 | 39 | .. automodule:: cusignal.estimation.filters 40 | :members: 41 | :undoc-members: 42 | 43 | 44 | Filtering 45 | ========= 46 | 47 | Resample 48 | -------- 49 | 50 | .. automodule:: cusignal.filtering.resample 51 | :members: 52 | :undoc-members: 53 | 54 | FIR Filters 55 | ----------- 56 | 57 | .. automodule:: cusignal.filtering.filtering.firfilter 58 | :members: 59 | :undoc-members: 60 | 61 | .. automodule:: cusignal.filter_design.fir_filter_design 62 | :members: 63 | :undoc-members: 64 | 65 | Channelizer 66 | ----------- 67 | 68 | .. automodule:: cusignal.filtering.channelize_poly 69 | :members: 70 | :undoc-members: 71 | 72 | Filter Design 73 | ============= 74 | 75 | Resample 76 | -------- 77 | 78 | .. automodule:: cusignal.filter_design.fir_filter_design 79 | :members: 80 | :undoc-members: 81 | 82 | 83 | Peak Finding 84 | ============ 85 | 86 | Peak Finding 87 | ------------ 88 | 89 | .. automodule:: cusignal.peak_finding.peak_finding 90 | :members: 91 | :undoc-members: 92 | 93 | 94 | Window Functions 95 | ================ 96 | 97 | Windows 98 | ------- 99 | 100 | .. automodule:: cusignal.windows.windows 101 | :members: 102 | :undoc-members: 103 | 104 | 105 | Waveforms 106 | ========= 107 | 108 | Waveform Generation 109 | ------------------- 110 | 111 | .. automodule:: cusignal.waveforms.waveforms 112 | :members: 113 | :undoc-members: 114 | 115 | 116 | Spectrum Analysis 117 | ================= 118 | 119 | Spectral 120 | -------- 121 | 122 | .. automodule:: cusignal.spectral_analysis.spectral 123 | :members: 124 | :undoc-members: 125 | 126 | Acoustics 127 | --------- 128 | 129 | .. automodule:: cusignal.acoustics.cepstrum 130 | :members: 131 | :undoc-members: 132 | 133 | 134 | Wavelets 135 | ======== 136 | 137 | Wavelets 138 | -------- 139 | 140 | .. automodule:: cusignal.wavelets.wavelets 141 | :members: 142 | :undoc-members: 143 | 144 | 145 | B-splines 146 | ========= 147 | 148 | B-splines 149 | --------- 150 | 151 | .. automodule:: cusignal.bsplines.bsplines 152 | :members: 153 | :undoc-members: 154 | 155 | 156 | Utilities 157 | ========= 158 | 159 | Array Tools 160 | ----------- 161 | 162 | .. automodule:: cusignal.utils.arraytools 163 | :members: 164 | :undoc-members: 165 | 166 | FFTPack Helper 167 | -------------- 168 | 169 | .. automodule:: cusignal.utils.fftpack_helper 170 | :members: 171 | :undoc-members: 172 | 173 | 174 | IO 175 | == 176 | 177 | Reader 178 | ------ 179 | 180 | .. automodule:: cusignal.io.reader 181 | :members: 182 | :undoc-members: 183 | 184 | Writer 185 | ------ 186 | 187 | .. automodule:: cusignal.io.writer 188 | :members: 189 | :undoc-members: 190 | 191 | 192 | Radar/Phased Array 193 | ================== 194 | 195 | Radar Tools 196 | ----------- 197 | 198 | .. automodule:: cusignal.radartools.radartools 199 | :members: 200 | :undoc-members: 201 | 202 | .. automodule:: cusignal.radartools.beamformers 203 | :members: 204 | :undoc-members: -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2022, NVIDIA CORPORATION. 2 | # -- General configuration ------------------------------------------------ 3 | 4 | # If your documentation needs a minimal Sphinx version, state it here. 5 | # 6 | # needs_sphinx = '1.0' 7 | 8 | # Add any Sphinx extension module names here, as strings. They can be 9 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 10 | # ones. 11 | extensions = [ 12 | 'sphinx.ext.intersphinx', 13 | 'sphinx.ext.autodoc', 14 | 'sphinx.ext.autosummary', 15 | 'sphinx_copybutton', 16 | 'numpydoc', 17 | 'IPython.sphinxext.ipython_console_highlighting', 18 | 'IPython.sphinxext.ipython_directive', 19 | ] 20 | 21 | copybutton_prompt_text = ">>> " 22 | autosummary_generate = True 23 | ipython_mplbackend = 'str' 24 | 25 | # Add any paths that contain templates here, relative to this directory. 26 | templates_path = ['_templates'] 27 | 28 | # The suffix(es) of source filenames. 29 | # You can specify multiple suffix as a list of string: 30 | # 31 | # source_suffix = ['.rst', '.md'] 32 | source_suffix = '.rst' 33 | 34 | # The master toctree document. 35 | master_doc = 'index' 36 | 37 | # General information about the project. 38 | project = 'cusignal' 39 | copyright = '2019-2023, NVIDIA Corporation' 40 | author = 'NVIDIA Corporation' 41 | 42 | # The version info for the project you're documenting, acts as replacement for 43 | # |version| and |release|, also used in various other places throughout the 44 | # built documents. 45 | # 46 | # The short X.Y version. 47 | version = '23.10' 48 | # The full version, including alpha/beta/rc tags. 49 | release = '23.10.00' 50 | 51 | # The language for content autogenerated by Sphinx. Refer to documentation 52 | # for a list of supported languages. 53 | # 54 | # This is also used if you do content translation via gettext catalogs. 55 | # Usually you set "language" from the command line for these cases. 56 | language = 'en' 57 | 58 | # List of patterns, relative to source directory, that match files and 59 | # directories to ignore when looking for source files. 60 | # This patterns also effect to html_static_path and html_extra_path 61 | exclude_patterns = [] 62 | 63 | # The name of the Pygments (syntax highlighting) style to use. 64 | pygments_style = 'sphinx' 65 | 66 | # If true, `todo` and `todoList` produce output, else they produce nothing. 67 | todo_include_todos = False 68 | 69 | 70 | # -- Options for HTML output ---------------------------------------------- 71 | 72 | # The theme to use for HTML and HTML Help pages. See the documentation for 73 | # a list of builtin themes. 74 | # 75 | 76 | html_theme = 'pydata_sphinx_theme' 77 | html_logo = "_static/RAPIDS-logo-purple.png" 78 | 79 | 80 | # Theme options are theme-specific and customize the look and feel of a theme 81 | # further. For a list of options available for each theme, see the 82 | # documentation. 83 | # 84 | html_theme_options = { 85 | "external_links": [], 86 | # https://github.com/pydata/pydata-sphinx-theme/issues/1220 87 | "icon_links": [], 88 | "github_url": "https://github.com/rapidsai/cusignal", 89 | "twitter_url": "https://twitter.com/rapidsai", 90 | "show_toc_level": 1, 91 | "navbar_align": "right", 92 | } 93 | 94 | # Add any paths that contain custom static files (such as style sheets) here, 95 | # relative to this directory. They are copied after the builtin static files, 96 | # so a file named "default.css" will overwrite the builtin "default.css". 97 | html_static_path = ['_static'] 98 | 99 | 100 | # -- Options for HTMLHelp output ------------------------------------------ 101 | 102 | # Output file base name for HTML help builder. 103 | htmlhelp_basename = 'cusignaldoc' 104 | 105 | 106 | # -- Options for LaTeX output --------------------------------------------- 107 | 108 | latex_elements = { 109 | # The paper size ('letterpaper' or 'a4paper'). 110 | # 111 | # 'papersize': 'letterpaper', 112 | 113 | # The font size ('10pt', '11pt' or '12pt'). 114 | # 115 | # 'pointsize': '10pt', 116 | 117 | # Additional stuff for the LaTeX preamble. 118 | # 119 | # 'preamble': '', 120 | 121 | # Latex figure (float) alignment 122 | # 123 | # 'figure_align': 'htbp', 124 | } 125 | 126 | # Grouping the document tree into LaTeX files. List of tuples 127 | # (source start file, target name, title, 128 | # author, documentclass [howto, manual, or own class]). 129 | latex_documents = [ 130 | (master_doc, 'cusignal.tex', 'cusignal Documentation', 131 | 'NVIDIA Corporation', 'manual'), 132 | ] 133 | 134 | 135 | # -- Options for manual page output --------------------------------------- 136 | 137 | # One entry per manual page. List of tuples 138 | # (source start file, name, description, authors, manual section). 139 | man_pages = [ 140 | (master_doc, 'cusignal', 'cusignal Documentation', 141 | [author], 1) 142 | ] 143 | 144 | 145 | # -- Options for Texinfo output ------------------------------------------- 146 | 147 | # Grouping the document tree into Texinfo files. List of tuples 148 | # (source start file, target name, title, author, 149 | # dir menu entry, description, category) 150 | texinfo_documents = [ 151 | (master_doc, 'cusignal', 'cusignal Documentation', 152 | author, 'cusignal', 'One line description of project.', 153 | 'Miscellaneous'), 154 | ] 155 | 156 | 157 | # Example configuration for intersphinx: refer to the Python standard library. 158 | intersphinx_mapping = {'https://docs.python.org/': None} 159 | 160 | 161 | # Config numpydoc 162 | numpydoc_show_inherited_class_members = True 163 | numpydoc_class_members_toctree = False 164 | numpydoc_attributes_as_param_list = False 165 | 166 | 167 | def setup(app): 168 | app.add_css_file("https://docs.rapids.ai/assets/css/custom.css") 169 | app.add_js_file("https://docs.rapids.ai/assets/js/custom.js", loading_method="defer") 170 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to cusignal's documentation! 2 | ==================================== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | :caption: Contents: 7 | 8 | api.rst 9 | 10 | Indices and tables 11 | ================== 12 | 13 | * :ref:`genindex` 14 | * :ref:`modindex` 15 | * :ref:`search` 16 | -------------------------------------------------------------------------------- /notebooks/api_guide/bspline_examples.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import cupy as cp\n", 10 | "import cusignal \n", 11 | "from scipy import signal\n", 12 | "import numpy as np" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "### Gaussian Approximation to B-Spline of order N" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 2, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "cx = np.random.rand(int(1e8))\n", 29 | "gx = cp.random.rand(int(1e8))\n", 30 | "N = 1000" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 3, 36 | "metadata": {}, 37 | "outputs": [ 38 | { 39 | "name": "stdout", 40 | "output_type": "stream", 41 | "text": [ 42 | "CPU times: user 1.89 s, sys: 638 ms, total: 2.52 s\n", 43 | "Wall time: 2.52 s\n" 44 | ] 45 | } 46 | ], 47 | "source": [ 48 | "%%timeit\n", 49 | "cspline = signal.gauss_spline(cx, N)" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 4, 55 | "metadata": {}, 56 | "outputs": [ 57 | { 58 | "name": "stdout", 59 | "output_type": "stream", 60 | "text": [ 61 | "CPU times: user 17.4 ms, sys: 5.72 ms, total: 23.1 ms\n", 62 | "Wall time: 21.5 ms\n" 63 | ] 64 | } 65 | ], 66 | "source": [ 67 | "%%timeit\n", 68 | "gspline = cusignal.gauss_spline(gx, N)" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "metadata": {}, 74 | "source": [ 75 | "### Cubic B-Spline" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": 5, 81 | "metadata": {}, 82 | "outputs": [ 83 | { 84 | "name": "stdout", 85 | "output_type": "stream", 86 | "text": [ 87 | "CPU times: user 1.76 s, sys: 2.08 s, total: 3.84 s\n", 88 | "Wall time: 3.84 s\n" 89 | ] 90 | } 91 | ], 92 | "source": [ 93 | "%%timeit\n", 94 | "ccspline = signal.cubic(cx)" 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": 6, 100 | "metadata": {}, 101 | "outputs": [ 102 | { 103 | "name": "stdout", 104 | "output_type": "stream", 105 | "text": [ 106 | "CPU times: user 850 ms, sys: 89.2 ms, total: 939 ms\n", 107 | "Wall time: 940 ms\n" 108 | ] 109 | } 110 | ], 111 | "source": [ 112 | "%%timeit\n", 113 | "gcspline = cusignal.cubic(gx)" 114 | ] 115 | }, 116 | { 117 | "cell_type": "markdown", 118 | "metadata": {}, 119 | "source": [ 120 | "### Quadratic B-Spline" 121 | ] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "execution_count": 7, 126 | "metadata": {}, 127 | "outputs": [ 128 | { 129 | "name": "stdout", 130 | "output_type": "stream", 131 | "text": [ 132 | "CPU times: user 3.25 s, sys: 2.1 s, total: 5.36 s\n", 133 | "Wall time: 5.35 s\n" 134 | ] 135 | } 136 | ], 137 | "source": [ 138 | "%%timeit\n", 139 | "cqspline = signal.quadratic(cx)" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": 8, 145 | "metadata": {}, 146 | "outputs": [ 147 | { 148 | "name": "stdout", 149 | "output_type": "stream", 150 | "text": [ 151 | "CPU times: user 146 ms, sys: 77 ms, total: 223 ms\n", 152 | "Wall time: 221 ms\n" 153 | ] 154 | } 155 | ], 156 | "source": [ 157 | "%%timeit\n", 158 | "gqspline = cusignal.quadratic(gx)" 159 | ] 160 | } 161 | ], 162 | "metadata": { 163 | "kernelspec": { 164 | "display_name": "Python 3", 165 | "language": "python", 166 | "name": "python3" 167 | }, 168 | "language_info": { 169 | "codemirror_mode": { 170 | "name": "ipython", 171 | "version": 3 172 | }, 173 | "file_extension": ".py", 174 | "mimetype": "text/x-python", 175 | "name": "python", 176 | "nbconvert_exporter": "python", 177 | "pygments_lexer": "ipython3", 178 | "version": "3.8.1" 179 | } 180 | }, 181 | "nbformat": 4, 182 | "nbformat_minor": 4 183 | } 184 | -------------------------------------------------------------------------------- /notebooks/api_guide/filter_design_examples.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import cupy as cp\n", 10 | "import cusignal \n", 11 | "from scipy import signal\n", 12 | "import numpy as np" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "### FIR Filter Design with Window" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 2, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "numtaps = int(1e8)\n", 29 | "f1, f2 = 0.1, 0.2" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 3, 35 | "metadata": {}, 36 | "outputs": [ 37 | { 38 | "name": "stdout", 39 | "output_type": "stream", 40 | "text": [ 41 | "13.6 s ± 204 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" 42 | ] 43 | } 44 | ], 45 | "source": [ 46 | "%%timeit\n", 47 | "cfirwin = signal.firwin(numtaps, [f1, f2], pass_zero=False)" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 4, 53 | "metadata": {}, 54 | "outputs": [ 55 | { 56 | "name": "stdout", 57 | "output_type": "stream", 58 | "text": [ 59 | "136 ms ± 33.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" 60 | ] 61 | } 62 | ], 63 | "source": [ 64 | "%%timeit\n", 65 | "gfirwin = cusignal.firwin(numtaps, [f1, f2], pass_zero=False)" 66 | ] 67 | } 68 | ], 69 | "metadata": { 70 | "kernelspec": { 71 | "display_name": "Python 3", 72 | "language": "python", 73 | "name": "python3" 74 | }, 75 | "language_info": { 76 | "codemirror_mode": { 77 | "name": "ipython", 78 | "version": 3 79 | }, 80 | "file_extension": ".py", 81 | "mimetype": "text/x-python", 82 | "name": "python", 83 | "nbconvert_exporter": "python", 84 | "pygments_lexer": "ipython3", 85 | "version": "3.8.2" 86 | } 87 | }, 88 | "nbformat": 4, 89 | "nbformat_minor": 4 90 | } 91 | -------------------------------------------------------------------------------- /notebooks/api_guide/peak_finding_examples.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import cupy as cp\n", 10 | "import cusignal \n", 11 | "from scipy import signal\n", 12 | "import numpy as np" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": 2, 18 | "metadata": {}, 19 | "outputs": [], 20 | "source": [ 21 | "csig = np.random.rand(int(1e8))\n", 22 | "gsig = cp.random.rand(int(1e8))" 23 | ] 24 | }, 25 | { 26 | "cell_type": "markdown", 27 | "metadata": {}, 28 | "source": [ 29 | "### Relative Minimum of Data - cuSignal does not support mode" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 3, 35 | "metadata": {}, 36 | "outputs": [ 37 | { 38 | "name": "stdout", 39 | "output_type": "stream", 40 | "text": [ 41 | "CPU times: user 1.67 s, sys: 1.97 s, total: 3.64 s\n", 42 | "Wall time: 3.64 s\n" 43 | ] 44 | } 45 | ], 46 | "source": [ 47 | "%%timeit\n", 48 | "cmin = signal.argrelmin(csig)" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 4, 54 | "metadata": {}, 55 | "outputs": [ 56 | { 57 | "name": "stdout", 58 | "output_type": "stream", 59 | "text": [ 60 | "CPU times: user 698 ms, sys: 48.7 ms, total: 747 ms\n", 61 | "Wall time: 751 ms\n" 62 | ] 63 | } 64 | ], 65 | "source": [ 66 | "%%timeit\n", 67 | "gmin = cusignal.argrelmin(gsig)" 68 | ] 69 | }, 70 | { 71 | "cell_type": "markdown", 72 | "metadata": {}, 73 | "source": [ 74 | "### Relative Maximum of Data" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 5, 80 | "metadata": {}, 81 | "outputs": [ 82 | { 83 | "name": "stdout", 84 | "output_type": "stream", 85 | "text": [ 86 | "CPU times: user 1.72 s, sys: 1.83 s, total: 3.54 s\n", 87 | "Wall time: 3.54 s\n" 88 | ] 89 | } 90 | ], 91 | "source": [ 92 | "%%timeit\n", 93 | "cmax = signal.argrelmax(csig)" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 6, 99 | "metadata": {}, 100 | "outputs": [ 101 | { 102 | "name": "stdout", 103 | "output_type": "stream", 104 | "text": [ 105 | "CPU times: user 262 ms, sys: 23.1 ms, total: 285 ms\n", 106 | "Wall time: 284 ms\n" 107 | ] 108 | } 109 | ], 110 | "source": [ 111 | "%%timeit\n", 112 | "gmax = cusignal.argrelmax(gsig)" 113 | ] 114 | }, 115 | { 116 | "cell_type": "markdown", 117 | "metadata": {}, 118 | "source": [ 119 | "### Relative Extrema of Data" 120 | ] 121 | }, 122 | { 123 | "cell_type": "code", 124 | "execution_count": 7, 125 | "metadata": {}, 126 | "outputs": [ 127 | { 128 | "name": "stdout", 129 | "output_type": "stream", 130 | "text": [ 131 | "CPU times: user 1.64 s, sys: 1.91 s, total: 3.55 s\n", 132 | "Wall time: 3.55 s\n" 133 | ] 134 | } 135 | ], 136 | "source": [ 137 | "%%timeit\n", 138 | "cex = signal.argrelextrema(csig, np.less)" 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": 8, 144 | "metadata": {}, 145 | "outputs": [ 146 | { 147 | "name": "stdout", 148 | "output_type": "stream", 149 | "text": [ 150 | "CPU times: user 91.6 ms, sys: 31.6 ms, total: 123 ms\n", 151 | "Wall time: 122 ms\n" 152 | ] 153 | } 154 | ], 155 | "source": [ 156 | "%%timeit\n", 157 | "gex = cusignal.argrelextrema(gsig, cp.less)" 158 | ] 159 | } 160 | ], 161 | "metadata": { 162 | "kernelspec": { 163 | "display_name": "Python 3", 164 | "language": "python", 165 | "name": "python3" 166 | }, 167 | "language_info": { 168 | "codemirror_mode": { 169 | "name": "ipython", 170 | "version": 3 171 | }, 172 | "file_extension": ".py", 173 | "mimetype": "text/x-python", 174 | "name": "python", 175 | "nbconvert_exporter": "python", 176 | "pygments_lexer": "ipython3", 177 | "version": "3.8.1" 178 | } 179 | }, 180 | "nbformat": 4, 181 | "nbformat_minor": 4 182 | } 183 | -------------------------------------------------------------------------------- /notebooks/api_guide/radar_examples.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import cusignal\n", 10 | "import cupy as cp" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "### Pulse Compression" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 2, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "num_pulses = 128\n", 27 | "num_samples_per_pulse = 9000\n", 28 | "template_length = 1000\n", 29 | "\n", 30 | "x = cp.random.randn(num_pulses, num_samples_per_pulse) + 1j*cp.random.randn(num_pulses, num_samples_per_pulse)\n", 31 | "template = cp.random.randn(template_length) + 1j*cp.random.randn(template_length)" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 4, 37 | "metadata": {}, 38 | "outputs": [ 39 | { 40 | "name": "stdout", 41 | "output_type": "stream", 42 | "text": [ 43 | "803 µs ± 210 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n" 44 | ] 45 | } 46 | ], 47 | "source": [ 48 | "%%timeit\n", 49 | "pc_out = cusignal.pulse_compression(x, template, normalize=True, window='hamming')" 50 | ] 51 | } 52 | ], 53 | "metadata": { 54 | "kernelspec": { 55 | "display_name": "Python 3", 56 | "language": "python", 57 | "name": "python3" 58 | }, 59 | "language_info": { 60 | "codemirror_mode": { 61 | "name": "ipython", 62 | "version": 3 63 | }, 64 | "file_extension": ".py", 65 | "mimetype": "text/x-python", 66 | "name": "python", 67 | "nbconvert_exporter": "python", 68 | "pygments_lexer": "ipython3", 69 | "version": "3.8.5" 70 | } 71 | }, 72 | "nbformat": 4, 73 | "nbformat_minor": 4 74 | } 75 | -------------------------------------------------------------------------------- /notebooks/api_guide/waveform_examples.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import cupy as cp\n", 10 | "import cusignal \n", 11 | "from scipy import signal\n", 12 | "import numpy as np" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": 2, 18 | "metadata": {}, 19 | "outputs": [], 20 | "source": [ 21 | "ct = np.linspace(0, 10, int(1e7))\n", 22 | "gt = cp.linspace(0, 10, int(1e7))" 23 | ] 24 | }, 25 | { 26 | "cell_type": "markdown", 27 | "metadata": {}, 28 | "source": [ 29 | "### Square Wave" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 3, 35 | "metadata": {}, 36 | "outputs": [ 37 | { 38 | "name": "stdout", 39 | "output_type": "stream", 40 | "text": [ 41 | "447 ms ± 565 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" 42 | ] 43 | } 44 | ], 45 | "source": [ 46 | "%%timeit\n", 47 | "cpwm = signal.square(ct, duty=0.5)" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 4, 53 | "metadata": {}, 54 | "outputs": [ 55 | { 56 | "name": "stdout", 57 | "output_type": "stream", 58 | "text": [ 59 | "8.68 ms ± 2.17 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" 60 | ] 61 | } 62 | ], 63 | "source": [ 64 | "%%timeit\n", 65 | "gpwm = cusignal.square(gt, duty=0.5)" 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "### Gaussian Modulated Sinusoid" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": 5, 78 | "metadata": {}, 79 | "outputs": [ 80 | { 81 | "name": "stdout", 82 | "output_type": "stream", 83 | "text": [ 84 | "645 ms ± 1.27 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" 85 | ] 86 | } 87 | ], 88 | "source": [ 89 | "%%timeit\n", 90 | "ci, cq, ce = signal.gausspulse(ct, fc=5, retquad=True, retenv=True)" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 6, 96 | "metadata": {}, 97 | "outputs": [ 98 | { 99 | "name": "stdout", 100 | "output_type": "stream", 101 | "text": [ 102 | "3.13 ms ± 417 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n" 103 | ] 104 | } 105 | ], 106 | "source": [ 107 | "%%timeit\n", 108 | "gi, gq, ge = cusignal.gausspulse(gt, fc=5, retquad=True, retenv=True)" 109 | ] 110 | }, 111 | { 112 | "cell_type": "markdown", 113 | "metadata": {}, 114 | "source": [ 115 | "### Chirp" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": 7, 121 | "metadata": {}, 122 | "outputs": [ 123 | { 124 | "name": "stdout", 125 | "output_type": "stream", 126 | "text": [ 127 | "309 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" 128 | ] 129 | } 130 | ], 131 | "source": [ 132 | "%%timeit\n", 133 | "cw = signal.chirp(ct, f0=6, f1=1, t1=10, method='linear')" 134 | ] 135 | }, 136 | { 137 | "cell_type": "code", 138 | "execution_count": 8, 139 | "metadata": {}, 140 | "outputs": [ 141 | { 142 | "name": "stdout", 143 | "output_type": "stream", 144 | "text": [ 145 | "2.37 ms ± 4.48 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n" 146 | ] 147 | } 148 | ], 149 | "source": [ 150 | "%%timeit\n", 151 | "gw = cusignal.chirp(gt, f0=6, f1=1, t1=10, method='linear')" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": 9, 157 | "metadata": {}, 158 | "outputs": [ 159 | { 160 | "name": "stdout", 161 | "output_type": "stream", 162 | "text": [ 163 | "735 ms ± 701 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" 164 | ] 165 | } 166 | ], 167 | "source": [ 168 | "%%timeit\n", 169 | "cw = signal.chirp(ct, f0=1500, f1=250, t1=10, method='quadratic')" 170 | ] 171 | }, 172 | { 173 | "cell_type": "code", 174 | "execution_count": 10, 175 | "metadata": {}, 176 | "outputs": [ 177 | { 178 | "name": "stdout", 179 | "output_type": "stream", 180 | "text": [ 181 | "2.8 ms ± 10.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n" 182 | ] 183 | } 184 | ], 185 | "source": [ 186 | "%%timeit\n", 187 | "gw = cusignal.chirp(gt, f0=1500, f1=250, t1=10, method='quadratic')" 188 | ] 189 | }, 190 | { 191 | "cell_type": "markdown", 192 | "metadata": {}, 193 | "source": [ 194 | "### Unit Impulse" 195 | ] 196 | }, 197 | { 198 | "cell_type": "code", 199 | "execution_count": 11, 200 | "metadata": {}, 201 | "outputs": [ 202 | { 203 | "name": "stdout", 204 | "output_type": "stream", 205 | "text": [ 206 | "21.5 µs ± 38.2 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n" 207 | ] 208 | } 209 | ], 210 | "source": [ 211 | "%%timeit\n", 212 | "cimp = signal.unit_impulse(int(1e8), 'mid')" 213 | ] 214 | }, 215 | { 216 | "cell_type": "code", 217 | "execution_count": 12, 218 | "metadata": {}, 219 | "outputs": [ 220 | { 221 | "name": "stdout", 222 | "output_type": "stream", 223 | "text": [ 224 | "1.35 ms ± 32.9 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n" 225 | ] 226 | } 227 | ], 228 | "source": [ 229 | "%%timeit\n", 230 | "gimp = cusignal.unit_impulse(int(1e8), 'mid')" 231 | ] 232 | } 233 | ], 234 | "metadata": { 235 | "kernelspec": { 236 | "display_name": "Python 3", 237 | "language": "python", 238 | "name": "python3" 239 | }, 240 | "language_info": { 241 | "codemirror_mode": { 242 | "name": "ipython", 243 | "version": 3 244 | }, 245 | "file_extension": ".py", 246 | "mimetype": "text/x-python", 247 | "name": "python", 248 | "nbconvert_exporter": "python", 249 | "pygments_lexer": "ipython3", 250 | "version": "3.8.1" 251 | } 252 | }, 253 | "nbformat": 4, 254 | "nbformat_minor": 4 255 | } 256 | -------------------------------------------------------------------------------- /notebooks/api_guide/wavelets_examples.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import cupy as cp\n", 10 | "import cusignal \n", 11 | "from scipy import signal\n", 12 | "import numpy as np" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": 2, 18 | "metadata": {}, 19 | "outputs": [], 20 | "source": [ 21 | "# This admittedly may not be realistic with a wavelet, but keeping consistent perf array sizes (or tying to!)\n", 22 | "M = int(1e8)\n", 23 | "csig = np.random.rand(int(1e7))\n", 24 | "gsig = cp.random.rand(int(1e7))" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "### Morlet" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 3, 37 | "metadata": {}, 38 | "outputs": [ 39 | { 40 | "name": "stdout", 41 | "output_type": "stream", 42 | "text": [ 43 | "7.64 s ± 1.34 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" 44 | ] 45 | } 46 | ], 47 | "source": [ 48 | "%%timeit\n", 49 | "cmorlet = signal.morlet(M)" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 4, 55 | "metadata": {}, 56 | "outputs": [ 57 | { 58 | "name": "stdout", 59 | "output_type": "stream", 60 | "text": [ 61 | "39.6 ms ± 29.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" 62 | ] 63 | } 64 | ], 65 | "source": [ 66 | "%%timeit\n", 67 | "gmorlet = cusignal.morlet(M)" 68 | ] 69 | }, 70 | { 71 | "cell_type": "markdown", 72 | "metadata": {}, 73 | "source": [ 74 | "### Ricker" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 5, 80 | "metadata": {}, 81 | "outputs": [ 82 | { 83 | "name": "stdout", 84 | "output_type": "stream", 85 | "text": [ 86 | "3.6 s ± 53.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" 87 | ] 88 | } 89 | ], 90 | "source": [ 91 | "%%timeit\n", 92 | "cricker = signal.ricker(M, int(1e3))" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": 6, 98 | "metadata": {}, 99 | "outputs": [ 100 | { 101 | "name": "stdout", 102 | "output_type": "stream", 103 | "text": [ 104 | "294 µs ± 16.5 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" 105 | ] 106 | } 107 | ], 108 | "source": [ 109 | "%%timeit\n", 110 | "gricker = cusignal.ricker(M, int(1e3))" 111 | ] 112 | }, 113 | { 114 | "cell_type": "markdown", 115 | "metadata": {}, 116 | "source": [ 117 | "### Continuous Wavelet Transform" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": 7, 123 | "metadata": {}, 124 | "outputs": [ 125 | { 126 | "name": "stdout", 127 | "output_type": "stream", 128 | "text": [ 129 | "14.7 s ± 97.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" 130 | ] 131 | } 132 | ], 133 | "source": [ 134 | "%%timeit\n", 135 | "ccwt = signal.cwt(csig, signal.ricker, np.arange(1,31))" 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": 8, 141 | "metadata": {}, 142 | "outputs": [ 143 | { 144 | "name": "stdout", 145 | "output_type": "stream", 146 | "text": [ 147 | "291 ms ± 7.75 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" 148 | ] 149 | } 150 | ], 151 | "source": [ 152 | "%%timeit\n", 153 | "gcwt = cusignal.cwt(gsig, cusignal.ricker, cp.arange(1,31))" 154 | ] 155 | } 156 | ], 157 | "metadata": { 158 | "kernelspec": { 159 | "display_name": "Python 3", 160 | "language": "python", 161 | "name": "python3" 162 | }, 163 | "language_info": { 164 | "codemirror_mode": { 165 | "name": "ipython", 166 | "version": 3 167 | }, 168 | "file_extension": ".py", 169 | "mimetype": "text/x-python", 170 | "name": "python", 171 | "nbconvert_exporter": "python", 172 | "pygments_lexer": "ipython3", 173 | "version": "3.8.1" 174 | } 175 | }, 176 | "nbformat": 4, 177 | "nbformat_minor": 4 178 | } 179 | -------------------------------------------------------------------------------- /notebooks/sdr/sdr_wfm_demod.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "#### [First-Run Only] Environment Setup\n", 8 | "\n", 9 | "The use of this notebook requires an SDR device to be connected to the local machine." 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": null, 15 | "metadata": { 16 | "scrolled": true, 17 | "tags": [] 18 | }, 19 | "outputs": [], 20 | "source": [ 21 | "# SoapySDR module corresponds to SDR selection, e.g.\n", 22 | "# soapy-module-lms7 -> lime\n", 23 | "# soapy-module-rtlsdr -> rtlsdr\n", 24 | "\n", 25 | "!mamba install -y soapysdr-module-lms7 pyaudio" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": {}, 31 | "source": [ 32 | "#### Import Dependencies" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": null, 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "from SoapySDR import *\n", 42 | "import SoapySDR\n", 43 | "import pyaudio\n", 44 | "import signal\n", 45 | "import queue\n", 46 | "import cupy as cp\n", 47 | "import cusignal as sig" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "#### Demodulator Settings" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [ 63 | "fm_freq = 96.9e6 # FM Station Frequency\n", 64 | "samp_rate = int(240e3)\n", 65 | "audio_fs = int(48e3)\n", 66 | "buff_len = int(1024*(samp_rate//audio_fs))" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "metadata": {}, 72 | "source": [ 73 | "#### SoapySDR Configuration" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": null, 79 | "metadata": {}, 80 | "outputs": [], 81 | "source": [ 82 | "args = dict(driver=\"lime\") # SDR Selection (eg.: lime, rtlsdr, plutosdr...)\n", 83 | "sdr = SoapySDR.Device(args)\n", 84 | "sdr.setSampleRate(SOAPY_SDR_RX, 0, samp_rate)\n", 85 | "sdr.setFrequency(SOAPY_SDR_RX, 0, fm_freq)" 86 | ] 87 | }, 88 | { 89 | "cell_type": "markdown", 90 | "metadata": {}, 91 | "source": [ 92 | "#### FIFO Buffer and Shared Memory Allocation" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": null, 98 | "metadata": {}, 99 | "outputs": [], 100 | "source": [ 101 | "que = queue.Queue()\n", 102 | "buff = sig.get_shared_mem(buff_len, dtype=cp.complex64)" 103 | ] 104 | }, 105 | { 106 | "cell_type": "markdown", 107 | "metadata": {}, 108 | "source": [ 109 | "#### PyAudio Asynchronous Buffer" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": null, 115 | "metadata": {}, 116 | "outputs": [], 117 | "source": [ 118 | "def demod(in_data, frame_count, time_info, status):\n", 119 | " b = cp.array(que.get())\n", 120 | " b = cp.diff(cp.unwrap(cp.angle(b)))\n", 121 | " b = sig.resample_poly(b, 1, 5, window='hamm')\n", 122 | " b /= cp.pi\n", 123 | " b = cp.asnumpy(b).astype(cp.float32)\n", 124 | " return (b, pyaudio.paContinue)\n", 125 | "\n", 126 | "p = pyaudio.PyAudio()\n", 127 | "stream = p.open(format=pyaudio.paFloat32, channels=1, rate=audio_fs, output=True, stream_callback=demod)" 128 | ] 129 | }, 130 | { 131 | "cell_type": "markdown", 132 | "metadata": {}, 133 | "source": [ 134 | "#### Graceful Exit Handler" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": null, 140 | "metadata": {}, 141 | "outputs": [], 142 | "source": [ 143 | "def signal_handler(signum, frame):\n", 144 | " stream.stop_stream()\n", 145 | " stream.close()\n", 146 | " p.terminate()\n", 147 | " sdr.closeStream(rx)\n", 148 | " exit(-1)\n", 149 | " \n", 150 | "signal.signal(signal.SIGINT, signal_handler)" 151 | ] 152 | }, 153 | { 154 | "cell_type": "markdown", 155 | "metadata": {}, 156 | "source": [ 157 | "#### Start Collecting Data" 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": null, 163 | "metadata": {}, 164 | "outputs": [], 165 | "source": [ 166 | "rx = sdr.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CF32)\n", 167 | "sdr.activateStream(rx)\n", 168 | "stream.start_stream()\n", 169 | "\n", 170 | "while True:\n", 171 | " sdr.readStream(rx, [buff], buff_len, timeoutUs=int(8e12))\n", 172 | " que.put(buff.astype(cp.complex64).copy())" 173 | ] 174 | }, 175 | { 176 | "cell_type": "code", 177 | "execution_count": null, 178 | "metadata": {}, 179 | "outputs": [], 180 | "source": [] 181 | } 182 | ], 183 | "metadata": { 184 | "kernelspec": { 185 | "display_name": "Python 3 (ipykernel)", 186 | "language": "python", 187 | "name": "python3" 188 | }, 189 | "language_info": { 190 | "codemirror_mode": { 191 | "name": "ipython", 192 | "version": 3 193 | }, 194 | "file_extension": ".py", 195 | "mimetype": "text/x-python", 196 | "name": "python", 197 | "nbconvert_exporter": "python", 198 | "pygments_lexer": "ipython3", 199 | "version": "3.9.7" 200 | } 201 | }, 202 | "nbformat": 4, 203 | "nbformat_minor": 4 204 | } 205 | -------------------------------------------------------------------------------- /print_env.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Reports relevant environment information useful for diagnosing and 3 | # debugging cuSignal issues. 4 | # Usage: 5 | # "./print_env.sh" - prints to stdout 6 | # "./print_env.sh > env.txt" - prints to file "env.txt" 7 | 8 | print_env() { 9 | echo "**git***" 10 | if [ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" == "true" ]; then 11 | git log --decorate -n 1 12 | echo "**git submodules***" 13 | git submodule status --recursive 14 | else 15 | echo "Not inside a git repository" 16 | fi 17 | echo 18 | 19 | echo "***OS Information***" 20 | cat /etc/*-release 21 | uname -a 22 | echo 23 | 24 | echo "***GPU Information***" 25 | nvidia-smi 26 | echo 27 | 28 | echo "***CPU***" 29 | lscpu 30 | echo 31 | 32 | echo "***CMake***" 33 | which cmake && cmake --version 34 | echo 35 | 36 | echo "***g++***" 37 | which g++ && g++ --version 38 | echo 39 | 40 | echo "***nvcc***" 41 | which nvcc && nvcc --version 42 | echo 43 | 44 | echo "***Python***" 45 | which python && python -c "import sys; print('Python {0}.{1}.{2}'.format(sys.version_info[0], sys.version_info[1], sys.version_info[2]))" 46 | echo 47 | 48 | echo "***Environment Variables***" 49 | 50 | printf '%-32s: %s\n' PATH $PATH 51 | 52 | printf '%-32s: %s\n' LD_LIBRARY_PATH $LD_LIBRARY_PATH 53 | 54 | printf '%-32s: %s\n' NUMBAPRO_NVVM $NUMBAPRO_NVVM 55 | 56 | printf '%-32s: %s\n' NUMBAPRO_LIBDEVICE $NUMBAPRO_LIBDEVICE 57 | 58 | printf '%-32s: %s\n' CONDA_PREFIX $CONDA_PREFIX 59 | 60 | printf '%-32s: %s\n' PYTHON_PATH $PYTHON_PATH 61 | 62 | echo 63 | 64 | 65 | # Print conda packages if conda exists 66 | if type "conda" &> /dev/null; then 67 | echo '***conda packages***' 68 | which conda && conda list 69 | echo 70 | # Print pip packages if pip exists 71 | elif type "pip" &> /dev/null; then 72 | echo "conda not found" 73 | echo "***pip packages***" 74 | which pip && pip list 75 | echo 76 | else 77 | echo "conda not found" 78 | echo "pip not found" 79 | fi 80 | } 81 | 82 | echo "
Click here to see environment details
"
83 | echo "     "
84 | print_env | while read -r line; do
85 |     echo "     $line"
86 | done
87 | echo "
" 88 | -------------------------------------------------------------------------------- /python/.coveragerc: -------------------------------------------------------------------------------- 1 | # Configuration file for Python coverage tests 2 | [run] 3 | source = cusignal 4 | -------------------------------------------------------------------------------- /python/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include versioneer.py 2 | include cusignal/_version.py 3 | -------------------------------------------------------------------------------- /python/cusignal/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | from cusignal.acoustics.cepstrum import ( 22 | complex_cepstrum, 23 | inverse_complex_cepstrum, 24 | minimum_phase, 25 | real_cepstrum, 26 | ) 27 | from cusignal.bsplines.bsplines import cubic, gauss_spline, quadratic 28 | from cusignal.convolution.convolve import ( 29 | choose_conv_method, 30 | convolve, 31 | convolve1d2o, 32 | convolve1d3o, 33 | convolve2d, 34 | fftconvolve, 35 | ) 36 | from cusignal.convolution.correlate import correlate, correlate2d 37 | from cusignal.demod.demod import fm_demod 38 | from cusignal.estimation.filters import KalmanFilter 39 | from cusignal.filter_design.fir_filter_design import ( 40 | cmplx_sort, 41 | firwin, 42 | firwin2, 43 | kaiser_atten, 44 | kaiser_beta, 45 | ) 46 | from cusignal.filtering.filtering import ( 47 | channelize_poly, 48 | detrend, 49 | filtfilt, 50 | firfilter, 51 | firfilter2, 52 | firfilter_zi, 53 | freq_shift, 54 | hilbert, 55 | hilbert2, 56 | lfilter, 57 | lfilter_zi, 58 | sosfilt, 59 | wiener, 60 | ) 61 | from cusignal.filtering.resample import decimate, resample, resample_poly, upfirdn 62 | from cusignal.io.reader import read_bin, read_sigmf, unpack_bin 63 | from cusignal.io.writer import pack_bin, write_bin, write_sigmf 64 | from cusignal.peak_finding.peak_finding import argrelextrema, argrelmax, argrelmin 65 | from cusignal.radartools.beamformers import mvdr 66 | from cusignal.radartools.radartools import ambgfun, pulse_compression, pulse_doppler 67 | from cusignal.spectral_analysis.spectral import ( 68 | coherence, 69 | csd, 70 | istft, 71 | lombscargle, 72 | periodogram, 73 | spectrogram, 74 | stft, 75 | vectorstrength, 76 | welch, 77 | ) 78 | from cusignal.utils.arraytools import ( 79 | from_pycuda, 80 | get_pinned_array, 81 | get_pinned_mem, 82 | get_shared_array, 83 | get_shared_mem, 84 | ) 85 | from cusignal.waveforms.waveforms import ( 86 | chirp, 87 | gausspulse, 88 | sawtooth, 89 | square, 90 | unit_impulse, 91 | ) 92 | from cusignal.wavelets.wavelets import cwt, morlet, morlet2, qmf, ricker 93 | from cusignal.windows.windows import ( 94 | barthann, 95 | bartlett, 96 | blackman, 97 | blackmanharris, 98 | bohman, 99 | boxcar, 100 | chebwin, 101 | cosine, 102 | exponential, 103 | flattop, 104 | gaussian, 105 | general_cosine, 106 | general_gaussian, 107 | general_hamming, 108 | get_window, 109 | hamming, 110 | hann, 111 | kaiser, 112 | nuttall, 113 | parzen, 114 | taylor, 115 | triang, 116 | tukey, 117 | ) 118 | 119 | # Versioneer 120 | from ._version import get_versions 121 | 122 | __version__ = get_versions()["version"] 123 | del get_versions 124 | -------------------------------------------------------------------------------- /python/cusignal/acoustics/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | from cusignal.acoustics.cepstrum import ( 22 | complex_cepstrum, 23 | inverse_complex_cepstrum, 24 | minimum_phase, 25 | real_cepstrum, 26 | ) 27 | -------------------------------------------------------------------------------- /python/cusignal/acoustics/cepstrum.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | import cupy as cp 22 | 23 | _real_cepstrum_kernel = cp.ElementwiseKernel( 24 | "T spectrum", 25 | "T output", 26 | """ 27 | output = log( abs( spectrum ) ); 28 | """, 29 | "_real_cepstrum_kernel", 30 | options=("-std=c++11",), 31 | ) 32 | 33 | 34 | def real_cepstrum(x, n=None, axis=-1): 35 | r""" 36 | Calculates the real cepstrum of an input sequence x where the cepstrum is 37 | defined as the inverse Fourier transform of the log magnitude DFT 38 | (spectrum) of a signal. It's primarily used for source/speaker separation 39 | in speech signal processing 40 | 41 | Parameters 42 | ---------- 43 | x : ndarray 44 | Input sequence, if x is a matrix, return cepstrum in direction of axis 45 | n : int 46 | Size of Fourier Transform; If none, will use length of input array 47 | axis: int 48 | Direction for cepstrum calculation 49 | 50 | Returns 51 | ------- 52 | ceps : ndarray 53 | Complex cepstrum result 54 | """ 55 | x = cp.asarray(x) 56 | spectrum = cp.fft.fft(x, n=n, axis=axis) 57 | spectrum = _real_cepstrum_kernel(spectrum) 58 | return cp.fft.ifft(spectrum, n=n, axis=axis).real 59 | 60 | 61 | _complex_cepstrum_kernel = cp.ElementwiseKernel( 62 | "C spectrum, raw T unwrapped", 63 | "C output, T ndelay", 64 | """ 65 | ndelay = round( unwrapped[center] / M_PI ); 66 | const T temp { unwrapped[i] - ( M_PI * ndelay * i / center ) }; 67 | 68 | output = log( abs( spectrum ) ) + C( 0, temp ); 69 | """, 70 | "_complex_cepstrum_kernel", 71 | options=("-std=c++11",), 72 | return_tuple=True, 73 | loop_prep="const int center { static_cast( 0.5 * \ 74 | ( _ind.size() + 1 ) ) };", 75 | ) 76 | 77 | 78 | def complex_cepstrum(x, n=None, axis=-1): 79 | r""" 80 | Calculates the complex cepstrum of a real valued input sequence x 81 | where the cepstrum is defined as the inverse Fourier transform 82 | of the log magnitude DFT (spectrum) of a signal. It's primarily 83 | used for source/speaker separation in speech signal processing. 84 | 85 | The input is altered to have zero-phase at pi radians (180 degrees) 86 | Parameters 87 | ---------- 88 | x : ndarray 89 | Input sequence, if x is a matrix, return cepstrum in direction of axis 90 | n : int 91 | Size of Fourier Transform; If none, will use length of input array 92 | axis: int 93 | Direction for cepstrum calculation 94 | Returns 95 | ------- 96 | ceps : ndarray 97 | Complex cepstrum result 98 | """ 99 | x = cp.asarray(x) 100 | spectrum = cp.fft.fft(x, n=n, axis=axis) 101 | unwrapped = cp.unwrap(cp.angle(spectrum)) 102 | log_spectrum, ndelay = _complex_cepstrum_kernel(spectrum, unwrapped) 103 | ceps = cp.fft.ifft(log_spectrum, n=n, axis=axis).real 104 | 105 | return ceps, ndelay 106 | 107 | 108 | _inverse_complex_cepstrum_kernel = cp.ElementwiseKernel( 109 | "C log_spectrum, int32 ndelay, float64 pi", 110 | "C spectrum", 111 | """ 112 | const double wrapped { log_spectrum.imag() + M_PI * ndelay * i / center }; 113 | 114 | spectrum = exp( C( log_spectrum.real(), wrapped ) ) 115 | """, 116 | "_inverse_complex_cepstrum_kernel", 117 | options=("-std=c++11",), 118 | loop_prep="const double center { 0.5 * ( _ind.size() + 1 ) };", 119 | ) 120 | 121 | 122 | def inverse_complex_cepstrum(ceps, ndelay): 123 | r"""Compute the inverse complex cepstrum of a real sequence. 124 | ceps : ndarray 125 | Real sequence to compute inverse complex cepstrum of. 126 | ndelay: int 127 | The amount of samples of circular delay added to `x`. 128 | Returns 129 | ------- 130 | x : ndarray 131 | The inverse complex cepstrum of the real sequence `ceps`. 132 | The inverse complex cepstrum is given by 133 | .. math:: x[n] = F^{-1}\left{\exp(F(c[n]))\right} 134 | where :math:`c_[n]` is the input signal and :math:`F` and :math:`F_{-1} 135 | are respectively the forward and backward Fourier transform. 136 | """ 137 | ceps = cp.asarray(ceps) 138 | log_spectrum = cp.fft.fft(ceps) 139 | spectrum = _inverse_complex_cepstrum_kernel(log_spectrum, ndelay, cp.pi) 140 | iceps = cp.fft.ifft(spectrum).real 141 | 142 | return iceps 143 | 144 | 145 | _minimum_phase_kernel = cp.ElementwiseKernel( 146 | "T ceps", 147 | "T window", 148 | """ 149 | if ( !i ) { 150 | window = ceps; 151 | } else if ( i < bend ) { 152 | window = ceps * 2.0; 153 | } else if ( i == bend ) { 154 | window = ceps * ( 1 - odd ); 155 | } else { 156 | window = 0; 157 | } 158 | """, 159 | "_minimum_phase_kernel", 160 | options=("-std=c++11",), 161 | loop_prep="const bool odd { _ind.size() & 1 }; \ 162 | const int bend { static_cast( 0.5 * \ 163 | ( _ind.size() + odd ) ) };", 164 | ) 165 | 166 | 167 | def minimum_phase(x, n=None): 168 | r"""Compute the minimum phase reconstruction of a real sequence. 169 | x : ndarray 170 | Real sequence to compute the minimum phase reconstruction of. 171 | n : {None, int}, optional 172 | Length of the Fourier transform. 173 | Compute the minimum phase reconstruction of a real sequence using the 174 | real cepstrum. 175 | Returns 176 | ------- 177 | m : ndarray 178 | The minimum phase reconstruction of the real sequence `x`. 179 | """ 180 | if n is None: 181 | n = len(x) 182 | ceps = real_cepstrum(x, n=n) 183 | window = _minimum_phase_kernel(ceps) 184 | m = cp.fft.ifft(cp.exp(cp.fft.fft(window))).real 185 | 186 | return m 187 | -------------------------------------------------------------------------------- /python/cusignal/bsplines/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | from cusignal.bsplines.bsplines import cubic, gauss_spline, quadratic 22 | -------------------------------------------------------------------------------- /python/cusignal/bsplines/bsplines.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | import cupy as cp 22 | 23 | _gauss_spline_kernel = cp.ElementwiseKernel( 24 | "T x, int32 n", 25 | "T output", 26 | """ 27 | output = 1 / sqrt( 2.0 * M_PI * signsq ) * exp( -( x * x ) * r_signsq ); 28 | """, 29 | "_gauss_spline_kernel", 30 | options=("-std=c++11",), 31 | loop_prep="const double signsq { ( n + 1 ) / 12.0 }; \ 32 | const double r_signsq { 0.5 / signsq };", 33 | ) 34 | 35 | 36 | def gauss_spline(x, n): 37 | """Gaussian approximation to B-spline basis function of order n. 38 | 39 | Parameters 40 | ---------- 41 | n : int 42 | The order of the spline. Must be nonnegative, i.e. n >= 0 43 | 44 | References 45 | ---------- 46 | .. [1] Bouma H., Vilanova A., Bescos J.O., ter Haar Romeny B.M., Gerritsen 47 | F.A. (2007) Fast and Accurate Gaussian Derivatives Based on B-Splines. 48 | In: Sgallari F., Murli A., Paragios N. (eds) Scale Space and Variational 49 | Methods in Computer Vision. SSVM 2007. Lecture Notes in Computer 50 | Science, vol 4485. Springer, Berlin, Heidelberg 51 | """ 52 | x = cp.asarray(x) 53 | 54 | return _gauss_spline_kernel(x, n) 55 | 56 | 57 | _cubic_kernel = cp.ElementwiseKernel( 58 | "T x", 59 | "T res", 60 | """ 61 | const T ax { abs( x ) }; 62 | 63 | if( ax < 1 ) { 64 | res = 2.0 / 3 - 1.0 / 2 * ax * ax * ( 2.0 - ax ); 65 | } else if( !( ax < 1 ) && ( ax < 2 ) ) { 66 | res = 1.0 / 6 * ( 2.0 - ax ) * ( 2.0 - ax ) * ( 2.0 - ax ); 67 | } else { 68 | res = 0.0; 69 | } 70 | """, 71 | "_cubic_kernel", 72 | options=("-std=c++11",), 73 | ) 74 | 75 | 76 | def cubic(x): 77 | """A cubic B-spline. 78 | 79 | This is a special case of `bspline`, and equivalent to ``bspline(x, 3)``. 80 | """ 81 | x = cp.asarray(x) 82 | 83 | return _cubic_kernel(x) 84 | 85 | 86 | _quadratic_kernel = cp.ElementwiseKernel( 87 | "T x", 88 | "T res", 89 | """ 90 | const T ax { abs( x ) }; 91 | 92 | if( ax < 0.5 ) { 93 | res = 0.75 - ax * ax; 94 | } else if( !( ax < 0.5 ) && ( ax < 1.5 ) ) { 95 | res = ( ( ax - 1.5 ) * ( ax - 1.5 ) ) * 0.5 ; 96 | } else { 97 | res = 0.0; 98 | } 99 | """, 100 | "_quadratic_kernel", 101 | options=("-std=c++11",), 102 | ) 103 | 104 | 105 | def quadratic(x): 106 | """A quadratic B-spline. 107 | 108 | This is a special case of `bspline`, and equivalent to ``bspline(x, 2)``. 109 | """ 110 | x = cp.asarray(x) 111 | 112 | return _quadratic_kernel(x) 113 | -------------------------------------------------------------------------------- /python/cusignal/convolution/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | from cusignal.convolution.convolve import ( 22 | choose_conv_method, 23 | convolve, 24 | convolve1d2o, 25 | convolve1d3o, 26 | convolve2d, 27 | fftconvolve, 28 | ) 29 | from cusignal.convolution.correlate import correlate, correlate2d, correlation_lags 30 | -------------------------------------------------------------------------------- /python/cusignal/demod/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | from cusignal.demod.demod import fm_demod 22 | -------------------------------------------------------------------------------- /python/cusignal/demod/demod.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | import cupy as cp 22 | 23 | 24 | def fm_demod(x, axis=-1): 25 | """ 26 | Demodulate Frequency Modulated Signal 27 | 28 | Parameters 29 | ---------- 30 | x : ndarray 31 | Received complex valued signal or batch of signals 32 | 33 | Returns 34 | ------- 35 | y : ndarray 36 | The demodulated output with the same shape as `x`. 37 | """ 38 | 39 | x = cp.asarray(x) 40 | 41 | if cp.isrealobj(x): 42 | raise AssertionError("Input signal must be complex-valued") 43 | x_angle = cp.unwrap(cp.angle(x), axis=axis) 44 | y = cp.diff(x_angle, axis=axis) 45 | return y 46 | -------------------------------------------------------------------------------- /python/cusignal/estimation/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | from cusignal.estimation.filters import KalmanFilter 22 | -------------------------------------------------------------------------------- /python/cusignal/filter_design/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | from cusignal.filter_design.fir_filter_design import ( 22 | cmplx_sort, 23 | firwin, 24 | firwin2, 25 | kaiser_atten, 26 | kaiser_beta, 27 | ) 28 | -------------------------------------------------------------------------------- /python/cusignal/filter_design/filter_design_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | import numpy as np 22 | 23 | 24 | def _validate_sos(sos): 25 | """Helper to validate a SOS input""" 26 | sos = np.atleast_2d(sos) 27 | if sos.ndim != 2: 28 | raise ValueError("sos array must be 2D") 29 | n_sections, m = sos.shape 30 | if m != 6: 31 | raise ValueError("sos array must be shape (n_sections, 6)") 32 | if not (sos[:, 3] == 1).all(): 33 | raise ValueError("sos[:, 3] should be all ones") 34 | return sos, n_sections 35 | -------------------------------------------------------------------------------- /python/cusignal/filtering/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | from cusignal.filtering.filtering import ( 22 | channelize_poly, 23 | detrend, 24 | filtfilt, 25 | firfilter, 26 | firfilter2, 27 | firfilter_zi, 28 | freq_shift, 29 | hilbert, 30 | hilbert2, 31 | lfilter, 32 | lfilter_zi, 33 | sosfilt, 34 | wiener, 35 | ) 36 | from cusignal.filtering.resample import decimate, resample, resample_poly, upfirdn 37 | -------------------------------------------------------------------------------- /python/cusignal/filtering/_channelizer_cuda.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | from ..utils._caches import _cupy_kernel_cache 22 | from ..utils.helper_tools import _get_function, _get_numSM, _print_atts 23 | 24 | _SUPPORTED_TYPES = [ 25 | "float32_complex64", 26 | "complex64_complex64", 27 | "float64_complex128", 28 | "complex128_complex128", 29 | ] 30 | 31 | 32 | class _cupy_channelizer_wrapper(object): 33 | def __init__(self, grid, block, kernel): 34 | if isinstance(grid, int): 35 | grid = (grid,) 36 | if isinstance(block, int): 37 | block = (block,) 38 | 39 | self.grid = grid 40 | self.block = block 41 | self.kernel = kernel 42 | 43 | def __call__(self, n_chans, n_taps, n_pts, x, h, y): 44 | 45 | kernel_args = (n_chans, n_taps, n_pts, x, h, y) 46 | 47 | self.kernel(self.grid, self.block, kernel_args) 48 | 49 | 50 | def _populate_kernel_cache(np_type, k_type): 51 | 52 | if np_type not in _SUPPORTED_TYPES: 53 | raise ValueError("Datatype {} not found for '{}'".format(np_type, k_type)) 54 | 55 | if (str(np_type), k_type) in _cupy_kernel_cache: 56 | return 57 | 58 | _cupy_kernel_cache[(str(np_type), k_type)] = _get_function( 59 | "/filtering/_channelizer.fatbin", 60 | "_cupy_" + k_type + "_" + str(np_type), 61 | ) 62 | 63 | 64 | def _get_backend_kernel(dtype, grid, block, k_type): 65 | 66 | kernel = _cupy_kernel_cache[(dtype, k_type)] 67 | if kernel: 68 | return _cupy_channelizer_wrapper(grid, block, kernel) 69 | else: 70 | raise ValueError("Kernel {} not found in _cupy_kernel_cache".format(k_type)) 71 | 72 | raise NotImplementedError("No kernel found for datatype {}".format(dtype)) 73 | 74 | 75 | def _channelizer(x, h, y, n_chans, n_taps, n_pts): 76 | 77 | # Blocks per grid sized for 2048 threads per SM 78 | np_type = str(x.dtype) + "_" + str(y.dtype) 79 | 80 | if n_taps <= 8: 81 | k_type = "channelizer_8x8" 82 | 83 | threadsperblock = (8, 8) 84 | blockspergrid = ((n_chans + 7) // 8, _get_numSM() * 32) 85 | 86 | _populate_kernel_cache(np_type, k_type) 87 | 88 | kernel = _get_backend_kernel( 89 | np_type, 90 | blockspergrid, 91 | threadsperblock, 92 | k_type, 93 | ) 94 | 95 | elif n_taps <= 16: 96 | k_type = "channelizer_16x16" 97 | 98 | threadsperblock = (16, 16) 99 | blockspergrid = ((n_chans + 15) // 16, _get_numSM() * 8) 100 | 101 | _populate_kernel_cache(np_type, k_type) 102 | 103 | kernel = _get_backend_kernel( 104 | np_type, 105 | blockspergrid, 106 | threadsperblock, 107 | k_type, 108 | ) 109 | 110 | elif n_taps <= 32: 111 | k_type = "channelizer_32x32" 112 | 113 | threadsperblock = (32, 32) 114 | blockspergrid = ((n_chans + 31) // 32, _get_numSM() * 2) 115 | 116 | _populate_kernel_cache(np_type, k_type) 117 | 118 | kernel = _get_backend_kernel( 119 | np_type, 120 | blockspergrid, 121 | threadsperblock, 122 | k_type, 123 | ) 124 | 125 | kernel(n_chans, n_taps, n_pts, x, h, y) 126 | 127 | _print_atts(kernel) 128 | -------------------------------------------------------------------------------- /python/cusignal/filtering/_sosfilt_cuda.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | from ..utils._caches import _cupy_kernel_cache 22 | from ..utils.helper_tools import _get_function, _print_atts 23 | 24 | _SUPPORTED_TYPES = ["float32", "float64"] 25 | 26 | 27 | class _cupy_sosfilt_wrapper(object): 28 | def __init__(self, grid, block, smem, kernel): 29 | if isinstance(grid, int): 30 | grid = (grid,) 31 | if isinstance(block, int): 32 | block = (block,) 33 | 34 | self.grid = grid 35 | self.block = block 36 | self.smem = smem 37 | self.kernel = kernel 38 | 39 | def __call__(self, sos, x, zi): 40 | 41 | kernel_args = ( 42 | x.shape[0], 43 | x.shape[1], 44 | sos.shape[0], 45 | zi.shape[2], 46 | sos, 47 | zi, 48 | x, 49 | ) 50 | 51 | self.kernel(self.grid, self.block, kernel_args, shared_mem=self.smem) 52 | 53 | 54 | def _populate_kernel_cache(np_type, k_type): 55 | 56 | if np_type not in _SUPPORTED_TYPES: 57 | raise ValueError("Datatype {} not found for '{}'".format(np_type, k_type)) 58 | 59 | if (str(np_type), k_type) in _cupy_kernel_cache: 60 | return 61 | 62 | _cupy_kernel_cache[(str(np_type), k_type)] = _get_function( 63 | "/filtering/_sosfilt.fatbin", 64 | "_cupy_" + k_type + "_" + str(np_type), 65 | ) 66 | 67 | 68 | def _get_backend_kernel(dtype, grid, block, smem, k_type): 69 | kernel = _cupy_kernel_cache[(dtype.name, k_type)] 70 | if kernel: 71 | return _cupy_sosfilt_wrapper(grid, block, smem, kernel) 72 | else: 73 | raise ValueError("Kernel {} not found in _cupy_kernel_cache".format(k_type)) 74 | 75 | raise NotImplementedError("No kernel found for datatype {}".format(dtype.name)) 76 | 77 | 78 | def _sosfilt(sos, x, zi): 79 | 80 | threadsperblock = sos.shape[0] # Up-to (1024, 1) = 1024 max per block 81 | blockspergrid = x.shape[0] 82 | 83 | k_type = "sosfilt" 84 | 85 | _populate_kernel_cache(x.dtype, k_type) 86 | 87 | out_size = threadsperblock 88 | sos_size = sos.shape[0] * sos.shape[1] 89 | 90 | shared_mem = (out_size + sos_size) * x.dtype.itemsize 91 | 92 | kernel = _get_backend_kernel( 93 | x.dtype, 94 | blockspergrid, 95 | threadsperblock, 96 | shared_mem, 97 | k_type, 98 | ) 99 | print(zi.shape) 100 | 101 | kernel(sos, x, zi) 102 | 103 | _print_atts(kernel) 104 | -------------------------------------------------------------------------------- /python/cusignal/io/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | 22 | from cusignal.io.reader import read_bin, read_sigmf, unpack_bin 23 | from cusignal.io.writer import pack_bin, write_bin, write_sigmf 24 | -------------------------------------------------------------------------------- /python/cusignal/io/_reader_cuda.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | import cupy as cp 22 | 23 | from ..utils._caches import _cupy_kernel_cache 24 | from ..utils.helper_tools import _get_function, _get_tpb_bpg, _print_atts 25 | 26 | _SUPPORTED_TYPES = [ 27 | "int8", 28 | "uint8", 29 | "int16", 30 | "uint16", 31 | "int32", 32 | "uint32", 33 | "float32", 34 | "float64", 35 | "complex64", 36 | "complex128", 37 | ] 38 | 39 | 40 | class _cupy_unpack_wrapper(object): 41 | def __init__(self, grid, block, kernel): 42 | if isinstance(grid, int): 43 | grid = (grid,) 44 | if isinstance(block, int): 45 | block = (block,) 46 | 47 | self.grid = grid 48 | self.block = block 49 | self.kernel = kernel 50 | 51 | def __call__(self, out_size, little, binary, out): 52 | 53 | kernel_args = (out_size, little, binary, out) 54 | 55 | self.kernel(self.grid, self.block, kernel_args) 56 | 57 | 58 | def _populate_kernel_cache(np_type, k_type): 59 | 60 | if np_type not in _SUPPORTED_TYPES: 61 | raise ValueError("Datatype {} not found for '{}'".format(np_type, k_type)) 62 | 63 | if (str(np_type), k_type) in _cupy_kernel_cache: 64 | return 65 | 66 | _cupy_kernel_cache[(str(np_type), k_type)] = _get_function( 67 | "/io/_reader.fatbin", 68 | "_cupy_unpack_" + str(np_type), 69 | ) 70 | 71 | 72 | def _get_backend_kernel( 73 | dtype, 74 | grid, 75 | block, 76 | k_type, 77 | ): 78 | 79 | kernel = _cupy_kernel_cache[(str(dtype), k_type)] 80 | if kernel: 81 | return _cupy_unpack_wrapper(grid, block, kernel) 82 | else: 83 | raise ValueError("Kernel {} not found in _cupy_kernel_cache".format(k_type)) 84 | 85 | 86 | def _unpack(binary, dtype, endianness): 87 | 88 | data_size = cp.dtype(dtype).itemsize // binary.dtype.itemsize 89 | 90 | out_size = binary.shape[0] // data_size 91 | 92 | out = cp.empty_like(binary, dtype=dtype, shape=out_size) 93 | 94 | if endianness == "B": 95 | little = False 96 | else: 97 | little = True 98 | 99 | threadsperblock, blockspergrid = _get_tpb_bpg() 100 | 101 | k_type = "unpack" 102 | 103 | _populate_kernel_cache(out.dtype, k_type) 104 | 105 | kernel = _get_backend_kernel( 106 | out.dtype, 107 | blockspergrid, 108 | threadsperblock, 109 | k_type, 110 | ) 111 | 112 | kernel(out_size, little, binary, out) 113 | 114 | _print_atts(kernel) 115 | 116 | # Remove binary data 117 | del binary 118 | 119 | return out 120 | -------------------------------------------------------------------------------- /python/cusignal/io/_writer_cuda.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | import cupy as cp 21 | 22 | from ..utils._caches import _cupy_kernel_cache 23 | from ..utils.helper_tools import _get_function, _get_tpb_bpg, _print_atts 24 | 25 | _SUPPORTED_TYPES = [ 26 | "int8", 27 | "uint8", 28 | "int16", 29 | "uint16", 30 | "int32", 31 | "uint32", 32 | "float32", 33 | "float64", 34 | "complex64", 35 | "complex128", 36 | ] 37 | 38 | 39 | class _cupy_pack_wrapper(object): 40 | def __init__(self, grid, block, kernel): 41 | if isinstance(grid, int): 42 | grid = (grid,) 43 | if isinstance(block, int): 44 | block = (block,) 45 | 46 | self.grid = grid 47 | self.block = block 48 | self.kernel = kernel 49 | 50 | def __call__(self, out_size, binary, out): 51 | 52 | kernel_args = (out_size, binary, out) 53 | 54 | self.kernel(self.grid, self.block, kernel_args) 55 | 56 | 57 | def _populate_kernel_cache(np_type, k_type): 58 | 59 | if np_type not in _SUPPORTED_TYPES: 60 | raise ValueError("Datatype {} not found for '{}'".format(np_type, k_type)) 61 | 62 | if (str(np_type), k_type) in _cupy_kernel_cache: 63 | return 64 | 65 | _cupy_kernel_cache[(str(np_type), k_type)] = _get_function( 66 | "/io/_writer.fatbin", 67 | "_cupy_pack_" + str(np_type), 68 | ) 69 | 70 | 71 | def _get_backend_kernel( 72 | dtype, 73 | grid, 74 | block, 75 | k_type, 76 | ): 77 | 78 | kernel = _cupy_kernel_cache[(str(dtype), k_type)] 79 | if kernel: 80 | return _cupy_pack_wrapper(grid, block, kernel) 81 | else: 82 | raise ValueError("Kernel {} not found in _cupy_kernel_cache".format(k_type)) 83 | 84 | 85 | def _pack(binary): 86 | 87 | data_size = binary.dtype.itemsize * binary.shape[0] 88 | out_size = data_size 89 | 90 | out = cp.empty_like(binary, dtype=cp.ubyte, shape=out_size) 91 | 92 | threadsperblock, blockspergrid = _get_tpb_bpg() 93 | 94 | k_type = "pack" 95 | 96 | _populate_kernel_cache(out.dtype, k_type) 97 | 98 | kernel = _get_backend_kernel( 99 | out.dtype, 100 | blockspergrid, 101 | threadsperblock, 102 | k_type, 103 | ) 104 | 105 | kernel(out_size, binary, out) 106 | 107 | _print_atts(kernel) 108 | 109 | # Remove binary data 110 | del binary 111 | 112 | return out 113 | -------------------------------------------------------------------------------- /python/cusignal/io/writer.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | import cupy as cp 22 | 23 | from ._writer_cuda import _pack 24 | 25 | 26 | def write_bin(file, binary, buffer=None, append=True): 27 | """ 28 | Writes binary array to file. 29 | 30 | Parameters 31 | ---------- 32 | file : str 33 | A string of filename to store output. 34 | binary : ndarray 35 | Binary array to be written to file. 36 | buffer : ndarray, optional 37 | Pinned memory buffer to use when copying data from GPU. 38 | append : bool, optional 39 | Append to file if created. 40 | 41 | Returns 42 | ------- 43 | out : ndarray 44 | An 1-dimensional array containing binary data. 45 | 46 | """ 47 | 48 | # Get current stream, default or not. 49 | stream = cp.cuda.get_current_stream() 50 | 51 | if buffer is None: 52 | buffer = cp.asnumpy(binary) 53 | else: 54 | binary.get(out=buffer) 55 | 56 | if append is True: 57 | mode = "ab" 58 | else: 59 | mode = "wb" 60 | 61 | with open(file, mode) as f: 62 | stream.synchronize() 63 | buffer.tofile(f) 64 | 65 | 66 | def pack_bin(in1): 67 | """ 68 | Pack binary arrary. 69 | Data will be packed with little endian for NVIDIA GPU compatibility. 70 | 71 | Parameters 72 | ---------- 73 | in1 : ndarray 74 | The ndarray to be pack at binary. 75 | 76 | Returns 77 | ------- 78 | out : ndarray 79 | An 1-dimensional array containing packed binary data. 80 | 81 | """ 82 | 83 | out = _pack(in1) 84 | 85 | return out 86 | 87 | 88 | def write_sigmf(data_file, data, buffer=None, append=True): 89 | """ 90 | Pack and write binary array to file, with SigMF spec. 91 | 92 | Parameters 93 | ---------- 94 | file : str 95 | A string of filename to be read/unpacked to GPU. 96 | binary : ndarray 97 | Binary array to be written to file. 98 | buffer : ndarray, optional 99 | Pinned memory buffer to use when copying data from GPU. 100 | append : bool, optional 101 | Append to file if created. 102 | 103 | Returns 104 | ------- 105 | 106 | """ 107 | 108 | packed = pack_bin(data) 109 | 110 | write_bin(data_file, packed, buffer, append) 111 | -------------------------------------------------------------------------------- /python/cusignal/peak_finding/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | from cusignal.peak_finding.peak_finding import argrelextrema, argrelmax, argrelmin 22 | -------------------------------------------------------------------------------- /python/cusignal/peak_finding/_peak_finding_cuda.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | import cupy as cp 22 | 23 | from ..convolution.convolution_utils import _iDivUp 24 | from ..utils._caches import _cupy_kernel_cache 25 | from ..utils.helper_tools import _get_function, _get_tpb_bpg, _print_atts 26 | 27 | _modedict = { 28 | cp.less: 0, 29 | cp.greater: 1, 30 | cp.less_equal: 2, 31 | cp.greater_equal: 3, 32 | cp.equal: 4, 33 | cp.not_equal: 5, 34 | } 35 | 36 | _SUPPORTED_TYPES = [ 37 | "int32", 38 | "int64", 39 | "float32", 40 | "float64", 41 | ] 42 | 43 | 44 | class _cupy_boolrelextrema_1d_wrapper(object): 45 | def __init__(self, grid, block, kernel): 46 | if isinstance(grid, int): 47 | grid = (grid,) 48 | if isinstance(block, int): 49 | block = (block,) 50 | 51 | self.grid = grid 52 | self.block = block 53 | self.kernel = kernel 54 | 55 | def __call__( 56 | self, 57 | data, 58 | comp, 59 | axis, 60 | order, 61 | clip, 62 | out, 63 | ): 64 | 65 | kernel_args = (data.shape[axis], order, clip, comp, data, out) 66 | 67 | self.kernel(self.grid, self.block, kernel_args) 68 | 69 | 70 | class _cupy_boolrelextrema_2d_wrapper(object): 71 | def __init__(self, grid, block, kernel): 72 | if isinstance(grid, int): 73 | grid = (grid,) 74 | if isinstance(block, int): 75 | block = (block,) 76 | 77 | self.grid = grid 78 | self.block = block 79 | self.kernel = kernel 80 | 81 | def __call__( 82 | self, 83 | data, 84 | comp, 85 | axis, 86 | order, 87 | clip, 88 | out, 89 | ): 90 | 91 | kernel_args = ( 92 | data.shape[1], 93 | data.shape[0], 94 | order, 95 | clip, 96 | comp, 97 | axis, 98 | data, 99 | out, 100 | ) 101 | 102 | self.kernel(self.grid, self.block, kernel_args) 103 | 104 | 105 | def _populate_kernel_cache(np_type, k_type): 106 | 107 | if np_type not in _SUPPORTED_TYPES: 108 | raise ValueError("Datatype {} not found for '{}'".format(np_type, k_type)) 109 | 110 | if (str(np_type), k_type) in _cupy_kernel_cache: 111 | return 112 | 113 | _cupy_kernel_cache[(str(np_type), k_type)] = _get_function( 114 | "/peak_finding/_peak_finding.fatbin", 115 | "_cupy_" + k_type + "_" + str(np_type), 116 | ) 117 | 118 | 119 | def _get_backend_kernel(dtype, grid, block, k_type): 120 | 121 | kernel = _cupy_kernel_cache[(str(dtype), k_type)] 122 | if kernel: 123 | if k_type == "boolrelextrema_1D": 124 | return _cupy_boolrelextrema_1d_wrapper(grid, block, kernel) 125 | else: 126 | return _cupy_boolrelextrema_2d_wrapper(grid, block, kernel) 127 | else: 128 | raise ValueError("Kernel {} not found in _cupy_kernel_cache".format(k_type)) 129 | 130 | 131 | def _peak_finding(data, comparator, axis, order, mode, results): 132 | 133 | comp = _modedict[comparator] 134 | 135 | if mode == "clip": 136 | clip = True 137 | else: 138 | clip = False 139 | 140 | if data.ndim == 1: 141 | k_type = "boolrelextrema_1D" 142 | 143 | threadsperblock, blockspergrid = _get_tpb_bpg() 144 | 145 | _populate_kernel_cache(data.dtype, k_type) 146 | 147 | kernel = _get_backend_kernel( 148 | data.dtype, 149 | blockspergrid, 150 | threadsperblock, 151 | k_type, 152 | ) 153 | else: 154 | k_type = "boolrelextrema_2D" 155 | 156 | threadsperblock = (16, 16) 157 | blockspergrid = ( 158 | _iDivUp(data.shape[1], threadsperblock[0]), 159 | _iDivUp(data.shape[0], threadsperblock[1]), 160 | ) 161 | 162 | _populate_kernel_cache(data.dtype, k_type) 163 | 164 | kernel = _get_backend_kernel( 165 | data.dtype, 166 | blockspergrid, 167 | threadsperblock, 168 | k_type, 169 | ) 170 | 171 | kernel(data, comp, axis, order, clip, results) 172 | 173 | _print_atts(kernel) 174 | -------------------------------------------------------------------------------- /python/cusignal/radartools/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | from cusignal.radartools.beamformers import mvdr 22 | from cusignal.radartools.radartools import ( 23 | ambgfun, 24 | ca_cfar, 25 | cfar_alpha, 26 | pulse_compression, 27 | pulse_doppler, 28 | ) 29 | -------------------------------------------------------------------------------- /python/cusignal/radartools/beamformers.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | import cupy as cp 22 | 23 | 24 | def mvdr(x, sv, calc_cov=True): 25 | """ 26 | Minimum variance distortionless response (MVDR) beamformer weights 27 | 28 | Parameters 29 | ---------- 30 | x : ndarray 31 | Received signal or input covariance matrix, assume 2D array with 32 | size [num_sensors, num_samples] 33 | 34 | sv: ndarray 35 | Steering vector, assume 1D array with size [num_sensors, 1] 36 | 37 | calc_cov : bool 38 | Determine whether to calculate covariance matrix. Simply put, calc_cov 39 | defines whether x input is made of sensor/observation data or is 40 | a precalculated covariance matrix 41 | 42 | Note: Unlike MATLAB where input matrix x is of size MxN where N represents 43 | the number of array elements, we assume row-major formatted data where each 44 | row is assumed to be complex-valued data from a given sensor (i.e. NxM) 45 | """ 46 | if x.shape[0] > x.shape[1]: 47 | raise ValueError( 48 | "Matrix has more sensors than samples. Consider \ 49 | transposing and remember cuSignal is row-major, unlike MATLAB" 50 | ) 51 | 52 | if x.shape[0] != sv.shape[0]: 53 | raise ValueError("Steering Vector and input data do not align") 54 | 55 | if calc_cov: 56 | R = cp.cov(x) 57 | else: 58 | R = cp.asarray(x) 59 | 60 | R_inv = cp.linalg.inv(R) 61 | svh = cp.transpose(cp.conj(sv)) 62 | 63 | wB = cp.matmul(R_inv, sv) 64 | # wA is a 1x1 scalar 65 | wA = cp.matmul(svh, wB) 66 | w = wB / wA 67 | 68 | return w 69 | -------------------------------------------------------------------------------- /python/cusignal/spectral_analysis/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | from cusignal.spectral_analysis.spectral import ( 22 | coherence, 23 | csd, 24 | istft, 25 | lombscargle, 26 | periodogram, 27 | spectrogram, 28 | stft, 29 | vectorstrength, 30 | welch, 31 | ) 32 | -------------------------------------------------------------------------------- /python/cusignal/spectral_analysis/_spectral_cuda.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | 22 | from ..utils._caches import _cupy_kernel_cache 23 | from ..utils.helper_tools import _get_function, _get_tpb_bpg, _print_atts 24 | 25 | _SUPPORTED_TYPES = ["float32", "float64"] 26 | 27 | 28 | class _cupy_lombscargle_wrapper(object): 29 | def __init__(self, grid, block, kernel): 30 | if isinstance(grid, int): 31 | grid = (grid,) 32 | if isinstance(block, int): 33 | block = (block,) 34 | 35 | self.grid = grid 36 | self.block = block 37 | self.kernel = kernel 38 | 39 | def __call__( 40 | self, 41 | x, 42 | y, 43 | freqs, 44 | pgram, 45 | y_dot, 46 | ): 47 | 48 | kernel_args = ( 49 | x.shape[0], 50 | freqs.shape[0], 51 | x, 52 | y, 53 | freqs, 54 | pgram, 55 | y_dot, 56 | ) 57 | 58 | self.kernel(self.grid, self.block, kernel_args) 59 | 60 | 61 | def _populate_kernel_cache(np_type, k_type): 62 | 63 | if np_type not in _SUPPORTED_TYPES: 64 | raise ValueError("Datatype {} not found for '{}'".format(np_type, k_type)) 65 | 66 | if (str(np_type), k_type) in _cupy_kernel_cache: 67 | return 68 | 69 | _cupy_kernel_cache[(str(np_type), k_type)] = _get_function( 70 | "/spectral_analysis/_spectral.fatbin", 71 | "_cupy_" + k_type + "_" + str(np_type), 72 | ) 73 | 74 | 75 | def _get_backend_kernel(dtype, grid, block, k_type): 76 | 77 | kernel = _cupy_kernel_cache[(str(dtype), k_type)] 78 | if kernel: 79 | return _cupy_lombscargle_wrapper(grid, block, kernel) 80 | else: 81 | raise ValueError("Kernel {} not found in _cupy_kernel_cache".format(k_type)) 82 | 83 | 84 | def _lombscargle(x, y, freqs, pgram, y_dot): 85 | 86 | threadsperblock, blockspergrid = _get_tpb_bpg() 87 | 88 | k_type = "lombscargle" 89 | 90 | _populate_kernel_cache(pgram.dtype, k_type) 91 | 92 | kernel = _get_backend_kernel( 93 | pgram.dtype, 94 | blockspergrid, 95 | threadsperblock, 96 | k_type, 97 | ) 98 | 99 | kernel(x, y, freqs, pgram, y_dot) 100 | 101 | _print_atts(kernel) 102 | -------------------------------------------------------------------------------- /python/cusignal/test/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | import cupy as cp 22 | import numpy as np 23 | import pytest 24 | 25 | # Fixtures with (scope="session") will execute once 26 | # and be shared will all tests that need it. 27 | 28 | 29 | def pytest_configure(config): 30 | config.addinivalue_line("markers", "cpu: mark CPU test cases") 31 | 32 | 33 | # Generate data for using range 34 | @pytest.fixture(scope="session") 35 | def range_data_gen(): 36 | def _generate(num_samps, endpoint=False): 37 | 38 | cpu_sig = np.arange(num_samps) 39 | gpu_sig = cp.asarray(cpu_sig) 40 | 41 | return cpu_sig, gpu_sig 42 | 43 | return _generate 44 | 45 | 46 | # Generate data for using linspace 47 | @pytest.fixture(scope="session") 48 | def linspace_data_gen(): 49 | def _generate(start, stop, num_samps, endpoint=False, dtype=np.float64): 50 | 51 | cpu_time = np.linspace(start, stop, num_samps, endpoint, dtype=dtype) 52 | cpu_sig = np.cos(-(cpu_time**2) / 6.0) 53 | gpu_sig = cp.asarray(cpu_sig) 54 | 55 | return cpu_sig, gpu_sig 56 | 57 | return _generate 58 | 59 | 60 | # Generate data for using linspace 61 | @pytest.fixture(scope="session") 62 | def linspace_range_gen(): 63 | def _generate(num_samps): 64 | 65 | cpu_sig = np.arange(num_samps) / num_samps 66 | gpu_sig = cp.asarray(cpu_sig) 67 | 68 | return cpu_sig, gpu_sig 69 | 70 | return _generate 71 | 72 | 73 | # Generate array with random data 74 | @pytest.fixture(scope="session") 75 | def rand_data_gen(): 76 | def _generate(num_samps, dim=1, dtype=np.float64): 77 | 78 | if dtype is np.float32 or dtype is np.float64: 79 | inp = tuple(np.ones(dim, dtype=int) * num_samps) 80 | cpu_sig = np.random.random(inp) 81 | cpu_sig = cpu_sig.astype(dtype) 82 | gpu_sig = cp.asarray(cpu_sig) 83 | else: 84 | inp = tuple(np.ones(dim, dtype=int) * num_samps) 85 | cpu_sig = np.random.random(inp) + 1j * np.random.random(inp) 86 | cpu_sig = cpu_sig.astype(dtype) 87 | gpu_sig = cp.asarray(cpu_sig) 88 | 89 | return cpu_sig, gpu_sig 90 | 91 | return _generate 92 | 93 | 94 | # Generate time array with linspace 95 | @pytest.fixture(scope="session") 96 | def time_data_gen(): 97 | def _generate(start, stop, num_samps): 98 | 99 | cpu_sig = np.linspace(start, stop, num_samps) 100 | gpu_sig = cp.asarray(cpu_sig) 101 | 102 | return cpu_sig, gpu_sig 103 | 104 | return _generate 105 | 106 | 107 | # Generate input for lombscargle 108 | @pytest.fixture(scope="session") 109 | def lombscargle_gen(rand_data_gen): 110 | def _generate(num_in_samps, num_out_samps): 111 | 112 | A = 2.0 113 | w = 1.0 114 | phi = 0.5 * np.pi 115 | frac_points = 0.9 # Fraction of points to select 116 | 117 | r, _ = rand_data_gen(num_in_samps, 1) 118 | cpu_x = np.linspace(0.01, 10 * np.pi, num_in_samps) 119 | 120 | cpu_x = cpu_x[r >= frac_points] 121 | 122 | cpu_y = A * np.cos(w * cpu_x + phi) 123 | 124 | cpu_f = np.linspace(0.01, 10, num_out_samps) 125 | 126 | gpu_x = cp.asarray(cpu_x) 127 | gpu_y = cp.asarray(cpu_y) 128 | gpu_f = cp.asarray(cpu_f) 129 | 130 | return cpu_x, cpu_y, cpu_f, gpu_x, gpu_y, gpu_f 131 | 132 | return _generate 133 | -------------------------------------------------------------------------------- /python/cusignal/test/io/test_bin.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | import cupy as cp 22 | 23 | import cusignal 24 | 25 | 26 | def test_read_paged(tmpdir): 27 | data_fname = tmpdir.join("test_read.sigmf-data") 28 | 29 | actual = cp.random.rand(100).astype(cp.complex64) 30 | actual.tofile(data_fname) 31 | 32 | expect = cusignal.read_bin(str(data_fname), dtype=cp.complex64) 33 | 34 | cp.testing.assert_array_equal(actual, expect) 35 | 36 | 37 | def test_read_pinned_buffer(tmpdir): 38 | data_fname = tmpdir.join("test_read.sigmf-data") 39 | 40 | actual = cp.random.rand(100).astype(cp.complex64) 41 | actual.tofile(data_fname) 42 | 43 | binary = cusignal.read_bin(str(data_fname), dtype=cp.complex64) 44 | buffer = cusignal.get_pinned_mem(binary.shape, cp.complex64) 45 | 46 | expect = cusignal.read_bin(str(data_fname), buffer, dtype=cp.complex64) 47 | 48 | cp.testing.assert_array_equal(actual, expect) 49 | 50 | 51 | def test_read_shared_buffer(tmpdir): 52 | data_fname = tmpdir.join("test_read.sigmf-data") 53 | 54 | actual = cp.random.rand(100).astype(cp.complex64) 55 | actual.tofile(data_fname) 56 | 57 | binary = cusignal.read_bin(str(data_fname), dtype=cp.complex64) 58 | buffer = cusignal.get_shared_mem(binary.shape, cp.complex64) 59 | 60 | expect = cusignal.read_bin(str(data_fname), buffer, dtype=cp.complex64) 61 | 62 | cp.testing.assert_array_equal(actual, expect) 63 | 64 | 65 | def test_write_paged(tmpdir): 66 | data_fname = tmpdir.join("test_read.sigmf-data") 67 | 68 | actual = cp.random.rand(100).astype(cp.complex64) 69 | 70 | cusignal.write_bin(str(data_fname), actual) 71 | 72 | expect = cusignal.read_bin(str(data_fname), dtype=cp.complex64) 73 | 74 | cp.testing.assert_array_equal(actual, expect) 75 | 76 | 77 | def test_write_pinned_buffer(tmpdir): 78 | data_fname = tmpdir.join("test_read.sigmf-data") 79 | 80 | actual = cp.random.rand(100).astype(cp.complex64) 81 | 82 | cusignal.write_bin(str(data_fname), actual) 83 | 84 | binary = cusignal.read_bin(str(data_fname), dtype=cp.complex64) 85 | buffer = cusignal.get_pinned_mem(binary.shape, cp.complex64) 86 | 87 | cusignal.write_bin(str(data_fname), actual, buffer=buffer, append=False) 88 | 89 | expect = cusignal.read_bin(str(data_fname), buffer=buffer) 90 | 91 | cp.testing.assert_array_equal(actual, expect) 92 | 93 | 94 | def test_write_shared_buffer(tmpdir): 95 | data_fname = tmpdir.join("test_read.sigmf-data") 96 | 97 | actual = cp.random.rand(100).astype(cp.complex64) 98 | 99 | cusignal.write_bin(str(data_fname), actual) 100 | 101 | binary = cusignal.read_bin(str(data_fname), dtype=cp.complex64) 102 | buffer = cusignal.get_shared_mem(binary.shape, cp.complex64) 103 | 104 | cusignal.write_bin(str(data_fname), actual, buffer=buffer, append=False) 105 | 106 | expect = cusignal.read_bin(str(data_fname), buffer=buffer) 107 | 108 | cp.testing.assert_array_equal(actual, expect) 109 | -------------------------------------------------------------------------------- /python/cusignal/test/io/test_sigmf.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | import json 22 | 23 | import cupy as cp 24 | 25 | import cusignal 26 | 27 | 28 | def test_read_paged(tmpdir): 29 | data_fname = tmpdir.join("test_read.sigmf-data") 30 | meta_fname = tmpdir.join("test_read.sigmf-meta") 31 | 32 | actual = cp.random.rand(100).astype(cp.complex64) 33 | meta = {"core:datatype": "cf32"} 34 | 35 | actual.tofile(data_fname) 36 | meta_fname.write(json.dumps(meta)) 37 | 38 | expect = cusignal.read_sigmf(str(data_fname), str(meta_fname)) 39 | 40 | cp.testing.assert_array_equal(actual, expect) 41 | 42 | 43 | def test_read_pinned_buffer(tmpdir): 44 | data_fname = tmpdir.join("test_read.sigmf-data") 45 | meta_fname = tmpdir.join("test_read.sigmf-meta") 46 | 47 | actual = cp.random.rand(100).astype(cp.complex64) 48 | meta = {"core:datatype": "cf32"} 49 | 50 | actual.tofile(data_fname) 51 | meta_fname.write(json.dumps(meta)) 52 | 53 | binary = cusignal.read_bin(str(data_fname)) 54 | buffer = cusignal.get_pinned_mem(binary.shape, cp.ubyte) 55 | 56 | expect = cusignal.read_sigmf(str(data_fname), str(meta_fname), buffer) 57 | 58 | cp.testing.assert_array_equal(actual, expect) 59 | 60 | 61 | def test_read_shared_buffer(tmpdir): 62 | data_fname = tmpdir.join("test_read.sigmf-data") 63 | meta_fname = tmpdir.join("test_read.sigmf-meta") 64 | 65 | actual = cp.random.rand(100).astype(cp.complex64) 66 | meta = {"core:datatype": "cf32"} 67 | 68 | actual.tofile(data_fname) 69 | meta_fname.write(json.dumps(meta)) 70 | 71 | binary = cusignal.read_bin(str(data_fname)) 72 | buffer = cusignal.get_shared_mem(binary.shape, cp.ubyte) 73 | 74 | expect = cusignal.read_sigmf(str(data_fname), str(meta_fname), buffer) 75 | 76 | cp.testing.assert_array_equal(actual, expect) 77 | 78 | 79 | def test_write_paged(tmpdir): 80 | data_fname = tmpdir.join("test_read.sigmf-data") 81 | meta_fname = tmpdir.join("test_read.sigmf-meta") 82 | 83 | actual = cp.random.rand(100).astype(cp.complex64) 84 | meta = {"core:datatype": "cf32"} 85 | 86 | cusignal.write_sigmf(str(data_fname), actual) 87 | meta_fname.write(json.dumps(meta)) 88 | 89 | expect = cusignal.read_sigmf(str(data_fname), str(meta_fname)) 90 | 91 | cp.testing.assert_array_equal(actual, expect) 92 | 93 | 94 | def test_write_pinned_buffer(tmpdir): 95 | data_fname = tmpdir.join("test_read.sigmf-data") 96 | meta_fname = tmpdir.join("test_read.sigmf-meta") 97 | 98 | actual = cp.random.rand(100).astype(cp.complex64) 99 | meta = {"core:datatype": "cf32"} 100 | 101 | cusignal.write_bin(str(data_fname), actual) 102 | meta_fname.write(json.dumps(meta)) 103 | 104 | binary = cusignal.read_bin(str(data_fname)) 105 | buffer = cusignal.get_pinned_mem(binary.shape, cp.ubyte) 106 | 107 | cusignal.write_sigmf(str(data_fname), actual, buffer=buffer, append=False) 108 | 109 | expect = cusignal.read_sigmf(str(data_fname), str(meta_fname)) 110 | 111 | cp.testing.assert_array_equal(actual, expect) 112 | 113 | 114 | def test_write_shared_buffer(tmpdir): 115 | data_fname = tmpdir.join("test_read.sigmf-data") 116 | meta_fname = tmpdir.join("test_read.sigmf-meta") 117 | 118 | actual = cp.random.rand(100).astype(cp.complex64) 119 | meta = {"core:datatype": "cf32"} 120 | 121 | cusignal.write_bin(str(data_fname), actual) 122 | meta_fname.write(json.dumps(meta)) 123 | 124 | binary = cusignal.read_bin(str(data_fname)) 125 | buffer = cusignal.get_shared_mem(binary.shape, cp.ubyte) 126 | 127 | cusignal.write_sigmf(str(data_fname), actual, buffer=buffer, append=False) 128 | 129 | expect = cusignal.read_sigmf(str(data_fname), str(meta_fname)) 130 | 131 | cp.testing.assert_array_equal(actual, expect) 132 | -------------------------------------------------------------------------------- /python/cusignal/test/test_arraytools.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | import cupy as cp 22 | import pytest 23 | 24 | import cusignal 25 | 26 | 27 | @pytest.mark.parametrize("dtype", [cp.ubyte, cp.complex64]) 28 | @pytest.mark.parametrize("shape", [1024, (32, 32)]) 29 | def test_get_pinned_mem(dtype, shape): 30 | arr = cusignal.get_pinned_mem(shape=shape, dtype=dtype) 31 | 32 | if isinstance(shape, int): 33 | shape = (shape,) 34 | 35 | assert arr.shape == shape 36 | assert arr.dtype == dtype 37 | -------------------------------------------------------------------------------- /python/cusignal/test/test_bsplines.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | import cupy as cp 22 | import pytest 23 | from scipy import signal 24 | 25 | import cusignal 26 | from cusignal.testing.utils import _check_rapids_pytest_benchmark, array_equal 27 | 28 | gpubenchmark = _check_rapids_pytest_benchmark() 29 | 30 | 31 | class TestBsplines: 32 | @pytest.mark.parametrize("x", [2**16]) 33 | @pytest.mark.parametrize("n", [1]) 34 | @pytest.mark.benchmark(group="GaussSpline") 35 | class TestGaussSpline: 36 | def cpu_version(self, x, n): 37 | return signal.gauss_spline(x, n) 38 | 39 | def gpu_version(self, d_x, n): 40 | with cp.cuda.Stream.null: 41 | out = cusignal.gauss_spline(d_x, n) 42 | cp.cuda.Stream.null.synchronize() 43 | return out 44 | 45 | @pytest.mark.cpu 46 | def test_gauss_spline_cpu(self, benchmark, rand_data_gen, x, n): 47 | 48 | cpu_sig, _ = rand_data_gen(x) 49 | benchmark(self.cpu_version, cpu_sig, n) 50 | 51 | def test_gauss_spline_gpu(self, gpubenchmark, rand_data_gen, x, n): 52 | 53 | cpu_sig, gpu_sig = rand_data_gen(x) 54 | output = gpubenchmark(self.gpu_version, gpu_sig, n) 55 | 56 | key = self.cpu_version(cpu_sig, n) 57 | array_equal(output, key) 58 | 59 | @pytest.mark.parametrize("x", [2**16]) 60 | @pytest.mark.benchmark(group="Cubic") 61 | class TestCubic: 62 | def cpu_version(self, x): 63 | return signal.cubic(x) 64 | 65 | def gpu_version(self, d_x): 66 | with cp.cuda.Stream.null: 67 | out = cusignal.cubic(d_x) 68 | cp.cuda.Stream.null.synchronize() 69 | return out 70 | 71 | @pytest.mark.cpu 72 | def test_cubic_cpu(self, benchmark, rand_data_gen, x): 73 | cpu_sig, _ = rand_data_gen(x) 74 | benchmark(self.cpu_version, cpu_sig) 75 | 76 | def test_cubic_gpu(self, gpubenchmark, rand_data_gen, x): 77 | 78 | cpu_sig, gpu_sig = rand_data_gen(x) 79 | output = gpubenchmark(self.gpu_version, gpu_sig) 80 | 81 | key = self.cpu_version(cpu_sig) 82 | array_equal(output, key) 83 | 84 | @pytest.mark.parametrize("x", [2**16]) 85 | @pytest.mark.benchmark(group="Quadratic") 86 | class TestQuadratic: 87 | def cpu_version(self, x): 88 | return signal.quadratic(x) 89 | 90 | def gpu_version(self, d_x): 91 | with cp.cuda.Stream.null: 92 | out = cusignal.quadratic(d_x) 93 | cp.cuda.Stream.null.synchronize() 94 | return out 95 | 96 | @pytest.mark.cpu 97 | def test_quadratic_cpu(self, benchmark, rand_data_gen, x): 98 | cpu_sig, _ = rand_data_gen(x) 99 | benchmark(self.cpu_version, cpu_sig) 100 | 101 | def test_quadratic_gpu(self, gpubenchmark, rand_data_gen, x): 102 | 103 | cpu_sig, gpu_sig = rand_data_gen(x) 104 | output = gpubenchmark(self.gpu_version, gpu_sig) 105 | 106 | key = self.cpu_version(cpu_sig) 107 | array_equal(output, key) 108 | -------------------------------------------------------------------------------- /python/cusignal/test/test_filters.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /python/cusignal/test/test_peak_finding.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | import cupy as cp 22 | import numpy as np 23 | import pytest 24 | from scipy import signal 25 | 26 | import cusignal 27 | from cusignal.testing.utils import _check_rapids_pytest_benchmark, array_equal 28 | 29 | gpubenchmark = _check_rapids_pytest_benchmark() 30 | 31 | 32 | class TestPeakFinding: 33 | @pytest.mark.benchmark(group="Argrelmin") 34 | @pytest.mark.parametrize("dim, num_samps", [(1, 2**15), (2, 2**8), (3, 2**5)]) 35 | @pytest.mark.parametrize("axis", [-1]) 36 | @pytest.mark.parametrize("order", [1, 2]) 37 | @pytest.mark.parametrize("mode", ["clip", "wrap"]) 38 | class TestArgrelmin: 39 | def cpu_version(self, sig, axis, order, mode): 40 | return signal.argrelmin(sig, axis, order, mode) 41 | 42 | def gpu_version(self, sig, axis, order, mode): 43 | with cp.cuda.Stream.null: 44 | out = cusignal.argrelmin(sig, axis, order, mode) 45 | cp.cuda.Stream.null.synchronize() 46 | return out 47 | 48 | @pytest.mark.cpu 49 | def test_argrelmin_cpu( 50 | self, rand_data_gen, benchmark, dim, num_samps, axis, order, mode 51 | ): 52 | cpu_sig, _ = rand_data_gen(num_samps, dim) 53 | benchmark(self.cpu_version, cpu_sig, axis, order, mode) 54 | 55 | def test_argrelmin_gpu( 56 | self, 57 | rand_data_gen, 58 | gpubenchmark, 59 | dim, 60 | num_samps, 61 | axis, 62 | order, 63 | mode, 64 | ): 65 | cpu_sig, gpu_sig = rand_data_gen(num_samps, dim) 66 | output = gpubenchmark(self.gpu_version, gpu_sig, axis, order, mode) 67 | key = self.cpu_version(cpu_sig, axis, order, mode) 68 | array_equal(output, key) 69 | 70 | @pytest.mark.benchmark(group="TestArgrelmax") 71 | @pytest.mark.parametrize("dim, num_samps", [(1, 2**15), (2, 2**8), (3, 2**5)]) 72 | @pytest.mark.parametrize("axis", [-1]) 73 | @pytest.mark.parametrize("order", [1, 2]) 74 | @pytest.mark.parametrize("mode", ["clip", "wrap"]) 75 | class TestArgrelmax: 76 | def cpu_version(self, sig, axis, order, mode): 77 | return signal.argrelmax(sig, axis, order, mode) 78 | 79 | def gpu_version(self, sig, axis, order, mode): 80 | with cp.cuda.Stream.null: 81 | out = cusignal.argrelmax(sig, axis, order, mode) 82 | cp.cuda.Stream.null.synchronize() 83 | return out 84 | 85 | @pytest.mark.cpu 86 | def test_argrelmax_cpu( 87 | self, rand_data_gen, benchmark, dim, num_samps, axis, order, mode 88 | ): 89 | cpu_sig, _ = rand_data_gen(num_samps, dim) 90 | benchmark(self.cpu_version, cpu_sig, axis, order, mode) 91 | 92 | def test_argrelmax_gpu( 93 | self, 94 | rand_data_gen, 95 | gpubenchmark, 96 | dim, 97 | num_samps, 98 | axis, 99 | order, 100 | mode, 101 | ): 102 | cpu_sig, gpu_sig = rand_data_gen(num_samps, dim) 103 | output = gpubenchmark(self.gpu_version, gpu_sig, axis, order, mode) 104 | key = self.cpu_version(cpu_sig, axis, order, mode) 105 | array_equal(output, key) 106 | 107 | @pytest.mark.benchmark(group="Argrelextrema") 108 | @pytest.mark.parametrize("dim, num_samps", [(1, 2**15), (2, 2**8), (3, 2**5)]) 109 | @pytest.mark.parametrize("axis", [-1]) 110 | @pytest.mark.parametrize("order", [1, 2]) 111 | @pytest.mark.parametrize("mode", ["clip", "wrap"]) 112 | class TestArgrelextrema: 113 | def cpu_version(self, sig, axis, order, mode): 114 | return signal.argrelextrema(sig, np.less, axis, order, mode) 115 | 116 | def gpu_version(self, sig, axis, order, mode): 117 | with cp.cuda.Stream.null: 118 | out = cusignal.argrelextrema(sig, cp.less, axis, order, mode) 119 | cp.cuda.Stream.null.synchronize() 120 | return out 121 | 122 | @pytest.mark.cpu 123 | def test_argrelextrema_cpu( 124 | self, 125 | rand_data_gen, 126 | benchmark, 127 | dim, 128 | num_samps, 129 | axis, 130 | order, 131 | mode, 132 | ): 133 | cpu_sig, _ = rand_data_gen(num_samps, dim) 134 | benchmark(self.cpu_version, cpu_sig, axis, order, mode) 135 | 136 | def test_argrelextrema_gpu( 137 | self, 138 | rand_data_gen, 139 | gpubenchmark, 140 | dim, 141 | num_samps, 142 | axis, 143 | order, 144 | mode, 145 | ): 146 | cpu_sig, gpu_sig = rand_data_gen(num_samps, dim) 147 | output = gpubenchmark(self.gpu_version, gpu_sig, axis, order, mode) 148 | key = self.cpu_version(cpu_sig, axis, order, mode) 149 | array_equal(output, key) 150 | -------------------------------------------------------------------------------- /python/cusignal/test/test_radartools.py: -------------------------------------------------------------------------------- 1 | import cupy as cp 2 | import pytest 3 | from numpy import vectorize 4 | 5 | from cusignal.radartools import ca_cfar, cfar_alpha 6 | from cusignal.testing.utils import array_equal 7 | 8 | 9 | class TestCaCfar: 10 | @pytest.mark.benchmark(group="CFAR") 11 | @pytest.mark.parametrize( 12 | "length, guard_cells, reference_cells", [(100, 1, 5), (11, 2, 3), (100, 10, 20)] 13 | ) 14 | class TestOneD: 15 | def expected(self, length, guard_cells, reference_cells): 16 | out = cp.zeros(length) 17 | N = 2 * reference_cells 18 | alpha = cfar_alpha(0.001, N) 19 | out[ 20 | guard_cells + reference_cells : -guard_cells - reference_cells 21 | ] = cp.ones(length - 2 * guard_cells - 2 * reference_cells) 22 | return alpha * out 23 | 24 | def test_1d_ones(self, length, guard_cells, reference_cells): 25 | array = cp.ones(length) 26 | mask, _ = ca_cfar(array, guard_cells, reference_cells) 27 | key = self.expected(length, guard_cells, reference_cells) 28 | array_equal(mask, key) 29 | 30 | @pytest.mark.parametrize( 31 | "length, gc, rc", [(1, 1, 1), (10, 2, 3), (10, 0, 5), (10, 5, 0)] 32 | ) 33 | class TestFailuresOneD: 34 | def test_1d_failures(self, length, gc, rc): 35 | with pytest.raises(ValueError): 36 | _, _ = ca_cfar(cp.zeros(length), gc, rc) 37 | 38 | @pytest.mark.benchmark(group="CFAR") 39 | @pytest.mark.parametrize( 40 | "shape, gc, rc", [((10, 10), (1, 1), (2, 2)), ((10, 100), (1, 10), (2, 20))] 41 | ) 42 | class TestTwoD: 43 | def expected(self, shape, gc, rc): 44 | out = cp.zeros(shape) 45 | N = 2 * rc[0] * (2 * rc[1] + 2 * gc[1] + 1) 46 | N += 2 * (2 * gc[0] + 1) * rc[1] 47 | alpha = cfar_alpha(0.001, N) 48 | out[ 49 | gc[0] + rc[0] : -gc[0] - rc[0], gc[1] + rc[1] : -gc[1] - rc[1] 50 | ] = cp.ones( 51 | (shape[0] - 2 * gc[0] - 2 * rc[0], shape[1] - 2 * gc[1] - 2 * rc[1]) 52 | ) 53 | return alpha * out 54 | 55 | def test_2d_ones(self, shape, gc, rc): 56 | array = cp.ones(shape) 57 | mask, _ = ca_cfar(array, gc, rc) 58 | key = self.expected(shape, gc, rc) 59 | array_equal(mask, key) 60 | 61 | @pytest.mark.parametrize( 62 | "shape, gc, rc", 63 | [ 64 | ((3, 3), (1, 2), (1, 10)), 65 | ((3, 3), (1, 1), (10, 1)), 66 | ((5, 5), (3, 3), (3, 3)), 67 | ], 68 | ) 69 | class TestFailuresTwoD: 70 | def test_2d_failures(self, shape, gc, rc): 71 | with pytest.raises(ValueError): 72 | _, _ = ca_cfar(cp.zeros(shape), gc, rc) 73 | 74 | @pytest.mark.parametrize( 75 | "shape, gc, rc, points", 76 | [ 77 | (10, 1, 1, (6,)), 78 | (100, 10, 20, (34, 67)), 79 | ((100, 200), (5, 10), (10, 20), [(31, 45), (50, 111)]), 80 | ], 81 | ) 82 | class TestDetection: 83 | def test_point_detection(self, shape, gc, rc, points): 84 | """ 85 | Placing points too close together can yield unexpected results. 86 | """ 87 | array = cp.zeros(shape) 88 | for point in points: 89 | array[point] = 1e3 90 | threshold, detections = ca_cfar(array, gc, rc) 91 | key = array - threshold 92 | f = vectorize(lambda x: True if x > 0 else False) 93 | key = f(key.get()) 94 | array_equal(detections, key) 95 | -------------------------------------------------------------------------------- /python/cusignal/test/test_wavelets.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | import cupy as cp 22 | import numpy as np 23 | import pytest 24 | from scipy import signal 25 | 26 | import cusignal 27 | from cusignal.testing.utils import _check_rapids_pytest_benchmark, array_equal 28 | 29 | gpubenchmark = _check_rapids_pytest_benchmark() 30 | 31 | 32 | class TestWavelets: 33 | @pytest.mark.benchmark(group="Qmf") 34 | @pytest.mark.parametrize("num_samps", [2**14]) 35 | class TestQmf: 36 | def cpu_version(self, sig): 37 | return signal.qmf(sig) 38 | 39 | def gpu_version(self, sig): 40 | with cp.cuda.Stream.null: 41 | out = cusignal.qmf(sig) 42 | cp.cuda.Stream.null.synchronize() 43 | return out 44 | 45 | @pytest.mark.cpu 46 | def test_qmf_cpu(self, range_data_gen, benchmark, num_samps): 47 | cpu_sig, _ = range_data_gen(num_samps) 48 | benchmark(self.cpu_version, cpu_sig) 49 | 50 | def test_qmf_gpu(self, range_data_gen, gpubenchmark, num_samps): 51 | 52 | cpu_sig, gpu_sig = range_data_gen(num_samps) 53 | output = gpubenchmark(self.gpu_version, gpu_sig) 54 | 55 | key = self.cpu_version(cpu_sig) 56 | array_equal(output, key) 57 | 58 | @pytest.mark.benchmark(group="Morlet") 59 | @pytest.mark.parametrize("num_samps", [2**14]) 60 | class TestMorlet: 61 | def cpu_version(self, num_samps): 62 | return signal.morlet(num_samps) 63 | 64 | def gpu_version(self, num_samps): 65 | with cp.cuda.Stream.null: 66 | out = cusignal.morlet(num_samps) 67 | cp.cuda.Stream.null.synchronize() 68 | return out 69 | 70 | @pytest.mark.cpu 71 | def test_morlet_cpu(self, benchmark, num_samps): 72 | benchmark(self.cpu_version, num_samps) 73 | 74 | def test_morlet_gpu(self, gpubenchmark, num_samps): 75 | 76 | output = gpubenchmark(self.gpu_version, num_samps) 77 | 78 | key = self.cpu_version(num_samps) 79 | array_equal(output, key) 80 | 81 | @pytest.mark.benchmark(group="Ricker") 82 | @pytest.mark.parametrize("num_samps", [2**14]) 83 | @pytest.mark.parametrize("a", [10, 1000]) 84 | class TestRicker: 85 | def cpu_version(self, num_samps, a): 86 | return signal.ricker(num_samps, a) 87 | 88 | def gpu_version(self, num_samps, a): 89 | with cp.cuda.Stream.null: 90 | out = cusignal.ricker(num_samps, a) 91 | cp.cuda.Stream.null.synchronize() 92 | return out 93 | 94 | @pytest.mark.cpu 95 | def test_ricker_cpu(self, benchmark, num_samps, a): 96 | benchmark(self.cpu_version, num_samps, a) 97 | 98 | def test_ricker_gpu(self, gpubenchmark, num_samps, a): 99 | 100 | output = gpubenchmark(self.gpu_version, num_samps, a) 101 | 102 | key = self.cpu_version(num_samps, a) 103 | array_equal(output, key) 104 | 105 | @pytest.mark.benchmark(group="Morlet2") 106 | @pytest.mark.parametrize("num_samps", [2**14]) 107 | @pytest.mark.parametrize("s", [10, 1000]) 108 | class TestMorlet2: 109 | def cpu_version(self, num_samps, s): 110 | return signal.morlet2(num_samps, s) 111 | 112 | def gpu_version(self, num_samps, s): 113 | with cp.cuda.Stream.null: 114 | out = cusignal.morlet2(num_samps, s) 115 | cp.cuda.Stream.null.synchronize() 116 | return out 117 | 118 | @pytest.mark.cpu 119 | def test_morlet2_cpu(self, benchmark, num_samps, s): 120 | benchmark(self.cpu_version, num_samps, s) 121 | 122 | def test_morlet2_gpu(self, gpubenchmark, num_samps, s): 123 | 124 | output = gpubenchmark(self.gpu_version, num_samps, s) 125 | 126 | key = self.cpu_version(num_samps, s) 127 | array_equal(output, key) 128 | 129 | @pytest.mark.benchmark(group="CWT") 130 | @pytest.mark.parametrize("dtype", [np.float64, np.complex128]) 131 | @pytest.mark.parametrize("num_samps", [2**14]) 132 | @pytest.mark.parametrize("widths", [31, 127]) 133 | class TestCWT: 134 | def cpu_version(self, sig, wavelet, widths): 135 | return signal.cwt(sig, wavelet, np.arange(1, widths)) 136 | 137 | def gpu_version(self, sig, wavelet, widths): 138 | with cp.cuda.Stream.null: 139 | out = cusignal.cwt(sig, wavelet, np.arange(1, widths)) 140 | cp.cuda.Stream.null.synchronize() 141 | return out 142 | 143 | @pytest.mark.cpu 144 | def test_cwt_cpu(self, rand_data_gen, benchmark, dtype, num_samps, widths): 145 | cpu_sig, _ = rand_data_gen(num_samps, 1, dtype) 146 | wavelet = signal.ricker 147 | benchmark(self.cpu_version, cpu_sig, wavelet, widths) 148 | 149 | def test_cwt_gpu(self, rand_data_gen, gpubenchmark, dtype, num_samps, widths): 150 | 151 | cpu_sig, gpu_sig = rand_data_gen(num_samps, 1, dtype) 152 | cu_wavelet = cusignal.ricker 153 | output = gpubenchmark(self.gpu_version, gpu_sig, cu_wavelet, widths) 154 | 155 | wavelet = signal.ricker 156 | key = self.cpu_version(cpu_sig, wavelet, widths) 157 | array_equal(output, key) 158 | -------------------------------------------------------------------------------- /python/cusignal/testing/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rapidsai/cusignal/136453a3c8ef381f502a1edd51ca741f6c159f4a/python/cusignal/testing/__init__.py -------------------------------------------------------------------------------- /python/cusignal/testing/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | import cupy as cp 21 | import pytest_benchmark 22 | 23 | 24 | def array_equal(a, b, rtol=1e-7, atol=1e-5): 25 | 26 | if isinstance(a, tuple): # Test functions with multiple outputs 27 | if a[0].dtype == cp.float32 or a[0].dtype == cp.complex64: 28 | rtol = 1e-3 29 | atol = 1e-3 30 | 31 | # Relaxed tolerances for single-precision arrays. 32 | if a[0].dtype == cp.float32 or b[0].dtype == cp.float32: 33 | rtol = 1e-1 34 | atol = 1e-1 35 | 36 | for i in range(len(a)): 37 | cp.testing.assert_allclose(a[i], b[i], rtol=rtol, atol=atol) 38 | 39 | elif not isinstance(a, (float, int)): 40 | if a.dtype == cp.float32 or a.dtype == cp.complex64: 41 | rtol = 1e-3 42 | atol = 1e-3 43 | 44 | # Relaxed tolerances for single-precision arrays. 45 | if a.dtype == cp.float32 or b.dtype == cp.float32: 46 | rtol = 1e-1 47 | atol = 1e-1 48 | 49 | cp.testing.assert_allclose(a, b, rtol=rtol, atol=atol) 50 | 51 | 52 | def _check_rapids_pytest_benchmark(): 53 | try: 54 | from rapids_pytest_benchmark import setFixtureParamNames 55 | except ImportError: 56 | print( 57 | "\n\nWARNING: rapids_pytest_benchmark is not installed, " 58 | "falling back to pytest_benchmark fixtures.\n" 59 | ) 60 | 61 | # if rapids_pytest_benchmark is not available, just perfrom time-only 62 | # benchmarking and replace the util functions with nops 63 | gpubenchmark = pytest_benchmark.plugin.benchmark 64 | 65 | def setFixtureParamNames(*args, **kwargs): 66 | pass 67 | 68 | return gpubenchmark 69 | -------------------------------------------------------------------------------- /python/cusignal/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | from cusignal.utils.arraytools import ( 22 | from_pycuda, 23 | get_pinned_array, 24 | get_pinned_mem, 25 | get_shared_array, 26 | get_shared_mem, 27 | ) 28 | -------------------------------------------------------------------------------- /python/cusignal/utils/_caches.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | # Kernel caches 22 | _cupy_kernel_cache = {} 23 | -------------------------------------------------------------------------------- /python/cusignal/utils/helper_tools.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | import os 22 | from pathlib import Path 23 | 24 | import cupy as cp 25 | 26 | 27 | def _get_numSM(): 28 | 29 | device_id = cp.cuda.Device() 30 | 31 | return device_id.attributes["MultiProcessorCount"] 32 | 33 | 34 | def _get_max_smem(): 35 | 36 | device_id = cp.cuda.Device() 37 | 38 | return device_id.attributes["MaxSharedMemoryPerBlock"] 39 | 40 | 41 | def _get_max_tpb(): 42 | 43 | device_id = cp.cuda.Device() 44 | 45 | return device_id.attributes["MaxThreadsPerBlock"] 46 | 47 | 48 | def _get_max_gdx(): 49 | 50 | device_id = cp.cuda.Device() 51 | 52 | return device_id.attributes["MaxGridDimX"] 53 | 54 | 55 | def _get_max_gdy(): 56 | 57 | device_id = cp.cuda.Device() 58 | 59 | return device_id.attributes["MaxGridDimY"] 60 | 61 | 62 | def _get_tpb_bpg(): 63 | 64 | numSM = _get_numSM() 65 | threadsperblock = 512 66 | blockspergrid = numSM * 20 67 | 68 | return threadsperblock, blockspergrid 69 | 70 | 71 | def _get_function(fatbin, func): 72 | 73 | dir = os.path.dirname(Path(__file__).parent) 74 | 75 | module = cp.RawModule( 76 | path=dir + fatbin, 77 | ) 78 | return module.get_function(func) 79 | 80 | 81 | def _print_atts(func): 82 | if os.environ.get("CUSIGNAL_DEV_DEBUG") == "True": 83 | print("name:", func.kernel.name) 84 | print("max_threads_per_block:", func.kernel.max_threads_per_block) 85 | print("num_regs:", func.kernel.num_regs) 86 | print( 87 | "max_dynamic_shared_size_bytes:", 88 | func.kernel.max_dynamic_shared_size_bytes, 89 | ) 90 | print("shared_size_bytes:", func.kernel.shared_size_bytes) 91 | print( 92 | "preferred_shared_memory_carveout:", 93 | func.kernel.preferred_shared_memory_carveout, 94 | ) 95 | print("const_size_bytes:", func.kernel.const_size_bytes) 96 | print("local_size_bytes:", func.kernel.local_size_bytes) 97 | print("ptx_version:", func.kernel.ptx_version) 98 | print("binary_version:", func.kernel.binary_version) 99 | print() 100 | -------------------------------------------------------------------------------- /python/cusignal/waveforms/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | from cusignal.waveforms.waveforms import ( 22 | chirp, 23 | gausspulse, 24 | sawtooth, 25 | square, 26 | unit_impulse, 27 | ) 28 | -------------------------------------------------------------------------------- /python/cusignal/wavelets/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | from cusignal.wavelets.wavelets import cwt, morlet, morlet2, qmf, ricker 22 | -------------------------------------------------------------------------------- /python/cusignal/windows/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | from cusignal.windows.windows import ( 22 | barthann, 23 | bartlett, 24 | blackman, 25 | blackmanharris, 26 | bohman, 27 | boxcar, 28 | chebwin, 29 | cosine, 30 | exponential, 31 | flattop, 32 | gaussian, 33 | general_cosine, 34 | general_gaussian, 35 | general_hamming, 36 | get_window, 37 | hamming, 38 | hann, 39 | kaiser, 40 | nuttall, 41 | parzen, 42 | taylor, 43 | triang, 44 | tukey, 45 | ) 46 | -------------------------------------------------------------------------------- /python/setup.cfg: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | 21 | [versioneer] 22 | VCS = git 23 | style = pep440 24 | versionfile_source = cusignal/_version.py 25 | versionfile_build = cusignal/_version.py 26 | tag_prefix = v 27 | parentdir_prefix = cusignal- 28 | 29 | [flake8] 30 | exclude = docs, __init__.py, versioneer.py 31 | max-line-length = 88 32 | ignore = 33 | # line break before binary operator 34 | W503 35 | # line break after binary operator 36 | W504 37 | # whilespace before : 38 | E203 39 | 40 | [isort] 41 | line_length=88 42 | multi_line_output=3 43 | include_trailing_comma=True 44 | force_grid_wrap=0 45 | combine_as_imports=True 46 | order_by_type=True 47 | known_rapids= 48 | rmm 49 | cuml 50 | cugraph 51 | dask_cudf 52 | cudf 53 | ucp 54 | known_first_party= 55 | cusignal 56 | default_section=THIRDPARTY 57 | sections=FUTURE,STDLIB,THIRDPARTY,RAPIDS,FIRSTPARTY,LOCALFOLDER 58 | skip= 59 | .eggs 60 | .git 61 | .hg 62 | .mypy_cache 63 | .tox 64 | .venv 65 | build 66 | dist 67 | __init__.py 68 | versioneer.py 69 | 70 | [tool:pytest] 71 | addopts = 72 | --benchmark-sort=mean 73 | --benchmark-min-rounds=25 74 | --benchmark-warmup=on 75 | --benchmark-warmup-iterations=10 76 | --benchmark-disable-gc 77 | --benchmark-disable 78 | --strict-markers 79 | markers = 80 | cpu: marks tests as cpu functions (deselect with '-m "not cpu"') 81 | -------------------------------------------------------------------------------- /python/setup.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation 6 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | # and/or sell copies of the Software, and to permit persons to whom the 8 | # Software is furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | # DEALINGS IN THE SOFTWARE. 20 | from setuptools import find_packages, setup 21 | 22 | import versioneer 23 | 24 | INSTALL_REQUIRES = ["numba"] 25 | 26 | setup( 27 | name="cusignal", 28 | version=versioneer.get_version(), 29 | description="cuSignal - GPU Signal Processing", 30 | url="https://github.com/rapidsai/cusignal", 31 | author="NVIDIA Corporation", 32 | license="MIT", 33 | packages=find_packages(include=["cusignal", "cusignal.*"]), 34 | cmdclass=versioneer.get_cmdclass(), 35 | install_requires=INSTALL_REQUIRES, 36 | zip_safe=False, 37 | package_data={"": ["*.fatbin"]}, 38 | ) 39 | --------------------------------------------------------------------------------