sergiev commited on
Commit
30eb8f4
·
verified ·
1 Parent(s): c30c87c

Upload folder using huggingface_hub

Browse files
.gitignore CHANGED
@@ -1,177 +1,177 @@
1
- # CUSTOM
2
- .gradio
3
-
4
- # Byte-compiled / optimized / DLL files
5
- __pycache__/
6
- *.py[cod]
7
- *$py.class
8
-
9
- # C extensions
10
- *.so
11
-
12
- # Distribution / packaging
13
- .Python
14
- build/
15
- develop-eggs/
16
- dist/
17
- downloads/
18
- eggs/
19
- .eggs/
20
- lib/
21
- lib64/
22
- parts/
23
- sdist/
24
- var/
25
- wheels/
26
- share/python-wheels/
27
- *.egg-info/
28
- .installed.cfg
29
- *.egg
30
- MANIFEST
31
-
32
- # PyInstaller
33
- # Usually these files are written by a python script from a template
34
- # before PyInstaller builds the exe, so as to inject date/other infos into it.
35
- *.manifest
36
- *.spec
37
-
38
- # Installer logs
39
- pip-log.txt
40
- pip-delete-this-directory.txt
41
-
42
- # Unit test / coverage reports
43
- htmlcov/
44
- .tox/
45
- .nox/
46
- .coverage
47
- .coverage.*
48
- .cache
49
- nosetests.xml
50
- coverage.xml
51
- *.cover
52
- *.py,cover
53
- .hypothesis/
54
- .pytest_cache/
55
- cover/
56
-
57
- # Translations
58
- *.mo
59
- *.pot
60
-
61
- # Django stuff:
62
- *.log
63
- local_settings.py
64
- db.sqlite3
65
- db.sqlite3-journal
66
-
67
- # Flask stuff:
68
- instance/
69
- .webassets-cache
70
-
71
- # Scrapy stuff:
72
- .scrapy
73
-
74
- # Sphinx documentation
75
- docs/_build/
76
-
77
- # PyBuilder
78
- .pybuilder/
79
- target/
80
-
81
- # Jupyter Notebook
82
- .ipynb_checkpoints
83
-
84
- # IPython
85
- profile_default/
86
- ipython_config.py
87
-
88
- # pyenv
89
- # For a library or package, you might want to ignore these files since the code is
90
- # intended to run in multiple environments; otherwise, check them in:
91
- # .python-version
92
-
93
- # pipenv
94
- # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
95
- # However, in case of collaboration, if having platform-specific dependencies or dependencies
96
- # having no cross-platform support, pipenv may install dependencies that don't work, or not
97
- # install all needed dependencies.
98
- #Pipfile.lock
99
-
100
- # UV
101
- # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
102
- # This is especially recommended for binary packages to ensure reproducibility, and is more
103
- # commonly ignored for libraries.
104
- #uv.lock
105
-
106
- # poetry
107
- # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
108
- # This is especially recommended for binary packages to ensure reproducibility, and is more
109
- # commonly ignored for libraries.
110
- # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
111
- #poetry.lock
112
-
113
- # pdm
114
- # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
115
- #pdm.lock
116
- # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
117
- # in version control.
118
- # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
119
- .pdm.toml
120
- .pdm-python
121
- .pdm-build/
122
-
123
- # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
124
- __pypackages__/
125
-
126
- # Celery stuff
127
- celerybeat-schedule
128
- celerybeat.pid
129
-
130
- # SageMath parsed files
131
- *.sage.py
132
-
133
- # Environments
134
- .env
135
- .venv
136
- env/
137
- venv/
138
- ENV/
139
- env.bak/
140
- venv.bak/
141
-
142
- # Spyder project settings
143
- .spyderproject
144
- .spyproject
145
-
146
- # Rope project settings
147
- .ropeproject
148
-
149
- # mkdocs documentation
150
- /site
151
-
152
- # mypy
153
- .mypy_cache/
154
- .dmypy.json
155
- dmypy.json
156
-
157
- # Pyre type checker
158
- .pyre/
159
-
160
- # pytype static type analyzer
161
- .pytype/
162
-
163
- # Cython debug symbols
164
- cython_debug/
165
-
166
- # PyCharm
167
- # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
168
- # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
169
- # and can be added to the global gitignore or merged into this file. For a more nuclear
170
- # option (not recommended) you can uncomment the following to ignore the entire idea folder.
171
- #.idea/
172
-
173
- # Ruff stuff:
174
- .ruff_cache/
175
-
176
- # PyPI configuration file
177
- .pypirc
 
1
+ # CUSTOM
2
+ .gradio
3
+
4
+ # Byte-compiled / optimized / DLL files
5
+ __pycache__/
6
+ *.py[cod]
7
+ *$py.class
8
+
9
+ # C extensions
10
+ *.so
11
+
12
+ # Distribution / packaging
13
+ .Python
14
+ build/
15
+ develop-eggs/
16
+ dist/
17
+ downloads/
18
+ eggs/
19
+ .eggs/
20
+ lib/
21
+ lib64/
22
+ parts/
23
+ sdist/
24
+ var/
25
+ wheels/
26
+ share/python-wheels/
27
+ *.egg-info/
28
+ .installed.cfg
29
+ *.egg
30
+ MANIFEST
31
+
32
+ # PyInstaller
33
+ # Usually these files are written by a python script from a template
34
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
35
+ *.manifest
36
+ *.spec
37
+
38
+ # Installer logs
39
+ pip-log.txt
40
+ pip-delete-this-directory.txt
41
+
42
+ # Unit test / coverage reports
43
+ htmlcov/
44
+ .tox/
45
+ .nox/
46
+ .coverage
47
+ .coverage.*
48
+ .cache
49
+ nosetests.xml
50
+ coverage.xml
51
+ *.cover
52
+ *.py,cover
53
+ .hypothesis/
54
+ .pytest_cache/
55
+ cover/
56
+
57
+ # Translations
58
+ *.mo
59
+ *.pot
60
+
61
+ # Django stuff:
62
+ *.log
63
+ local_settings.py
64
+ db.sqlite3
65
+ db.sqlite3-journal
66
+
67
+ # Flask stuff:
68
+ instance/
69
+ .webassets-cache
70
+
71
+ # Scrapy stuff:
72
+ .scrapy
73
+
74
+ # Sphinx documentation
75
+ docs/_build/
76
+
77
+ # PyBuilder
78
+ .pybuilder/
79
+ target/
80
+
81
+ # Jupyter Notebook
82
+ .ipynb_checkpoints
83
+
84
+ # IPython
85
+ profile_default/
86
+ ipython_config.py
87
+
88
+ # pyenv
89
+ # For a library or package, you might want to ignore these files since the code is
90
+ # intended to run in multiple environments; otherwise, check them in:
91
+ # .python-version
92
+
93
+ # pipenv
94
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
95
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
96
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
97
+ # install all needed dependencies.
98
+ #Pipfile.lock
99
+
100
+ # UV
101
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
102
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
103
+ # commonly ignored for libraries.
104
+ #uv.lock
105
+
106
+ # poetry
107
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
108
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
109
+ # commonly ignored for libraries.
110
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
111
+ #poetry.lock
112
+
113
+ # pdm
114
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
115
+ #pdm.lock
116
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
117
+ # in version control.
118
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
119
+ .pdm.toml
120
+ .pdm-python
121
+ .pdm-build/
122
+
123
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
124
+ __pypackages__/
125
+
126
+ # Celery stuff
127
+ celerybeat-schedule
128
+ celerybeat.pid
129
+
130
+ # SageMath parsed files
131
+ *.sage.py
132
+
133
+ # Environments
134
+ .env
135
+ .venv
136
+ env/
137
+ venv/
138
+ ENV/
139
+ env.bak/
140
+ venv.bak/
141
+
142
+ # Spyder project settings
143
+ .spyderproject
144
+ .spyproject
145
+
146
+ # Rope project settings
147
+ .ropeproject
148
+
149
+ # mkdocs documentation
150
+ /site
151
+
152
+ # mypy
153
+ .mypy_cache/
154
+ .dmypy.json
155
+ dmypy.json
156
+
157
+ # Pyre type checker
158
+ .pyre/
159
+
160
+ # pytype static type analyzer
161
+ .pytype/
162
+
163
+ # Cython debug symbols
164
+ cython_debug/
165
+
166
+ # PyCharm
167
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
168
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
169
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
170
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
171
+ #.idea/
172
+
173
+ # Ruff stuff:
174
+ .ruff_cache/
175
+
176
+ # PyPI configuration file
177
+ .pypirc
Dockerfile ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use an official Python runtime as a parent image
2
+ FROM python:3.12-slim
3
+
4
+ # Set the working directory in the container
5
+ WORKDIR /app
6
+
7
+ # Copy the requirements file into the container
8
+ COPY requirements.txt .
9
+
10
+ # Install dependencies
11
+ RUN pip install --no-cache-dir -r requirements.txt
12
+
13
+ # Copy the application code and assets
14
+ COPY src/ ./src/
15
+ COPY img/ ./img/
16
+
17
+ # Make port 7860 available to the world outside this container
18
+ EXPOSE 7860
19
+
20
+ # Run the application
21
+ CMD ["python", "src/app_gradio.py"]
README.md CHANGED
@@ -1,6 +1,67 @@
1
- ---
2
- title: radar_image_quality
3
- app_file: app_gradio.py
4
- sdk: gradio
5
- sdk_version: 5.23.3
6
- ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: radar_image_quality
3
+ app_file: src/app_gradio.py
4
+ sdk: gradio
5
+ sdk_version: 5.25.2
6
+ ---
7
+ # Radar Image Quality Gradio App
8
+
9
+ ## Overview
10
+ The Radar Image Quality Gradio App is designed to evaluate the parameters of radar image quality generated by a bistatic radar system. This application provides an interactive interface for users to input various parameters and visualize the results.
11
+
12
+ ## Project Structure
13
+ ```
14
+ radar-image-quality
15
+ ├── src
16
+ │ ├── app_backend.py # Backend logic for calculations and data processing
17
+ │ ├── app_gradio.py # Gradio interface setup
18
+ │ └── test_backend.py # Unit tests for backend functions
19
+ ├── img
20
+ │ ├── ai_day.png # Image for daytime representation
21
+ │ ├── ai_night.png # Image for nighttime representation
22
+ │ ├── bistatic_radar.jpg # Image representing bistatic radar
23
+ │ ├── iu_day.png # Image for daytime representation of the university
24
+ │ └── iu_night.png # Image for nighttime representation of the university
25
+ ├── Dockerfile # Docker instructions for building the image
26
+ ├── requirements.txt # Python dependencies
27
+ └── README.md # Project documentation
28
+ ```
29
+
30
+ ## Setup Instructions
31
+ 1. **Clone the repository:**
32
+ ```bash
33
+ git clone <repository-url>
34
+ cd radar_image_quality
35
+ ```
36
+
37
+ 2. **Install dependencies:**
38
+ It is recommended to use a virtual environment. You can create one using:
39
+ ```bash
40
+ python -m venv venv
41
+ source venv/bin/activate # On Windows use `venv\Scripts\activate`
42
+ ```
43
+ Then install the required packages:
44
+ ```bash
45
+ pip install -r requirements.txt
46
+ ```
47
+
48
+ 3. **Run the application:**
49
+ You can run the Gradio app directly using:
50
+ ```bash
51
+ python src/app_gradio.py
52
+ ```
53
+
54
+ ## Docker Instructions
55
+ To build and run the Docker container, use the following commands:
56
+ 1. **Build the Docker image:**
57
+ ```bash
58
+ docker build -t radar-image-quality .
59
+ ```
60
+
61
+ 2. **Run the Docker container:**
62
+ ```bash
63
+ docker run -p 7860:7860 radar-image-quality
64
+ ```
65
+
66
+ ## Usage
67
+ Once the application is running, open your web browser and navigate to `http://localhost:7860` to access the Gradio interface. You can input various parameters related to the radar system and visualize the results.
docker_build.sh ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ IMAGE_NAME="radar-quality-calculator"
3
+ function docker_build {
4
+ # Image name
5
+ # Check if Docker is installed
6
+ if ! command -v docker &>/dev/null; then
7
+ echo "Docker could not be found. Please install Docker to proceed."
8
+ return
9
+ fi
10
+ # Check if Docker daemon is running
11
+ if ! docker info &>/dev/null; then
12
+ echo "Docker daemon is not running. Please start Docker to proceed."
13
+ return
14
+ fi
15
+ # Check if Dockerfile exists
16
+ if [ ! -f Dockerfile ]; then
17
+ echo "Dockerfile not found in the current directory. Please ensure you are in the correct directory."
18
+ return
19
+ fi
20
+
21
+ # Remove existing image if it exists
22
+ echo "Removing existing image if it exists..."
23
+ docker rmi -f $IMAGE_NAME 2>/dev/null || true
24
+
25
+ # Build new image
26
+ echo "Building new image..."
27
+ docker build -t $IMAGE_NAME .
28
+
29
+ echo "Build complete!"
30
+ }
31
+
32
+ docker_build
docker_run.sh ADDED
@@ -0,0 +1 @@
 
 
1
+ docker run -p 7860:7860 radar-quality-calculator
img/ai_day.png ADDED
img/ai_night.png ADDED
img/bistatic_radar.jpg ADDED
img/iu_day.png ADDED
img/iu_night.png ADDED
requirements.txt CHANGED
@@ -1 +1 @@
1
- gradio
 
1
+ gradio>=5.25.2
src/app_backend.py ADDED
@@ -0,0 +1,567 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Модуль для расчета параметров РЛС по модели бистатической РЛС
3
+ Автор кода: Владислав Калинников
4
+ """
5
+
6
+ import math as mt
7
+ from typing import List
8
+
9
+ # скорость света в вакууме, м|с
10
+ C = 299792458
11
+ # постоянная Больцмана, Дж/К
12
+ BOLTZMANN = 1.38 * 10 ** (-23)
13
+ # температура предатчика/приемника, К
14
+ RADAR_TEMPERATURE = 290
15
+
16
+ # ширина антенны, м
17
+ # ANTENNA_WIDTH = 0.08
18
+ # длина антенны, м
19
+ # ANTENNA_LENGTH = 0.25
20
+ # коэффициент усиления антенны, дБ
21
+ # ANTENNA_GAIN = 14
22
+ # длина волны, м
23
+ # WAVELENGTH = 0.032
24
+ # пиковая мощность, ВТ
25
+ # PEAK_POWER = 10
26
+ # полоса пропускания, МГц
27
+ # BANDWIDTH = 1000
28
+ # шум-фактор, дБ
29
+ # NOISE_FACTOR = 3
30
+
31
+ # коэффициент заполнения
32
+ # q_fill = 0.08
33
+ # угол поляризации, град. 0 - горизонтальная поляризация, 90 - вертикальная поляризация
34
+ # POLATIZATION_TILT_ANGLE = 0
35
+
36
+
37
+ # функция определяет координаты углов области пересечения проекций на земную поверхность главных лепестков
38
+ # point_name - имя точки (A,B,C,D), по умолчанию равно A
39
+ # h - высота полета в м, uav_interval - размер базы между РЛС, м
40
+ # psi_t - угол курса оси главного лепестка ДНА на излучение (по часовой стрелке>0, против часовой <0), град
41
+ # psi_r - угол курса оси главного лепестка ДНА на прием (по часовой стрелке>0, против часовой <0), град
42
+ def footprint_corner_crd(
43
+ point_name: str,
44
+ h: float,
45
+ uav_interval: float,
46
+ psi_t: float,
47
+ psi_r: float,
48
+ wavelength: float,
49
+ antenna_length: float,
50
+ ):
51
+ # угловой размер главного главного лепестка по азимуту
52
+ theta = wavelength / antenna_length
53
+ # угол курса главного лепестка ДНА на излучение в радианах
54
+ psi_t = psi_t * mt.pi / 180
55
+ # угол курса главного лепестка ДНА на прием в радианах
56
+ psi_r = psi_r * mt.pi / 180
57
+ if psi_r - psi_t > theta:
58
+ # начальные значения поправок угла курса точки относительно РЛС1 и РЛС2
59
+ dpsi_1 = 0.1
60
+ dpsi_2 = 0.1
61
+ # начальные обновленные значения поправок угла курса точки относительно РЛС1 и РЛС2
62
+ dpsi_1upd = 0
63
+ dpsi_2upd = 0
64
+ # коэффициенты для расчета углов места и углов курса точки относительно РЛС1 и РЛС2
65
+ k1 = 1
66
+ k2 = 1
67
+ if point_name == "B":
68
+ k1 = 1
69
+ k2 = -1
70
+ elif point_name == "C":
71
+ k1 = -1
72
+ k2 = -1
73
+ elif point_name == "D":
74
+ k1 = -1
75
+ k2 = 1
76
+ # определение углов места и углов курса точки относительно РЛС1 и РЛС2 методом последовательных приближений
77
+ while abs(dpsi_1upd - dpsi_1) > 0.01 or abs(dpsi_2upd - dpsi_2) > 0.01:
78
+ dpsi_1 = dpsi_1upd
79
+ dpsi_2 = dpsi_2upd
80
+ psi_1 = psi_t + dpsi_1
81
+ psi_2 = psi_r + dpsi_2
82
+ phi_1 = mt.atan(uav_interval / h * mt.cos(psi_2) / mt.sin(psi_2 - psi_1))
83
+ phi_2 = mt.atan(uav_interval / h * mt.cos(psi_1) / mt.sin(psi_2 - psi_1))
84
+ if (
85
+ abs(mt.sin(theta / 2) / mt.sin(phi_1)) > 1
86
+ or abs(mt.sin(theta / 2) / mt.sin(phi_2)) > 1
87
+ ):
88
+ return "none"
89
+ dpsi_1upd = k1 * mt.asin(mt.sin(theta / 2) / mt.sin(phi_1))
90
+ dpsi_2upd = k2 * mt.asin(mt.sin(theta / 2) / mt.sin(phi_2))
91
+ # итоговые значения углов места и углов курса точки относительно РЛС1 и РЛС2
92
+ dpsi_1 = dpsi_1upd
93
+ dpsi_2 = dpsi_2upd
94
+ psi_1 = psi_t + dpsi_1
95
+ psi_2 = psi_r + dpsi_2
96
+ phi_1 = mt.atan(uav_interval / h * mt.cos(psi_2) / mt.sin(psi_2 - psi_1))
97
+ phi_2 = mt.atan(uav_interval / h * mt.cos(psi_1) / mt.sin(psi_2 - psi_1))
98
+ # координаты точки
99
+ x = h * mt.tan(phi_2) * mt.cos(psi_2)
100
+ y = h * mt.tan(phi_2) * mt.sin(psi_2)
101
+ return [x, y]
102
+ else:
103
+ return "none"
104
+
105
+
106
+ # функция определяет водность облаков, г|м3
107
+ # cloud_thickness - толщина облаков
108
+ def cloud_liquid_water_content(cloud_thickness: float) -> float:
109
+ if cloud_thickness != 0:
110
+ W = 0.132574 * (cloud_thickness / 1000) ** 2.30215
111
+ return W / cloud_thickness * 1000
112
+ else:
113
+ return 0
114
+
115
+
116
+ # функция определяет ординтаты точек пересечения выпуклого многоугольника (polygon) с лучом, имеющем ординату x
117
+ def polygon_cross_points(polygon: List[float], x: float) -> List[float]:
118
+ y1 = "none"
119
+ y2 = "none"
120
+ for i in range(0, len(polygon[0])):
121
+ if i < len(polygon[0]) - 1:
122
+ k = i + 1
123
+ else:
124
+ k = 0
125
+ if x >= min(polygon[0][i], polygon[0][k]) and x <= max(
126
+ polygon[0][i], polygon[0][k]
127
+ ):
128
+ if polygon[0][i] != polygon[0][k]:
129
+ if y1 == "none":
130
+ y1 = (polygon[1][k] - polygon[1][i]) / (
131
+ polygon[0][k] - polygon[0][i]
132
+ ) * (x - polygon[0][i]) + polygon[1][i]
133
+ else:
134
+ y2 = (polygon[1][k] - polygon[1][i]) / (
135
+ polygon[0][k] - polygon[0][i]
136
+ ) * (x - polygon[0][i]) + polygon[1][i]
137
+ else:
138
+ y1 = polygon[1][i]
139
+ y2 = polygon[1][k]
140
+ return [min(y1, y2), max(y1, y2)]
141
+
142
+
143
+ # функция определяет координаты углов РЛИ
144
+ # h - высота полета в м, uav_interval - размер базы между РЛС, м
145
+ # psi_t - угол курса оси главного лепестка ДНА на излучение (по часовой стрелке>0, против часовой <0), град
146
+ # psi_r - угол курса оси главного лепестка ДНА на прием (по часовой стрелке>0, против часовой <0), град
147
+ def frame_corner_crd(
148
+ h: float,
149
+ uav_interval: float,
150
+ psi_t: float,
151
+ psi_r: float,
152
+ wavelength: float,
153
+ antenna_length: float,
154
+ ):
155
+ # координаты области пересечения проекций на земную поверхность главных лепестков
156
+ crd_A = footprint_corner_crd(
157
+ point_name="A",
158
+ h=h,
159
+ uav_interval=uav_interval,
160
+ psi_t=psi_t,
161
+ psi_r=psi_r,
162
+ wavelength=wavelength,
163
+ antenna_length=antenna_length,
164
+ )
165
+ crd_B = footprint_corner_crd(
166
+ point_name="B",
167
+ h=h,
168
+ uav_interval=uav_interval,
169
+ psi_t=psi_t,
170
+ psi_r=psi_r,
171
+ wavelength=wavelength,
172
+ antenna_length=antenna_length,
173
+ )
174
+ crd_C = footprint_corner_crd(
175
+ point_name="C",
176
+ h=h,
177
+ uav_interval=uav_interval,
178
+ psi_t=psi_t,
179
+ psi_r=psi_r,
180
+ wavelength=wavelength,
181
+ antenna_length=antenna_length,
182
+ )
183
+ crd_D = footprint_corner_crd(
184
+ point_name="D",
185
+ h=h,
186
+ uav_interval=uav_interval,
187
+ psi_t=psi_t,
188
+ psi_r=psi_r,
189
+ wavelength=wavelength,
190
+ antenna_length=antenna_length,
191
+ )
192
+ if crd_A != "none" and crd_B != "none" and crd_C != "none" and crd_D != "none":
193
+ polygon = [
194
+ [crd_A[0], crd_B[0], crd_C[0], crd_D[0]],
195
+ [crd_A[1], crd_B[1], crd_C[1], crd_D[1]],
196
+ ]
197
+ # максимальное и минимальное значение абсциисы области пересечения проекций на земную поверхность главных лепестков
198
+ x_min = min(polygon[0])
199
+ x_max = max(polygon[0])
200
+ # точность оценики координат углов РЛИ
201
+ accuracy = 20
202
+ # число итераций для поиска максимальной площади РЛИ
203
+ N = 1 + int((x_max - x_min) / accuracy)
204
+ # шаг по оси абсцисс при поиске максимальной плоащади РЛИ
205
+ dx = (x_max - x_min) / N
206
+ # начальные значения коориднат углов и площади РЛИ
207
+ s_upd = 0
208
+ # dq_upd = 100
209
+ x1_upd = "none"
210
+ x2_upd = "none"
211
+ y1_upd = "none"
212
+ y2_upd = "none"
213
+ # поиск макисальной площади и углов РЛИ
214
+ for i in range(0, N - 1):
215
+ x1 = x_min + i * dx
216
+ for j in range(i + 1, N):
217
+ x2 = x_min + j * dx
218
+ y11 = polygon_cross_points(polygon, x1)[0]
219
+ y12 = polygon_cross_points(polygon, x1)[1]
220
+ y21 = polygon_cross_points(polygon, x2)[0]
221
+ y22 = polygon_cross_points(polygon, x2)[1]
222
+ if y11 >= y21 and y12 <= y22:
223
+ y1 = y11
224
+ y2 = y12
225
+ elif y11 <= y21 and y12 >= y21 and y12 <= y22:
226
+ y1 = y21
227
+ y2 = y12
228
+ elif y11 <= y22 and y11 >= y21 and y12 >= y22:
229
+ y1 = y11
230
+ y2 = y22
231
+ elif y11 <= y21 and y12 >= y22:
232
+ y1 = y21
233
+ y2 = y22
234
+ else:
235
+ y1 = "none"
236
+ y2 = "none"
237
+ if y1 != "none" and y2 != "none":
238
+ s = (x2 - x1) * (y2 - y1)
239
+ # dq = abs((y2-y1)/(x2-x1)-q)
240
+ if s > s_upd: # dq < dq_upd:
241
+ s_upd = s
242
+ # dq_upd = dq
243
+ x1_upd = x1
244
+ x2_upd = x2
245
+ y1_upd = y1
246
+ y2_upd = y2
247
+ # возврат массива координат углов РЛК (точек T1,T2,T3,T4)
248
+ return [[x1_upd, x1_upd, x2_upd, x2_upd], [y1_upd, y2_upd, y2_upd, y1_upd]]
249
+ else:
250
+ return "none"
251
+
252
+
253
+ # параметры a1, a2, a3 модели Кулемина для расчета УЭПР разных типов подстилающих поверхностей, дБ
254
+ kulemin_parameters = {
255
+ "лес летом": [-20, 10, 6],
256
+ "лес зимой": [-40, 10, 6],
257
+ "луг высокотравный": [-21, 10, 6],
258
+ "луг низкотравный": [-28, 10, 6],
259
+ "пашня": [-37, 18, 15],
260
+ "снег": [-34, 25, 15],
261
+ }
262
+
263
+
264
+ # функция определеяет УЭПР поверхности в дБ согласно модели Кулемина
265
+ # surface_type - тип подстилающей поверхности (пашня, снег и т.д.), phi - угол падения, град
266
+ # если задан неизвестный тип подстилающей поверхности, функция вернет значение -20 дБ
267
+ def kulemin_specific_rcs(surface_type, phi, wavelength):
268
+ # частота зондирования в ГГц
269
+ f = C / wavelength * 10 ** (-9)
270
+ # угол скольжения в град
271
+ slip = 90 - phi
272
+ if kulemin_parameters.get(surface_type) != None:
273
+ a1, a2, a3 = kulemin_parameters[surface_type]
274
+ return a1 + a2 * mt.log(slip / 20, 10) + a3 * mt.log(f / 10, 10)
275
+ else:
276
+ return -20
277
+
278
+
279
+ # функция определяет коэффициент погонного ослабления в облаке, дБ/км/(г/м3)
280
+ def itu_cloud_attenuation(wavelength):
281
+ # частота зондирования в ГГц
282
+ f = C / wavelength * 10 ** (-9)
283
+ theta = 300 / 273.15
284
+ eps0 = 77.66 + 103.3 * (theta - 1)
285
+ eps1 = 0.0671 * eps0
286
+ eps2 = 3.52
287
+ fp = 20.20 - 146 * (theta - 1) + 316 * (theta - 1) ** 2
288
+ fs = 39.8 * fp
289
+ eps_prime = f * (eps0 - eps1) / fp / (1 + (f / fp) ** 2) + f * (
290
+ eps1 - eps2
291
+ ) / fs / (1 + (f / fs) ** 2)
292
+ eps_double_prime = (
293
+ (eps0 - eps1) / (1 + (f / fp) ** 2) + (eps1 - eps2) / (1 + (f / fs) ** 2) + eps2
294
+ )
295
+ nabla = (2 + eps_prime) / eps_double_prime
296
+ return 0.819 * f / eps_double_prime / (1 + nabla**2)
297
+
298
+
299
+ # параметры kh, ah, kv, av модели погонного ослабления в дожде МСЭ-R P.838-3 для частот 7 - 12 ГГц
300
+ itu_rain_parameters = {
301
+ 7: [0.001915, 1.4810, 0.001425, 1.4745],
302
+ 8: [0.004115, 1.3905, 0.003450, 1.3797],
303
+ 9: [0.007535, 1.3155, 0.006691, 1.2895],
304
+ 10: [0.012170, 1.2571, 0.011290, 1.2156],
305
+ 11: [0.017720, 1.2140, 0.017310, 1.1617],
306
+ 12: [0.023860, 1.1825, 0.024550, 1.1216],
307
+ }
308
+
309
+ # классификация погодных условий по интенсивности осадков, мм/ч
310
+ rain_rate_classes = {
311
+ "ясно": 0,
312
+ "слабый дождь": 5,
313
+ "умеренный дождь": 12,
314
+ "сильный дождь": 30,
315
+ "ливень": 40,
316
+ }
317
+
318
+
319
+ # функция определяет коэффициент погонного ослабления в дожде в дБ/км для диапазона X согласно модели МСЭ-R P.838-3
320
+ # rain_rate - интенсивность дождя в мм/ч, phi- угол падения, град
321
+ # если длина волны зондирования лежит не в диапазоне X, функция вернет 0
322
+ def itu_rain_attenuation(
323
+ rain_rate: float, phi: float, wavelength: float, polarization_tilt_angle: float
324
+ ) -> float:
325
+ # частота зондирования в ГГц
326
+ f = C / wavelength * 10 ** (-9)
327
+ # угол скольжения в радианах
328
+ slip = (90 - phi) * mt.pi / 180
329
+ # угол поляризации в радианах
330
+ tilt = polarization_tilt_angle * mt.pi / 180
331
+ # целочисленные значения частот вокруг частоты зондирования
332
+ f1 = int(f)
333
+ f2 = int(f) + 1
334
+ if (itu_rain_parameters.get(f1) != None) and (itu_rain_parameters.get(f2) != None):
335
+ # параметры модели для частоты f1
336
+ kh1 = itu_rain_parameters[f1][0]
337
+ ah1 = itu_rain_parameters[f1][1]
338
+ kv1 = itu_rain_parameters[f1][2]
339
+ av1 = itu_rain_parameters[f1][3]
340
+ # параметры модели для частоты f2
341
+ kh2 = itu_rain_parameters[f2][0]
342
+ ah2 = itu_rain_parameters[f2][1]
343
+ kv2 = itu_rain_parameters[f2][2]
344
+ av2 = itu_rain_parameters[f2][3]
345
+ # интерполяция параметров модели на частоту зондирования f
346
+ kh = kh1 + (kh2 - kh1) / (f2 - f1) * (f - f1)
347
+ ah = ah1 + (ah2 - ah1) / (f2 - f1) * (f - f1)
348
+ kv = kv1 + (kv2 - kv1) / (f2 - f1) * (f - f1)
349
+ av = av1 + (av2 - av1) / (f2 - f1) * (f - f1)
350
+ # параметры модели для заданной поляризации
351
+ k = (kh + kv + (kh - kv) * (mt.cos(slip)) ** 2 * mt.cos(2 * tilt)) / 2
352
+ a = (
353
+ (
354
+ kh * ah
355
+ + kv * av
356
+ + (kh * ah - kv * av) * (mt.cos(slip)) ** 2 * mt.cos(2 * tilt)
357
+ )
358
+ / 2
359
+ / k
360
+ )
361
+ return k * (rain_rate) ** a
362
+ else:
363
+ return 0
364
+
365
+
366
+ # входные параметры модели:
367
+ # v - скорость полета, м/с
368
+ # h - высота полета, м
369
+ # uav_interval - размер базы между РЛС, м
370
+ # psi_t - угол курса оси главного лепестка ДНА на излучение (по часовой стрелке>0, против часовой <0), град
371
+ # psi_r - угол курса оси главного лепестка ДНА на прием (по часовой стрелке>0, против часовой <0), град
372
+ # srcs - УЭПР фона, дБ или тип поверхности по модели Кулемина
373
+ # cloud_base - высота нижней границы облаков, м
374
+ # cloud_thickness - толщина облаков, м
375
+ # rain_rate - интенсивность дождя, мм/ч
376
+
377
+ # выходные параметры модели:
378
+ # dx - предельное разрешение по горизонтальной дальности в центре РЛК, м
379
+ # dy - предельное разрешение по азимуту в центре РЛК, м
380
+ # snr - отношение сигнал/шум фона в центре РЛК, дБ
381
+ # tau - длина импульса, с
382
+ # tau_echo - длина эхо-сигнала, с
383
+ # t_repeat - период повторения импульсов, с
384
+ # t_synthesis_max - максимальное время синтеза апертуры, с
385
+
386
+
387
+ def bistatic_radar_model(
388
+ v: float,
389
+ h: float,
390
+ uav_interval: float,
391
+ psi_t: float,
392
+ psi_r: float,
393
+ srcs: str | float,
394
+ cloud_base: float,
395
+ cloud_thickness: float,
396
+ rain_rate: float,
397
+ q_fill: float,
398
+ bandwidth: float,
399
+ wavelength: float,
400
+ antenna_gain: float,
401
+ antenna_length: float,
402
+ noise_factor: float,
403
+ peak_power: float,
404
+ polarization_tilt_angle: float,
405
+ ):
406
+ # координаты РЛС1
407
+ x1 = 0
408
+ y1 = uav_interval
409
+ # координаты РЛС2
410
+ x2 = 0
411
+ y2 = 0
412
+ # коодинаты точки T1
413
+ frame_crd = frame_corner_crd(
414
+ h=h,
415
+ uav_interval=uav_interval,
416
+ psi_t=psi_t,
417
+ psi_r=psi_r,
418
+ wavelength=wavelength,
419
+ antenna_length=antenna_length,
420
+ )
421
+ if frame_crd != "none":
422
+ x_t1 = frame_crd[0][0]
423
+ y_t1 = frame_crd[1][0]
424
+ # коодинаты точки T2
425
+ x_t2 = frame_crd[0][1]
426
+ y_t2 = frame_crd[1][1]
427
+ # коодинаты точки T3
428
+ x_t3 = frame_crd[0][2]
429
+ y_t3 = frame_crd[1][2]
430
+ # коодинаты точки T4
431
+ x_t4 = frame_crd[0][3]
432
+ y_t4 = frame_crd[1][3]
433
+ # коодинаты центра РЛК
434
+ xo = (x_t2 + x_t3) / 2
435
+ yo = (y_t1 + y_t2) / 2
436
+ # наклонные дальности от РЛС1 до углов и центра РЛК
437
+ r1_t1 = mt.sqrt((x_t1 - x1) ** 2 + (y_t1 - y1) ** 2 + h**2)
438
+ r1_t2 = mt.sqrt((x_t2 - x1) ** 2 + (y_t1 - y1) ** 2 + h**2)
439
+ r1_t3 = mt.sqrt((x_t3 - x1) ** 2 + (y_t1 - y1) ** 2 + h**2)
440
+ r1_t4 = mt.sqrt((x_t4 - x1) ** 2 + (y_t1 - y1) ** 2 + h**2)
441
+ r1_o = mt.sqrt((xo - x1) ** 2 + (yo - y1) ** 2 + h**2)
442
+ # наклонные дальности от РЛС2 до углов и центра РЛК
443
+ r2_t1 = mt.sqrt((x_t1 - x2) ** 2 + (y_t1 - y2) ** 2 + h**2)
444
+ r2_t2 = mt.sqrt((x_t2 - x2) ** 2 + (y_t1 - y2) ** 2 + h**2)
445
+ r2_t3 = mt.sqrt((x_t3 - x2) ** 2 + (y_t1 - y2) ** 2 + h**2)
446
+ r2_t4 = mt.sqrt((x_t4 - x2) ** 2 + (y_t1 - y2) ** 2 + h**2)
447
+ r2_o = mt.sqrt((xo - x2) ** 2 + (yo - y2) ** 2 + h**2)
448
+ # угол падения импульса от РЛС1 в центр РЛК
449
+ phi1_o = mt.atan(h / r1_o) * 180 / mt.pi
450
+ # угол отражения импульса от центра РЛК к РЛС2
451
+ phi2_o = mt.atan(h / r2_o) * 180 / mt.pi
452
+ # модуль градиента от суммы наклонных дальностей от РЛС1 и РЛС2 до центра РЛК
453
+ grad_r = mt.sqrt((xo / r1_o + xo / r2_o) ** 2 + (yo / r1_o + yo / r2_o) ** 2)
454
+ # модуль градиента от суммы доплеровских частот на трассах от РЛС1 до центра РЛК и от центра РЛК до РЛС2
455
+ grad_f = (
456
+ v
457
+ / wavelength
458
+ * mt.sqrt(
459
+ (1 / r1_o + 1 / r2_o - xo**2 / r1_o**3 - xo**2 / r2_o**3) ** 2
460
+ + (xo * yo / r1_o**3 + xo * yo / r2_o**3) ** 2
461
+ )
462
+ )
463
+ # длина импульса
464
+ tau = min(r1_t1 + r2_t1, r1_t2 + r2_t2) / C
465
+ # длина эхо-сигнала
466
+ tau_echo = (
467
+ tau
468
+ + max(r1_t3 + r2_t3, r1_t4 + r2_t4) / C
469
+ - min(r1_t1 + r2_t1, r1_t2 + r2_t2) / C
470
+ )
471
+ # период повторения импульсов
472
+ t_repeat = tau / q_fill
473
+ # максимальный коэффициент сжатия
474
+ k_compression_max = bandwidth * 1000000 * tau
475
+ # максимальное время синтеза апертуры
476
+ t_synthesis_max = 2 * (x_t3 - x_t2) / v
477
+ # максимальное число когерентных импульсов
478
+ n_coh_max = 1 + int(t_synthesis_max / t_repeat)
479
+ # разрешение по горизонтальной дальности
480
+ dx = C * tau / k_compression_max / grad_r
481
+ # разрешение по азимуту
482
+ dy = 1 / t_synthesis_max / grad_f
483
+ # УЭПР фона
484
+ if type(srcs) == str:
485
+ srcs = kulemin_specific_rcs(surface_type=srcs, phi=(phi1_o + phi2_o) / 2, wavelength=wavelength)
486
+ # ЭПР точечного отражателя фона
487
+ sigma = 10 ** (srcs / 10) * dx * dy
488
+ # эффективная площадь антенны
489
+ antenna_area = 10 ** (antenna_gain / 10) * wavelength**2 / 4 / mt.pi
490
+ # мощность эхо-сигнала от центра РЛК
491
+ p_echo = (
492
+ peak_power
493
+ * 10 ** (antenna_gain / 10)
494
+ * antenna_area
495
+ / (4 * mt.pi * r1_o * r2_o) ** 2
496
+ * sigma
497
+ * k_compression_max
498
+ * n_coh_max
499
+ )
500
+ # мощность шума
501
+ p_noise = (
502
+ BOLTZMANN
503
+ * 10 ** (noise_factor / 10)
504
+ * RADAR_TEMPERATURE
505
+ * bandwidth
506
+ * 1000000
507
+ )
508
+ # отношение сигнал/шум без учета погоды
509
+ snr = 10 * mt.log(p_echo / p_noise, 10)
510
+ # протяженность наклонных дальностей в облаках и дожде, км
511
+ if cloud_thickness != 0:
512
+ cloud_path1 = (
513
+ r1_o
514
+ / 1000
515
+ * (min(h, cloud_base + cloud_thickness) - min(h, cloud_base))
516
+ / h
517
+ )
518
+ cloud_path2 = (
519
+ r2_o
520
+ / 1000
521
+ * (min(h, cloud_base + cloud_thickness) - min(h, cloud_base))
522
+ / h
523
+ )
524
+ rain_path1 = r1_o / 1000 * min(h, cloud_base) / h
525
+ rain_path2 = r2_o / 1000 * min(h, cloud_base) / h
526
+ else:
527
+ cloud_path1 = 0
528
+ cloud_path2 = 0
529
+ rain_path1 = 0
530
+ rain_path2 = 0
531
+ # водность облаков
532
+ w = cloud_liquid_water_content(cloud_thickness=cloud_thickness)
533
+ # ослабление в облаках по модели МСЭ-R P.840-7
534
+ cloud_att1 = itu_cloud_attenuation(wavelength=wavelength) * w * cloud_path1
535
+ cloud_att2 = itu_cloud_attenuation(wavelength=wavelength) * w * cloud_path2
536
+ # ослабление в дожде по модели МСЭ-R P.838-3
537
+ rain_att1 = (
538
+ itu_rain_attenuation(
539
+ rain_rate=rain_rate,
540
+ phi=phi1_o,
541
+ wavelength=wavelength,
542
+ polarization_tilt_angle=polarization_tilt_angle,
543
+ )
544
+ * rain_path1
545
+ )
546
+ rain_att2 = (
547
+ itu_rain_attenuation(
548
+ rain_rate=rain_rate,
549
+ phi=phi2_o,
550
+ wavelength=wavelength,
551
+ polarization_tilt_angle=polarization_tilt_angle,
552
+ )
553
+ * rain_path2
554
+ )
555
+ # отношение сигнал/шум с учетом погод��ых условий
556
+ snr = snr - cloud_att1 - cloud_att2 - rain_att1 - rain_att2
557
+ return {
558
+ "dx": dx,
559
+ "dy": dy,
560
+ "snr": snr,
561
+ "tau": tau,
562
+ "tau_echo": tau_echo,
563
+ "t_repeat": t_repeat,
564
+ "t_synthesis_max": t_synthesis_max,
565
+ }
566
+ else:
567
+ return "none"
src/app_gradio.py ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import app_backend
3
+
4
+ BG_CHOICES = ("Задать значение", "Выбрать из модели Кулемина")
5
+ KULEMIN = {
6
+ "лес летом": [-20, 10, 6],
7
+ "лес зимой": [-40, 10, 6],
8
+ "луг высокотравный": [-21, 10, 6],
9
+ "луг низкотравный": [-28, 10, 6],
10
+ "пашня": [-37, 18, 15],
11
+ "снег": [-34, 25, 15],
12
+ }
13
+ LOGOS_HEADER = """
14
+ <style>
15
+ .logo-container {
16
+ display: flex;
17
+ gap: 20px; /* расстояние между логотипами */
18
+ align-items: center;
19
+ }
20
+ /* По умолчанию (светлая тема) показываем дневные варианты */
21
+ #iu-day, #ai-day {
22
+ display: block;
23
+ }
24
+ #iu-night, #ai-night {
25
+ display: none;
26
+ }
27
+ /* Для тёмной темы — наоборот, показываем ночные варианты */
28
+ @media (prefers-color-scheme: dark) {
29
+ #iu-day, #ai-day {
30
+ display: none;
31
+ }
32
+ #iu-night, #ai-night {
33
+ display: block;
34
+ }
35
+ }
36
+ </style>
37
+
38
+ <div class="logo-container">
39
+ <img id="iu-day" src='gradio_api/file=./img/iu_day.png' alt='УНИВЕРСИТЕТ ИННОПОЛИС' width=200>
40
+ <img id="iu-night" src='gradio_api/file=./img/iu_night.png' alt='УНИВЕРСИТЕТ ИННОПОЛИС' width=200>
41
+
42
+ <img id="ai-day" src='gradio_api/file=./img/ai_day.png' alt='ЦЕНТР ИСКУССТВЕННОГО ИНТЕЛЛЕКТА' width=200>
43
+ <img id="ai-night" src='gradio_api/file=./img/ai_night.png' alt='ЦЕНТР ИСКУССТВЕННОГО ИНТЕЛЛЕКТА' width=200>
44
+ </div>
45
+ """
46
+
47
+
48
+ def main(i):
49
+ try:
50
+ out = app_backend.bistatic_radar_model(
51
+ v=i[speed],
52
+ h=i[height],
53
+ uav_interval=i[uav_interval],
54
+ psi_t=i[psit],
55
+ psi_r=i[psir],
56
+ srcs=i[bg_type] if i[bg_mode] == BG_CHOICES[1] else i[bg_value],
57
+ cloud_base=i[cloud_base],
58
+ cloud_thickness=i[cloud_thickness],
59
+ rain_rate=i[rain_intensivity],
60
+ q_fill=i[q_fill],
61
+ bandwidth=i[bandwidth],
62
+ wavelength=i[wavelength],
63
+ antenna_gain=i[antenna_gain],
64
+ antenna_length=i[antenna_length],
65
+ noise_factor=i[noise_factor],
66
+ peak_power=i[peak_power],
67
+ polarization_tilt_angle=0 if i[polar_type] == "H" else 90,
68
+ )
69
+ return f"{out["dx"]:.3f}", f"{out["dy"]:.3f}", f"{out["snr"]:.1f}"
70
+ except:
71
+ return ["ОШИБКА: недопустимая комбинация входных параметров"] * 3
72
+
73
+
74
+ def update_visibility(radio):
75
+ if radio == BG_CHOICES[0]:
76
+ return gr.update(visible=True), gr.update(visible=False)
77
+ return gr.update(visible=False), gr.update(visible=True)
78
+
79
+
80
+ input_set = set()
81
+ # Create the Gradio pyinterface
82
+ with gr.Blocks(
83
+ title="РЛС-калькулятор",
84
+ # css="footer{display:none !important}",
85
+ # theme=gr.themes.Ocean(),
86
+ ) as demo:
87
+ gr.HTML(LOGOS_HEADER)
88
+ gr.Markdown(
89
+ "# Калькулятор оценки параметров качества радиолокационного изображения двухпозиционной РЛС"
90
+ )
91
+ with gr.Row():
92
+ with gr.Column():
93
+ gr.Markdown(
94
+ """
95
+ Калькулятор позволяет рассчитать параметры качества радиолокационного изображения (РЛИ), формируемого в передней зоне обзора двухпозиционной полуактивной радиолокационной станции (РЛС) авиационного базирования.
96
+
97
+ В рассматриваемой схеме главный лепесток диаграммы направленности антенны (ДНА) на излучение активной компоненты РЛС подсвечивает область в передней зоне обзора, тогда как главный лепесток ДНА на прием направлен так, чтобы существовала возможность фиксации отраженного эхо-сигнала. Формирование РЛИ происходит на пересечении областей земной поверхности в пределах главных лепестков ДНА на излучение и на прием.
98
+
99
+ Каждая одиночная РЛС использует одинаковую передающую и приемную антенны, вследствие чего равны угловые размеры главных лепестков на излучение и на прием.
100
+ """
101
+ )
102
+ with gr.Column():
103
+ gr.HTML(
104
+ "<img src='gradio_api/file=./img/bistatic_radar.jpg' alt='Схема относительного расположения РЛС на паре БВС' width=640>"
105
+ )
106
+ # v - скорость полета, h - высота полета, dl - размер базы между РЛС, psir - угол курса оси главного лепестка ДНА на прием
107
+ with gr.Row():
108
+ with gr.Column():
109
+ gr.Markdown("## Параметры бортовой РЛС")
110
+ psir = gr.Slider(
111
+ minimum=10,
112
+ maximum=60,
113
+ value=30,
114
+ step=0.1,
115
+ label="Угол курса оси главного лепестка ДНА на прием, град",
116
+ )
117
+ input_set.add(psir)
118
+ psit = gr.Slider(
119
+ minimum=-60,
120
+ maximum=-10,
121
+ value=-30,
122
+ step=0.1,
123
+ label="Угол курса оси главного лепестка ДНА на излучение, град",
124
+ )
125
+ input_set.add(psit)
126
+ antenna_length = gr.Slider(
127
+ minimum=0.05,
128
+ maximum=0.3,
129
+ value=0.1,
130
+ step=0.01,
131
+ label="Длина антенны, м",
132
+ )
133
+ input_set.add(antenna_length)
134
+ antenna_gain = gr.Slider(
135
+ minimum=5,
136
+ maximum=20,
137
+ value=10,
138
+ step=0.1,
139
+ label="Коэффициент усиления антенны, дБ",
140
+ )
141
+ input_set.add(antenna_gain)
142
+ wavelength = gr.Slider(
143
+ minimum=0.02,
144
+ maximum=0.04,
145
+ value=0.03,
146
+ step=0.001,
147
+ label="Длина волны, м",
148
+ )
149
+ input_set.add(wavelength)
150
+ peak_power = gr.Slider(
151
+ minimum=1,
152
+ maximum=10,
153
+ value=5,
154
+ step=0.1,
155
+ label="Пиковая мощность, ВТ",
156
+ )
157
+ input_set.add(peak_power)
158
+ bandwidth = gr.Slider(
159
+ minimum=500,
160
+ maximum=2000,
161
+ value=1000,
162
+ step=1,
163
+ label="Полоса пропускания, МГц",
164
+ )
165
+ input_set.add(bandwidth)
166
+ noise_factor = gr.Slider(
167
+ minimum=1,
168
+ maximum=3,
169
+ value=2,
170
+ step=0.01,
171
+ label="Шум-фактор, дБ",
172
+ )
173
+ input_set.add(noise_factor)
174
+
175
+ gr.Markdown("## Параметры режима работы РЛС")
176
+ with gr.Row():
177
+ q_fill = gr.Slider(
178
+ minimum=0.05,
179
+ maximum=0.25,
180
+ value=0.1,
181
+ step=0.001,
182
+ label="Коэффициент заполнения",
183
+ )
184
+ input_set.add(q_fill)
185
+ polar_type = gr.Radio(
186
+ choices=["H", "V"], label="Тип поляризации", value="H"
187
+ )
188
+ input_set.add(polar_type)
189
+ with gr.Column():
190
+ gr.Markdown("## Траекторные параметры")
191
+ speed = gr.Slider(
192
+ minimum=5,
193
+ maximum=30,
194
+ value=20,
195
+ step=0.1,
196
+ label="Скорость полета, м/с",
197
+ )
198
+ input_set.add(speed)
199
+ height = gr.Slider(
200
+ minimum=200,
201
+ maximum=2000,
202
+ value=1000,
203
+ step=1,
204
+ label="Высота полета, м",
205
+ )
206
+ input_set.add(height)
207
+ uav_interval = gr.Slider(
208
+ minimum=200,
209
+ maximum=2000,
210
+ value=1000,
211
+ step=1,
212
+ label="Длина базы между РЛС, м",
213
+ )
214
+ input_set.add(uav_interval)
215
+ gr.Markdown("## Параметры условий местности")
216
+ cloud_base = gr.Slider(
217
+ minimum=0,
218
+ maximum=1500,
219
+ value=750,
220
+ step=1,
221
+ label="Высота нижней границы облаков, м",
222
+ )
223
+ input_set.add(cloud_base)
224
+ cloud_thickness = gr.Slider(
225
+ minimum=0, maximum=6000, value=3000, step=1, label="Толщина облаков, м"
226
+ )
227
+ input_set.add(cloud_thickness)
228
+ rain_intensivity = gr.Slider(
229
+ minimum=0,
230
+ maximum=80,
231
+ value=40,
232
+ step=1,
233
+ label="Интенсивность дождя, мм/ч",
234
+ )
235
+ input_set.add(rain_intensivity)
236
+ bg_mode = gr.Radio(
237
+ choices=BG_CHOICES, label="УЭПР фона поверхности", value=BG_CHOICES[0]
238
+ )
239
+ input_set.add(bg_mode)
240
+ bg_value = gr.Slider(
241
+ minimum=-30, maximum=10, value=0, step=0.1, label="", visible=True
242
+ )
243
+ input_set.add(bg_value)
244
+ bg_type = gr.Dropdown(
245
+ choices=KULEMIN.keys(), visible=False, label="", filterable=False
246
+ )
247
+ input_set.add(bg_type)
248
+
249
+ with gr.Column():
250
+ gr.Markdown("## Предельные параметры качества РЛИ")
251
+ # Output displays
252
+ output_hr = gr.Text(label="Разрешение по горизонтальной дальности, м")
253
+ output_ar = gr.Text(label="Разрешение по азимуту, м")
254
+ output_snr = gr.Text(label="Отношение сигнал/шум, дБ")
255
+ with gr.Row():
256
+ gr.Markdown(
257
+ "*Калькулятор оценки параметров качества радиолокационного изображения двухпозиционной РЛС подготовлен за счет средств гранта, предоставленного по договору от 30.10.2024 № 70-2024-001319, заключенному АНО ВО «Университет Иннополис» с Фондом поддержки проектов Национальной технологической инициативы*"
258
+ )
259
+ # Set up the event listeners for real-time updates
260
+ output_list = [output_hr, output_ar, output_snr]
261
+ bg_mode.change(fn=update_visibility, inputs=bg_mode, outputs=[bg_value, bg_type])
262
+ for inp in input_set:
263
+ inp.change(fn=main, inputs=input_set, outputs=output_list)
264
+ if __name__ == "__main__":
265
+ demo.launch(share=False, allowed_paths=["."], server_name="0.0.0.0")
test_backend.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Backend functions test suite.
2
+ This module contains unit tests for the backend functions of the application.
3
+ This module is designed to ensure the correctness and reliability of the backend logic
4
+ """
5
+
6
+ import unittest
7
+
8
+ from src.app_backend import (
9
+ footprint_corner_crd,
10
+ cloud_liquid_water_content,
11
+ polygon_cross_points,
12
+ frame_corner_crd,
13
+ kulemin_specific_rcs,
14
+ itu_cloud_attenuation,
15
+ itu_rain_attenuation,
16
+ bistatic_radar_model
17
+ )
18
+
19
+ class TestBackendFunctions(unittest.TestCase):
20
+
21
+ def test_footprint_corner_crd(self):
22
+ result = footprint_corner_crd('A', 1000, 500, 30, 60)
23
+ self.assertNotEqual(result, 'none')
24
+ self.assertIsInstance(result, list)
25
+ self.assertEqual(len(result), 2)
26
+
27
+ def test_cloud_liquid_water_content(self):
28
+ self.assertAlmostEqual(cloud_liquid_water_content(1000), 0.132574, places=5)
29
+ self.assertEqual(cloud_liquid_water_content(0), 0)
30
+
31
+ def test_polygon_cross_points(self):
32
+ polygon = [[0, 1, 1, 0], [0, 0, 1, 1]]
33
+ result = polygon_cross_points(polygon, 0.5)
34
+ self.assertEqual(result, [0.0, 1.0])
35
+
36
+ def test_frame_corner_crd(self):
37
+ result = frame_corner_crd(1000, 500, 30, 60)
38
+ self.assertNotEqual(result, 'none')
39
+ self.assertIsInstance(result, list)
40
+ self.assertEqual(len(result), 2)
41
+
42
+ def test_kulemin_specific_rcs(self):
43
+ result = kulemin_specific_rcs('лес летом', 45)
44
+ self.assertIsInstance(result, float)
45
+ self.assertNotEqual(result, -20)
46
+
47
+ unknown_surface = kulemin_specific_rcs('unknown', 45)
48
+ self.assertEqual(unknown_surface, -20)
49
+
50
+ def test_itu_cloud_attenuation(self):
51
+ result = itu_cloud_attenuation()
52
+ self.assertIsInstance(result, float)
53
+ self.assertGreater(result, 0)
54
+
55
+ def test_itu_rain_attenuation(self):
56
+ result = itu_rain_attenuation(10, 45)
57
+ self.assertIsInstance(result, float)
58
+ self.assertGreaterEqual(result, 0)
59
+
60
+ def test_bistatic_radar_model(self):
61
+ result = bistatic_radar_model(
62
+ v=200,
63
+ h=1000,
64
+ uav_interval=500,
65
+ psi_t=30,
66
+ psi_r=60,
67
+ srcs='лес летом',
68
+ cloud_base=500,
69
+ cloud_thickness=1000,
70
+ rain_rate=10
71
+ )
72
+ self.assertNotEqual(result, 'none')
73
+ self.assertIsInstance(result, dict)
74
+ self.assertIn('dx', result)
75
+ self.assertIn('dy', result)
76
+ self.assertIn('snr', result)
77
+ self.assertIn('tau', result)
78
+ self.assertIn('tau_echo', result)
79
+ self.assertIn('t_repeat', result)
80
+ self.assertIn('t_synthesis_max', result)
81
+
82
+ if __name__ == '__main__':
83
+ unittest.main()