├── .github
└── workflows
│ ├── generate_documentations.yml
│ ├── release_macos_arm64.yml
│ ├── release_macos_arm64_freetier.yml
│ ├── release_macos_x64.yml
│ ├── release_macos_x64_freetier.yml
│ ├── release_ubuntu_22_x64.yml
│ ├── release_ubuntu_22_x64_freetier.yml
│ ├── release_windows_x64.yml
│ ├── release_windows_x64_freetier.yml
│ ├── unit_test_macos_arm64.yml
│ ├── unit_test_macos_x64.yml
│ ├── unit_test_ubuntu_22_x64.yml
│ ├── unit_test_ubuntu_24_x64.yml
│ └── unit_test_windows_x64.yml
├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── assets
├── azimuth_elevation.svg
├── performance.svg
├── phi_theta.svg
├── radarsimcpp.svg
├── radarsimdoc.svg
├── radarsimnb.svg
├── radarsimpy.svg
├── radarsimx.svg
└── yaw_pitch_roll.svg
├── batch_build_linux.sh
├── batch_build_linux_cuda.sh
├── batch_build_win.bat
├── batch_build_win_cuda.bat
├── build_instructions.md
├── build_linux.sh
├── build_macos.sh
├── build_win.bat
├── gen_docs
├── Makefile
├── _static
│ ├── radarsimdoc.png
│ ├── radarsimdoc.svg
│ └── radarsimx_main.svg
├── api
│ ├── index.rst
│ ├── process.rst
│ ├── radar.rst
│ ├── sim.rst
│ └── tools.rst
├── conf.py
├── index.rst
├── make.bat
└── user_guide
│ ├── build.rst
│ ├── coordinate.rst
│ ├── dependence.rst
│ ├── examples.rst
│ ├── features.rst
│ ├── index.rst
│ └── installation.rst
├── models
├── ball_1m.stl
├── cr.stl
├── dihedral.stl
├── half_ring.stl
├── pannel.stl
├── plate.stl
├── plate5x5.stl
├── surface.stl
├── surface_400x400.stl
├── surface_60x60.stl
├── turbine.stl
└── vehicles
│ ├── ford_raptor.stl
│ ├── gasoline_tanker.stl
│ ├── honda_cb400.stl
│ ├── lamborgini_aventador.stl
│ ├── scania_truck.stl
│ └── tesla_model_s.stl
├── references
├── An Efficient and Robust Ray–Box Intersection Algorithm.pdf
├── Gordon_1975_Far-field approximations to the Kirchoff-Helmholtz representations of scattered.pdf
├── Guerrero_2018_Frequency-modulated continuous-wave radar in automotive applications.pdf
├── Hung_2000_Matrix-construction calibration method for antenna arrays.pdf
├── Hwang_2015_Radar cross section analysis using physical optics and its applications to.pdf
├── Karras_2012_Maximizing parallelism in the construction of BVHs, octrees, and k-d trees.pdf
├── Mahafza_2015_Chapter 4 radar detection.pdf
├── Reflection and Refraction of Plane EM Waves.pdf
├── Zhao_2012_Fast physical optics calculation for SAR imaging of complex scatterers.pdf
├── add_phase_noise.m
└── exact_and_approximate_pd_formulas_in_frsp.pdf
├── requirements.txt
├── setup.py
├── src
└── radarsimpy
│ ├── __init__.py
│ ├── includes
│ ├── __init__.py
│ ├── radarsimc.pxd
│ ├── rsvector.pxd
│ └── type_def.pxd
│ ├── lib
│ ├── __init__.py
│ ├── cp_radarsimc.pxd
│ └── cp_radarsimc.pyx
│ ├── mesh_kit.py
│ ├── processing.py
│ ├── radar.py
│ ├── receiver.py
│ ├── simulator.pyx
│ ├── simulator_lidar.pyx
│ ├── simulator_radar.pyx
│ ├── simulator_rcs.pyx
│ ├── tools.py
│ └── transmitter.py
└── tests
├── __init__.py
├── test_config_radar.py
├── test_config_receiver.py
├── test_config_transmitter.py
├── test_module_sim_lidar.py
├── test_module_sim_radar_ideal.py
├── test_module_sim_radar_mesh.py
├── test_module_sim_rcs.py
├── test_module_tools.py
├── test_processing_cfar.py
├── test_processing_doa.py
├── test_system_arbitrary_waveform.py
├── test_system_cw_radar.py
├── test_system_fmcw_radar.py
├── test_system_interference.py
├── test_system_mimo_radar.py
├── test_system_phase_noise.py
└── test_system_pulsed_radar.py
/.github/workflows/generate_documentations.yml:
--------------------------------------------------------------------------------
1 | name: Generate Documentations
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*"
7 | workflow_dispatch:
8 |
9 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
10 | permissions:
11 | contents: read
12 | pages: write
13 | id-token: write
14 |
15 | jobs:
16 | build:
17 | runs-on: ubuntu-24.04
18 | strategy:
19 | matrix:
20 | python-version: ["3.12"]
21 | c_compiler: [gcc-14]
22 | cxx_compiler: [g++-14]
23 |
24 | steps:
25 | - uses: actions/checkout@v4
26 | with:
27 | ssh-key: ${{secrets.RADARSIMC}}
28 | submodules: recursive
29 | - name: Set up Python ${{matrix.python-version}}
30 | uses: actions/setup-python@v5
31 | with:
32 | python-version: ${{matrix.python-version}}
33 | - name: Install dependencies
34 | run: |
35 | python -m pip install --upgrade pip
36 | pip install -r requirements.txt
37 | pip install Sphinx pydata-sphinx-theme
38 | - name: Build
39 | env:
40 | CC: ${{matrix.c_compiler}}
41 | CXX: ${{matrix.cxx_compiler}}
42 | run: |
43 | sudo chown -R $USER:$USER /home/runner/work/radarsimpy
44 | chmod +x build_linux.sh
45 | ./build_linux.sh --tier=standard --arch=cpu --test=off
46 | - name: Generate documentation
47 | run: |
48 | cd gen_docs && make html && cd ..
49 | - name: Archive documentation
50 | if: success()
51 | uses: actions/upload-artifact@v4
52 | with:
53 | name: docs
54 | path: ./gen_docs/_build/html
55 | - name: Setup Pages
56 | uses: actions/configure-pages@v4
57 | - name: Upload artifact
58 | uses: actions/upload-pages-artifact@v3
59 | with:
60 | # Upload entire repository
61 | path: "./gen_docs/_build/html"
62 | - name: Deploy to GitHub Pages
63 | id: deployment
64 | uses: actions/deploy-pages@v4
65 |
--------------------------------------------------------------------------------
/.github/workflows/release_macos_arm64.yml:
--------------------------------------------------------------------------------
1 | name: Release on MacOS Apple Silicon
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*"
7 | workflow_dispatch:
8 |
9 | jobs:
10 | build:
11 | runs-on: macos-15
12 | strategy:
13 | matrix:
14 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
15 | c_compiler: [gcc-14]
16 | cxx_compiler: [g++-14]
17 |
18 | steps:
19 | - uses: actions/checkout@v4
20 | with:
21 | ssh-key: ${{secrets.RADARSIMC}}
22 | submodules: recursive
23 | - uses: maxim-lobanov/setup-xcode@v1.6.0
24 | with:
25 | # Version of Xcode to use
26 | xcode-version: '16.3'
27 | - name: Set up Python ${{matrix.python-version}}
28 | uses: actions/setup-python@v5
29 | with:
30 | python-version: ${{matrix.python-version}}
31 | - name: Install dependencies
32 | run: |
33 | python -m pip install --upgrade pip
34 | pip install -r requirements.txt
35 | - name: Build
36 | env:
37 | CC: ${{matrix.c_compiler}}
38 | CXX: ${{matrix.cxx_compiler}}
39 | run: |
40 | chmod +x build_macos.sh
41 | ./build_macos.sh --tier=standard --arch=cpu --test=off
42 | - name: Archive built module
43 | uses: actions/upload-artifact@v4
44 | if: success()
45 | with:
46 | name: radarsimpy_macos_arm_py${{matrix.python-version}}
47 | path: ./radarsimpy
48 |
--------------------------------------------------------------------------------
/.github/workflows/release_macos_arm64_freetier.yml:
--------------------------------------------------------------------------------
1 | name: Release on MacOS Apple Silicon Free Tier
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*"
7 | workflow_dispatch:
8 |
9 | jobs:
10 | build:
11 | runs-on: macos-15
12 | strategy:
13 | matrix:
14 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
15 | c_compiler: [gcc-14]
16 | cxx_compiler: [g++-14]
17 |
18 | steps:
19 | - uses: actions/checkout@v4
20 | with:
21 | ssh-key: ${{secrets.RADARSIMC}}
22 | submodules: recursive
23 | - uses: maxim-lobanov/setup-xcode@v1.6.0
24 | with:
25 | # Version of Xcode to use
26 | xcode-version: '16.3'
27 | - name: Set up Python ${{matrix.python-version}}
28 | uses: actions/setup-python@v5
29 | with:
30 | python-version: ${{matrix.python-version}}
31 | - name: Install dependencies
32 | run: |
33 | python -m pip install --upgrade pip
34 | pip install -r requirements.txt
35 | - name: Build
36 | env:
37 | CC: ${{matrix.c_compiler}}
38 | CXX: ${{matrix.cxx_compiler}}
39 | run: |
40 | chmod +x build_macos.sh
41 | ./build_macos.sh --tier=free --arch=cpu --test=off
42 | - name: Archive built module
43 | uses: actions/upload-artifact@v4
44 | if: success()
45 | with:
46 | name: radarsimpy_macos_arm_py${{matrix.python-version}}_freetier
47 | path: ./radarsimpy
48 |
--------------------------------------------------------------------------------
/.github/workflows/release_macos_x64.yml:
--------------------------------------------------------------------------------
1 | name: Release on MacOS x64
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*"
7 |
8 | jobs:
9 | build:
10 | runs-on: macos-13
11 | strategy:
12 | matrix:
13 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
14 | c_compiler: [gcc-14]
15 | cxx_compiler: [g++-14]
16 |
17 | steps:
18 | - uses: actions/checkout@v4
19 | with:
20 | ssh-key: ${{secrets.RADARSIMC}}
21 | submodules: recursive
22 | - uses: maxim-lobanov/setup-xcode@v1.6.0
23 | with:
24 | # Version of Xcode to use
25 | xcode-version: '15.2'
26 | - name: Set up Python ${{matrix.python-version}}
27 | uses: actions/setup-python@v5
28 | with:
29 | python-version: ${{matrix.python-version}}
30 | - name: Install dependencies
31 | run: |
32 | python -m pip install --upgrade pip
33 | pip install -r requirements.txt
34 | - name: Build
35 | env:
36 | CC: ${{matrix.c_compiler}}
37 | CXX: ${{matrix.cxx_compiler}}
38 | run: |
39 | chmod +x build_macos.sh
40 | ./build_macos.sh --tier=standard --arch=cpu --test=off
41 | - name: Archive built module
42 | uses: actions/upload-artifact@v4
43 | if: success()
44 | with:
45 | name: radarsimpy_macos_py${{matrix.python-version}}
46 | path: ./radarsimpy
47 |
--------------------------------------------------------------------------------
/.github/workflows/release_macos_x64_freetier.yml:
--------------------------------------------------------------------------------
1 | name: Release on MacOS x64 Free Tier
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*"
7 |
8 | jobs:
9 | build:
10 | runs-on: macos-13
11 | strategy:
12 | matrix:
13 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
14 | c_compiler: [gcc-14]
15 | cxx_compiler: [g++-14]
16 |
17 | steps:
18 | - uses: actions/checkout@v4
19 | with:
20 | ssh-key: ${{secrets.RADARSIMC}}
21 | submodules: recursive
22 | - uses: maxim-lobanov/setup-xcode@v1.6.0
23 | with:
24 | # Version of Xcode to use
25 | xcode-version: '15.2'
26 | - name: Set up Python ${{matrix.python-version}}
27 | uses: actions/setup-python@v5
28 | with:
29 | python-version: ${{matrix.python-version}}
30 | - name: Install dependencies
31 | run: |
32 | python -m pip install --upgrade pip
33 | pip install -r requirements.txt
34 | - name: Build
35 | env:
36 | CC: ${{matrix.c_compiler}}
37 | CXX: ${{matrix.cxx_compiler}}
38 | run: |
39 | chmod +x build_macos.sh
40 | ./build_macos.sh --tier=free --arch=cpu --test=off
41 | - name: Archive built module
42 | uses: actions/upload-artifact@v4
43 | if: success()
44 | with:
45 | name: radarsimpy_macos_py${{matrix.python-version}}_freetier
46 | path: ./radarsimpy
47 |
--------------------------------------------------------------------------------
/.github/workflows/release_ubuntu_22_x64.yml:
--------------------------------------------------------------------------------
1 | name: Release on Ubuntu 22.04 x64
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*"
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-22.04
11 | strategy:
12 | matrix:
13 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
14 | c_compiler: [gcc-11]
15 | cxx_compiler: [g++-11]
16 |
17 | steps:
18 | - uses: actions/checkout@v4
19 | with:
20 | ssh-key: ${{secrets.RADARSIMC}}
21 | submodules: recursive
22 | - name: Set up Python ${{matrix.python-version}}
23 | uses: actions/setup-python@v5
24 | with:
25 | python-version: ${{matrix.python-version}}
26 | - name: Install dependencies
27 | run: |
28 | python -m pip install --upgrade pip
29 | pip install -r requirements.txt
30 | - name: Build
31 | env:
32 | CC: ${{matrix.c_compiler}}
33 | CXX: ${{matrix.cxx_compiler}}
34 | run: |
35 | sudo chown -R $USER:$USER /home/runner/work/radarsimpy
36 | chmod +x build_linux.sh
37 | ./build_linux.sh --tier=standard --arch=cpu --test=off
38 | - name: Archive built module
39 | uses: actions/upload-artifact@v4
40 | if: success()
41 | with:
42 | name: radarsimpy_ubuntu_22_py${{matrix.python-version}}
43 | path: ./radarsimpy
44 |
--------------------------------------------------------------------------------
/.github/workflows/release_ubuntu_22_x64_freetier.yml:
--------------------------------------------------------------------------------
1 | name: Release on Ubuntu 22.04 x64 Free Tier
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*"
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-22.04
11 | strategy:
12 | matrix:
13 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
14 | c_compiler: [gcc-11]
15 | cxx_compiler: [g++-11]
16 |
17 | steps:
18 | - uses: actions/checkout@v4
19 | with:
20 | ssh-key: ${{secrets.RADARSIMC}}
21 | submodules: recursive
22 | - name: Set up Python ${{matrix.python-version}}
23 | uses: actions/setup-python@v5
24 | with:
25 | python-version: ${{matrix.python-version}}
26 | - name: Install dependencies
27 | run: |
28 | python -m pip install --upgrade pip
29 | pip install -r requirements.txt
30 | - name: Build
31 | env:
32 | CC: ${{matrix.c_compiler}}
33 | CXX: ${{matrix.cxx_compiler}}
34 | run: |
35 | sudo chown -R $USER:$USER /home/runner/work/radarsimpy
36 | chmod +x build_linux.sh
37 | ./build_linux.sh --tier=free --arch=cpu --test=off
38 | - name: Archive built module
39 | uses: actions/upload-artifact@v4
40 | if: success()
41 | with:
42 | name: radarsimpy_ubuntu_22_py${{matrix.python-version}}_freetier
43 | path: ./radarsimpy
44 |
--------------------------------------------------------------------------------
/.github/workflows/release_windows_x64.yml:
--------------------------------------------------------------------------------
1 | name: Release on Windows x64
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*"
7 |
8 | jobs:
9 | build:
10 | runs-on: windows-latest
11 | strategy:
12 | matrix:
13 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
14 |
15 | steps:
16 | # - name: Remove Windows OpenSSH and use the default ssh in git
17 | # run: Remove-WindowsCapability -Online -Name OpenSSH.Client
18 | - uses: actions/checkout@v4
19 | with:
20 | ssh-key: ${{secrets.RADARSIMC}}
21 | submodules: recursive
22 | - name: Set up Python ${{matrix.python-version}}
23 | uses: actions/setup-python@v5
24 | with:
25 | python-version: ${{matrix.python-version}}
26 | - name: Install dependencies
27 | run: |
28 | python -m pip install --upgrade pip
29 | pip install -r requirements.txt
30 | - name: Build
31 | run: |
32 | .\build_win.bat --tier=standard --arch=cpu --test=off
33 | - name: Archive built module
34 | uses: actions/upload-artifact@v4
35 | if: success()
36 | with:
37 | name: radarsimpy_win_py${{matrix.python-version}}
38 | path: .\radarsimpy
39 |
--------------------------------------------------------------------------------
/.github/workflows/release_windows_x64_freetier.yml:
--------------------------------------------------------------------------------
1 | name: Release on Windows x64 Free Tier
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*"
7 |
8 | jobs:
9 | build:
10 | runs-on: windows-latest
11 | strategy:
12 | matrix:
13 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
14 |
15 | steps:
16 | # - name: Remove Windows OpenSSH and use the default ssh in git
17 | # run: Remove-WindowsCapability -Online -Name OpenSSH.Client
18 | - uses: actions/checkout@v4
19 | with:
20 | ssh-key: ${{secrets.RADARSIMC}}
21 | submodules: recursive
22 | - name: Set up Python ${{matrix.python-version}}
23 | uses: actions/setup-python@v5
24 | with:
25 | python-version: ${{matrix.python-version}}
26 | - name: Install dependencies
27 | run: |
28 | python -m pip install --upgrade pip
29 | pip install -r requirements.txt
30 | - name: Build
31 | run: |
32 | .\build_win.bat --tier=free --arch=cpu --test=off
33 | - name: Archive built module
34 | uses: actions/upload-artifact@v4
35 | if: success()
36 | with:
37 | name: radarsimpy_win_py${{matrix.python-version}}_freetier
38 | path: .\radarsimpy
39 |
--------------------------------------------------------------------------------
/.github/workflows/unit_test_macos_arm64.yml:
--------------------------------------------------------------------------------
1 | name: MacOS Apple Silicon
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | pull_request:
7 | branches: [master]
8 |
9 | jobs:
10 | build:
11 | runs-on: macos-15
12 | strategy:
13 | matrix:
14 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
15 | c_compiler: [gcc-14]
16 | cxx_compiler: [g++-14]
17 |
18 | steps:
19 | - uses: actions/checkout@v4
20 | with:
21 | ssh-key: ${{secrets.RADARSIMC}}
22 | submodules: recursive
23 | - uses: maxim-lobanov/setup-xcode@v1.6.0
24 | with:
25 | # Version of Xcode to use
26 | xcode-version: '16.3'
27 | - name: Set up Python ${{matrix.python-version}}
28 | uses: actions/setup-python@v5
29 | with:
30 | python-version: ${{matrix.python-version}}
31 | - name: Install dependencies
32 | run: |
33 | python -m pip install --upgrade pip
34 | pip install -r requirements.txt
35 | - name: Build & Test
36 | env:
37 | CC: ${{matrix.c_compiler}}
38 | CXX: ${{matrix.cxx_compiler}}
39 | run: |
40 | chmod +x build_macos.sh
41 | ./build_macos.sh --tier=standard --arch=cpu --test=on
42 |
--------------------------------------------------------------------------------
/.github/workflows/unit_test_macos_x64.yml:
--------------------------------------------------------------------------------
1 | name: MacOS x64
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | pull_request:
7 | branches: [master]
8 |
9 | jobs:
10 | build:
11 | runs-on: macos-13
12 | strategy:
13 | matrix:
14 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
15 | c_compiler: [gcc-14]
16 | cxx_compiler: [g++-14]
17 |
18 | steps:
19 | - uses: actions/checkout@v4
20 | with:
21 | ssh-key: ${{secrets.RADARSIMC}}
22 | submodules: recursive
23 | - uses: maxim-lobanov/setup-xcode@v1.6.0
24 | with:
25 | # Version of Xcode to use
26 | xcode-version: '15.2'
27 | - name: Set up Python ${{matrix.python-version}}
28 | uses: actions/setup-python@v5
29 | with:
30 | python-version: ${{matrix.python-version}}
31 | - name: Install dependencies
32 | run: |
33 | python -m pip install --upgrade pip
34 | pip install -r requirements.txt
35 | - name: Build & Test
36 | env:
37 | CC: ${{matrix.c_compiler}}
38 | CXX: ${{matrix.cxx_compiler}}
39 | run: |
40 | chmod +x build_macos.sh
41 | ./build_macos.sh --tier=standard --arch=cpu --test=on
42 |
--------------------------------------------------------------------------------
/.github/workflows/unit_test_ubuntu_22_x64.yml:
--------------------------------------------------------------------------------
1 | name: Ubuntu 22.04 x64
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | pull_request:
7 | branches: [master]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-22.04
12 | strategy:
13 | matrix:
14 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
15 | c_compiler: [gcc-11]
16 | cxx_compiler: [g++-11]
17 |
18 | steps:
19 | - uses: actions/checkout@v4
20 | with:
21 | ssh-key: ${{secrets.RADARSIMC}}
22 | submodules: recursive
23 | - name: Set up Python ${{matrix.python-version}}
24 | uses: actions/setup-python@v5
25 | with:
26 | python-version: ${{matrix.python-version}}
27 | - name: Install dependencies
28 | run: |
29 | python -m pip install --upgrade pip
30 | pip install -r requirements.txt
31 | - name: Build & Test
32 | env:
33 | CC: ${{matrix.c_compiler}}
34 | CXX: ${{matrix.cxx_compiler}}
35 | run: |
36 | sudo chown -R $USER:$USER /home/runner/work/radarsimpy
37 | chmod +x build_linux.sh
38 | ./build_linux.sh --tier=standard --arch=cpu --test=on
39 |
--------------------------------------------------------------------------------
/.github/workflows/unit_test_ubuntu_24_x64.yml:
--------------------------------------------------------------------------------
1 | name: Ubuntu 24.04 x64
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | pull_request:
7 | branches: [master]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-24.04
12 | strategy:
13 | matrix:
14 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
15 | c_compiler: [gcc-13]
16 | cxx_compiler: [g++-13]
17 |
18 | steps:
19 | - uses: actions/checkout@v4
20 | with:
21 | ssh-key: ${{secrets.RADARSIMC}}
22 | submodules: recursive
23 | - name: Set up Python ${{matrix.python-version}}
24 | uses: actions/setup-python@v5
25 | with:
26 | python-version: ${{matrix.python-version}}
27 | - name: Install dependencies
28 | run: |
29 | python -m pip install --upgrade pip
30 | pip install -r requirements.txt
31 | - name: Build & Test
32 | env:
33 | CC: ${{matrix.c_compiler}}
34 | CXX: ${{matrix.cxx_compiler}}
35 | run: |
36 | sudo chown -R $USER:$USER /home/runner/work/radarsimpy
37 | chmod +x build_linux.sh
38 | ./build_linux.sh --tier=standard --arch=cpu --test=on
39 |
--------------------------------------------------------------------------------
/.github/workflows/unit_test_windows_x64.yml:
--------------------------------------------------------------------------------
1 | name: Windows x64
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | pull_request:
7 | branches: [master]
8 |
9 | jobs:
10 | build:
11 | runs-on: windows-latest
12 | strategy:
13 | matrix:
14 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
15 |
16 | steps:
17 | # - name: Remove Windows OpenSSH and use the default ssh in git
18 | # run: Remove-WindowsCapability -Online -Name OpenSSH.Client
19 | - uses: actions/checkout@v4
20 | with:
21 | ssh-key: ${{secrets.RADARSIMC}}
22 | submodules: recursive
23 | - name: Set up Python ${{matrix.python-version}}
24 | uses: actions/setup-python@v5
25 | with:
26 | python-version: ${{matrix.python-version}}
27 | - name: Install dependencies
28 | run: |
29 | python -m pip install --upgrade pip
30 | pip install -r requirements.txt
31 | - name: Build & Test
32 | run: |
33 | .\build_win.bat --tier=standard --arch=cpu --test=on
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib64/
18 | parts/
19 | sdist/
20 | var/
21 | wheels/
22 | *.egg-info/
23 | .installed.cfg
24 | *.egg
25 | MANIFEST
26 |
27 | # PyInstaller
28 | # Usually these files are written by a python script from a template
29 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
30 | *.manifest
31 | *.spec
32 |
33 | # Installer logs
34 | pip-log.txt
35 | pip-delete-this-directory.txt
36 |
37 | # Unit test / coverage reports
38 | htmlcov/
39 | .tox/
40 | .coverage
41 | .coverage.*
42 | .cache
43 | nosetests.xml
44 | coverage.xml
45 | *.cover
46 | .hypothesis/
47 | .pytest_cache/
48 |
49 | # Translations
50 | *.mo
51 | *.pot
52 |
53 | # Django stuff:
54 | *.log
55 | local_settings.py
56 | db.sqlite3
57 |
58 | # Flask stuff:
59 | instance/
60 | .webassets-cache
61 |
62 | # Scrapy stuff:
63 | .scrapy
64 |
65 | # Sphinx documentation
66 | docs/_build/
67 |
68 | # PyBuilder
69 | target/
70 |
71 | # Jupyter Notebook
72 | .ipynb_checkpoints
73 |
74 | # pyenv
75 | .python-version
76 |
77 | # celery beat schedule file
78 | celerybeat-schedule
79 |
80 | # SageMath parsed files
81 | *.sage.py
82 |
83 | # Environments
84 | .env
85 | .venv
86 | env/
87 | venv/
88 | ENV/
89 | env.bak/
90 | venv.bak/
91 |
92 | # Spyder project settings
93 | .spyderproject
94 | .spyproject
95 |
96 | # Rope project settings
97 | .ropeproject
98 |
99 | # mkdocs documentation
100 | /site
101 |
102 | # mypy
103 | .mypy_cache/
104 |
105 | \.idea/
106 |
107 | \.vscode/
108 | \.VSCodeCounter/
109 |
110 | release/
111 | radarsimpy/
112 | !src/radarsimpy/
113 |
114 | src/radarsimpy/*.html
115 | src/radarsimpy/sbr/*.html
116 |
117 | CMakeLists.txt.user
118 |
119 | src/build-*/
120 |
121 | src/radarsim_main/.vs/
122 |
123 | src/radarsimcpp/.vs/
124 |
125 | src/radarsimcpp/CMakeSettings.json
126 |
127 | src/radarsimc_entry/.vs/
128 |
129 | tests/radarsimpy
130 |
131 | src/radarsimcpp/build*
132 |
133 | src/radarsimcpp/entry/.vs/
134 |
135 | gen_docs/_build/
136 |
137 | *.dll
138 |
139 | debug/*
140 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "src/radarsimcpp"]
2 | path = src/radarsimcpp
3 | url = git@github.com:rookiepeng/radarsimcpp.git
4 |
--------------------------------------------------------------------------------
/assets/azimuth_elevation.svg:
--------------------------------------------------------------------------------
1 |
2 |
228 |
--------------------------------------------------------------------------------
/assets/radarsimx.svg:
--------------------------------------------------------------------------------
1 |
2 |
226 |
--------------------------------------------------------------------------------
/batch_build_linux.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Display banner and copyright information
4 | echo "Automatic build script of radarsimcpp/radarsimpy for Linux"
5 | echo ""
6 | echo "----------"
7 | echo "RadarSimPy - A Radar Simulator Built with Python"
8 | echo "Copyright (C) 2018 - PRESENT radarsimx.com"
9 | echo "E-mail: info@radarsimx.com"
10 | echo "Website: https://radarsimx.com"
11 | echo ""
12 | echo "██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗"
13 | echo "██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝"
14 | echo "██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝ "
15 | echo "██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗ "
16 | echo "██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗"
17 | echo "╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝"
18 |
19 | # Store current working directory for later reference
20 | workpath=$(pwd)
21 |
22 | # Clean previous build artifacts and directories
23 | echo "## Clean old build files ##"
24 | rm -rf ./src/radarsimcpp/build
25 | rm -rf ./radarsimpy
26 |
27 | # Build CPU-only C++ library
28 | echo "## Building libradarsimcpp.so with CPU ##"
29 | mkdir ./src/radarsimcpp/build
30 | cd ./src/radarsimcpp/build
31 |
32 | # Configure CMake for CPU-only build
33 | cmake -DCMAKE_BUILD_TYPE=Release -DGTEST=ON ..
34 | cmake --build .
35 |
36 | # Build Python extensions for multiple Python versions (Free Tier)
37 | echo "## Building radarsimpy with Cython ##"
38 | cd $workpath
39 | # Build CPU-only extensions for Python 3.9-3.13
40 | conda run -n py313 python setup.py build_ext -b ./ --tier free --arch cpu
41 | conda run -n py312 python setup.py build_ext -b ./ --tier free --arch cpu
42 | conda run -n py311 python setup.py build_ext -b ./ --tier free --arch cpu
43 | conda run -n py310 python setup.py build_ext -b ./ --tier free --arch cpu
44 | conda run -n py39 python setup.py build_ext -b ./ --tier free --arch cpu
45 |
46 | # Copy built libraries and Python files
47 | echo "## Copying lib files to ./radarsimpy ##"
48 | cp ./src/radarsimpy/*.py ./radarsimpy
49 | cp ./src/radarsimpy/lib/__init__.py ./radarsimpy/lib
50 | cp ./src/radarsimcpp/build/*.so ./radarsimpy
51 |
52 | # Clean intermediate build files
53 | echo "## Cleaning radarsimpy builds ##"
54 | rm -rf build
55 | # Remove generated C/C++/HTML files
56 | rm -f ./src/radarsimpy/*.c
57 | rm -f ./src/radarsimpy/*.cpp
58 | rm -f ./src/radarsimpy/*.html
59 | rm -f ./src/radarsimpy/raytracing/*.c
60 | rm -f ./src/radarsimpy/raytracing/*.cpp
61 | rm -f ./src/radarsimpy/raytracing/*.html
62 | rm -f ./src/radarsimpy/lib/*.cpp
63 | rm -f ./src/radarsimpy/lib/*.html
64 | rm -f ./src/*.cpp
65 | rm -f ./src/*.html
66 |
67 | # Package Free Tier CPU release
68 | echo "## Copying lib files to freetier release folder ##"
69 | rm -rf ./trial/Linux_x86_64_CPU
70 | mkdir ./trial/Linux_x86_64_CPU
71 | mkdir ./trial/Linux_x86_64_CPU/radarsimpy
72 | cp -rf ./radarsimpy/* ./trial/Linux_x86_64_CPU/radarsimpy
73 |
74 | # Clean and rebuild for Standard Tier
75 | rm -rf ./radarsimpy
76 | # Build CPU-only extensions for Standard Tier
77 | conda run -n py313 python setup.py build_ext -b ./ --tier standard --arch cpu
78 | conda run -n py312 python setup.py build_ext -b ./ --tier standard --arch cpu
79 | conda run -n py311 python setup.py build_ext -b ./ --tier standard --arch cpu
80 | conda run -n py310 python setup.py build_ext -b ./ --tier standard --arch cpu
81 | conda run -n py39 python setup.py build_ext -b ./ --tier standard --arch cpu
82 |
83 | # Copy files for Standard Tier
84 | echo "## Copying lib files to ./radarsimpy ##"
85 | cp ./src/radarsimpy/*.py ./radarsimpy
86 | cp ./src/radarsimpy/lib/__init__.py ./radarsimpy/lib
87 | cp ./src/radarsimcpp/build/*.so ./radarsimpy
88 |
89 | # Final cleanup of build artifacts
90 | echo "## Cleaning radarsimpy builds ##"
91 | rm -rf build
92 | rm -f ./src/radarsimpy/*.c
93 | rm -f ./src/radarsimpy/*.cpp
94 | rm -f ./src/radarsimpy/*.html
95 | rm -f ./src/radarsimpy/raytracing/*.c
96 | rm -f ./src/radarsimpy/raytracing/*.cpp
97 | rm -f ./src/radarsimpy/raytracing/*.html
98 | rm -f ./src/radarsimpy/lib/*.cpp
99 | rm -f ./src/radarsimpy/lib/*.html
100 | rm -f ./src/*.cpp
101 | rm -f ./src/*.html
102 |
103 | # Package Standard Tier CPU release
104 | echo "## Copying lib files to standard release folder ##"
105 | rm -rf ./standard/Linux_x86_64_CPU
106 | mkdir ./standard/Linux_x86_64_CPU
107 | mkdir ./standard/Linux_x86_64_CPU/radarsimpy
108 | cp -rf ./radarsimpy/* ./standard/Linux_x86_64_CPU/radarsimpy
109 |
110 | # Run unit tests
111 | echo "## Build completed ##"
112 | echo "## Run Google test ##"
113 | ./src/radarsimcpp/build/radarsimcpp_test
114 |
--------------------------------------------------------------------------------
/batch_build_linux_cuda.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Display banner and copyright information
4 | echo "Automatic build script of radarsimcpp/radarsimpy for Linux"
5 | echo ""
6 | echo "----------"
7 | echo "RadarSimPy - A Radar Simulator Built with Python"
8 | echo "Copyright (C) 2018 - PRESENT radarsimx.com"
9 | echo "E-mail: info@radarsimx.com"
10 | echo "Website: https://radarsimx.com"
11 | echo ""
12 | echo "██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗"
13 | echo "██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝"
14 | echo "██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝ "
15 | echo "██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗ "
16 | echo "██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗"
17 | echo "╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝"
18 |
19 | # Store current working directory for later reference
20 | workpath=$(pwd)
21 |
22 | # Clean previous build artifacts and directories
23 | echo "## Clean old build files ##"
24 | rm -rf ./src/radarsimcpp/build
25 | rm -rf ./radarsimpy
26 |
27 | # Build CUDA-enabled C++ library
28 | echo "## Building libradarsimcpp.so with GPU ##"
29 | mkdir ./src/radarsimcpp/build
30 | cd ./src/radarsimcpp/build
31 |
32 | # Configure CMake for GPU build with CUDA support
33 | cmake -DCMAKE_BUILD_TYPE=Release -DGPU_BUILD=ON -DGTEST=ON ..
34 | cmake --build .
35 |
36 | # Build Python extensions for multiple Python versions (Free Tier)
37 | echo "## Building radarsimpy with Cython ##"
38 | cd $workpath
39 | # Build GPU-enabled extensions for Python 3.9-3.13
40 | conda run -n py313 python setup.py build_ext -b ./ --tier free --arch gpu
41 | conda run -n py312 python setup.py build_ext -b ./ --tier free --arch gpu
42 | conda run -n py311 python setup.py build_ext -b ./ --tier free --arch gpu
43 | conda run -n py310 python setup.py build_ext -b ./ --tier free --arch gpu
44 | conda run -n py39 python setup.py build_ext -b ./ --tier free --arch gpu
45 |
46 | # Copy built libraries and Python files
47 | echo "## Copying lib files to ./radarsimpy ##"
48 | cp ./src/radarsimpy/*.py ./radarsimpy
49 | cp ./src/radarsimpy/lib/__init__.py ./radarsimpy/lib
50 | cp ./src/radarsimcpp/build/*.so ./radarsimpy
51 |
52 | # Clean intermediate build files
53 | echo "## Cleaning radarsimpy builds ##"
54 | rm -rf build
55 | # Remove generated C/C++/HTML files
56 | rm -f ./src/radarsimpy/*.c
57 | rm -f ./src/radarsimpy/*.cpp
58 | rm -f ./src/radarsimpy/*.html
59 | rm -f ./src/radarsimpy/raytracing/*.c
60 | rm -f ./src/radarsimpy/raytracing/*.cpp
61 | rm -f ./src/radarsimpy/raytracing/*.html
62 | rm -f ./src/radarsimpy/lib/*.cpp
63 | rm -f ./src/radarsimpy/lib/*.html
64 | rm -f ./src/*.cpp
65 | rm -f ./src/*.html
66 |
67 | # Package Free Tier GPU release
68 | echo "## Copying lib files to freetier release folder ##"
69 | rm -rf ./trial/Linux_x86_64_GPU
70 | mkdir ./trial/Linux_x86_64_GPU
71 | mkdir ./trial/Linux_x86_64_GPU/radarsimpy
72 | cp -rf ./radarsimpy/* ./trial/Linux_x86_64_GPU/radarsimpy
73 |
74 | # Clean and rebuild for Standard Tier
75 | rm -rf ./radarsimpy
76 | # Build GPU-enabled extensions for Standard Tier
77 | conda run -n py313 python setup.py build_ext -b ./ --tier standard --arch gpu
78 | conda run -n py312 python setup.py build_ext -b ./ --tier standard --arch gpu
79 | conda run -n py311 python setup.py build_ext -b ./ --tier standard --arch gpu
80 | conda run -n py310 python setup.py build_ext -b ./ --tier standard --arch gpu
81 | conda run -n py39 python setup.py build_ext -b ./ --tier standard --arch gpu
82 |
83 | # Copy files for Standard Tier
84 | echo "## Copying lib files to ./radarsimpy ##"
85 | cp ./src/radarsimpy/*.py ./radarsimpy
86 | cp ./src/radarsimpy/lib/__init__.py ./radarsimpy/lib
87 | cp ./src/radarsimcpp/build/*.so ./radarsimpy
88 |
89 | # Final cleanup of build artifacts
90 | echo "## Cleaning radarsimpy builds ##"
91 | rm -rf build
92 | rm -f ./src/radarsimpy/*.c
93 | rm -f ./src/radarsimpy/*.cpp
94 | rm -f ./src/radarsimpy/*.html
95 | rm -f ./src/radarsimpy/raytracing/*.c
96 | rm -f ./src/radarsimpy/raytracing/*.cpp
97 | rm -f ./src/radarsimpy/raytracing/*.html
98 | rm -f ./src/radarsimpy/lib/*.cpp
99 | rm -f ./src/radarsimpy/lib/*.html
100 | rm -f ./src/*.cpp
101 | rm -f ./src/*.html
102 |
103 | # Package Standard Tier GPU release
104 | echo "## Copying lib files to standard release folder ##"
105 | rm -rf ./standard/Linux_x86_64_GPU
106 | mkdir ./standard/Linux_x86_64_GPU
107 | mkdir ./standard/Linux_x86_64_GPU/radarsimpy
108 | cp -rf ./radarsimpy/* ./standard/Linux_x86_64_GPU/radarsimpy
109 |
110 | # Run unit tests
111 | echo "## Build completed ##"
112 | echo "## Run Google test ##"
113 | ./src/radarsimcpp/build/radarsimcpp_test
114 |
--------------------------------------------------------------------------------
/batch_build_win.bat:
--------------------------------------------------------------------------------
1 | REM Display header and copyright information
2 | @ECHO OFF
3 |
4 | ECHO Automatic build script of radarsimcpp/radarsimpy for Windows
5 | ECHO:
6 | ECHO ----------
7 | ECHO RadarSimPy - A Radar Simulator Built with Python
8 | ECHO Copyright (C) 2018 - PRESENT radarsimx.com
9 | ECHO E-mail: info@radarsimx.com
10 | ECHO Website: https://radarsimx.com
11 | ECHO:
12 | ECHO ###### ##### # #
13 | ECHO # # ## ##### ## ##### # # # # # # #
14 | ECHO # # # # # # # # # # # # ## ## # #
15 | ECHO ###### # # # # # # # # ##### # # ## # #
16 | ECHO # # ###### # # ###### ##### # # # # # #
17 | ECHO # # # # # # # # # # # # # # # # #
18 | ECHO # # # # ##### # # # # ##### # # # # #
19 | ECHO:
20 |
21 | REM Store current directory path
22 | SET pwd=%cd%
23 |
24 | REM Clean up previous build artifacts
25 | ECHO clean old build files
26 | RMDIR /Q/S .\src\radarsimcpp\build
27 |
28 | ECHO clean old radarsimpy module
29 | RMDIR /Q/S .\radarsimpy
30 |
31 | REM Create and navigate to build directory
32 | MD ".\src\radarsimcpp\build"
33 | CD ".\src\radarsimcpp\build"
34 |
35 | REM Build C++ library with CMake
36 | ECHO ## Building radarsimcpp.dll with MSVC ##
37 | cmake -DGTEST=ON ..
38 | cmake --build . --config Release
39 |
40 | REM Build Python extensions for multiple Python versions (Free Tier)
41 | ECHO ## Building radarsimpy with Cython ##
42 | CD %pwd%
43 | REM Build for Python 3.9-3.13 with CPU support
44 | conda.exe run -n py313 python setup.py build_ext -b ./ --tier free --arch cpu
45 | conda.exe run -n py312 python setup.py build_ext -b ./ --tier free --arch cpu
46 | conda.exe run -n py311 python setup.py build_ext -b ./ --tier free --arch cpu
47 | conda.exe run -n py310 python setup.py build_ext -b ./ --tier free --arch cpu
48 | conda.exe run -n py39 python setup.py build_ext -b ./ --tier free --arch cpu
49 |
50 | REM Copy built files to radarsimpy directory
51 | ECHO ## Copying dll files to ./radarsimpy ##
52 | XCOPY ".\src\radarsimcpp\build\Release\radarsimcpp.dll" ".\radarsimpy\"
53 | XCOPY ".\src\radarsimpy\*.py" ".\radarsimpy\"
54 | XCOPY ".\src\radarsimpy\lib\__init__.py" ".\radarsimpy\lib\"
55 |
56 | REM Clean up intermediate build files
57 | ECHO ## Cleaning radarsimpy builds ##
58 | RMDIR build /s /q
59 |
60 | DEL ".\src\radarsimpy\*.c"
61 | DEL ".\src\radarsimpy\*.cpp"
62 | DEL ".\src\radarsimpy\*.html"
63 | DEL ".\src\radarsimpy\raytracing\*.c"
64 | DEL ".\src\radarsimpy\raytracing\*.cpp"
65 | DEL ".\src\radarsimpy\raytracing\*.html"
66 | DEL ".\src\radarsimpy\lib\*.cpp"
67 | DEL ".\src\radarsimpy\lib\*.html"
68 | DEL ".\src\*.cpp"
69 | DEL ".\src\*.html"
70 |
71 | REM Create FreeTier distribution
72 | ECHO ## Copying lib files to freetier release folder ##
73 | RMDIR /Q/S .\trial\Windows_x86_64_CPU
74 | XCOPY /E /I .\radarsimpy .\trial\Windows_x86_64_CPU\radarsimpy
75 |
76 | RMDIR /Q/S .\radarsimpy
77 |
78 | REM Build Standard Tier version
79 | REM Build Python extensions for multiple Python versions (Standard Tier)
80 | conda.exe run -n py313 python setup.py build_ext -b ./ --tier standard --arch cpu
81 | conda.exe run -n py312 python setup.py build_ext -b ./ --tier standard --arch cpu
82 | conda.exe run -n py311 python setup.py build_ext -b ./ --tier standard --arch cpu
83 | conda.exe run -n py310 python setup.py build_ext -b ./ --tier standard --arch cpu
84 | conda.exe run -n py39 python setup.py build_ext -b ./ --tier standard --arch cpu
85 |
86 | REM Copy built files to radarsimpy directory
87 | ECHO ## Copying dll files to ./radarsimpy ##
88 | XCOPY ".\src\radarsimcpp\build\Release\radarsimcpp.dll" ".\radarsimpy\"
89 | XCOPY ".\src\radarsimpy\*.py" ".\radarsimpy\"
90 | XCOPY ".\src\radarsimpy\lib\__init__.py" ".\radarsimpy\lib\"
91 |
92 | REM Clean up intermediate build files
93 | ECHO ## Cleaning radarsimpy builds ##
94 | RMDIR build /s /q
95 |
96 | DEL ".\src\radarsimpy\*.c"
97 | DEL ".\src\radarsimpy\*.cpp"
98 | DEL ".\src\radarsimpy\*.html"
99 | DEL ".\src\radarsimpy\raytracing\*.c"
100 | DEL ".\src\radarsimpy\raytracing\*.cpp"
101 | DEL ".\src\radarsimpy\raytracing\*.html"
102 | DEL ".\src\radarsimpy\lib\*.cpp"
103 | DEL ".\src\radarsimpy\lib\*.html"
104 | DEL ".\src\*.cpp"
105 | DEL ".\src\*.html"
106 |
107 | REM Create Standard Tier distribution
108 | ECHO ## Copying lib files to standard release folder ##
109 | RMDIR /Q/S .\standard\Windows_x86_64_CPU
110 | XCOPY /E /I .\radarsimpy .\standard\Windows_x86_64_CPU\radarsimpy
111 |
112 | REM Build completed
113 | ECHO ## Build completed ##
114 |
115 | REM Run unit tests
116 | ECHO ## Run Google test ##
117 | .\src\radarsimcpp\build\Release\radarsimcpp_test.exe
118 |
--------------------------------------------------------------------------------
/batch_build_win_cuda.bat:
--------------------------------------------------------------------------------
1 | REM Display header and copyright information
2 | @ECHO OFF
3 |
4 | ECHO Automatic build script of radarsimcpp/radarsimpy for Windows
5 | ECHO:
6 | ECHO ----------
7 | ECHO RadarSimPy - A Radar Simulator Built with Python
8 | ECHO Copyright (C) 2018 - PRESENT radarsimx.com
9 | ECHO E-mail: info@radarsimx.com
10 | ECHO Website: https://radarsimx.com
11 | ECHO:
12 | ECHO ###### ##### # #
13 | ECHO # # ## ##### ## ##### # # # # # # #
14 | ECHO # # # # # # # # # # # # ## ## # #
15 | ECHO ###### # # # # # # # # ##### # # ## # #
16 | ECHO # # ###### # # ###### ##### # # # # # #
17 | ECHO # # # # # # # # # # # # # # # # #
18 | ECHO # # # # ##### # # # # ##### # # # # #
19 | ECHO:
20 |
21 | REM Store current directory path
22 | SET pwd=%cd%
23 |
24 | REM Clean up previous build artifacts
25 | ECHO clean old build files
26 | RMDIR /Q/S .\src\radarsimcpp\build
27 |
28 | ECHO clean old radarsimpy module
29 | RMDIR /Q/S .\radarsimpy
30 |
31 | REM Create and navigate to build directory
32 | MD ".\src\radarsimcpp\build"
33 | CD ".\src\radarsimcpp\build"
34 |
35 | REM Build C++ library with CMake (with CUDA support)
36 | ECHO ## Building radarsimcpp.dll with MSVC ##
37 | cmake -DGPU_BUILD=ON -DGTEST=ON ..
38 | cmake --build . --config Release
39 |
40 | REM Build Python extensions for multiple Python versions (Free Tier)
41 | ECHO ## Building radarsimpy with Cython ##
42 | CD %pwd%
43 | REM Build for Python 3.9-3.13 with GPU support
44 | conda.exe run -n py313 python setup.py build_ext -b ./ --tier=free --arch=gpu
45 | conda.exe run -n py312 python setup.py build_ext -b ./ --tier=free --arch=gpu
46 | conda.exe run -n py311 python setup.py build_ext -b ./ --tier=free --arch=gpu
47 | conda.exe run -n py310 python setup.py build_ext -b ./ --tier=free --arch=gpu
48 | conda.exe run -n py39 python setup.py build_ext -b ./ --tier=free --arch=gpu
49 |
50 | REM Copy built files to radarsimpy directory
51 | ECHO ## Copying dll files to ./radarsimpy ##
52 | XCOPY ".\src\radarsimcpp\build\Release\radarsimcpp.dll" ".\radarsimpy\"
53 | XCOPY ".\src\radarsimpy\*.py" ".\radarsimpy\"
54 | XCOPY ".\src\radarsimpy\lib\__init__.py" ".\radarsimpy\lib\"
55 |
56 | REM Clean up intermediate build files
57 | ECHO ## Cleaning radarsimpy builds ##
58 | RMDIR build /s /q
59 |
60 | DEL ".\src\radarsimpy\*.c"
61 | DEL ".\src\radarsimpy\*.cpp"
62 | DEL ".\src\radarsimpy\*.html"
63 | DEL ".\src\radarsimpy\raytracing\*.c"
64 | DEL ".\src\radarsimpy\raytracing\*.cpp"
65 | DEL ".\src\radarsimpy\raytracing\*.html"
66 | DEL ".\src\radarsimpy\lib\*.cpp"
67 | DEL ".\src\radarsimpy\lib\*.html"
68 | DEL ".\src\*.cpp"
69 | DEL ".\src\*.html"
70 |
71 | REM Create FreeTier GPU distribution
72 | ECHO ## Copying lib files to freetier release folder ##
73 | RMDIR /Q/S .\trial\Windows_x86_64_GPU
74 | XCOPY /E /I .\radarsimpy .\trial\Windows_x86_64_GPU\radarsimpy
75 |
76 | RMDIR /Q/S .\radarsimpy
77 |
78 | REM Build Standard Tier GPU version
79 | REM Build Python extensions for multiple Python versions (Standard Tier)
80 | conda.exe run -n py313 python setup.py build_ext -b ./ --tier=standard --arch=gpu
81 | conda.exe run -n py312 python setup.py build_ext -b ./ --tier=standard --arch=gpu
82 | conda.exe run -n py311 python setup.py build_ext -b ./ --tier=standard --arch=gpu
83 | conda.exe run -n py310 python setup.py build_ext -b ./ --tier=standard --arch=gpu
84 | conda.exe run -n py39 python setup.py build_ext -b ./ --tier=standard --arch=gpu
85 |
86 | REM Copy built files to radarsimpy directory
87 | ECHO ## Copying dll files to ./radarsimpy ##
88 | XCOPY ".\src\radarsimcpp\build\Release\radarsimcpp.dll" ".\radarsimpy\"
89 | XCOPY ".\src\radarsimpy\*.py" ".\radarsimpy\"
90 | XCOPY ".\src\radarsimpy\lib\__init__.py" ".\radarsimpy\lib\"
91 |
92 | REM Clean up intermediate build files
93 | ECHO ## Cleaning radarsimpy builds ##
94 | RMDIR build /s /q
95 |
96 | DEL ".\src\radarsimpy\*.c"
97 | DEL ".\src\radarsimpy\*.cpp"
98 | DEL ".\src\radarsimpy\*.html"
99 | DEL ".\src\radarsimpy\raytracing\*.c"
100 | DEL ".\src\radarsimpy\raytracing\*.cpp"
101 | DEL ".\src\radarsimpy\raytracing\*.html"
102 | DEL ".\src\radarsimpy\lib\*.cpp"
103 | DEL ".\src\radarsimpy\lib\*.html"
104 | DEL ".\src\*.cpp"
105 | DEL ".\src\*.html"
106 |
107 | REM Create Standard Tier GPU distribution
108 | ECHO ## Copying lib files to standard release folder ##
109 | RMDIR /Q/S .\standard\Windows_x86_64_GPU
110 | XCOPY /E /I .\radarsimpy .\standard\Windows_x86_64_GPU\radarsimpy
111 |
112 | REM Run unit tests
113 | ECHO ## Run Google test ##
114 | .\src\radarsimcpp\build\Release\radarsimcpp_test.exe
115 |
--------------------------------------------------------------------------------
/build_instructions.md:
--------------------------------------------------------------------------------
1 | # RadarSimPy Build Instructions
2 |
3 | ## Prerequisites for All Platforms
4 |
5 | - Python 3.9 or higher
6 | - CMake 3.20 or higher
7 | - C++ compiler with C++20 support
8 | - Python dependencies:
9 |
10 | ```bash
11 | pip install -r requirements.txt
12 | ```
13 |
14 | ## Windows (MSVC)
15 |
16 | 1. Install required tools:
17 | - [Microsoft Visual Studio 2022](https://visualstudio.microsoft.com/) with "Desktop development with C++" workload
18 | - [CMake](https://cmake.org/download/) (Windows x64 Installer)
19 | - [CUDA Toolkit 12](https://developer.nvidia.com/cuda-downloads) (Required only for GPU version)
20 |
21 | 2. Build the project:
22 |
23 | ```batch
24 | # For CPU version
25 | build_win.bat --arch=cpu --test=on
26 |
27 | # For GPU version (requires CUDA)
28 | build_win.bat --arch=gpu --test=on
29 | ```
30 |
31 | ## Ubuntu 22.04/24.04
32 |
33 | 1. Install system dependencies:
34 |
35 | ```bash
36 | # Basic development tools
37 | sudo apt-get update
38 | sudo apt-get install -y build-essential
39 | sudo snap install cmake --classic
40 |
41 | # For GPU version only
42 | # Install CUDA following NVIDIA's official guide:
43 | # https://developer.nvidia.com/cuda-downloads
44 |
45 | # Set up CUDA environment variables
46 | echo 'export PATH=/usr/local/cuda/bin:$PATH' >> ~/.bashrc
47 | echo 'export CUDA_PATH=/usr/local/cuda' >> ~/.bashrc
48 | source ~/.bashrc
49 | ```
50 |
51 | 2. Build the project:
52 |
53 | ```bash
54 | # For CPU version
55 | ./build_linux.sh --arch=cpu --test=on
56 |
57 | # For GPU version
58 | ./build_linux.sh --arch=gpu --test=on
59 | ```
60 |
61 | ## MacOS
62 |
63 | 1. Install build tools:
64 |
65 | ```bash
66 | # Install Homebrew if not already installed
67 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
68 |
69 | # Install required tools
70 | brew install cmake gcc
71 | ```
72 |
73 | 2. Build the project:
74 |
75 | ```bash
76 | ./build_macos.sh --arch=cpu --test=on
77 | ```
78 |
79 | ## Build Output
80 |
81 | The compiled module will be available in the `radarsimpy` folder.
82 |
83 | ## Build Options
84 |
85 | - `--arch`: Build architecture (`cpu` or `gpu`)
86 | - `--test`: Enable testing (`on` or `off`)
87 |
88 | ## Troubleshooting
89 |
90 | - If CMake fails to find CUDA, ensure CUDA_PATH environment variable is set correctly
91 |
--------------------------------------------------------------------------------
/build_linux.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Function to display help information and usage instructions
4 | Help()
5 | {
6 | # Display Help
7 | echo
8 | echo "Usages:"
9 | echo
10 | echo "Syntax: build_linux.sh --tier=[standard|free] --arch=[cpu|gpu] --test=[on|off]"
11 | echo "options:"
12 | echo " --help Show the usages of the parameters"
13 | echo " --tier Build tier, choose 'standard' or 'free'. Default is 'standard'"
14 | echo " --arch Build architecture, choose 'cpu' or 'gpu'. Default is 'cpu'"
15 | echo " --test Enable or disable unit test, choose 'on' or 'off'. Default is 'on'"
16 | echo
17 | }
18 |
19 | # Default configuration values
20 | TIER="standard" # Build tier (standard/free)
21 | ARCH="cpu" # Build architecture (cpu/gpu)
22 | TEST="on" # Unit test flag (on/off)
23 |
24 | # Parse command line arguments
25 | # Supports --help, --tier, --arch, and --test parameters
26 | for i in "$@"; do
27 | case $i in
28 | --help*)
29 | Help
30 | exit;;
31 | --tier=*)
32 | TIER="${i#*=}"
33 | shift # past argument
34 | ;;
35 | --arch=*)
36 | ARCH="${i#*=}"
37 | shift # past argument
38 | ;;
39 | --test=*)
40 | TEST="${i#*=}"
41 | shift # past argument
42 | ;;
43 | --*)
44 | echo "Unknown option $1"
45 | exit 1
46 | ;;
47 | *)
48 | ;;
49 | esac
50 | done
51 |
52 | # Validate the tier parameter
53 | if [ "${TIER,,}" != "standard" ] && [ "${TIER,,}" != "free" ]; then
54 | echo "ERROR: Invalid --tier parameters, please choose 'free' or 'standard'"
55 | exit 1
56 | fi
57 |
58 | # Validate the architecture parameter
59 | if [ "${ARCH,,}" != "cpu" ] && [ "${ARCH,,}" != "gpu" ]; then
60 | echo "ERROR: Invalid --arch parameters, please choose 'cpu' or 'gpu'"
61 | exit 1
62 | fi
63 |
64 | # Validate the test parameter
65 | if [ "${TEST,,}" != "on" ] && [ "${TEST,,}" != "off" ]; then
66 | echo "ERROR: Invalid --test parameters, please choose 'on' or 'off'"
67 | exit 1
68 | fi
69 |
70 | # Display project banner and copyright information
71 | echo "Automatic build script of radarsimcpp/radarsimpy for Linux"
72 | echo ""
73 | echo "----------"
74 | echo "RadarSimPy - A Radar Simulator Built with Python"
75 | echo "Copyright (C) 2018 - PRESENT radarsimx.com"
76 | echo "E-mail: info@radarsimx.com"
77 | echo "Website: https://radarsimx.com"
78 | echo ""
79 | echo "██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗"
80 | echo "██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝"
81 | echo "██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝ "
82 | echo "██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗ "
83 | echo "██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗"
84 | echo "╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝"
85 |
86 | # Store current working directory
87 | workpath=$(pwd)
88 |
89 | # Clean up previous build artifacts
90 | echo "## Clean old build files ##"
91 | rm -rf ./src/radarsimcpp/build
92 | rm -rf ./radarsimpy
93 |
94 | # Build libradarsimcpp.so
95 | echo "## Building libradarsimcpp.so with ${ARCH^^} ##"
96 | mkdir ./src/radarsimcpp/build
97 | cd ./src/radarsimcpp/build
98 |
99 | # Configure CMake based on architecture and test settings
100 | if [ "${ARCH,,}" == "gpu" ]; then
101 | if [ "${TEST,,}" == "on" ]; then
102 | # GPU build with tests enabled
103 | cmake -DCMAKE_BUILD_TYPE=Release -DGPU_BUILD=ON -DGTEST=ON ..
104 | elif [ "${TEST,,}" == "off" ]; then
105 | # GPU build without tests
106 | cmake -DCMAKE_BUILD_TYPE=Release -DGPU_BUILD=ON -DGTEST=OFF ..
107 | fi
108 | elif [ "${ARCH,,}" == "cpu" ]; then
109 | if [ "${TEST,,}" == "on" ]; then
110 | # CPU build with tests enabled
111 | cmake -DCMAKE_BUILD_TYPE=Release -DGTEST=ON ..
112 | elif [ "${TEST,,}" == "off" ]; then
113 | # CPU build without tests
114 | cmake -DCMAKE_BUILD_TYPE=Release -DGTEST=OFF ..
115 | fi
116 | fi
117 |
118 | # Build the project using CMake
119 | cmake --build .
120 |
121 | # Build Python extensions using Cython
122 | echo "## Building radarsimpy with Cython ##"
123 | cd $workpath
124 | python setup.py build_ext -b ./ --tier "${TIER}" --arch "${ARCH}"
125 |
126 | # Copy library files to radarsimpy directory
127 | echo "## Copying lib files to ./radarsimpy ##"
128 | cp ./src/radarsimpy/*.py ./radarsimpy
129 | cp ./src/radarsimpy/lib/__init__.py ./radarsimpy/lib
130 | cp ./src/radarsimcpp/build/*.so ./radarsimpy
131 |
132 | # Clean up intermediate build files
133 | echo "## Cleaning radarsimpy builds ##"
134 | rm -rf build
135 |
136 | # Remove generated C/C++ source files and HTML documentation
137 | rm -f ./src/radarsimpy/*.c
138 | rm -f ./src/radarsimpy/*.cpp
139 | rm -f ./src/radarsimpy/*.html
140 | rm -f ./src/radarsimpy/raytracing/*.c
141 | rm -f ./src/radarsimpy/raytracing/*.cpp
142 | rm -f ./src/radarsimpy/raytracing/*.html
143 | rm -f ./src/radarsimpy/lib/*.cpp
144 | rm -f ./src/radarsimpy/lib/*.html
145 | rm -f ./src/*.cpp
146 | rm -f ./src/*.html
147 |
148 | echo "## Build completed ##"
149 |
150 | return_code=0
151 | # Run tests if enabled
152 | if [ "${TEST,,}" == "on" ]; then
153 | # Run C++ unit tests using Google Test
154 | echo "## Run Google test ##"
155 | ./src/radarsimcpp/build/radarsimcpp_test
156 | return_code=$(($return_code + $?))
157 |
158 | # Run Python unit tests using pytest
159 | echo "## Pytest ##"
160 | pytest
161 | return_code=$(($return_code + $?))
162 | fi
163 |
164 | exit $return_code
165 |
--------------------------------------------------------------------------------
/build_macos.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Function to display help information and usage instructions
4 | Help()
5 | {
6 | # Display Help
7 | echo
8 | echo "Usages:"
9 | echo
10 | echo "Syntax: build_linux.sh --tier=[standard|free] --arch=[cpu|gpu] --test=[on|off]"
11 | echo "options:"
12 | echo " --help Show the usages of the parameters"
13 | echo " --tier Build tier, choose 'standard' or 'free'. Default is 'standard'"
14 | echo " --arch Build architecture, choose 'cpu' or 'gpu'. Default is 'cpu'"
15 | echo " --test Enable or disable unit test, choose 'on' or 'off'. Default is 'on'"
16 | echo
17 | }
18 |
19 | # Parse command line arguments
20 | # Supported arguments:
21 | # --tier: Build tier (standard/free)
22 | # --arch: Build architecture (cpu/gpu)
23 | # --test: Enable/disable unit testing (on/off)
24 | for i in "$@"; do
25 | case $i in
26 | --help*)
27 | Help
28 | exit;;
29 | --tier=*)
30 | TIER="${i#*=}"
31 | shift # past argument
32 | ;;
33 | --arch=*)
34 | ARCH="${i#*=}"
35 | shift # past argument
36 | ;;
37 | --test=*)
38 | TEST="${i#*=}"
39 | shift # past argument
40 | ;;
41 | --*)
42 | echo "Unknown option $1"
43 | exit 1
44 | ;;
45 | *)
46 | ;;
47 | esac
48 | done
49 |
50 | # Validate the tier parameter
51 | # Must be either 'standard' or 'free'
52 | if [ "${TIER}" != "standard" ] && [ "${TIER}" != "free" ]; then
53 | echo "ERROR: Invalid --tier parameters, please choose 'free' or 'standard'"
54 | exit 1
55 | fi
56 |
57 | # Validate the architecture parameter
58 | # Must be either 'cpu' or 'gpu'
59 | if [ "${ARCH}" != "cpu" ] && [ "${ARCH}" != "gpu" ]; then
60 | echo "ERROR: Invalid --arch parameters, please choose 'cpu' or 'gpu'"
61 | exit 1
62 | fi
63 |
64 | # Validate the test parameter
65 | # Must be either 'on' or 'off'
66 | if [ "${TEST}" != "on" ] && [ "${TEST}" != "off" ]; then
67 | echo "ERROR: Invalid --test parameters, please choose 'on' or 'off'"
68 | exit 1
69 | fi
70 |
71 | # Display welcome message and copyright information
72 | echo "Automatic build script of radarsimcpp/radarsimpy for macOS"
73 | echo ""
74 | echo "----------"
75 | echo "RadarSimPy - A Radar Simulator Built with Python"
76 | echo "Copyright (C) 2018 - PRESENT radarsimx.com"
77 | echo "E-mail: info@radarsimx.com"
78 | echo "Website: https://radarsimx.com"
79 | echo ""
80 | echo "██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗"
81 | echo "██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝"
82 | echo "██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝ "
83 | echo "██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗ "
84 | echo "██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗"
85 | echo "╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝"
86 |
87 | # Store current working directory
88 | workpath=$(pwd)
89 |
90 | # Clean up previous build artifacts
91 | echo "## Clean old build files ##"
92 | rm -rf ./src/radarsimcpp/build
93 | rm -rf ./radarsimpy
94 |
95 | # Build the C++ library
96 | echo "## Building libradarsimcpp.so with ${ARCH} ##"
97 | mkdir ./src/radarsimcpp/build
98 | cd ./src/radarsimcpp/build
99 |
100 | # Convert architecture and test parameters to lowercase for consistency
101 | ARCH_LOWER=$(echo "$ARCH" | tr '[:upper:]' '[:lower:]')
102 | TEST_LOWER=$(echo "$TEST" | tr '[:upper:]' '[:lower:]')
103 |
104 | # Configure CMake based on build parameters
105 | # GPU build with testing enabled/disabled
106 | if [ "${ARCH_LOWER}" = "gpu" ]; then
107 | if [ "${TEST_LOWER}" = "on" ]; then
108 | cmake -DCMAKE_BUILD_TYPE=Release -DGPU_BUILD=ON -DGTEST=ON ..
109 | elif [ "${TEST_LOWER}" = "off" ]; then
110 | cmake -DCMAKE_BUILD_TYPE=Release -DGPU_BUILD=ON -DGTEST=OFF ..
111 | fi
112 | # CPU build with testing enabled/disabled
113 | elif [ "${ARCH_LOWER}" = "cpu" ]; then
114 | if [ "${TEST_LOWER}" = "on" ]; then
115 | cmake -DCMAKE_BUILD_TYPE=Release -DGTEST=ON ..
116 | elif [ "${TEST_LOWER}" = "off" ]; then
117 | cmake -DCMAKE_BUILD_TYPE=Release -DGTEST=OFF ..
118 | fi
119 | fi
120 |
121 | # Build the project using CMake
122 | cmake --build .
123 |
124 | # Build Python extensions using Cython
125 | echo "## Building radarsimpy with Cython ##"
126 | cd $workpath
127 | python setup.py build_ext -b ./ --tier "${TIER}" --arch "${ARCH}"
128 |
129 | # Copy built files to the final location
130 | echo "## Copying lib files to ./radarsimpy ##"
131 | cp ./src/radarsimpy/*.py ./radarsimpy
132 | cp ./src/radarsimpy/lib/__init__.py ./radarsimpy/lib
133 | cp ./src/radarsimcpp/build/*.dylib ./radarsimpy
134 |
135 | # Clean up intermediate build files
136 | echo "## Cleaning radarsimpy builds ##"
137 | rm -rf build
138 |
139 | # Remove generated C/C++ source files and HTML documentation
140 | rm -f ./src/radarsimpy/*.c
141 | rm -f ./src/radarsimpy/*.cpp
142 | rm -f ./src/radarsimpy/*.html
143 | rm -f ./src/radarsimpy/raytracing/*.c
144 | rm -f ./src/radarsimpy/raytracing/*.cpp
145 | rm -f ./src/radarsimpy/raytracing/*.html
146 | rm -f ./src/radarsimpy/lib/*.cpp
147 | rm -f ./src/radarsimpy/lib/*.html
148 | rm -f ./src/*.cpp
149 | rm -f ./src/*.html
150 |
151 | echo "## Build completed ##"
152 |
153 | return_code=0
154 | # Run tests if testing is enabled
155 | if [ "${TEST}" == "on" ]; then
156 | # Run C++ unit tests
157 | echo "## Run Google test ##"
158 | ./src/radarsimcpp/build/radarsimcpp_test
159 | return_code=$(($return_code + $?))
160 |
161 | # Run Python unit tests
162 | echo "## Pytest ##"
163 | pytest
164 | return_code=$(($return_code + $?))
165 | fi
166 |
167 | exit $return_code
168 |
--------------------------------------------------------------------------------
/build_win.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | REM Default build configuration
4 | set TIER=standard
5 | set ARCH=cpu
6 | set TEST=on
7 |
8 | goto GETOPTS
9 |
10 | REM Help section - displays command line parameter usage
11 | :Help
12 | ECHO:
13 | ECHO Usages:
14 | ECHO --help Show the usages of the parameters
15 | ECHO --tier Build tier, choose 'standard' or 'free'. Default is 'standard'
16 | ECHO --arch Build architecture, choose 'cpu' or 'gpu'. Default is 'cpu'
17 | ECHO --test Enable or disable unit test, choose 'on' or 'off'. Default is 'on'
18 | ECHO:
19 | goto EOF
20 |
21 | REM Command line parameter parsing section
22 | :GETOPTS
23 | REM Parse command line arguments
24 | if /I "%1" == "--help" goto Help
25 | if /I "%1" == "--tier" set TIER=%2 & shift
26 | if /I "%1" == "--arch" set ARCH=%2 & shift
27 | if /I "%1" == "--test" set TEST=%2 & shift
28 | shift
29 | if not "%1" == "" goto GETOPTS
30 |
31 | REM Validate tier parameter
32 | if /I NOT %TIER% == free (
33 | if /I NOT %TIER% == standard (
34 | ECHO ERROR: Invalid --tier parameters, please choose 'free' or 'standard'
35 | goto EOF
36 | )
37 | )
38 |
39 | REM Validate architecture parameter
40 | if /I NOT %ARCH% == cpu (
41 | if /I NOT %ARCH% == gpu (
42 | ECHO ERROR: Invalid --arch parameters, please choose 'cpu' or 'gpu'
43 | goto EOF
44 | )
45 | )
46 |
47 | REM Validate test parameter
48 | if /I NOT %TEST% == on (
49 | if /I NOT %TEST% == off (
50 | ECHO ERROR: Invalid --test parameters, please choose 'on' or 'off'
51 | goto EOF
52 | )
53 | )
54 |
55 | REM Display banner and copyright information
56 | ECHO Automatic build script of radarsimcpp/radarsimpy for Windows
57 | ECHO:
58 | ECHO ----------
59 | ECHO RadarSimPy - A Radar Simulator Built with Python
60 | ECHO Copyright (C) 2018 - PRESENT radarsimx.com
61 | ECHO E-mail: info@radarsimx.com
62 | ECHO Website: https://radarsimx.com
63 | ECHO:
64 | ECHO ###### ##### # #
65 | ECHO # # ## ##### ## ##### # # # # # # #
66 | ECHO # # # # # # # # # # # # ## ## # #
67 | ECHO ###### # # # # # # # # ##### # # ## # #
68 | ECHO # # ###### # # ###### ##### # # # # # #
69 | ECHO # # # # # # # # # # # # # # # # #
70 | ECHO # # # # ##### # # # # ##### # # # # #
71 | ECHO:
72 |
73 | REM Store current directory for later use
74 | SET pwd=%cd%
75 |
76 | REM Clean up previous build artifacts
77 | ECHO clean old build files
78 | RMDIR /Q/S .\src\radarsimcpp\build
79 |
80 | ECHO clean old radarsimpy module
81 | RMDIR /Q/S .\radarsimpy
82 |
83 | REM Create and enter build directory
84 | @REM Create fresh build directory and change to it
85 | MD ".\src\radarsimcpp\build"
86 | CD ".\src\radarsimcpp\build"
87 |
88 | REM Configure CMake build based on architecture and test settings
89 | ECHO ## Building radarsimcpp.dll with MSVC ##
90 | @REM MSVC requires explicit Release configuration
91 | if /I %ARCH% == gpu (
92 | if /I %TEST% == on (
93 | cmake -DGPU_BUILD=ON -DGTEST=ON ..
94 | ) else (
95 | cmake -DGPU_BUILD=ON -DGTEST=OFF ..
96 | )
97 | ) else if /I %ARCH% == cpu (
98 | if /I %TEST% == on (
99 | cmake -DGTEST=ON ..
100 | ) else (
101 | cmake -DGTEST=OFF ..
102 | )
103 | )
104 | cmake --build . --config Release
105 |
106 | REM Build Python extensions using Cython
107 | ECHO ## Building radarsimpy with Cython ##
108 | CD %pwd%
109 | python setup.py build_ext -b ./ --tier %TIER% --arch %ARCH%
110 |
111 | REM Copy built artifacts to final locations
112 | ECHO ## Copying dll files to ./radarsimpy ##
113 | XCOPY ".\src\radarsimcpp\build\Release\radarsimcpp.dll" ".\radarsimpy\"
114 | XCOPY ".\src\radarsimpy\*.py" ".\radarsimpy\"
115 | XCOPY ".\src\radarsimpy\lib\__init__.py" ".\radarsimpy\lib\"
116 |
117 | REM Clean up intermediate build files
118 | ECHO ## Cleaning radarsimpy builds ##
119 | RMDIR build /s /q
120 |
121 | DEL ".\src\radarsimpy\*.c"
122 | DEL ".\src\radarsimpy\*.cpp"
123 | DEL ".\src\radarsimpy\*.html"
124 | DEL ".\src\radarsimpy\raytracing\*.c"
125 | DEL ".\src\radarsimpy\raytracing\*.cpp"
126 | DEL ".\src\radarsimpy\raytracing\*.html"
127 | DEL ".\src\radarsimpy\lib\*.cpp"
128 | DEL ".\src\radarsimpy\lib\*.html"
129 | DEL ".\src\*.cpp"
130 | DEL ".\src\*.html"
131 |
132 | SET TEST_FAILED=0
133 | REM Run tests if enabled
134 | if /I %TEST% == on (
135 | ECHO ## Run Google test ##
136 | .\src\radarsimcpp\build\Release\radarsimcpp_test.exe
137 | if errorlevel 1 (
138 | echo Google test failed!
139 | SET TEST_FAILED=1
140 | )
141 |
142 | ECHO ## Pytest ##
143 | pytest
144 | if errorlevel 1 (
145 | echo Pytest failed!
146 | SET TEST_FAILED=1
147 | )
148 | )
149 |
150 | exit /b %TEST_FAILED%
151 |
152 | :EOF
--------------------------------------------------------------------------------
/gen_docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = .
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 |
--------------------------------------------------------------------------------
/gen_docs/_static/radarsimdoc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/gen_docs/_static/radarsimdoc.png
--------------------------------------------------------------------------------
/gen_docs/api/index.rst:
--------------------------------------------------------------------------------
1 | API
2 | ===
3 |
4 | .. toctree::
5 | :maxdepth: 2
6 |
7 | radar
8 | sim
9 | process
10 | tools
11 |
--------------------------------------------------------------------------------
/gen_docs/api/process.rst:
--------------------------------------------------------------------------------
1 | Processing
2 | ===========
3 |
4 | .. automodule:: radarsimpy.processing
5 | :members:
6 | :undoc-members:
7 | :inherited-members:
8 | :show-inheritance:
9 | :exclude-members: os_cfar_threshold
--------------------------------------------------------------------------------
/gen_docs/api/radar.rst:
--------------------------------------------------------------------------------
1 | Radar Model
2 | ===========
3 |
4 | Radar Configuration and Phase Noise Modeling in Python
5 |
6 | This module contains classes and functions to define and simulate
7 | the parameters and behavior of radar systems. It includes tools for
8 | configuring radar system properties, modeling oscillator phase noise,
9 | and simulating radar motion and noise characteristics. A major focus
10 | of the module is on accurately modeling radar signal properties,
11 | including phase noise and noise amplitudes.
12 |
13 | ---
14 |
15 | - Copyright (C) 2018 - PRESENT radarsimx.com
16 | - E-mail: info@radarsimx.com
17 | - Website: https://radarsimx.com
18 |
19 | ::
20 |
21 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
22 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
23 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
24 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
25 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
26 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
27 |
28 | radarsimpy.Transmitter
29 | -----------------------
30 |
31 | .. autoclass:: radarsimpy.Transmitter
32 | :members:
33 | :undoc-members:
34 | :inherited-members:
35 | :show-inheritance:
36 | :exclude-members: validate_rf_prop, validate_waveform_prop, process_waveform_modulation, process_pulse_modulation, process_txchannel_prop
37 |
38 | radarsimpy.Receiver
39 | --------------------
40 |
41 | .. autoclass:: radarsimpy.Receiver
42 | :members:
43 | :undoc-members:
44 | :inherited-members:
45 | :show-inheritance:
46 | :exclude-members: validate_bb_prop, process_rxchannel_prop
47 |
48 | radarsimpy.Radar
49 | -----------------
50 |
51 | .. autoclass:: radarsimpy.Radar
52 | :members:
53 | :undoc-members:
54 | :inherited-members:
55 | :show-inheritance:
56 | :exclude-members: cal_noise, gen_timestamp, validate_radar_motion, process_radar_motion
57 |
--------------------------------------------------------------------------------
/gen_docs/api/sim.rst:
--------------------------------------------------------------------------------
1 | Simulator
2 | ===========
3 |
4 | .. automodule:: radarsimpy.simulator
5 | :members:
6 | :undoc-members:
7 | :inherited-members:
8 | :show-inheritance:
9 | :exclude-members: raise_err
10 |
--------------------------------------------------------------------------------
/gen_docs/api/tools.rst:
--------------------------------------------------------------------------------
1 | Tools
2 | =================
3 |
4 | .. automodule:: radarsimpy.tools
5 | :members:
6 | :undoc-members:
7 | :inherited-members:
8 | :show-inheritance:
9 | :exclude-members: log_factorial, threshold, marcumq, pd_swerling0, pd_swerling1, pd_swerling2, pd_swerling3, pd_swerling4
10 |
--------------------------------------------------------------------------------
/gen_docs/conf.py:
--------------------------------------------------------------------------------
1 | """
2 | Configuration file for the Sphinx documentation builder.
3 |
4 | This file only contains a selection of the most common options. For a full
5 | list see the documentation:
6 | https://www.sphinx-doc.org/en/master/usage/configuration.html
7 |
8 | -- Path setup --------------------------------------------------------------
9 |
10 | If extensions (or modules to document with autodoc) are in another directory,
11 | add these directories to sys.path here. If the directory is relative to the
12 | documentation root, use os.path.abspath to make it absolute, like shown here.
13 | """
14 |
15 | import os
16 | import sys
17 | import datetime
18 |
19 | sys.path.insert(0, os.path.abspath(".."))
20 |
21 | import radarsimpy # pylint: disable=wrong-import-position
22 |
23 | # -- Project information -----------------------------------------------------
24 |
25 | project = "RadarSimPy" # pylint: disable=invalid-name
26 | copyright = ( # pylint: disable=redefined-builtin, invalid-name
27 | "2018 - " + str(datetime.datetime.now().year) + ", RadarSimX LLC"
28 | )
29 | version = radarsimpy.__version__ # pylint: disable=invalid-name
30 | release = version # pylint: disable=invalid-name
31 |
32 | pygments_style = "sphinx"
33 |
34 | # -- General configuration ---------------------------------------------------
35 |
36 | # Add any Sphinx extension module names here, as strings. They can be
37 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
38 | # ones.
39 | extensions = [
40 | "sphinx.ext.intersphinx",
41 | "sphinx.ext.autodoc",
42 | "sphinx.ext.mathjax",
43 | "sphinx.ext.viewcode",
44 | "sphinx.ext.doctest", # Add doctest extension
45 | ]
46 |
47 | autodoc_typehints = "description"
48 |
49 | # Add any paths that contain templates here, relative to this directory.
50 | templates_path = ["_templates"]
51 |
52 | html_favicon = "_static/radarsimdoc.png" # pylint: disable=invalid-name
53 |
54 | # List of patterns, relative to source directory, that match files and
55 | # directories to ignore when looking for source files.
56 | # This pattern also affects html_static_path and html_extra_path.
57 | exclude_patterns = []
58 |
59 |
60 | # -- Options for HTML output -------------------------------------------------
61 |
62 | # The theme to use for HTML and HTML Help pages. See the documentation for
63 | # a list of builtin themes.
64 | #
65 | html_theme = "pydata_sphinx_theme" # pylint: disable=invalid-name
66 |
67 | html_theme_options = {
68 | "logo": {
69 | "text": "RadarSimPy v" + version,
70 | "image_light": "_static/radarsimdoc.svg",
71 | "image_dark": "_static/radarsimdoc.svg",
72 | },
73 | "navbar_align": "left",
74 | "secondary_sidebar_items": ["page-toc"],
75 | "show_nav_level": 2,
76 | "show_toc_level": 2,
77 | "show_version_warning_banner": True,
78 | "header_links_before_dropdown": 8,
79 | "icon_links": [
80 | {
81 | "name": "RadarSimX",
82 | "url": "https://radarsimx.com/",
83 | "icon": "fas fa-globe",
84 | },
85 | {
86 | "name": "GitHub",
87 | "url": "https://github.com/radarsimx/radarsimpy",
88 | "icon": "fab fa-github",
89 | },
90 | ],
91 | "footer_start": ["copyright"],
92 | "footer_center ": ["sphinx-version"],
93 | "footer_end": ["theme-version"],
94 | }
95 |
96 | html_context = {
97 | "default_mode": "auto",
98 | "display_github": True,
99 | "github_user": "radarsimx",
100 | "github_repo": "radarsimpy",
101 | }
102 |
103 | # Add any paths that contain custom static files (such as style sheets) here,
104 | # relative to this directory. They are copied after the builtin static files,
105 | # so a file named "default.css" will overwrite the builtin "default.css".
106 | # html_static_path = ["_static"]
107 |
--------------------------------------------------------------------------------
/gen_docs/index.rst:
--------------------------------------------------------------------------------
1 | .. RadarSimPy documentation master file, created by
2 | sphinx-quickstart on Wed Dec 16 08:59:19 2020.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to RadarSimPy's Documentation!
7 | ======================================
8 |
9 | |
10 |
11 | .. image:: _static/radarsimx_main.svg
12 | :width: 60%
13 | :alt: RadarSimX
14 | :target: https://radarsimx.com
15 |
16 | |
17 |
18 | User Guide
19 | ----------
20 |
21 | Step-by-step guides to help you get started with RadarSimPy and understand key concepts.
22 |
23 | .. toctree::
24 | :maxdepth: 2
25 |
26 | user_guide/index
27 |
28 |
29 | API
30 | ---
31 |
32 | Complete reference documentation for all RadarSimPy classes and functions.
33 |
34 | .. toctree::
35 | :maxdepth: 2
36 |
37 | api/index
38 |
--------------------------------------------------------------------------------
/gen_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=.
11 | set BUILDDIR=_build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/gen_docs/user_guide/build.rst:
--------------------------------------------------------------------------------
1 | Build Instructions
2 | ==================
3 |
4 | .. warning::
5 | Building radarsimpy requires access to the radarsimcpp source code. If you don't have access,
6 | please use the pre-built module. For organizations seeking full source code access for customization
7 | or advanced integration, please `submit Quote for Source Code `_.
8 |
9 | Windows
10 | -------
11 |
12 | **CPU Version**
13 |
14 | .. code-block:: batch
15 |
16 | build_win.bat --arch cpu --test=on
17 |
18 | **GPU Version (CUDA)**
19 |
20 | .. code-block:: batch
21 |
22 | build_win.bat --arch gpu --test=on
23 |
24 | Linux
25 | -----
26 |
27 | **CPU Version**
28 |
29 | .. code-block:: bash
30 |
31 | ./build_linux.sh --arch=cpu --test=on
32 |
33 | **GPU Version (CUDA)**
34 |
35 | .. code-block:: bash
36 |
37 | ./build_linux.sh --arch=gpu --test=on
38 |
39 | MacOS
40 | -----
41 |
42 | .. code-block:: bash
43 |
44 | ./build_macos.sh --arch=cpu --test=on
45 |
--------------------------------------------------------------------------------
/gen_docs/user_guide/coordinate.rst:
--------------------------------------------------------------------------------
1 | Coordinate Systems
2 | ===================
3 |
4 | **Global Coordinate**
5 |
6 | - **axis** (m): ``[x, y, z]``
7 | - **phi** (deg): angle on the x-y plane. 0 deg is the positive x-axis, 90 deg is the positive y-axis
8 | - **theta** (deg): angle on the z-x plane. 0 deg is the positive z-axis, 90 deg is the x-y plane
9 |
10 | .. image:: https://raw.githubusercontent.com/radarsimx/radarsimpy/refs/heads/master/assets/phi_theta.svg
11 | :width: 400
12 | :alt: Phi Theta Plot
13 |
14 | **Local Coordinate**
15 |
16 | - **yaw** (deg): rotation along the z-axis. Positive yaw rotates the object from the positive x-axis to the positive y-axis
17 | - **pitch** (deg): rotation along the y-axis. Positive pitch rotates the object from the positive x-axis to the positive z-axis
18 | - **roll** (deg): rotation along the x-axis. Positive roll rotates the object from the positive y-axis to the positive z-axis
19 | - **origin** (m): ``[x, y, z]``, the motion (rotation and translation) centor of the object. Radar's origin is always at ``[0, 0, 0]``
20 |
21 | .. image:: https://raw.githubusercontent.com/radarsimx/radarsimpy/master/assets/yaw_pitch_roll.svg
22 | :width: 400
23 | :alt: Yaw Pitch Roll Plot
24 |
25 | - **azimuth** (deg): azimuth -90 ~ 90 deg equal to phi -90 ~ 90 deg
26 | - **elevation** (deg): elevation -90 ~ 90 deg equal to theta 180 ~ 0 deg
27 |
28 | .. image:: https://raw.githubusercontent.com/radarsimx/radarsimpy/master/assets/azimuth_elevation.svg
29 | :width: 400
30 | :alt: Azimuth Elevation Plot
31 |
--------------------------------------------------------------------------------
/gen_docs/user_guide/dependence.rst:
--------------------------------------------------------------------------------
1 | Dependencies
2 | ============
3 |
4 | Python Requirements
5 | -------------------
6 |
7 | * ``Python`` >= 3.9
8 | * ``NumPy`` >= 2.0
9 | * ``SciPy`` >= 1.11.0
10 | * One of the following mesh processing libraries:
11 |
12 | * ``PyMeshLab`` >= 2022.2
13 | * ``PyVista`` >= 0.43.0
14 | * ``trimesh`` >= 4.0.0
15 | * ``meshio`` >= 5.3.0
16 |
17 | System Requirements
18 | -------------------
19 |
20 | Windows
21 | ^^^^^^^
22 | * `Visual C++ Runtime `_
23 | * For GPU version (CUDA 12): Latest NVIDIA drivers - See `compatibility guide `_
24 |
25 | Linux
26 | ^^^^^
27 |
28 | **Ubuntu 22.04/24.04**
29 |
30 | * GCC (included by default)
31 | * For GPU version (CUDA 12): Latest NVIDIA drivers
32 |
33 | **Other Linux distributions**
34 |
35 | * Try the Ubuntu builds first
36 | * `Request a custom build `_ if needed
37 |
38 | MacOS
39 | ^^^^^
40 |
41 | **Intel/Apple Silicon**
42 |
43 | * GCC 14 installation::
44 |
45 | brew install gcc@14
46 |
--------------------------------------------------------------------------------
/gen_docs/user_guide/examples.rst:
--------------------------------------------------------------------------------
1 | Usage Examples
2 | ==============
3 |
4 | All usage examples are available on `radarsimx.com `_.
5 | Source files can be found in the `radarsimnb repository `_.
6 |
7 | Waveform
8 | --------
9 | * `Pulsed Radar `_
10 | * `Interferometric Radar `_
11 | * `Arbitrary waveform `_
12 | * `PMCW radar `_
13 | * `Doppler radar `_
14 | * `FMCW radar `_
15 |
16 | MIMO
17 | ----
18 | * `Imaging radar `_
19 | * `DoA estimation `_
20 | * `TDM MIMO FMCW radar `_
21 |
22 | Angle Estimation
23 | ----------------
24 | * `Imaging radar `_
25 | * `DoA estimation `_
26 |
27 | Ray Tracing
28 | -----------
29 | * `Imaging radar `_
30 | * `Multi-path effect `_
31 | * `Micro-Doppler `_
32 | * `Doppler of a turbine `_
33 | * `FMCW radar with a car `_
34 | * `FMCW radar with a plate `_
35 | * `FMCW radar with a corner reflector `_
36 | * `Cross-Polarization and Co-Polarization RCS `_
37 | * `Car RCS `_
38 | * `Plate RCS `_
39 | * `Corner reflector RCS `_
40 | * `LIDAR point cloud `_
41 |
42 | CFAR
43 | ----
44 | * `FMCW radar with a corner reflector `_
45 | * `CFAR `_
46 |
47 | Interference
48 | ------------
49 | * `Interference `_
50 |
51 | System Characterization
52 | -----------------------
53 | * `FMCW Radar Link Budget (Point Target) `_
54 | * `Phase noise `_
55 | * `Receiver operating characteristic (ROC) `_
56 |
57 | Radar Cross Section
58 | -------------------
59 | * `Cross-Polarization and Co-Polarization RCS `_
60 | * `Car RCS `_
61 | * `Plate RCS `_
62 | * `Corner reflector RCS `_
63 |
64 | LiDAR
65 | -----
66 | * `LIDAR point cloud `_
67 |
--------------------------------------------------------------------------------
/gen_docs/user_guide/features.rst:
--------------------------------------------------------------------------------
1 | Key Features
2 | ============
3 |
4 | Radar Modeling
5 | --------------
6 |
7 | **Radar Transceiver Modeling**
8 |
9 | * Arbitrary waveform (CW, FMCW, PMCW, Pulse, ...)
10 | * Phase noise
11 | * Phase/amplitude modulation (CDM, FDM, DDM, TDM, ...)
12 | * Fast-time/slow-time modulation
13 |
14 | Simulation
15 | ----------
16 |
17 | * Radar baseband data from point targets
18 | * Radar baseband data from 3D modeled objects/environment
19 | * Interference simulation
20 | * Target's RCS simulation
21 | * LiDAR point cloud from 3D modeled objects/environment
22 |
23 | Signal Processing
24 | -----------------
25 |
26 | **Range/Doppler Processing**
27 |
28 | * Direction of arrival (DoA) estimation
29 | * Multiple techniques for ULA DoA estimation:
30 |
31 | * MUltiple SIgnal Classification (MUSIC)
32 | * Root-MUSIC
33 | * Estimation of Signal Parameters via Rational Invariance Techniques (ESPRIT)
34 |
35 | * Iterative Adaptive Approach (IAA) for amplitude and phase estimation
36 |
37 | **Beamforming**
38 |
39 | * Capon beamformer
40 | * Bartlett beamformer
41 |
42 | **CFAR Processing**
43 |
44 | * 1D/2D cell-averaging CFAR (CA-CFAR)
45 | * 1D/2D ordered-statistic CFAR (OS-CFAR)
46 |
47 | Characterization
48 | ----------------
49 |
50 | * Radar detection characteristics based on Swerling's models
51 |
--------------------------------------------------------------------------------
/gen_docs/user_guide/index.rst:
--------------------------------------------------------------------------------
1 | User Guide
2 | ==========
3 |
4 | .. toctree::
5 | :maxdepth: 2
6 | :caption: Get started
7 |
8 | features
9 | dependence
10 | installation
11 | coordinate
12 | examples
13 | build
14 |
--------------------------------------------------------------------------------
/gen_docs/user_guide/installation.rst:
--------------------------------------------------------------------------------
1 | Installation
2 | ============
3 |
4 | Quick Start
5 | -----------
6 |
7 | 1. Download the `pre-built module `_
8 | 2. Extract the package
9 | 3. Place the radarsimpy folder in your project directory
10 |
11 | Directory Structure
12 | -------------------
13 |
14 | The following shows the typical project structure after installation:
15 |
16 | Common Files
17 | ^^^^^^^^^^^^
18 | .. code-block:: none
19 |
20 | your_project/
21 | ├── your_project.py
22 | ├── your_project.ipynb
23 | └── radarsimpy/
24 | ├── __init__.py
25 | ├── radar.py
26 | ├── processing.py
27 | └── ...
28 |
29 | Platform-Specific Files
30 | ^^^^^^^^^^^^^^^^^^^^^^^
31 |
32 | **Windows**::
33 |
34 | radarsimpy/
35 | ├── radarsimcpp.dll
36 | └── simulator.xxx.pyd
37 |
38 | **Linux**::
39 |
40 | radarsimpy/
41 | ├── libradarsimcpp.so
42 | └── simulator.xxx.so
43 |
44 | **MacOS**::
45 |
46 | radarsimpy/
47 | ├── libradarsimcpp.dylib
48 | └── simulator.xxx.so
49 |
50 | Verification
51 | ------------
52 |
53 | To verify the installation, run:
54 |
55 | .. code-block:: python
56 |
57 | import radarsimpy
58 | print(radarsimpy.__version__)
59 |
--------------------------------------------------------------------------------
/models/ball_1m.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/models/ball_1m.stl
--------------------------------------------------------------------------------
/models/cr.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/models/cr.stl
--------------------------------------------------------------------------------
/models/dihedral.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/models/dihedral.stl
--------------------------------------------------------------------------------
/models/half_ring.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/models/half_ring.stl
--------------------------------------------------------------------------------
/models/pannel.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/models/pannel.stl
--------------------------------------------------------------------------------
/models/plate.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/models/plate.stl
--------------------------------------------------------------------------------
/models/plate5x5.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/models/plate5x5.stl
--------------------------------------------------------------------------------
/models/surface.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/models/surface.stl
--------------------------------------------------------------------------------
/models/surface_400x400.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/models/surface_400x400.stl
--------------------------------------------------------------------------------
/models/surface_60x60.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/models/surface_60x60.stl
--------------------------------------------------------------------------------
/models/turbine.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/models/turbine.stl
--------------------------------------------------------------------------------
/models/vehicles/ford_raptor.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/models/vehicles/ford_raptor.stl
--------------------------------------------------------------------------------
/models/vehicles/gasoline_tanker.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/models/vehicles/gasoline_tanker.stl
--------------------------------------------------------------------------------
/models/vehicles/honda_cb400.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/models/vehicles/honda_cb400.stl
--------------------------------------------------------------------------------
/models/vehicles/lamborgini_aventador.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/models/vehicles/lamborgini_aventador.stl
--------------------------------------------------------------------------------
/models/vehicles/scania_truck.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/models/vehicles/scania_truck.stl
--------------------------------------------------------------------------------
/models/vehicles/tesla_model_s.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/models/vehicles/tesla_model_s.stl
--------------------------------------------------------------------------------
/references/An Efficient and Robust Ray–Box Intersection Algorithm.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/references/An Efficient and Robust Ray–Box Intersection Algorithm.pdf
--------------------------------------------------------------------------------
/references/Gordon_1975_Far-field approximations to the Kirchoff-Helmholtz representations of scattered.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/references/Gordon_1975_Far-field approximations to the Kirchoff-Helmholtz representations of scattered.pdf
--------------------------------------------------------------------------------
/references/Guerrero_2018_Frequency-modulated continuous-wave radar in automotive applications.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/references/Guerrero_2018_Frequency-modulated continuous-wave radar in automotive applications.pdf
--------------------------------------------------------------------------------
/references/Hung_2000_Matrix-construction calibration method for antenna arrays.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/references/Hung_2000_Matrix-construction calibration method for antenna arrays.pdf
--------------------------------------------------------------------------------
/references/Hwang_2015_Radar cross section analysis using physical optics and its applications to.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/references/Hwang_2015_Radar cross section analysis using physical optics and its applications to.pdf
--------------------------------------------------------------------------------
/references/Karras_2012_Maximizing parallelism in the construction of BVHs, octrees, and k-d trees.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/references/Karras_2012_Maximizing parallelism in the construction of BVHs, octrees, and k-d trees.pdf
--------------------------------------------------------------------------------
/references/Mahafza_2015_Chapter 4 radar detection.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/references/Mahafza_2015_Chapter 4 radar detection.pdf
--------------------------------------------------------------------------------
/references/Reflection and Refraction of Plane EM Waves.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/references/Reflection and Refraction of Plane EM Waves.pdf
--------------------------------------------------------------------------------
/references/Zhao_2012_Fast physical optics calculation for SAR imaging of complex scatterers.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/references/Zhao_2012_Fast physical optics calculation for SAR imaging of complex scatterers.pdf
--------------------------------------------------------------------------------
/references/add_phase_noise.m:
--------------------------------------------------------------------------------
1 | function Sout = add_phase_noise( Sin, Fs, phase_noise_freq, phase_noise_power, VALIDATION_ON )
2 | %
3 | % function Sout = add_phase_noise( Sin, Fs, phase_noise_freq, phase_noise_power, VALIDATION_ON )
4 | %
5 | % Oscillator Phase Noise Model
6 | %
7 | % INPUT:
8 | % Sin - input COMPLEX signal
9 | % Fs - sampling frequency ( in Hz ) of Sin
10 | % phase_noise_freq - frequencies at which SSB Phase Noise is defined (offset from carrier in Hz)
11 | % phase_noise_power - SSB Phase Noise power ( in dBc/Hz )
12 | % VALIDATION_ON - 1 - perform validation, 0 - don't perfrom validation
13 | %
14 | % OUTPUT:
15 | % Sout - output COMPLEX phase noised signal
16 | %
17 | % NOTE:
18 | % Input signal should be complex
19 | %
20 | % EXAMPLE ( How to use add_phase_noise ):
21 | % Assume SSB Phase Noise is specified as follows:
22 | % -------------------------------------------------------
23 | % | Offset From Carrier | Phase Noise |
24 | % -------------------------------------------------------
25 | % | 1 kHz | -84 dBc/Hz |
26 | % | 10 kHz | -100 dBc/Hz |
27 | % | 100 kHz | -96 dBc/Hz |
28 | % | 1 MHz | -109 dBc/Hz |
29 | % | 10 MHz | -122 dBc/Hz |
30 | % -------------------------------------------------------
31 | %
32 | % Assume that we have 10000 samples of complex sinusoid of frequency 3 KHz
33 | % sampled at frequency 40MHz:
34 | %
35 | % Fc = 3e3; % carrier frequency
36 | % Fs = 40e6; % sampling frequency
37 | % t = 0:9999;
38 | % S = exp(j*2*pi*Fc/Fs*t); % complex sinusoid
39 | %
40 | % Then, to produce phase noised signal S1 from the original signal S run follows:
41 | %
42 | % Fs = 40e6;
43 | % phase_noise_freq = [ 1e3, 10e3, 100e3, 1e6, 10e6 ]; % Offset From Carrier
44 | % phase_noise_power = [ -84, -100, -96, -109, -122 ]; % Phase Noise power
45 | % S1 = add_phase_noise( S, Fs, phase_noise_freq, phase_noise_power );
46 |
47 | % Version 1.0
48 | % Alex Bur-Guy, October 2005
49 | % alex@wavion.co.il
50 | %
51 | % Revisions:
52 | % Version 1.5 - Comments. Validation.
53 | % Version 1.0 - initial version
54 |
55 | % NOTES:
56 | % 1) The presented model is a simple VCO phase noise model based on the following consideration:
57 | % If the output of an oscillator is given as V(t) = V0 * cos( w0*t + phi(t) ),
58 | % then phi(t) is defined as the phase noise. In cases of small noise
59 | % sources (a valid assumption in any usable system), a narrowband modulation approximation can
60 | % be used to express the oscillator output as:
61 | %
62 | % V(t) = V0 * cos( w0*t + phi(t) )
63 | %
64 | % = V0 * [cos(w0*t)*cos(phi(t)) - sin(w0*t)*sin(phi(t)) ]
65 | %
66 | % ~ V0 * [cos(w0*t) - sin(w0*t)*phi(t)]
67 | %
68 | % This shows that phase noise will be mixed with the carrier to produce sidebands around the carrier.
69 | %
70 | %
71 | % 2) In other words, exp(j*x) ~ (1+j*x) for small x
72 | %
73 | % 3) Phase noise = 0 dBc/Hz at freq. offset of 0 Hz
74 | %
75 | % 4) The lowest phase noise level is defined by the input SSB phase noise power at the maximal
76 | % freq. offset from DC. (IT DOES NOT BECOME EQUAL TO ZERO )
77 | %
78 | % The generation process is as follows:
79 | % First of all we interpolate (in log-scale) SSB phase noise power spectrum in M
80 | % equally spaced points (on the interval [0 Fs/2] including bounds ).
81 | %
82 | % After that we calculate required frequency shape of the phase noise by X(m) = sqrt(P(m)*dF(m))
83 | % and after that complement it by the symmetrical negative part of the spectrum.
84 | %
85 | % After that we generate AWGN of power 1 in the freq domain and multiply it sample-by-sample to
86 | % the calculated shape
87 | %
88 | % Finally we perform 2*M-2 points IFFT to such generated noise
89 | % ( See comments inside the code )
90 | %
91 | % 0 dBc/Hz
92 | % \ /
93 | % \ /
94 | % \ /
95 | % \P dBc/Hz /
96 | % .\ /
97 | % . \ /
98 | % . \ /
99 | % . \____________________________________________/ /_ This level is defined by the phase_noise_power at the maximal freq. offset from DC defined in phase_noise_freq
100 | % . \
101 | % |__| _|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__ (N points)
102 | % 0 dF Fs/2 Fs
103 | % DC
104 | %
105 | %
106 | % For some basics about Oscillator phase noise see:
107 | % http://www.circuitsage.com/pll/plldynamics.pdf
108 | %
109 | % http://www.wj.com/pdf/technotes/LO_phase_noise.pdf
110 |
111 | if nargin < 5
112 | VALIDATION_ON = 0;
113 | end
114 |
115 | % Check Input
116 | error( nargchk(4,5,nargin) );
117 |
118 | if ~any( imag(Sin(:)) )
119 | error( 'Input signal should be complex signal' );
120 | end
121 | if max(phase_noise_freq) >= Fs/2
122 | error( 'Maximal frequency offset should be less than Fs/2');
123 | end
124 |
125 | % Make sure phase_noise_freq and phase_noise_power are the row vectors
126 | phase_noise_freq = phase_noise_freq(:).';
127 | phase_noise_power = phase_noise_power(:).';
128 | if length( phase_noise_freq ) ~= length( phase_noise_power )
129 | error('phase_noise_freq and phase_noise_power should be of the same length');
130 | end
131 |
132 | % Sort phase_noise_freq and phase_noise_power
133 | [phase_noise_freq, indx] = sort( phase_noise_freq );
134 | phase_noise_power = phase_noise_power( indx );
135 |
136 | % Add 0 dBc/Hz @ DC
137 | if ~any(phase_noise_freq == 0)
138 | phase_noise_power = [ 0, phase_noise_power ];
139 | phase_noise_freq = [0, phase_noise_freq];
140 | end
141 |
142 | % Calculate input length
143 | N = prod( size( Sin ) );
144 |
145 | % Define M number of points (frequency resolution) in the positive spectrum
146 | % (M equally spaced points on the interval [0 Fs/2] including bounds),
147 | % then the number of points in the negative spectrum will be M-2
148 | % ( interval (Fs/2, Fs) not including bounds )
149 | %
150 | % The total number of points in the frequency domain will be 2*M-2, and if we want
151 | % to get the same length as the input signal, then
152 | % 2*M-2 = N
153 | % M-1 = N/2
154 | % M = N/2 + 1
155 | %
156 | % So, if N is even then M = N/2 + 1, and if N is odd we will take M = (N+1)/2 + 1
157 | %
158 | if rem(N,2), % N odd
159 | M = (N+1)/2 + 1;
160 | else
161 | M = N/2 + 1;
162 | end
163 |
164 |
165 | % Equally spaced partitioning of the half spectrum
166 | F = linspace( 0, Fs/2, M ); % Freq. Grid
167 | dF = [diff(F) F(end)-F(end-1)]; % Delta F
168 |
169 |
170 | % Perform interpolation of phase_noise_power in log-scale
171 | intrvlNum = length( phase_noise_freq );
172 | logP = zeros( 1, M );
173 | for intrvlIndex = 1 : intrvlNum,
174 | leftBound = phase_noise_freq(intrvlIndex);
175 | t1 = phase_noise_power(intrvlIndex);
176 | if intrvlIndex == intrvlNum
177 | rightBound = Fs/2;
178 | t2 = phase_noise_power(end);
179 | inside = find( F>=leftBound & F<=rightBound );
180 | else
181 | rightBound = phase_noise_freq(intrvlIndex+1);
182 | t2 = phase_noise_power(intrvlIndex+1);
183 | inside = find( F>=leftBound & F-' ); % approximation ( 1+j*x )
250 | xlabel('Frequency [Hz]');
251 | ylabel('dBc/Hz');
252 | legend( ...
253 | 'Input SSB phase noise power', ...
254 | 'Interpolated SSB phase noise power', ...
255 | 'Positive spectrum of the generated phase noise exp(j*x)', ...
256 | 'Positive spectrum of the approximation ( 1+j*x )' ...
257 | );
258 | end
259 |
--------------------------------------------------------------------------------
/references/exact_and_approximate_pd_formulas_in_frsp.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radarsimx/radarsimpy/0d312d496e0b99dedd8c1fbbfb5de978bc374c0f/references/exact_and_approximate_pd_formulas_in_frsp.pdf
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | numpy
2 | scipy
3 | trimesh
4 | cython
5 | setuptools
6 | pytest
7 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | """
2 | Setup script for a Python package "radarsimpy"
3 |
4 | ---
5 |
6 | - Copyright (C) 2018 - PRESENT radarsimx.com
7 | - E-mail: info@radarsimx.com
8 | - Website: https://radarsimx.com
9 |
10 | ::
11 |
12 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
13 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
14 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
15 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
16 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
17 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
18 |
19 | """
20 |
21 | # Import required system and platform modules
22 | import platform
23 | import argparse
24 | import sys
25 | import os
26 | from os.path import join as pjoin
27 | from setuptools import setup
28 | from setuptools import Extension
29 | from Cython.Distutils import build_ext
30 | from Cython.Build import cythonize
31 | import numpy
32 |
33 | # Set up command line argument parser for build configuration
34 | ap = argparse.ArgumentParser()
35 | ap.add_argument(
36 | "-t", "--tier", required=False, help="Build tier, choose `free` or `standard`"
37 | )
38 | ap.add_argument(
39 | "-a", "--arch", required=False, help="Build architecture, choose `cpu` or `gpu`"
40 | )
41 |
42 | # Parse command line arguments, separating setup.py specific args from pass-through args
43 | args, unknown = ap.parse_known_args()
44 | sys.argv = [sys.argv[0]] + unknown
45 |
46 | # Determine build tier (free vs standard)
47 | # Default to standard if not specified
48 | if args.tier is None:
49 | ARG_TIER = "standard"
50 | elif args.tier.lower() == "free":
51 | ARG_TIER = "free"
52 | elif args.tier.lower() == "standard":
53 | ARG_TIER = "standard"
54 | else:
55 | raise ValueError("Invalid --tier parameters, please choose 'free' or 'standard'")
56 |
57 | # Determine build architecture (CPU vs GPU)
58 | # Default to CPU if not specified
59 | if args.arch is None:
60 | ARG_ARCH = "cpu"
61 | elif args.arch.lower() == "cpu":
62 | ARG_ARCH = "cpu"
63 | elif args.arch.lower() == "gpu":
64 | ARG_ARCH = "gpu"
65 | else:
66 | raise ValueError("Invalid --arch parameters, please choose 'cpu' or 'gpu'")
67 |
68 | # Detect operating system for platform-specific configurations
69 | os_type = platform.system() # 'Linux', 'Windows', 'macOS'
70 |
71 | # Set platform-specific build configurations
72 | if os_type == "Linux":
73 | # Linux-specific: Set rpath to find shared libraries in the same directory
74 | LINK_ARGS = ["-Wl,-rpath,$ORIGIN"]
75 | LIB_DIRS = [
76 | "src/radarsimcpp/build",
77 | "src/radarsimcpp/hdf5-lib-build/libs/lib_linux_gcc11_x86_64/lib",
78 | ]
79 | LIBS = ["hdf5", "hdf5_cpp", "hdf5_hl", "hdf5_hl_cpp"]
80 | if args.arch == "gpu":
81 | NVCC = "nvcc"
82 | CUDALIB = "lib64"
83 | LIBS = LIBS + ["cudart"]
84 | elif os_type == "Darwin": # macOS
85 | LIBS = []
86 | if platform.processor() == "arm": # M1/M2 processors
87 | LINK_ARGS = ["-Wl,-rpath,$ORIGIN"]
88 | LIB_DIRS = ["src/radarsimcpp/build"]
89 | else: # Intel processors
90 | LINK_ARGS = ["-Wl,-rpath,$ORIGIN"]
91 | LIB_DIRS = ["src/radarsimcpp/build"]
92 | elif os_type == "Windows":
93 | LINK_ARGS = []
94 | LIB_DIRS = ["src/radarsimcpp/build/Release"]
95 | LIBS = []
96 | if args.arch == "gpu":
97 | NVCC = "nvcc.exe"
98 | CUDALIB = "lib\\x64"
99 | LIBS = ["cudart"]
100 |
101 | def find_in_path(name, path):
102 | """
103 | Iterates over the directories in the search path by splitting the path string using
104 | os.pathsep as the delimiter. os.pathsep is a string that represents the separator
105 | used in the PATH environment variable on the current operating system
106 | (e.g., : on Unix-like systems and ; on Windows).
107 |
108 | :param name: The name of the file
109 | :type name: str
110 | :param path: The search path
111 | :type path: str
112 | :return: The absolute path of the file
113 | :rtype: str
114 | """
115 | for path_name in path.split(os.pathsep):
116 | binpath = pjoin(path_name, name)
117 | if os.path.exists(binpath):
118 | return os.path.abspath(binpath)
119 | return None
120 |
121 | def locate_cuda():
122 | """
123 | Locate the CUDA installation on the system
124 |
125 | :raises EnvironmentError: The nvcc binary could not be located in your $PATH.
126 | Either add it to your path, or set $CUDA_PATH
127 | :raises EnvironmentError: The CUDA path could not be located in
128 | :return: dict with keys 'home', 'nvcc', 'include', and 'lib64'
129 | and values giving the absolute path to each directory.
130 | """
131 | # The code first checks if the CUDA_PATH environment variable is set.
132 | # If it is, it uses the value of CUDA_PATH as the CUDA installation directory
133 | # and constructs the path to the nvcc binary (NVIDIA CUDA Compiler) inside that directory.
134 | if "CUDA_PATH" in os.environ:
135 | home = os.environ["CUDA_PATH"]
136 | nvcc = pjoin(home, "bin", NVCC)
137 | else:
138 | # If the CUDA_PATH environment variable is not set, it searches for the nvcc
139 | # binary in the system's PATH environment variable. If nvcc is not found in
140 | # the PATH, it raises an EnvironmentError. Otherwise, it sets the home variable
141 | # to the parent directory of nvcc.
142 | default_path = pjoin(os.sep, "usr", "local", "cuda", "bin")
143 | nvcc = find_in_path(NVCC, os.environ["PATH"] + os.pathsep + default_path)
144 | if nvcc is None:
145 | raise EnvironmentError(
146 | "The nvcc binary could not be located in your $PATH. "
147 | "Either add it to your path, or set $CUDA_PATH"
148 | )
149 | home = os.path.dirname(os.path.dirname(nvcc))
150 |
151 | cudaconfig = {
152 | "home": home,
153 | "nvcc": nvcc,
154 | "include": pjoin(home, "include"),
155 | "lib64": pjoin(home, CUDALIB),
156 | }
157 | for key, val in cudaconfig.items():
158 | if not os.path.exists(val):
159 | raise EnvironmentError(
160 | "The CUDA " + key + " path could not be located in " + val
161 | )
162 |
163 | return cudaconfig
164 |
165 | # Configure build macros based on tier and architecture
166 | if ARG_TIER == "free":
167 | if ARG_ARCH == "gpu":
168 | MACROS = [
169 | ("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION"), # NumPy API version
170 | ("_FREETIER_", 1), # Enable free tier features
171 | ("_CUDA_", None), # Enable CUDA support
172 | ]
173 | elif ARG_ARCH == "cpu":
174 | MACROS = [
175 | ("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION"),
176 | ("_FREETIER_", 1)
177 | ]
178 | else: # standard tier
179 | if ARG_ARCH == "gpu":
180 | MACROS = [
181 | ("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION"),
182 | ("_CUDA_", None)
183 | ]
184 | elif ARG_ARCH == "cpu":
185 | MACROS = [("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")]
186 |
187 | # Set include directories for header files
188 | INCLUDE_DIRS = ["src/radarsimcpp/includes", "src/radarsimcpp/includes/rsvector"]
189 |
190 | # Add CUDA-specific configurations if GPU build is selected
191 | if ARG_ARCH == "gpu":
192 | CUDA = locate_cuda()
193 | INCLUDE_DIRS = INCLUDE_DIRS + [CUDA["include"]]
194 | LIB_DIRS = LIB_DIRS + [CUDA["lib64"]]
195 |
196 | # Define Cython extension modules to be built
197 | ext_modules = [
198 | # Core radar simulation C++ wrapper
199 | Extension(
200 | "radarsimpy.lib.cp_radarsimc",
201 | ["src/radarsimpy/lib/cp_radarsimc.pyx"],
202 | define_macros=MACROS,
203 | include_dirs=INCLUDE_DIRS,
204 | libraries=["radarsimcpp"] + LIBS,
205 | library_dirs=LIB_DIRS,
206 | extra_link_args=LINK_ARGS,
207 | ),
208 | # High-level simulator interface
209 | Extension(
210 | "radarsimpy.simulator",
211 | ["src/radarsimpy/simulator.pyx"],
212 | define_macros=MACROS,
213 | include_dirs=INCLUDE_DIRS,
214 | libraries=["radarsimcpp"] + LIBS,
215 | library_dirs=LIB_DIRS,
216 | extra_link_args=LINK_ARGS,
217 | ),
218 | ]
219 |
220 | # Configure and run setup
221 | setup(
222 | name="radarsimpy",
223 | cmdclass={"build_ext": build_ext}, # Use Cython's build_ext
224 | ext_modules=cythonize(
225 | ext_modules,
226 | annotate=False, # Don't generate HTML annotation files
227 | compiler_directives={"language_level": "3"}, # Use Python 3 syntax
228 | ),
229 | include_dirs=[numpy.get_include()], # Include NumPy headers
230 | )
231 |
--------------------------------------------------------------------------------
/src/radarsimpy/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | A Radar Simulator for Python
3 |
4 | RadarSimPy is a powerful and versatile Python-based Radar Simulator that models
5 | radar transceivers and simulates baseband data from point targets and 3D models.
6 | Its signal processing tools offer range/Doppler processing, direction of arrival
7 | estimation, and beamforming using various cutting-edge techniques, and you can
8 | even characterize radar detection using Swerling's models. Whether you're a beginner
9 | or an advanced user, RadarSimPy is the perfect tool for anyone looking to develop
10 | new radar technologies or expand their knowledge of radar systems.
11 |
12 | ---
13 |
14 | - Copyright (C) 2018 - PRESENT radarsimx.com
15 | - E-mail: info@radarsimx.com
16 | - Website: https://radarsimx.com
17 |
18 | ::
19 |
20 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
21 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
22 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
23 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
24 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
25 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
26 |
27 | """
28 |
29 | from .radar import Radar
30 | from .transmitter import Transmitter
31 | from .receiver import Receiver
32 |
33 | __version__ = "13.1.0"
34 |
--------------------------------------------------------------------------------
/src/radarsimpy/includes/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | A Python module for radar simulation
3 |
4 | ---
5 |
6 | - Copyright (C) 2018 - PRESENT radarsimx.com
7 | - E-mail: info@radarsimx.com
8 | - Website: https://radarsimx.com
9 |
10 | ::
11 |
12 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
13 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
14 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
15 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
16 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
17 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
18 |
19 | """
20 |
--------------------------------------------------------------------------------
/src/radarsimpy/includes/radarsimc.pxd:
--------------------------------------------------------------------------------
1 | # distutils: language = c++
2 | """
3 | A Python module for radar simulation
4 |
5 | ---
6 |
7 | - Copyright (C) 2018 - PRESENT radarsimx.com
8 | - E-mail: info@radarsimx.com
9 | - Website: https://radarsimx.com
10 |
11 | ::
12 |
13 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
14 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
15 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
16 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
17 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
18 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
19 |
20 | """
21 |
22 | #------------------------------------------------------------------------------
23 | # Imports
24 | #------------------------------------------------------------------------------
25 | from libcpp cimport bool
26 | from libcpp.complex cimport complex as cpp_complex
27 | from libcpp.string cimport string
28 | from radarsimpy.includes.rsvector cimport Vec3, Vec2
29 | from radarsimpy.includes.type_def cimport int_t, vector
30 |
31 | #------------------------------------------------------------------------------
32 | # Memory Management
33 | #------------------------------------------------------------------------------
34 | cdef extern from "libs/mem_lib.hpp":
35 | cdef void Mem_Copy[T](T * ptr, int_t size, vector[T] &vect) except +
36 | cdef void Mem_Copy_Complex[T](T * ptr_real, T * ptr_imag,
37 | int_t size, vector[cpp_complex[T]] &vect) except +
38 | cdef void Mem_Copy_Vec3[T](T *ptr_x, T *ptr_y, T *ptr_z,
39 | int_t size, vector[Vec3[T]] &vect) except +
40 |
41 | cdef extern from "libs/free_tier.hpp":
42 | cdef int IsFreeTier() except +
43 |
44 | cdef extern from "type_def.hpp":
45 | cdef enum ErrorType:
46 | NO_ERROR
47 | ERROR_TOO_MANY_RAYS_PER_GRID
48 |
49 | #------------------------------------------------------------------------------
50 | # Target
51 | #------------------------------------------------------------------------------
52 | cdef extern from "target.hpp":
53 | cdef cppclass Target[T]:
54 | Target() except +
55 | Target(const T * points,
56 | const int_t * cells,
57 | const int_t & cell_size,
58 | const Vec3[T] & origin,
59 | const vector[Vec3[T]] & location_array,
60 | const vector[Vec3[T]] & speed_array,
61 | const vector[Vec3[T]] & rotation_array,
62 | const vector[Vec3[T]] & rotation_rate_array,
63 | const cpp_complex[T] & ep,
64 | const cpp_complex[T] & mu,
65 | const bool & skip_diffusion) except +
66 | Target(const T * points,
67 | const int_t * cells,
68 | const int_t & cell_size) except +
69 | Target(const T * points,
70 | const int_t * cells,
71 | const int_t & cell_size,
72 | const Vec3[T] & origin,
73 | const Vec3[T] & location,
74 | const Vec3[T] & speed,
75 | const Vec3[T] & rotation,
76 | const Vec3[T] & rotation_rate,
77 | const bool & skip_diffusion) except +
78 |
79 | #------------------------------------------------------------------------------
80 | # Ray
81 | #------------------------------------------------------------------------------
82 | cdef extern from "ray.hpp":
83 | cdef cppclass Ray[T]:
84 | Ray() except +
85 | Vec3[T] * direction_
86 | Vec3[T] * location_
87 | int reflections_
88 |
89 | #------------------------------------------------------------------------------
90 | # RCS
91 | #------------------------------------------------------------------------------
92 | cdef extern from "simulator_rcs.hpp":
93 | cdef cppclass RcsSimulator[T]:
94 | RcsSimulator() except +
95 | vector[T] Run(vector[Target[float]] & targets,
96 | vector[Vec3[T]] inc_dir_array,
97 | vector[Vec3[T]] obs_dir_array,
98 | Vec3[cpp_complex[T]] inc_polarization,
99 | Vec3[cpp_complex[T]] obs_polarization,
100 | T frequency,
101 | T density) except +
102 |
103 | #------------------------------------------------------------------------------
104 | # Point Cloud
105 | #------------------------------------------------------------------------------
106 | cdef extern from "simulator_lidar.hpp":
107 | cdef cppclass LidarSimulator[T]:
108 | LidarSimulator() except +
109 | void AddTarget(const Target[T] & target)
110 | void Run(const vector[T] & phi,
111 | const vector[T] & theta,
112 | const Vec3[T] & position)
113 |
114 | vector[Ray[T]] cloud_
115 |
116 | #------------------------------------------------------------------------------
117 | # Point Target
118 | #------------------------------------------------------------------------------
119 | cdef extern from "point.hpp":
120 | cdef cppclass Point[T]:
121 | Point() except +
122 | Point(const vector[Vec3[T]] & loc,
123 | const Vec3[T] & speed,
124 | const vector[T] & rcs,
125 | const vector[T] & phs) except +
126 |
127 | #------------------------------------------------------------------------------
128 | # Transmitter Components
129 | #------------------------------------------------------------------------------
130 | cdef extern from "transmitter.hpp":
131 | cdef cppclass TxChannel[T]:
132 | TxChannel() except +
133 | TxChannel(const Vec3[T] & location,
134 | const Vec3[cpp_complex[T]] & polar,
135 | const vector[T] & phi,
136 | const vector[T] & phi_ptn,
137 | const vector[T] & theta,
138 | const vector[T] & theta_ptn,
139 | const T & antenna_gain,
140 | const vector[T] & mod_t,
141 | const vector[cpp_complex[T]] & mod_var,
142 | const vector[cpp_complex[T]] & pulse_mod,
143 | const T & delay,
144 | const T & grid) except +
145 |
146 | cdef cppclass Transmitter[H, L]:
147 | Transmitter() except +
148 | Transmitter(const L & tx_power,
149 | const vector[H] & freq,
150 | const vector[H] & freq_time,
151 | const vector[H] & freq_offset,
152 | const vector[H] & pulse_start_time) except +
153 | Transmitter(const L & tx_power,
154 | const vector[H] & freq,
155 | const vector[H] & freq_time,
156 | const vector[H] & freq_offset,
157 | const vector[H] & pulse_start_time,
158 | const vector[cpp_complex[H]] & phase_noise) except +
159 | void AddChannel(const TxChannel[L] & channel)
160 |
161 | #------------------------------------------------------------------------------
162 | # Receiver Components
163 | #------------------------------------------------------------------------------
164 | cdef extern from "receiver.hpp":
165 | cdef cppclass RxChannel[T]:
166 | RxChannel() except +
167 | RxChannel(const Vec3[T] & location,
168 | const Vec3[cpp_complex[T]] & polar,
169 | const vector[T] & phi,
170 | const vector[T] & phi_ptn,
171 | const vector[T] & theta,
172 | const vector[T] & theta_ptn,
173 | const T & antenna_gain) except +
174 |
175 | cdef cppclass Receiver[T]:
176 | Receiver() except +
177 | Receiver(const T & fs,
178 | const T & rf_gain,
179 | const T & resistor,
180 | const T & baseband_gain,
181 | const T & baseband_bw) except +
182 | void AddChannel(const RxChannel[T] & channel)
183 |
184 | #------------------------------------------------------------------------------
185 | # Radar System
186 | #------------------------------------------------------------------------------
187 | cdef extern from "radar.hpp":
188 | cdef cppclass Radar[H, L]:
189 | Radar() except +
190 | Radar(Transmitter[H, L] & tx,
191 | Receiver[L] & rx,
192 | vector[H] & frame_start_time,
193 | vector[Vec3[L]] & location_array,
194 | Vec3[L] speed_array,
195 | vector[Vec3[L]] & rotation_array,
196 | Vec3[L] rotrate_array) except +
197 | void InitBaseband(H *bb_real,
198 | H *bb_imag) except +
199 | void SyncBaseband() except +
200 | void FreeDeviceMemory() except +
201 |
202 | #------------------------------------------------------------------------------
203 | # Simulators
204 | #------------------------------------------------------------------------------
205 | cdef extern from "simulator_point.hpp":
206 | cdef cppclass PointSimulator[H, L]:
207 | PointSimulator() except +
208 | void Run(Radar[H, L] & radar,
209 | vector[Point[L]] & points)
210 |
211 | cdef extern from "simulator_mesh.hpp":
212 | cdef cppclass MeshSimulator[H, L]:
213 | MeshSimulator() except +
214 | ErrorType Run(Radar[H, L] & radar,
215 | vector[Target[L]] & targets,
216 | int level,
217 | L density,
218 | Vec2[int_t] ray_filter,
219 | bool back_propagating,
220 | string log_path,
221 | bool debug)
222 |
223 | cdef extern from "simulator_interference.hpp":
224 | cdef cppclass InterferenceSimulator[H, L]:
225 | InterferenceSimulator() except +
226 | void Run(Radar[H, L] & radar,
227 | Radar[H, L] & interf_radar)
228 |
--------------------------------------------------------------------------------
/src/radarsimpy/includes/rsvector.pxd:
--------------------------------------------------------------------------------
1 | # distutils: language = c++
2 | """
3 | A Python module for radar simulation
4 |
5 | ---
6 |
7 | - Copyright (C) 2018 - PRESENT radarsimx.com
8 | - E-mail: info@radarsimx.com
9 | - Website: https://radarsimx.com
10 |
11 | ::
12 |
13 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
14 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
15 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
16 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
17 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
18 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
19 |
20 | """
21 |
22 | """
23 | rsvector - Vector library module
24 | """
25 |
26 | cdef extern from "rsvector.hpp" namespace "rsv" nogil:
27 | # 3D vector class
28 | cdef cppclass Vec3[T]:
29 | Vec3() except +
30 | Vec3(const T&, const T&, const T&) except +
31 | Vec3(T*) except +
32 |
33 | Vec3& operator=(const Vec3&)
34 | T& operator[](const unsigned int&)
35 |
36 | # 2D vector class
37 | cdef cppclass Vec2[T]:
38 | Vec2() except +
39 | Vec2(const T&, const T&) except +
40 | Vec2(T*) except +
41 |
42 | Vec2& operator=(const Vec2&)
43 | T& operator[](const unsigned int&)
44 |
--------------------------------------------------------------------------------
/src/radarsimpy/includes/type_def.pxd:
--------------------------------------------------------------------------------
1 | # distutils: language = c++
2 | """
3 | A Python module for radar simulation
4 |
5 | ---
6 |
7 | - Copyright (C) 2018 - PRESENT radarsimx.com
8 | - E-mail: info@radarsimx.com
9 | - Website: https://radarsimx.com
10 |
11 | ::
12 |
13 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
14 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
15 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
16 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
17 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
18 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
19 |
20 | """
21 |
22 |
23 | ctypedef int int_t
24 | ctypedef unsigned int uint_t
25 |
26 | ctypedef float float_t
27 |
28 |
29 | """
30 | C++ vector
31 |
32 | Copy from Cython's libcpp/vector.pxd
33 | Remove ALLOCATOR=*, otherwise 'const &' doesn't work
34 | """
35 | cdef extern from "" namespace "std" nogil:
36 | cdef cppclass vector[T]:
37 | ctypedef size_t size_type
38 | ctypedef ptrdiff_t difference_type
39 |
40 | cppclass const_iterator
41 | cppclass iterator:
42 | iterator() except +
43 | iterator(iterator&) except +
44 | T& operator*()
45 | iterator operator++()
46 | iterator operator--()
47 | iterator operator++(int)
48 | iterator operator--(int)
49 | iterator operator+(size_type)
50 | iterator operator-(size_type)
51 | difference_type operator-(iterator)
52 | difference_type operator-(const_iterator)
53 | bint operator==(iterator)
54 | bint operator==(const_iterator)
55 | bint operator!=(iterator)
56 | bint operator!=(const_iterator)
57 | bint operator<(iterator)
58 | bint operator<(const_iterator)
59 | bint operator>(iterator)
60 | bint operator>(const_iterator)
61 | bint operator<=(iterator)
62 | bint operator<=(const_iterator)
63 | bint operator>=(iterator)
64 | bint operator>=(const_iterator)
65 | cppclass const_iterator:
66 | const_iterator() except +
67 | const_iterator(iterator&) except +
68 | const_iterator(const_iterator&) except +
69 | operator=(iterator&) except +
70 | const T& operator*()
71 | const_iterator operator++()
72 | const_iterator operator--()
73 | const_iterator operator++(int)
74 | const_iterator operator--(int)
75 | const_iterator operator+(size_type)
76 | const_iterator operator-(size_type)
77 | difference_type operator-(iterator)
78 | difference_type operator-(const_iterator)
79 | bint operator==(iterator)
80 | bint operator==(const_iterator)
81 | bint operator!=(iterator)
82 | bint operator!=(const_iterator)
83 | bint operator<(iterator)
84 | bint operator<(const_iterator)
85 | bint operator>(iterator)
86 | bint operator>(const_iterator)
87 | bint operator<=(iterator)
88 | bint operator<=(const_iterator)
89 | bint operator>=(iterator)
90 | bint operator>=(const_iterator)
91 |
92 | cppclass const_reverse_iterator
93 | cppclass reverse_iterator:
94 | reverse_iterator() except +
95 | reverse_iterator(reverse_iterator&) except +
96 | T& operator*()
97 | reverse_iterator operator++()
98 | reverse_iterator operator--()
99 | reverse_iterator operator++(int)
100 | reverse_iterator operator--(int)
101 | reverse_iterator operator+(size_type)
102 | reverse_iterator operator-(size_type)
103 | difference_type operator-(iterator)
104 | difference_type operator-(const_iterator)
105 | bint operator==(reverse_iterator)
106 | bint operator==(const_reverse_iterator)
107 | bint operator!=(reverse_iterator)
108 | bint operator!=(const_reverse_iterator)
109 | bint operator<(reverse_iterator)
110 | bint operator<(const_reverse_iterator)
111 | bint operator>(reverse_iterator)
112 | bint operator>(const_reverse_iterator)
113 | bint operator<=(reverse_iterator)
114 | bint operator<=(const_reverse_iterator)
115 | bint operator>=(reverse_iterator)
116 | bint operator>=(const_reverse_iterator)
117 | cppclass const_reverse_iterator:
118 | const_reverse_iterator() except +
119 | const_reverse_iterator(reverse_iterator&) except +
120 | operator=(reverse_iterator&) except +
121 | const T& operator*()
122 | const_reverse_iterator operator++()
123 | const_reverse_iterator operator--()
124 | const_reverse_iterator operator++(int)
125 | const_reverse_iterator operator--(int)
126 | const_reverse_iterator operator+(size_type)
127 | const_reverse_iterator operator-(size_type)
128 | difference_type operator-(iterator)
129 | difference_type operator-(const_iterator)
130 | bint operator==(reverse_iterator)
131 | bint operator==(const_reverse_iterator)
132 | bint operator!=(reverse_iterator)
133 | bint operator!=(const_reverse_iterator)
134 | bint operator<(reverse_iterator)
135 | bint operator<(const_reverse_iterator)
136 | bint operator>(reverse_iterator)
137 | bint operator>(const_reverse_iterator)
138 | bint operator<=(reverse_iterator)
139 | bint operator<=(const_reverse_iterator)
140 | bint operator>=(reverse_iterator)
141 | bint operator>=(const_reverse_iterator)
142 |
143 | vector() except +
144 | vector(vector&) except +
145 | vector(size_type) except +
146 | vector(size_type, T&) except +
147 | #vector[InputIt](InputIt, InputIt)
148 | T& operator[](size_type)
149 | #vector& operator=(vector&)
150 | bint operator==(vector&, vector&)
151 | bint operator!=(vector&, vector&)
152 | bint operator<(vector&, vector&)
153 | bint operator>(vector&, vector&)
154 | bint operator<=(vector&, vector&)
155 | bint operator>=(vector&, vector&)
156 | void assign(size_type, const T&)
157 | void assign[InputIt](InputIt, InputIt) except +
158 | T& at(size_type) except +
159 | T& back()
160 | iterator begin()
161 | const_iterator const_begin "begin"()
162 | const_iterator cbegin()
163 | size_type capacity()
164 | void clear()
165 | bint empty()
166 | iterator end()
167 | const_iterator const_end "end"()
168 | const_iterator cend()
169 | iterator erase(iterator)
170 | iterator erase(iterator, iterator)
171 | T& front()
172 | iterator insert(iterator, const T&) except +
173 | iterator insert(iterator, size_type, const T&) except +
174 | iterator insert[InputIt](iterator, InputIt, InputIt) except +
175 | size_type max_size()
176 | void pop_back()
177 | void push_back(T&) except +
178 | reverse_iterator rbegin()
179 | const_reverse_iterator const_rbegin "rbegin"()
180 | const_reverse_iterator crbegin()
181 | reverse_iterator rend()
182 | const_reverse_iterator const_rend "rend"()
183 | const_reverse_iterator crend()
184 | void reserve(size_type) except +
185 | void resize(size_type) except +
186 | void resize(size_type, T&) except +
187 | size_type size()
188 | void swap(vector&)
189 |
190 | # C++11 methods
191 | T* data()
192 | const T* const_data "data"()
193 | void shrink_to_fit() except +
194 | iterator emplace(const_iterator, ...) except +
195 | T& emplace_back(...) except +
196 |
--------------------------------------------------------------------------------
/src/radarsimpy/lib/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | A Python module for radar simulation
3 |
4 | ---
5 |
6 | - Copyright (C) 2018 - PRESENT radarsimx.com
7 | - E-mail: info@radarsimx.com
8 | - Website: https://radarsimx.com
9 |
10 | ::
11 |
12 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
13 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
14 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
15 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
16 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
17 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
18 |
19 | """
20 |
--------------------------------------------------------------------------------
/src/radarsimpy/lib/cp_radarsimc.pxd:
--------------------------------------------------------------------------------
1 | # distutils: language = c++
2 | """
3 | A Python module for radar simulation
4 |
5 | ---
6 |
7 | - Copyright (C) 2018 - PRESENT radarsimx.com
8 | - E-mail: info@radarsimx.com
9 | - Website: https://radarsimx.com
10 |
11 | ::
12 |
13 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
14 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
15 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
16 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
17 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
18 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
19 |
20 | """
21 |
22 | from radarsimpy.includes.radarsimc cimport Radar
23 | from radarsimpy.includes.radarsimc cimport Target
24 | from radarsimpy.includes.radarsimc cimport Point
25 | from radarsimpy.includes.type_def cimport float_t
26 |
27 |
28 | cdef Point[float_t] cp_Point(location, speed, rcs, phase, shape)
29 | cdef Radar[double, float_t] cp_Radar(radar, frame_start_time)
30 | cdef Target[float_t] cp_Target(radar, target, timestamp, mesh_module)
31 | cdef Target[float_t] cp_RCS_Target(target, mesh_module)
32 |
--------------------------------------------------------------------------------
/src/radarsimpy/mesh_kit.py:
--------------------------------------------------------------------------------
1 | """
2 | Script for loading 3D mesh files
3 |
4 | This script provides utilities to load 3D mesh files using various available Python
5 | mesh processing libraries.
6 |
7 | ---
8 |
9 | - Copyright (C) 2025 - PRESENT radarsimx.com
10 | - E-mail: info@radarsimx.com
11 | - Website: https://radarsimx.com
12 |
13 | ::
14 |
15 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
16 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
17 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
18 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
19 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
20 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
21 |
22 | """
23 |
24 | import importlib
25 | import numpy as np
26 |
27 |
28 | def check_module_installed(module_name: str) -> bool:
29 | """
30 | Check if a Python module is installed
31 |
32 | :param str module_name: Name of the module to check
33 |
34 | :return: True if module is installed, False otherwise
35 | :rtype: bool
36 | """
37 | return importlib.util.find_spec(module_name) is not None
38 |
39 |
40 | def safe_import(module_name: str) -> object:
41 | """
42 | Safely import a module without raising an exception if not found
43 |
44 | :param str module_name: Name of the module to import
45 |
46 | :return: Imported module object or None if import fails
47 | :rtype: object
48 | """
49 | try:
50 | return importlib.import_module(module_name)
51 | except ImportError:
52 | return None
53 |
54 |
55 | def import_mesh_module() -> object:
56 | """
57 | Import the first available mesh processing module from a predefined list
58 |
59 | Tries to import modules in this order: pyvista, pymeshlab, trimesh, meshio
60 |
61 | :return: The mesh processing module object
62 | :rtype: object
63 | :raises ImportError: If no valid mesh processing module is found
64 | """
65 | module_list = ["trimesh", "pyvista", "pymeshlab", "meshio"]
66 |
67 | for _, module_name in enumerate(module_list):
68 | if check_module_installed(module_name):
69 | module = safe_import(module_name)
70 | return module
71 |
72 | raise ImportError(
73 | "No valid module was found to process the 3D model file, "
74 | + "please install one of the following modules: "
75 | + "`pyvista`, `pymeshlab`, `trimesh`, `meshio`"
76 | )
77 |
78 |
79 | def load_mesh(mesh_file_name: str, scale: float, mesh_module: object) -> dict:
80 | """
81 | Load a 3D mesh file using the specified module
82 |
83 | :param str mesh_file_name: Path to the mesh file
84 | :param float scale: Scale factor to apply to the mesh vertices
85 | :param object mesh_module: The mesh processing module object
86 |
87 | :return: Dictionary containing mesh points and cells
88 | :rtype: dict with keys:
89 | - points (numpy.ndarray): Array of vertex coordinates
90 | - cells (numpy.ndarray): Array of face indices
91 | """
92 | if mesh_module.__name__ == "pyvista":
93 | mesh_data = mesh_module.read(mesh_file_name)
94 | points = np.array(mesh_data.points) / scale
95 | cells = mesh_data.faces.reshape(-1, 4)[:, 1:]
96 | return {"points": points, "cells": cells}
97 |
98 | if mesh_module.__name__ == "pymeshlab":
99 | ms = mesh_module.MeshSet()
100 | ms.load_new_mesh(mesh_file_name)
101 | mesh_data = ms.current_mesh()
102 | points = np.array(mesh_data.vertex_matrix()) / scale
103 | cells = np.array(mesh_data.face_matrix())
104 | if np.isfortran(points):
105 | points = np.ascontiguousarray(points)
106 | cells = np.ascontiguousarray(cells)
107 | ms.clear()
108 | return {"points": points, "cells": cells}
109 |
110 | if mesh_module.__name__ == "trimesh":
111 | mesh_data = mesh_module.load(mesh_file_name)
112 | points = np.array(mesh_data.vertices) / scale
113 | cells = np.array(mesh_data.faces)
114 | return {"points": points, "cells": cells}
115 |
116 | if mesh_module.__name__ == "meshio":
117 | mesh_data = mesh_module.read(mesh_file_name)
118 | points = mesh_data.points / scale
119 | cells = mesh_data.cells[0].data
120 | return {"points": points, "cells": cells}
121 |
122 | raise ImportError(
123 | "No valid module was found to process the 3D model file, "
124 | + "please install one of the following modules: "
125 | + "`pyvista`, `pymeshlab`, `trimesh`, `meshio`"
126 | )
127 |
--------------------------------------------------------------------------------
/src/radarsimpy/simulator.pyx:
--------------------------------------------------------------------------------
1 | # distutils: language = c++
2 | """
3 | The Python Module for Advanced Radar and Lidar Simulations
4 |
5 | This module provides tools for simulating and analyzing radar and lidar systems in complex 3D environments.
6 | The module supports a wide range of functionalities, including:
7 |
8 | 1. **Lidar Simulations**:
9 |
10 | - Simulate Lidar systems in dynamic or static 3D environments.
11 | - Generate point clouds and compute ray interactions with targets.
12 | - Model the dynamics of targets, such as motion and rotation.
13 |
14 | 2. **Radar Simulations**:
15 |
16 | - Simulate radar baseband responses for complex scenes.
17 | - Handle point targets, 3D mesh objects, interference modeling, and noise simulation.
18 | - Perform advanced ray-tracing for high-fidelity radar analysis.
19 |
20 | 3. **Radar Cross Section (RCS) Calculations**:
21 |
22 | - Calculate the RCS of targets using the Shooting and Bouncing Rays (SBR) method.
23 | - Model electromagnetic wave scattering from complex 3D geometries.
24 | - Support for defining target materials and permittivity properties.
25 |
26 | ---
27 |
28 | - Copyright (C) 2018 - PRESENT radarsimx.com
29 | - E-mail: info@radarsimx.com
30 | - Website: https://radarsimx.com
31 |
32 | ::
33 |
34 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
35 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
36 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
37 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
38 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
39 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
40 |
41 | """
42 |
43 | include "simulator_radar.pyx"
44 | include "simulator_lidar.pyx"
45 | include "simulator_rcs.pyx"
46 |
--------------------------------------------------------------------------------
/src/radarsimpy/simulator_lidar.pyx:
--------------------------------------------------------------------------------
1 | # distutils: language = c++
2 | """
3 | The Python Module for Lidar Simulations
4 |
5 | This module provides tools for simulating a lidar system in complex 3D environments. It leverages a high-performance C++ backend integrated with Python to support large-scale simulations with high accuracy and computational efficiency. The module includes features for simulating ray interactions with targets, generating point clouds, and modeling the dynamics of targets in the scene.
6 |
7 | ---
8 |
9 | - Copyright (C) 2018 - PRESENT radarsimx.com
10 | - E-mail: info@radarsimx.com
11 | - Website: https://radarsimx.com
12 |
13 | ::
14 |
15 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
16 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
17 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
18 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
19 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
20 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
21 |
22 | """
23 |
24 | # Core imports
25 | from libcpp cimport bool
26 | import numpy as np
27 | cimport numpy as np
28 | cimport cython
29 |
30 | # RadarSimX imports
31 | from radarsimpy.includes.radarsimc cimport Target, LidarSimulator
32 | from radarsimpy.includes.radarsimc cimport Mem_Copy
33 | from radarsimpy.includes.rsvector cimport Vec3
34 | from radarsimpy.includes.type_def cimport float_t, int_t, vector
35 |
36 | from radarsimpy.mesh_kit import import_mesh_module, load_mesh
37 |
38 | np.import_array()
39 | np_float = np.float32
40 |
41 |
42 | @cython.cdivision(True)
43 | @cython.boundscheck(False)
44 | @cython.wraparound(False)
45 | cpdef sim_lidar(lidar, targets, frame_time=0):
46 | """
47 | sim_lidar(lidar, targets, frame_time=0)
48 |
49 | Simulate a Lidar scene and compute ray interactions with targets.
50 |
51 | This function simulates a Lidar scanning scene in a 3D environment, calculating the interaction of Lidar rays with the provided targets. It handles both static and dynamic targets, allowing for customizable positions, velocities, and orientations of objects in the scene. The simulation produces a set of rays representing the Lidar's perception of the environment.
52 |
53 | :param dict lidar:
54 | Lidar configuration parameters. The following keys are required:
55 |
56 | - **position** (*numpy.ndarray*):
57 | The 3D position of the Lidar in meters (m), specified as [x, y, z].
58 | - **phi** (*numpy.ndarray*):
59 | Array of phi scanning angles in degrees (°). Phi represents the horizontal scanning angles in the Lidar's field of view. The total number of scanning directions is determined by the combination of phi and theta angles.
60 | - **theta** (*numpy.ndarray*):
61 | Array of theta scanning angles in degrees (°). Theta represents the vertical scanning angles in the Lidar's field of view. The total number of scanning directions is computed as:
62 | ``len(phi) * len(theta)``.
63 |
64 | :param list[dict] targets:
65 | A list of target objects in the scene. Each target is represented as a dictionary containing the following keys:
66 |
67 | - **model** (*str*):
68 | File path to the target model (3D object) in the scene.
69 | - **origin** (*numpy.ndarray*):
70 | The origin position (rotation and translation center) of the target model in meters (m), specified as [x, y, z].
71 | Default: ``[0, 0, 0]``.
72 | - **location** (*numpy.ndarray*):
73 | The 3D location of the target in meters (m), specified as [x, y, z].
74 | Default: ``[0, 0, 0]``.
75 | - **speed** (*numpy.ndarray*):
76 | Speed vector of the target in meters per second (m/s), specified as [vx, vy, vz].
77 | Default: ``[0, 0, 0]``.
78 | - **rotation** (*numpy.ndarray*):
79 | The angular orientation of the target in degrees (°), specified as [yaw, pitch, roll].
80 | Default: ``[0, 0, 0]``.
81 | - **rotation_rate** (*numpy.ndarray*):
82 | The angular rotation rate of the target in degrees per second (°/s), specified as [yaw rate, pitch rate, roll rate].
83 | Default: ``[0, 0, 0]``.
84 | - **unit** (*str*):
85 | The unit system for the target model's geometry.
86 | Supported values: ``mm``, ``cm``, ``m``.
87 | Default: ``m``.
88 |
89 | :param float frame_time:
90 | Simulation timestamp in seconds (s). This parameter determines the time reference for the Lidar's scanning operation and target positions.
91 | Default: ``0``.
92 |
93 | :return:
94 | Simulated Lidar rays based on the provided configuration and targets.
95 |
96 | :rtype:
97 | numpy.ndarray - A structured array representing the Lidar ray interactions with the scene, including details such as ray origins, directions, and intersections.
98 | """
99 | cdef LidarSimulator[float_t] lidar_sim_c
100 |
101 | # Memory view declarations
102 | cdef float_t[:, :] points_mv
103 | cdef int_t[:, :] cells_mv
104 | cdef float_t[:] origin_mv
105 | cdef float_t[:] speed_mv
106 | cdef float_t[:] location_mv
107 | cdef float_t[:] rotation_mv
108 | cdef float_t[:] rotation_rate_mv
109 | cdef float_t scale
110 | cdef int_t idx_c
111 |
112 | # Process targets
113 | mesh_module = import_mesh_module()
114 | for idx_c in range(0, len(targets)):
115 | # Unit conversion
116 | unit = targets[idx_c].get("unit", "m")
117 | scale = 1000 if unit == "mm" else 100 if unit == "cm" else 1
118 |
119 | mesh_data = load_mesh(targets[idx_c]["model"], scale, mesh_module)
120 | points_mv = mesh_data["points"].astype(np_float)
121 | cells_mv = mesh_data["cells"].astype(np.int32)
122 |
123 | # Target parameters
124 | origin_mv = np.array(targets[idx_c].get("origin", (0, 0, 0)), dtype=np_float)
125 | temp_location = np.array(targets[idx_c].get("location", (0, 0, 0))) + frame_time*np.array(targets[idx_c].get("speed", (0, 0, 0)))
126 | location_mv = temp_location.astype(np_float)
127 | speed_mv = np.array(targets[idx_c].get("speed", (0, 0, 0)), dtype=np_float)
128 |
129 | temp_rotation = np.array(targets[idx_c].get("rotation", (0, 0, 0))) + frame_time*np.array(targets[idx_c].get("rotation_rate", (0, 0, 0)))
130 | rotation_mv = np.radians(temp_rotation.astype(np_float))
131 | rotation_rate_mv = np.radians(
132 | np.array(targets[idx_c].get("rotation_rate", (0, 0, 0)), dtype=np_float)
133 | )
134 |
135 | # Add target to pointcloud
136 | lidar_sim_c.AddTarget(Target[float_t](&points_mv[0, 0],
137 | &cells_mv[0, 0],
138 | cells_mv.shape[0],
139 | Vec3[float_t](&origin_mv[0]),
140 | Vec3[float_t](&location_mv[0]),
141 | Vec3[float_t](&speed_mv[0]),
142 | Vec3[float_t](&rotation_mv[0]),
143 | Vec3[float_t](&rotation_rate_mv[0]),
144 | targets[idx_c].get("skip_diffusion", False)))
145 |
146 | # Lidar parameters
147 | cdef float_t[:] phi_mv = np.radians(np.array(lidar["phi"], dtype=np_float))
148 | cdef float_t[:] theta_mv = np.radians(np.array(lidar["theta"], dtype=np_float))
149 | cdef float_t[:] position_mv = np.array(lidar["position"], dtype=np_float)
150 |
151 | cdef vector[float_t] phi_vt
152 | Mem_Copy(&phi_mv[0], (phi_mv.shape[0]), phi_vt)
153 |
154 | cdef vector[float_t] theta_vt
155 | Mem_Copy(&theta_mv[0], (theta_mv.shape[0]), theta_vt)
156 |
157 | # Perform ray tracing
158 | lidar_sim_c.Run(phi_vt,
159 | theta_vt,
160 | Vec3[float_t](&position_mv[0]))
161 |
162 | # Prepare output
163 | ray_type = np.dtype([("positions", np_float, (3,)),
164 | ("directions", np_float, (3,))])
165 | rays = np.zeros(lidar_sim_c.cloud_.size(), dtype=ray_type)
166 |
167 | for idx_c in range(0, lidar_sim_c.cloud_.size()):
168 | rays[idx_c]["positions"][0] = lidar_sim_c.cloud_[idx_c].location_[1][0]
169 | rays[idx_c]["positions"][1] = lidar_sim_c.cloud_[idx_c].location_[1][1]
170 | rays[idx_c]["positions"][2] = lidar_sim_c.cloud_[idx_c].location_[1][2]
171 | rays[idx_c]["directions"][0] = lidar_sim_c.cloud_[idx_c].direction_[1][0]
172 | rays[idx_c]["directions"][1] = lidar_sim_c.cloud_[idx_c].direction_[1][1]
173 | rays[idx_c]["directions"][2] = lidar_sim_c.cloud_[idx_c].direction_[1][2]
174 |
175 | return rays
176 |
--------------------------------------------------------------------------------
/src/radarsimpy/simulator_rcs.pyx:
--------------------------------------------------------------------------------
1 | # distutils: language = c++
2 |
3 | """
4 | The Python Module for Radar Cross Section (RCS) Simulation
5 |
6 | This module provides tools for simulating and calculating the Radar Cross Section (RCS) of targets using the Shooting and Bouncing Rays (SBR) method. By leveraging a high-performance C++ backend integrated with Python, it enables accurate and efficient modeling of electromagnetic wave scattering from complex 3D target geometries. The module is designed for radar researchers, engineers, and educators.
7 |
8 | ---
9 |
10 | - Copyright (C) 2018 - PRESENT radarsimx.com
11 | - E-mail: info@radarsimx.com
12 | - Website: https://radarsimx.com
13 |
14 | ::
15 |
16 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
17 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
18 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
19 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
20 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
21 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
22 |
23 | """
24 |
25 | # Standard library imports
26 | import numpy as np
27 |
28 | # Cython imports
29 | cimport cython
30 | cimport numpy as np
31 |
32 | # Local imports
33 | from radarsimpy.includes.rsvector cimport Vec3
34 | from radarsimpy.includes.type_def cimport vector
35 | from radarsimpy.includes.radarsimc cimport Target, RcsSimulator, IsFreeTier
36 | from radarsimpy.lib.cp_radarsimc cimport cp_RCS_Target
37 | from libcpp.complex cimport complex as cpp_complex
38 |
39 | from radarsimpy.mesh_kit import import_mesh_module
40 |
41 | # Initialize NumPy
42 | np.import_array()
43 |
44 |
45 | @cython.cdivision(True)
46 | @cython.boundscheck(False)
47 | @cython.wraparound(False)
48 | cpdef sim_rcs(
49 | targets,
50 | f,
51 | inc_phi,
52 | inc_theta,
53 | inc_pol=[0, 0, 1],
54 | obs_phi=None,
55 | obs_theta=None,
56 | obs_pol=None,
57 | density=1
58 | ):
59 | """Calculate the Radar Cross Section (RCS) of targets using the Shooting and Bouncing Rays (SBR) method.
60 |
61 | This function computes the RCS of one or more targets by simulating how electromagnetic waves interact with the target models. The simulation uses the SBR technique, which accurately models wave scattering by tracing rays that shoot at the target and bounce off its surfaces.
62 |
63 | :param list[dict] targets:
64 | A list of target dictionaries specifying the properties of each target. Each dictionary contains the following keys:
65 |
66 | - **model** (*str*):
67 | File path to the 3D target model.
68 | - **origin** (*numpy.ndarray*):
69 | The origin position (rotation and translation center) of the target model in meters (m), specified as [x, y, z].
70 | Default: ``[0, 0, 0]``.
71 | - **location** (*numpy.ndarray*):
72 | The 3D location of the target in meters (m), specified as [x, y, z].
73 | Default: ``[0, 0, 0]``.
74 | - **rotation** (*numpy.ndarray*):
75 | The target's orientation in degrees (°), specified as [yaw, pitch, roll].
76 | Default: ``[0, 0, 0]``.
77 | - **permittivity** (*complex*):
78 | The target's permittivity, which represents its electromagnetic material properties.
79 | Default: Perfect Electric Conductor (PEC).
80 | - **unit** (*str*):
81 | Unit of measurement for the target model's geometry.
82 | Supported values: ``mm``, ``cm``, ``m``.
83 | Default: ``m``.
84 |
85 | :param float f:
86 | The center frequency of the incident electromagnetic wave in Hertz (Hz).
87 | :param float inc_phi:
88 | The horizontal incidence angle (phi) of the incoming wave in degrees (°).
89 | This angle is measured relative to the target at the transmitter's point of view.
90 | :param float inc_theta:
91 | The vertical incidence angle (theta) of the incoming wave in degrees (°).
92 | This angle is measured relative to the target at the transmitter's point of view.
93 | :param list[float] inc_pol:
94 | The polarization of the incident wave, specified as a 3D vector [x, y, z].
95 | Default: ``[0, 0, 1]`` (vertical polarization).
96 | :param float obs_phi:
97 | The horizontal observation angle (phi) in degrees (°).
98 | This is the angle at which the RCS is observed from the observer's point of view.
99 | Default: ``None`` (if not specified, it is set to the same value as `inc_phi`).
100 | :param float obs_theta:
101 | The vertical observation angle (theta) in degrees (°).
102 | This is the angle at which the RCS is observed from the observer's point of view.
103 | Default: ``None`` (if not specified, it is set to the same value as `inc_theta`).
104 | :param list[float] obs_pol:
105 | The polarization of the observer, specified as a 3D vector [x, y, z].
106 | Default: ``None`` (if not specified, it is set to the same value as `inc_pol`).
107 | :param float density:
108 | The ray density, defined as the number of rays per wavelength.
109 | Higher ray density improves accuracy but increases computational cost.
110 | Default: ``1.0``.
111 |
112 | :return:
113 | The Radar Cross Section (RCS) of the target(s) in square meters (m²).
114 | To convert the result to decibels relative to one square meter (dBsm), use:
115 | ``10 * log10(RCS)``.
116 | :rtype: float
117 | """
118 | if IsFreeTier():
119 | if len(targets) > 3:
120 | raise RuntimeError(
121 | "\nTrial Version Limitation - Target Count\n"
122 | "----------------------------------------\n"
123 | "Current limitation: Maximum 3 targets\n"
124 | "Your scene: {} targets\n\n"
125 | "This limitation helps maintain reasonable simulation times in the trial version.\n"
126 | "To simulate more targets, please upgrade to the Standard Version:\n"
127 | "→ https://radarsimx.com/product/radarsimpy/\n"
128 | .format(len(targets))
129 | )
130 |
131 | cdef vector[Target[float]] targets_vt
132 | cdef Vec3[cpp_complex[double]] inc_pol_cpp
133 | cdef Vec3[cpp_complex[double]] obs_pol_cpp
134 |
135 | # Set default observation parameters if not provided
136 | if obs_pol is None:
137 | obs_pol = inc_pol
138 | if obs_phi is None:
139 | obs_phi = inc_phi
140 | if obs_theta is None:
141 | obs_theta = inc_theta
142 |
143 | if isinstance(inc_phi, (list, tuple, np.ndarray)):
144 | inc_phi = np.array(inc_phi)
145 | else:
146 | inc_phi = np.array([inc_phi])
147 |
148 | if isinstance(inc_theta, (list, tuple, np.ndarray)):
149 | inc_theta = np.array(inc_theta)
150 | else:
151 | inc_theta = np.array([inc_theta])
152 |
153 | if np.shape(inc_phi)!=np.shape(inc_theta):
154 | raise ValueError('The lengths of `inc_phi` and `inc_theta` must be the same')
155 |
156 | if isinstance(obs_phi, (list, tuple, np.ndarray)):
157 | obs_phi = np.array(obs_phi)
158 | else:
159 | obs_phi = np.array([obs_phi])
160 |
161 | if isinstance(obs_theta, (list, tuple, np.ndarray)):
162 | obs_theta = np.array(obs_theta)
163 | else:
164 | obs_theta = np.array([obs_theta])
165 |
166 | if np.shape(obs_phi)!=np.shape(obs_theta):
167 | raise ValueError('The lengths of `obs_phi` and `obs_theta` must be the same')
168 |
169 | if np.shape(inc_phi)!=np.shape(obs_phi):
170 | raise ValueError('The lengths of `inc_phi` and `obs_phi` must be the same')
171 |
172 | cdef int array_size = np.size(obs_phi)
173 | cdef int idx
174 |
175 | # Convert polarization vectors to C++ types
176 | inc_pol_cpp = Vec3[cpp_complex[double]](
177 | cpp_complex[double](np.real(inc_pol[0]), np.imag(inc_pol[0])),
178 | cpp_complex[double](np.real(inc_pol[1]), np.imag(inc_pol[1])),
179 | cpp_complex[double](np.real(inc_pol[2]), np.imag(inc_pol[2]))
180 | )
181 |
182 | obs_pol_cpp = Vec3[cpp_complex[double]](
183 | cpp_complex[double](np.real(obs_pol[0]), np.imag(obs_pol[0])),
184 | cpp_complex[double](np.real(obs_pol[1]), np.imag(obs_pol[1])),
185 | cpp_complex[double](np.real(obs_pol[2]), np.imag(obs_pol[2]))
186 | )
187 |
188 | # Process targets
189 | mesh_module = import_mesh_module()
190 | for idx_c in range(0, len(targets)):
191 | targets_vt.push_back(cp_RCS_Target(targets[idx_c], mesh_module))
192 |
193 | # Convert angles to radians
194 | inc_phi_rad = np.radians(inc_phi)
195 | inc_theta_rad = np.radians(inc_theta)
196 | obs_phi_rad = np.radians(obs_phi)
197 | obs_theta_rad = np.radians(obs_theta)
198 |
199 | inc_dir_x=np.sin(inc_theta_rad) * np.cos(inc_phi_rad)
200 | inc_dir_y=np.sin(inc_theta_rad) * np.sin(inc_phi_rad)
201 | inc_dir_z=np.cos(inc_theta_rad)
202 |
203 | obs_dir_x=np.sin(obs_theta_rad) * np.cos(obs_phi_rad)
204 | obs_dir_y=np.sin(obs_theta_rad) * np.sin(obs_phi_rad)
205 | obs_dir_z=np.cos(obs_theta_rad)
206 |
207 | cdef vector[Vec3[double]] inc_dir
208 | cdef vector[Vec3[double]] obs_dir
209 |
210 | for idx in range(0, array_size):
211 |
212 | # Calculate direction vectors
213 | inc_dir.push_back(Vec3[double](
214 | (inc_dir_x[idx]),
215 | (inc_dir_y[idx]),
216 | (inc_dir_z[idx])
217 | ))
218 |
219 | obs_dir.push_back(Vec3[double](
220 | (obs_dir_x[idx]),
221 | (obs_dir_y[idx]),
222 | (obs_dir_z[idx])
223 | ))
224 |
225 | # Calculate RCS
226 | cdef RcsSimulator[double] rcs_sim_c
227 |
228 | cdef vector[double] rcs_vect = rcs_sim_c.Run(
229 | targets_vt,
230 | inc_dir,
231 | obs_dir,
232 | inc_pol_cpp,
233 | obs_pol_cpp,
234 | f,
235 | density)
236 |
237 | rcs=np.zeros(array_size)
238 |
239 | for idx in range(0, array_size):
240 | rcs[idx] = rcs_vect[idx]
241 |
242 | if array_size == 1:
243 | return rcs[0]
244 | else:
245 | return rcs
246 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | System level test of RadarSimPy
3 |
4 | ---
5 |
6 | - Copyright (C) 2018 - PRESENT radarsimx.com
7 | - E-mail: info@radarsimx.com
8 | - Website: https://radarsimx.com
9 |
10 | ::
11 |
12 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
13 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
14 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
15 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
16 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
17 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
18 |
19 | """
20 |
--------------------------------------------------------------------------------
/tests/test_config_radar.py:
--------------------------------------------------------------------------------
1 | """
2 | A Python module for radar simulation
3 |
4 | ---
5 |
6 | - Copyright (C) 2018 - PRESENT radarsimx.com
7 | - E-mail: info@radarsimx.com
8 | - Website: https://radarsimx.com
9 |
10 | ::
11 |
12 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
13 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
14 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
15 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
16 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
17 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
18 |
19 | """
20 |
21 | import pytest
22 |
23 | import numpy as np
24 |
25 | from radarsimpy import Radar, Transmitter, Receiver
26 | from radarsimpy.radar import cal_phase_noise
27 |
28 |
29 | class TestRadar:
30 | @pytest.fixture
31 | def radar_setup(self):
32 | """Fixture for setting up a basic radar system."""
33 | tx = Transmitter(f=10e9, t=1e-6, tx_power=10, pulses=10, prp=2e-6)
34 | rx = Receiver(fs=10e6)
35 | radar = Radar(transmitter=tx, receiver=rx)
36 | return radar
37 |
38 | def test_init_basic(self, radar_setup):
39 | """Test initialization with basic parameters."""
40 | radar = radar_setup
41 | # assert radar.time_prop["frame_size"] == 2
42 | # assert np.allclose(radar.time_prop["frame_start_time"], [0, 1e-3])
43 | assert radar.sample_prop["samples_per_pulse"] == 10
44 | assert radar.array_prop["size"] == 1
45 | np.testing.assert_allclose(radar.array_prop["virtual_array"], [[0, 0, 0]])
46 | assert radar.radar_prop["transmitter"].waveform_prop["f"][0] == 10e9
47 | assert radar.radar_prop["receiver"].bb_prop["fs"] == 10e6
48 | assert np.allclose(radar.radar_prop["location"], [0, 0, 0])
49 | assert np.allclose(radar.radar_prop["speed"], [0, 0, 0])
50 | assert np.allclose(radar.radar_prop["rotation"], [0, 0, 0])
51 | assert np.allclose(radar.radar_prop["rotation_rate"], [0, 0, 0])
52 |
53 | def test_gen_timestamp(self, radar_setup):
54 | """Test timestamp generation."""
55 | radar = radar_setup
56 | timestamp = radar.gen_timestamp()
57 | assert timestamp.shape == (1, 10, 10)
58 | assert np.allclose(timestamp[0, 0, 0], 0)
59 | assert np.allclose(timestamp[0, 9, 9], 1.89e-05)
60 |
61 | def test_cal_noise(self, radar_setup):
62 | """Test noise calculation."""
63 | radar = radar_setup
64 | noise = radar.cal_noise()
65 | assert isinstance(noise, float)
66 |
67 | def test_validate_radar_motion(self, radar_setup):
68 | """Test validation of radar motion inputs."""
69 | radar = radar_setup
70 | with pytest.raises(ValueError):
71 | radar.validate_radar_motion(
72 | location=[0, 0, [1, 2]],
73 | speed=[0, 0, 0],
74 | rotation=[0, 0, 0],
75 | rotation_rate=[0, 0, 0],
76 | )
77 |
78 | def test_process_radar_motion_scalar(self, radar_setup):
79 | """Test processing of radar motion with scalar inputs."""
80 | radar = radar_setup
81 | radar.process_radar_motion(
82 | location=[1, 2, 3],
83 | speed=[4, 5, 6],
84 | rotation=[7, 8, 9],
85 | rotation_rate=[10, 11, 12],
86 | )
87 | assert np.allclose(radar.radar_prop["location"], [1, 2, 3])
88 | assert np.allclose(radar.radar_prop["speed"], [4, 5, 6])
89 | assert np.allclose(radar.radar_prop["rotation"], np.radians([7, 8, 9]))
90 | assert np.allclose(radar.radar_prop["rotation_rate"], np.radians([10, 11, 12]))
91 |
92 | def test_cal_phase_noise(self):
93 | """Test phase noise calculation."""
94 | fs = 10e6
95 | freq = np.array([1e3, 1e4, 1e5])
96 | power = np.array([-100, -110, -120])
97 | signal = np.ones((10, 100), dtype=complex)
98 | phase_noise = cal_phase_noise(signal, fs, freq, power)
99 | assert phase_noise.shape == (10, 100)
100 | assert np.allclose(np.abs(phase_noise), 1)
101 |
102 | def test_cal_phase_noise_validation(self):
103 | """Test phase noise calculation with validation."""
104 | fs = 10e6
105 | freq = np.array([1e3, 1e4, 1e5])
106 | power = np.array([-100, -110, -120])
107 | signal = np.ones((10, 100), dtype=complex)
108 | phase_noise = cal_phase_noise(signal, fs, freq, power, validation=True)
109 | assert phase_noise.shape == (10, 100)
110 | assert np.allclose(np.abs(phase_noise), 1)
111 |
112 | def test_init_with_phase_noise(self):
113 | """Test initialization with phase noise."""
114 | tx = Transmitter(
115 | f=10e9,
116 | t=1e-6,
117 | tx_power=10,
118 | pulses=10,
119 | prp=2e-6,
120 | pn_f=np.array([1e3, 1e4, 1e5]),
121 | pn_power=np.array([-100, -110, -120]),
122 | )
123 | rx = Receiver(fs=10e6)
124 | radar = Radar(transmitter=tx, receiver=rx)
125 | assert radar.sample_prop["phase_noise"].shape == (191, )
126 |
127 | def test_init_with_phase_noise_validation(self):
128 | """Test initialization with phase noise and validation."""
129 | tx = Transmitter(
130 | f=10e9,
131 | t=1e-6,
132 | tx_power=10,
133 | pulses=10,
134 | prp=2e-6,
135 | pn_f=np.array([1e3, 1e4, 1e5]),
136 | pn_power=np.array([-100, -110, -120]),
137 | )
138 | rx = Receiver(fs=10e6)
139 | radar = Radar(transmitter=tx, receiver=rx, validation=True)
140 | assert radar.sample_prop["phase_noise"].shape == (191, )
141 |
142 | def test_init_with_multiple_channels(self):
143 | """Test initialization with multiple channels."""
144 | tx = Transmitter(
145 | f=10e9,
146 | t=1e-6,
147 | tx_power=10,
148 | pulses=10,
149 | prp=2e-6,
150 | channels=[{"location": (0, 0, 0)}, {"location": (10, 0, 0)}],
151 | )
152 | rx = Receiver(
153 | fs=10e6,
154 | channels=[{"location": (0, 0, 0)}, {"location": (0, 10, 0)}],
155 | )
156 | radar = Radar(transmitter=tx, receiver=rx, time=[0, 1e-3])
157 | assert radar.array_prop["size"] == 4
158 | np.testing.assert_allclose(
159 | radar.array_prop["virtual_array"],
160 | [[0, 0, 0], [0, 10, 0], [10, 0, 0], [10, 10, 0]],
161 | )
162 |
--------------------------------------------------------------------------------
/tests/test_config_receiver.py:
--------------------------------------------------------------------------------
1 | """
2 | A Python module for radar simulation
3 |
4 | ---
5 |
6 | - Copyright (C) 2018 - PRESENT radarsimx.com
7 | - E-mail: info@radarsimx.com
8 | - Website: https://radarsimx.com
9 |
10 | ::
11 |
12 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
13 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
14 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
15 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
16 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
17 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
18 |
19 | """
20 |
21 | import pytest
22 |
23 | import numpy as np
24 |
25 | from radarsimpy import Receiver
26 |
27 |
28 | class TestReceiver:
29 | def test_init_basic(self):
30 | """Test initialization with basic parameters."""
31 | rx = Receiver(fs=10e6)
32 | assert rx.bb_prop["fs"] == 10e6
33 | assert rx.rf_prop["noise_figure"] == 10
34 | assert rx.rf_prop["rf_gain"] == 0
35 | assert rx.bb_prop["load_resistor"] == 500
36 | assert rx.bb_prop["baseband_gain"] == 0
37 | assert rx.bb_prop["bb_type"] == "complex"
38 | assert rx.bb_prop["noise_bandwidth"] == 10e6
39 | assert rx.rxchannel_prop["size"] == 1
40 | np.testing.assert_allclose(rx.rxchannel_prop["locations"], [[0, 0, 0]])
41 |
42 | def test_init_custom_parameters(self):
43 | """Test initialization with custom parameters."""
44 | rx = Receiver(
45 | fs=20e6,
46 | noise_figure=5,
47 | rf_gain=10,
48 | load_resistor=100,
49 | baseband_gain=20,
50 | bb_type="real",
51 | )
52 | assert rx.bb_prop["fs"] == 20e6
53 | assert rx.rf_prop["noise_figure"] == 5
54 | assert rx.rf_prop["rf_gain"] == 10
55 | assert rx.bb_prop["load_resistor"] == 100
56 | assert rx.bb_prop["baseband_gain"] == 20
57 | assert rx.bb_prop["bb_type"] == "real"
58 | assert rx.bb_prop["noise_bandwidth"] == 10e6
59 |
60 | def test_validate_bb_prop(self):
61 | """Test validation of baseband properties."""
62 | rx = Receiver(fs=10e6)
63 | with pytest.raises(ValueError):
64 | rx.bb_prop["bb_type"] = "invalid"
65 | rx.validate_bb_prop(rx.bb_prop)
66 |
67 | def test_process_rxchannel_prop_basic(self):
68 | """Test processing of receiver channel properties with basic parameters."""
69 | rx = Receiver(fs=10e6)
70 | channels = [{"location": (1, 2, 3)}]
71 | rxch_prop = rx.process_rxchannel_prop(channels)
72 | assert rxch_prop["size"] == 1
73 | np.testing.assert_allclose(rxch_prop["locations"], [[1, 2, 3]])
74 | np.testing.assert_allclose(rxch_prop["polarization"], [[0, 0, 1]])
75 | assert rxch_prop["antenna_gains"][0] == 0
76 | np.testing.assert_allclose(rxch_prop["az_angles"][0], [-90, 90])
77 | np.testing.assert_allclose(rxch_prop["az_patterns"][0], [0, 0])
78 | np.testing.assert_allclose(rxch_prop["el_angles"][0], [-90, 90])
79 | np.testing.assert_allclose(rxch_prop["el_patterns"][0], [0, 0])
80 |
81 | def test_process_rxchannel_prop_custom_parameters(self):
82 | """Test processing of receiver channel properties with custom parameters."""
83 | rx = Receiver(fs=10e6)
84 | channels = [
85 | {
86 | "location": (4, 5, 6),
87 | "polarization": [1, 0, 0],
88 | "azimuth_angle": [-45, 45],
89 | "azimuth_pattern": [-3, -3],
90 | "elevation_angle": [-60, 60],
91 | "elevation_pattern": [-5, -5],
92 | }
93 | ]
94 | rxch_prop = rx.process_rxchannel_prop(channels)
95 | assert rxch_prop["size"] == 1
96 | np.testing.assert_allclose(rxch_prop["locations"], [[4, 5, 6]])
97 | np.testing.assert_allclose(rxch_prop["polarization"], [[1, 0, 0]])
98 | assert rxch_prop["antenna_gains"][0] == -3
99 | np.testing.assert_allclose(rxch_prop["az_angles"][0], [-45, 45])
100 | np.testing.assert_allclose(rxch_prop["az_patterns"][0], [0, 0])
101 | np.testing.assert_allclose(rxch_prop["el_angles"][0], [-60, 60])
102 | np.testing.assert_allclose(rxch_prop["el_patterns"][0], [0, 0])
103 |
104 | def test_process_rxchannel_prop_multiple_channels(self):
105 | """Test processing of receiver channel properties with multiple channels."""
106 | rx = Receiver(fs=10e6)
107 | channels = [
108 | {"location": (0, 0, 0)},
109 | {
110 | "location": (10, 0, 0),
111 | "polarization": [0, 1, 0],
112 | "azimuth_angle": [-90, 90],
113 | "azimuth_pattern": [-10, -10],
114 | "elevation_angle": [-90, 90],
115 | "elevation_pattern": [-10, -10],
116 | },
117 | ]
118 | rxch_prop = rx.process_rxchannel_prop(channels)
119 | assert rxch_prop["size"] == 2
120 | np.testing.assert_allclose(rxch_prop["locations"], [[0, 0, 0], [10, 0, 0]])
121 | np.testing.assert_allclose(rxch_prop["polarization"], [[0, 0, 1], [0, 1, 0]])
122 | np.testing.assert_allclose(rxch_prop["antenna_gains"], [0, -10])
123 |
124 | def test_process_rxchannel_prop_invalid_pattern_length(self):
125 | """Test processing of receiver channel properties with invalid pattern length."""
126 | rx = Receiver(fs=10e6)
127 | channels = [
128 | {
129 | "location": (0, 0, 0),
130 | "azimuth_angle": [-90, 90],
131 | "azimuth_pattern": [-10],
132 | }
133 | ]
134 | with pytest.raises(ValueError):
135 | rx.process_rxchannel_prop(channels)
136 |
137 | def test_process_rxchannel_prop_invalid_elevation_pattern_length(self):
138 | """Test processing of receiver channel properties with invalid elevation pattern length."""
139 | rx = Receiver(fs=10e6)
140 | channels = [
141 | {
142 | "location": (0, 0, 0),
143 | "elevation_angle": [-90, 90],
144 | "elevation_pattern": [-10],
145 | }
146 | ]
147 | with pytest.raises(ValueError):
148 | rx.process_rxchannel_prop(channels)
149 |
--------------------------------------------------------------------------------
/tests/test_module_sim_lidar.py:
--------------------------------------------------------------------------------
1 | """
2 | A Python module for radar simulation
3 |
4 | ---
5 |
6 | - Copyright (C) 2018 - PRESENT radarsimx.com
7 | - E-mail: info@radarsimx.com
8 | - Website: https://radarsimx.com
9 |
10 | ::
11 |
12 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
13 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
14 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
15 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
16 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
17 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
18 |
19 | """
20 |
21 | import numpy as np
22 |
23 | from radarsimpy.simulator import sim_lidar # pylint: disable=no-name-in-module
24 |
25 |
26 | def test_lidar_scene_basic():
27 | """
28 | Basic test case with a single target and a simple lidar setup.
29 | """
30 | lidar = {
31 | "position": np.array([0, 0, 0]),
32 | "phi": np.array([0]),
33 | "theta": np.array([90]),
34 | }
35 | targets = [
36 | {
37 | "model": "./models/plate5x5.stl",
38 | "location": np.array([10, 0, 0]),
39 | }
40 | ]
41 | rays = sim_lidar(lidar, targets)
42 | assert rays.shape[0] == 1 # Check if rays are generated
43 | assert np.allclose(
44 | rays[0]["positions"], [10, 0, 0], atol=1e-05
45 | ) # Check lidar position
46 | assert np.allclose(
47 | rays[0]["directions"], [-1, 0, 0], atol=1e-05
48 | ) # Check ray direction
49 |
50 |
51 | def test_lidar_scene_multiple_targets():
52 | """
53 | Test with multiple targets.
54 | """
55 | lidar = {
56 | "position": np.array([0, 0, 0]),
57 | "phi": np.array([0, 90]),
58 | "theta": np.array([90]),
59 | }
60 | targets = [
61 | {
62 | "model": "./models/ball_1m.stl",
63 | "location": np.array([10, 0, 0]),
64 | },
65 | {
66 | "model": "./models/ball_1m.stl",
67 | "location": np.array([0, 10, 0]),
68 | },
69 | ]
70 | rays = sim_lidar(lidar, targets)
71 | assert rays.shape[0] == 2 # Check if rays are generated for all targets
72 | assert np.allclose(
73 | rays[0]["positions"], [9.5000010e00, 0.0000000e00, -4.1525823e-07], atol=1e-05
74 | )
75 | assert np.allclose(
76 | rays[0]["directions"], [-0.9956786, 0.06597178, -0.06535852], atol=1e-05
77 | )
78 | assert np.allclose(
79 | rays[1]["positions"], [-4.1526718e-07, 9.5002060e00, -4.1526718e-07], atol=1e-05
80 | )
81 | assert np.allclose(
82 | rays[1]["directions"], [-0.03301523, -0.99731606, -0.06534925], atol=1e-05
83 | )
84 |
85 |
86 | def test_lidar_scene_target_movement():
87 | """
88 | Test with a moving target.
89 | """
90 | lidar = {
91 | "position": np.array([0, 0, 0]),
92 | "phi": np.array([0]),
93 | "theta": np.array([90]),
94 | }
95 | targets = [
96 | {
97 | "model": "./models/plate5x5.stl",
98 | "location": np.array([10, 0, 0]),
99 | "speed": np.array([1, 0, 0]),
100 | }
101 | ]
102 | rays_t0 = sim_lidar(lidar, targets, frame_time=0)
103 | rays_t1 = sim_lidar(lidar, targets, frame_time=1)
104 | assert np.allclose(rays_t0[0]["positions"], [10, 0, 0], atol=1e-05)
105 | assert np.allclose(rays_t0[0]["directions"], [-1, 0, 0], atol=1e-05)
106 | assert np.allclose(rays_t1[0]["positions"], [11, 0, 0], atol=1e-05)
107 | assert np.allclose(rays_t1[0]["directions"], [-1, 0, 0], atol=1e-05)
108 |
109 |
110 | def test_lidar_scene_target_rotation():
111 | """
112 | Test with a rotating target.
113 | """
114 | lidar = {
115 | "position": np.array([0, 0, 0]),
116 | "phi": np.array([0]),
117 | "theta": np.array([90]),
118 | }
119 | targets = [
120 | {
121 | "model": "./models/plate5x5.stl",
122 | "location": np.array([10, 0, 0]),
123 | "rotation_rate": np.array([45, 0, 0]),
124 | }
125 | ]
126 | rays_t0 = sim_lidar(lidar, targets, frame_time=0)
127 | rays_t1 = sim_lidar(lidar, targets, frame_time=1)
128 | assert np.allclose(rays_t0[0]["positions"], [10, 0, 0], atol=1e-05)
129 | assert np.allclose(rays_t0[0]["directions"], [-1, 0, 0], atol=1e-05)
130 | assert np.allclose(rays_t1[0]["positions"], [10, 0, 0], atol=1e-05)
131 | assert np.allclose(rays_t1[0]["directions"], [0, -1, 0], atol=1e-05)
132 |
--------------------------------------------------------------------------------
/tests/test_module_sim_rcs.py:
--------------------------------------------------------------------------------
1 | """
2 | A Python module for radar simulation
3 |
4 | ---
5 |
6 | - Copyright (C) 2018 - PRESENT radarsimx.com
7 | - E-mail: info@radarsimx.com
8 | - Website: https://radarsimx.com
9 |
10 | ::
11 |
12 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
13 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
14 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
15 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
16 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
17 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
18 |
19 | """
20 |
21 | import pytest
22 | import numpy as np
23 | import numpy.testing as npt
24 |
25 | from radarsimpy.simulator import sim_rcs # pylint: disable=no-name-in-module
26 |
27 |
28 | def test_rcs_momostatic():
29 | """
30 | Tests the radar cross-section (RCS) calculation for a monostatic radar system.
31 | """
32 | phi = 0
33 | theta = 90
34 | freq = np.array([1e9, 3e9])
35 | pol = np.array([0, 0, 1])
36 | density = 1
37 | rcs = np.zeros_like(freq)
38 | target = {
39 | "model": "./models/plate5x5.stl",
40 | "location": (0, 0, 0),
41 | }
42 | for f_idx, f in enumerate(freq):
43 | rcs[f_idx] = 10 * np.log10(
44 | sim_rcs([target], f, phi, theta, inc_pol=pol, density=density)
45 | )
46 |
47 | npt.assert_almost_equal(rcs, np.array([48.3, 59.2]), decimal=1)
48 |
49 |
50 | def test_rcs_bistatic():
51 | """
52 | Tests the radar cross-section (RCS) calculation for a bistatic radar system.
53 | """
54 | phi = np.array([-30, -24, 65])
55 | theta = 90
56 |
57 | inc_phi = 30
58 | inc_theta = 90
59 |
60 | freq = 1e9
61 | pol = np.array([0, 0, 1])
62 | density = 1
63 | rcs = np.zeros_like(phi)
64 |
65 | target = {
66 | "model": "./models/plate5x5.stl",
67 | "location": (0, 0, 0),
68 | }
69 | for phi_idx, phi_ang in enumerate(phi):
70 | rcs[phi_idx] = 10 * np.log10(
71 | sim_rcs(
72 | [target],
73 | freq,
74 | inc_phi=inc_phi,
75 | inc_theta=inc_theta,
76 | inc_pol=pol,
77 | obs_phi=phi_ang,
78 | obs_theta=theta,
79 | density=density,
80 | )
81 | )
82 |
83 | npt.assert_almost_equal(rcs, np.array([47, 34, 6]), decimal=0)
84 |
--------------------------------------------------------------------------------
/tests/test_module_tools.py:
--------------------------------------------------------------------------------
1 | """
2 | A Python module for radar simulation
3 |
4 | ---
5 |
6 | - Copyright (C) 2018 - PRESENT radarsimx.com
7 | - E-mail: info@radarsimx.com
8 | - Website: https://radarsimx.com
9 |
10 | ::
11 |
12 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
13 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
14 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
15 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
16 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
17 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
18 |
19 | """
20 |
21 | import numpy.testing as npt
22 |
23 | from radarsimpy.tools import roc_pd, roc_snr, threshold
24 |
25 |
26 | def test_roc_pd():
27 | """
28 | Test the ROC Pd function
29 | """
30 | npt.assert_almost_equal(roc_pd(1e-8, 13, 1, "Swerling 5"), 0.6287, decimal=4)
31 | npt.assert_almost_equal(roc_pd(1e-8, 11, 1, "Swerling 5"), 0.1683, decimal=4)
32 | npt.assert_almost_equal(roc_pd(1e-8, -3.2, 256, "Swerling 5"), 0.8411, decimal=4)
33 | npt.assert_almost_equal(roc_pd(1e-8, -4.8, 256, "Swerling 5"), 0.2249, decimal=4)
34 |
35 | npt.assert_almost_equal(roc_pd(1e-9, -10, 256, "Coherent"), 0.8765, decimal=4)
36 | npt.assert_almost_equal(roc_pd(1e-9, -12, 256, "Coherent"), 0.3767, decimal=4)
37 | npt.assert_almost_equal(roc_pd(1e-6, 12.4, 1, "Coherent"), 0.8733, decimal=4)
38 | npt.assert_almost_equal(roc_pd(1e-6, 8.8, 1, "Coherent"), 0.1953, decimal=4)
39 |
40 | npt.assert_almost_equal(roc_pd(1e-4, 16, 1, "Swerling 1"), 0.7980, decimal=4)
41 | npt.assert_almost_equal(roc_pd(1e-4, 6.8, 1, "Swerling 1"), 0.2036, decimal=4)
42 | npt.assert_almost_equal(roc_pd(1e-4, 3.6, 256, "Swerling 1"), 0.8959, decimal=4)
43 | npt.assert_almost_equal(roc_pd(1e-4, -7.6, 256, "Swerling 1"), 0.2560, decimal=4)
44 |
45 | npt.assert_almost_equal(roc_pd(1e-4, -4.4, 256, "Swerling 2"), 0.9120, decimal=4)
46 | npt.assert_almost_equal(roc_pd(1e-4, -7.2, 256, "Swerling 2"), 0.2125, decimal=4)
47 | npt.assert_almost_equal(roc_pd(1e-4, 16, 1, "Swerling 2"), 0.7980, decimal=4)
48 | npt.assert_almost_equal(roc_pd(1e-4, 6.8, 1, "Swerling 2"), 0.2036, decimal=4)
49 |
50 | npt.assert_almost_equal(roc_pd(1e-4, 15.2, 1, "Swerling 3"), 0.8846, decimal=4)
51 | npt.assert_almost_equal(roc_pd(1e-4, 6.8, 1, "Swerling 3"), 0.1931, decimal=4)
52 | npt.assert_almost_equal(roc_pd(1e-4, -0.4, 256, "Swerling 3"), 0.8889, decimal=4)
53 | npt.assert_almost_equal(roc_pd(1e-4, -8.4, 256, "Swerling 3"), 0.1775, decimal=4)
54 |
55 | npt.assert_almost_equal(roc_pd(1e-4, 15.2, 1, "Swerling 4"), 0.8846, decimal=4)
56 | npt.assert_almost_equal(roc_pd(1e-4, 6.8, 1, "Swerling 4"), 0.1931, decimal=4)
57 | npt.assert_almost_equal(roc_pd(1e-4, -4.8, 256, "Swerling 4"), 0.8413, decimal=4)
58 | npt.assert_almost_equal(roc_pd(1e-4, -7.2, 256, "Swerling 4"), 0.2155, decimal=4)
59 |
60 |
61 | def test_threshold():
62 | """
63 | Test the ROC threshold function
64 | """
65 | npt.assert_almost_equal(threshold(1e-4, 1), 9.21, decimal=2)
66 | npt.assert_almost_equal(threshold(1e-4, 10), 26.19, decimal=2)
67 | npt.assert_almost_equal(threshold(1e-4, 20), 41.03, decimal=2)
68 | npt.assert_almost_equal(threshold(1e-4, 40), 67.89, decimal=2)
69 |
70 |
71 | def test_roc_snr():
72 | """
73 | Test the ROC SNR function
74 | """
75 | npt.assert_almost_equal(roc_snr(1e-8, 0.6290, 1, "Swerling 5"), 13, decimal=0)
76 | npt.assert_almost_equal(roc_snr(1e-8, 0.1681, 1, "Swerling 5"), 11, decimal=0)
77 | npt.assert_almost_equal(roc_snr(1e-8, 0.8424, 256, "Swerling 5"), -3.2, decimal=1)
78 | npt.assert_almost_equal(roc_snr(1e-8, 0.2266, 256, "Swerling 5"), -4.8, decimal=1)
79 |
80 | npt.assert_almost_equal(roc_snr(1e-9, 0.8765, 256, "Coherent"), -10, decimal=0)
81 | npt.assert_almost_equal(roc_snr(1e-9, 0.3767, 256, "Coherent"), -12, decimal=0)
82 | npt.assert_almost_equal(roc_snr(1e-6, 0.8733, 1, "Coherent"), 12.4, decimal=1)
83 | npt.assert_almost_equal(roc_snr(1e-6, 0.1953, 1, "Coherent"), 8.8, decimal=1)
84 |
85 | npt.assert_almost_equal(roc_snr(1e-4, 0.7980, 1, "Swerling 1"), 16, decimal=0)
86 | npt.assert_almost_equal(roc_snr(1e-4, 0.2036, 1, "Swerling 1"), 6.8, decimal=1)
87 | npt.assert_almost_equal(roc_snr(1e-4, 0.8959, 256, "Swerling 1"), 3.6, decimal=1)
88 | npt.assert_almost_equal(roc_snr(1e-4, 0.2560, 256, "Swerling 1"), -7.6, decimal=1)
89 |
90 | npt.assert_almost_equal(roc_snr(1e-4, 0.9120, 256, "Swerling 2"), -4.4, decimal=1)
91 | npt.assert_almost_equal(roc_snr(1e-4, 0.2125, 256, "Swerling 2"), -7.2, decimal=1)
92 | npt.assert_almost_equal(roc_snr(1e-4, 0.7980, 1, "Swerling 2"), 16, decimal=0)
93 | npt.assert_almost_equal(roc_snr(1e-4, 0.2036, 1, "Swerling 2"), 6.8, decimal=1)
94 |
95 | npt.assert_almost_equal(roc_snr(1e-4, 0.8846, 1, "Swerling 3"), 15.2, decimal=1)
96 | npt.assert_almost_equal(roc_snr(1e-4, 0.1931, 1, "Swerling 3"), 6.8, decimal=1)
97 | npt.assert_almost_equal(roc_snr(1e-4, 0.8889, 256, "Swerling 3"), -0.4, decimal=1)
98 | npt.assert_almost_equal(roc_snr(1e-4, 0.1772, 256, "Swerling 3"), -8.4, decimal=1)
99 |
100 | npt.assert_almost_equal(roc_snr(1e-4, 0.8846, 1, "Swerling 4"), 15.2, decimal=1)
101 | npt.assert_almost_equal(roc_snr(1e-4, 0.1931, 1, "Swerling 4"), 6.8, decimal=1)
102 | npt.assert_almost_equal(roc_snr(1e-4, 0.8413, 256, "Swerling 4"), -4.8, decimal=1)
103 | npt.assert_almost_equal(roc_snr(1e-4, 0.2155, 256, "Swerling 4"), -7.2, decimal=1)
104 |
--------------------------------------------------------------------------------
/tests/test_system_cw_radar.py:
--------------------------------------------------------------------------------
1 | """
2 | System level test for raytracing-based sim_radar simulation
3 |
4 | ---
5 |
6 | - Copyright (C) 2018 - PRESENT radarsimx.com
7 | - E-mail: info@radarsimx.com
8 | - Website: https://radarsimx.com
9 |
10 | ::
11 |
12 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
13 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
14 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
15 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
16 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
17 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
18 |
19 | """
20 |
21 | import numpy as np
22 | from radarsimpy import Radar, Transmitter, Receiver
23 | from radarsimpy.simulator import sim_radar # pylint: disable=no-name-in-module
24 |
25 |
26 | def test_sim_cw():
27 | """
28 | Test the CW radar simulator.
29 | """
30 | tx = Transmitter(
31 | f=24.125e9, t=20, tx_power=10, pulses=1, channels=[{"location": (0, 0, 0)}]
32 | )
33 | rx = Receiver(
34 | fs=0.5,
35 | noise_figure=12,
36 | rf_gain=20,
37 | baseband_gain=50,
38 | load_resistor=1000,
39 | channels=[{"location": (0, 0, 0)}],
40 | )
41 | radar = Radar(transmitter=tx, receiver=rx)
42 |
43 | target = {
44 | "location": (
45 | 1.4 + 1e-3 * np.sin(2 * np.pi * 0.1 * radar.time_prop["timestamp"]),
46 | 0,
47 | 0,
48 | ),
49 | "rcs": -10,
50 | "phase": 0,
51 | }
52 | targets = [target]
53 |
54 | result = sim_radar(radar, targets)
55 |
56 | assert np.allclose(
57 | result["baseband"],
58 | np.array(
59 | [
60 | [
61 | [
62 | -0.28017324 + 0.57151868j,
63 | -0.62818491 + 0.09703288j,
64 | -0.55171423 + 0.31632635j,
65 | 0.08803159 + 0.63092172j,
66 | 0.30893151 + 0.55748964j,
67 | -0.28016539 + 0.57152253j,
68 | -0.62820815 + 0.09688231j,
69 | -0.55177488 + 0.31622055j,
70 | 0.08815256 + 0.63090483j,
71 | 0.3088246 + 0.55754887j,
72 | ]
73 | ]
74 | ]
75 | ),
76 | atol=1e-05,
77 | )
78 |
79 | assert np.allclose(
80 | result["timestamp"],
81 | np.array([[[0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0]]]),
82 | )
83 |
84 |
85 | def test_sim_cw_raytracing():
86 | """
87 | Test the CW radar simulator.
88 | """
89 | tx = Transmitter(
90 | f=24.125e9, t=20, tx_power=10, pulses=1, channels=[{"location": (0, 0, 0)}]
91 | )
92 | rx = Receiver(
93 | fs=0.5,
94 | noise_figure=12,
95 | rf_gain=20,
96 | baseband_gain=50,
97 | load_resistor=1000,
98 | channels=[{"location": (0, 0, 0)}],
99 | )
100 | radar = Radar(transmitter=tx, receiver=rx)
101 |
102 | target = {
103 | "model": "./models/cr.stl",
104 | "location": (
105 | 1.4 + 1e-3 * np.sin(2 * np.pi * 0.1 * radar.time_prop["timestamp"]),
106 | 0,
107 | 0,
108 | ),
109 | }
110 | targets = [target]
111 |
112 | result = sim_radar(radar, targets, density=1, level="sample")
113 |
114 | assert np.allclose(
115 | result["baseband"],
116 | np.array(
117 | [
118 | [
119 | [
120 | 2.00757447 + 2.22013679j,
121 | -0.67349305 + 2.91739497j,
122 | 0.41935286 + 2.9642617j,
123 | 2.90617447 + 0.7143177j,
124 | 2.96842678 - 0.37725781j,
125 | 2.00762345 + 2.22007286j,
126 | -0.67349343 + 2.91735525j,
127 | 0.41948373 + 2.96425345j,
128 | 2.90613151 + 0.71437308j,
129 | 2.96848674 - 0.37720091j,
130 | ]
131 | ]
132 | ]
133 | ),
134 | atol=1e-05,
135 | )
136 |
137 | assert np.allclose(
138 | result["timestamp"],
139 | np.array([[[0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0]]]),
140 | )
141 |
--------------------------------------------------------------------------------
/tests/test_system_phase_noise.py:
--------------------------------------------------------------------------------
1 | """
2 | A Python module for radar simulation
3 |
4 | ---
5 |
6 | - Copyright (C) 2018 - PRESENT radarsimx.com
7 | - E-mail: info@radarsimx.com
8 | - Website: https://radarsimx.com
9 |
10 | ::
11 |
12 | ██████╗ █████╗ ██████╗ █████╗ ██████╗ ███████╗██╗███╗ ███╗██╗ ██╗
13 | ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
14 | ██████╔╝███████║██║ ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
15 | ██╔══██╗██╔══██║██║ ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
16 | ██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
17 | ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
18 |
19 | """
20 |
21 | from scipy import signal
22 | import numpy as np
23 | import numpy.testing as npt
24 |
25 | from radarsimpy import Radar, Transmitter, Receiver
26 | from radarsimpy.simulator import sim_radar # pylint: disable=no-name-in-module
27 | from radarsimpy.radar import cal_phase_noise
28 | import radarsimpy.processing as proc
29 |
30 |
31 | def test_phase_noise():
32 | """
33 | This function tests phase noise calculation
34 | """
35 | sig = np.ones((1, 256))
36 | pn_f = np.array([1000, 10000, 100000, 1000000])
37 | pn_power_db_per_hz = np.array([-84, -100, -96, -109])
38 | fs = 4e6
39 |
40 | pn = cal_phase_noise(sig, fs, pn_f, pn_power_db_per_hz, validation=True)
41 |
42 | # f = np.linspace(0, fs, 256)
43 | spec = 20 * np.log10(np.abs(np.fft.fft(pn[0, :] / 256)))
44 |
45 | # pn_power_db = pn_power_db_per_hz+10*np.log10(fs/256)
46 |
47 | npt.assert_almost_equal(spec[1], -63.4, decimal=2)
48 | npt.assert_almost_equal(spec[6], -60.21, decimal=2)
49 | npt.assert_almost_equal(spec[64], -73.09, decimal=2)
50 |
51 |
52 | def test_fmcw_phase_noise():
53 | """
54 | This function tests the phase noise simulation
55 | """
56 | tx_channel = {"location": (0, 0, 0)}
57 |
58 | pn_f = np.array([1000, 10000, 100000, 1000000])
59 | pn_power = np.array([-65, -70, -65, -90])
60 |
61 | tx_pn = Transmitter(
62 | f=[24.125e9 - 50e6, 24.125e9 + 50e6],
63 | t=80e-6,
64 | tx_power=40,
65 | prp=100e-6,
66 | pulses=1,
67 | pn_f=pn_f,
68 | pn_power=pn_power,
69 | channels=[tx_channel],
70 | )
71 |
72 | tx = Transmitter(
73 | f=[24.125e9 - 50e6, 24.125e9 + 50e6],
74 | t=80e-6,
75 | tx_power=40,
76 | prp=100e-6,
77 | pulses=1,
78 | channels=[tx_channel],
79 | )
80 |
81 | rx_channel = {"location": (0, 0, 0)}
82 |
83 | rx = Receiver(
84 | fs=2e6,
85 | noise_figure=12,
86 | rf_gain=20,
87 | load_resistor=500,
88 | baseband_gain=30,
89 | channels=[rx_channel],
90 | )
91 |
92 | radar_pn = Radar(transmitter=tx_pn, receiver=rx, seed=1234, validation=True)
93 | radar = Radar(transmitter=tx, receiver=rx, seed=1234, validation=True)
94 |
95 | target_1 = {"location": (150, 20, 0), "speed": (0, 0, 0), "rcs": 60, "phase": 0}
96 |
97 | targets = [target_1]
98 |
99 | data_cpp_pn = sim_radar(radar_pn, targets)
100 | data_matrix_cpp_pn = data_cpp_pn["baseband"]
101 | data_cpp = sim_radar(radar, targets)
102 | data_matrix_cpp = data_cpp["baseband"]
103 |
104 | range_window = signal.windows.chebwin(radar.sample_prop["samples_per_pulse"], at=60)
105 | range_profile_pn = proc.range_fft(data_matrix_cpp_pn, range_window)
106 | range_profile = proc.range_fft(data_matrix_cpp, range_window)
107 |
108 | range_profile_pn = 20 * np.log10(np.abs(range_profile_pn[0, 0, :]))
109 | range_profile = 20 * np.log10(np.abs(range_profile[0, 0, :]))
110 |
111 | profile_diff = range_profile_pn - range_profile
112 |
113 | npt.assert_allclose(
114 | profile_diff,
115 | np.array(
116 | [
117 | 8.15236683e00,
118 | 8.62450253e00,
119 | 9.94566903e00,
120 | 8.41230320e00,
121 | 1.35971821e01,
122 | 1.62558002e01,
123 | 1.93212483e01,
124 | 1.31870147e01,
125 | 1.75406669e01,
126 | 1.38916956e01,
127 | 8.49327223e00,
128 | 1.86175487e01,
129 | 1.40706202e01,
130 | 1.76409000e01,
131 | 2.25048424e01,
132 | 1.45015542e01,
133 | 2.05210282e01,
134 | 1.86531317e01,
135 | 1.71046366e01,
136 | 4.10641684e00,
137 | 3.79405756e01,
138 | 2.75389544e01,
139 | 3.90926646e01,
140 | 6.27310149e00,
141 | 2.16279769e01,
142 | 2.52661677e01,
143 | 3.36658700e01,
144 | 2.88195604e01,
145 | 3.91194415e01,
146 | 4.59002235e01,
147 | 5.04732280e01,
148 | 3.94599231e01,
149 | 3.24503013e01,
150 | 2.96344893e01,
151 | 3.03904606e01,
152 | 2.83176478e01,
153 | 3.11181814e01,
154 | 2.53430024e01,
155 | 2.30302068e01,
156 | 1.72725494e01,
157 | 1.87363003e01,
158 | 1.71670574e01,
159 | 1.69392597e01,
160 | 1.04715126e01,
161 | 1.59758951e01,
162 | 7.97696140e00,
163 | 1.11580555e01,
164 | 1.44807343e01,
165 | 1.40912099e01,
166 | 1.41879078e01,
167 | 1.29359464e01,
168 | 1.20614666e01,
169 | 1.08958080e01,
170 | 8.03589480e00,
171 | 1.04874421e01,
172 | 6.87794869e00,
173 | 8.70538605e00,
174 | 1.02700420e01,
175 | -1.50547286e01,
176 | -1.89459088e00,
177 | 4.42629745e-01,
178 | 1.06804309e00,
179 | 7.46382310e00,
180 | -9.28290884e00,
181 | 7.02103212e00,
182 | 9.03193911e00,
183 | 4.89482735e00,
184 | 3.28958093e00,
185 | 5.25774634e00,
186 | 1.72219960e00,
187 | -7.17070791e-01,
188 | 4.87554162e00,
189 | 1.26008143e00,
190 | 4.53897983e00,
191 | -1.31826831e01,
192 | -3.97219210e-01,
193 | -1.88513576e01,
194 | -1.00752817e00,
195 | 5.18454718e-01,
196 | -6.54762623e-01,
197 | -9.00964293e-01,
198 | 9.64784119e-01,
199 | 4.68541185e00,
200 | 8.86610661e00,
201 | 1.16768714e01,
202 | 1.40424314e01,
203 | 1.23302152e01,
204 | 1.20765995e01,
205 | 1.62397170e01,
206 | 1.68698397e01,
207 | 1.63122911e01,
208 | 1.63895149e01,
209 | 2.22444422e01,
210 | 3.04330686e01,
211 | 3.34724037e01,
212 | 1.52160781e01,
213 | 1.19215742e01,
214 | 1.53405891e01,
215 | 2.20231153e01,
216 | -1.05176631e00,
217 | 8.30268334e-02,
218 | -3.95634294e-02,
219 | 5.80602668e-02,
220 | -6.59517939e-01,
221 | 1.34651845e01,
222 | 1.53163491e01,
223 | 2.45530362e01,
224 | 6.18439387e01,
225 | 2.27776171e01,
226 | 1.74963002e01,
227 | 1.77674211e01,
228 | 1.50284897e01,
229 | 1.25935400e01,
230 | 6.74313391e00,
231 | 6.07564392e00,
232 | 1.00810249e01,
233 | 4.78584396e00,
234 | -4.26958606e00,
235 | -5.58157923e00,
236 | -2.45911840e00,
237 | 4.72325979e00,
238 | 7.08286461e00,
239 | 3.99875291e00,
240 | 6.58567146e00,
241 | 7.95576358e00,
242 | 4.24917591e00,
243 | 4.43187106e00,
244 | 6.59002957e00,
245 | 5.28506440e00,
246 | -1.07894150e00,
247 | -2.71490104e00,
248 | 8.49118834e00,
249 | 7.33305209e00,
250 | 7.58354325e00,
251 | 3.00461831e00,
252 | 1.45074678e00,
253 | 9.11779594e00,
254 | 6.87048797e00,
255 | 3.04951896e-01,
256 | 8.08362341e00,
257 | 6.77752185e00,
258 | 6.09439334e00,
259 | 8.00496874e00,
260 | 9.93519129e00,
261 | 9.16553127e00,
262 | 9.02552562e00,
263 | 1.17643448e01,
264 | 4.90491193e00,
265 | -1.86823144e00,
266 | 6.35799399e00,
267 | 1.27685095e01,
268 | 1.34158011e01,
269 | 1.15192466e01,
270 | 1.08706573e01,
271 | 7.58792202e00,
272 | -8.31226080e00,
273 | 6.27604552e00,
274 | 7.86567283e00,
275 | 1.32263561e01,
276 | -6.63679916e00,
277 | ]
278 | ),
279 | atol=1,
280 | )
281 |
--------------------------------------------------------------------------------