FERS 1.0.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
antenna_factory.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-only
2//
3// Copyright (c) 2006-2008 Marc Brooker and Michael Inggs
4// Copyright (c) 2008-present FERS Contributors (see AUTHORS.md).
5//
6// See the GNU GPLv2 LICENSE file in the FERS project root for more information.
7
8/**
9 * @file antenna_factory.cpp
10 * @brief Implementation of the Antenna class and its derived classes.
11 */
12
14
15#include <algorithm>
16#include <cmath>
17#include <complex>
18#include <optional>
19#include <stdexcept>
20
21#include "core/config.h"
22#include "core/logging.h"
23#include "core/portable_utils.h"
24#include "math/geometry_ops.h"
26
27using logging::Level;
28using math::SVec3;
29using math::Vec3;
30
31namespace
32{
33 /**
34 * @brief Compute the sinc function.
35 *
36 * @param theta The angle for which to compute the sinc function.
37 * @return The value of the sinc function at the given angle theta.
38 */
39 RealType sinc(const RealType theta) noexcept
40 {
41 if (std::abs(theta) < EPSILON)
42 {
43 return 1.0;
44 }
45 return std::sin(theta) / theta;
46 }
47
48 /**
49 * @brief Compute the Bessel function of the first kind.
50 *
51 * @param x The value for which to compute the Bessel function.
52 * @return The value of the Bessel function of the first kind at the given value x.
53 */
54 RealType j1C(const RealType x) noexcept { return x == 0 ? 1.0 : core::besselJ1(x) / x; }
55
56 /**
57 * @brief Load antenna gain axis data from an XML element.
58 *
59 * @param set The interpolation set to store the gain axis data.
60 * @param axisXml The XML element containing the gain axis data.
61 */
62 void loadAntennaGainAxis(const interp::InterpSet* set, const XmlElement& axisXml) noexcept
63 {
64 XmlElement tmp = axisXml.childElement("gainsample");
65 while (tmp.isValid())
66 {
67 XmlElement angle_element = tmp.childElement("angle", 0);
68
69 if (XmlElement gain_element = tmp.childElement("gain", 0);
70 angle_element.isValid() && gain_element.isValid())
71 {
72 const RealType angle = std::stof(angle_element.getText());
73 const RealType gain = std::stof(gain_element.getText());
74 set->insertSample(angle, gain);
75 }
76
77 tmp = XmlElement(tmp.getNode()->next);
78 }
79 }
80}
81
82namespace antenna
83{
84 void Antenna::setEfficiencyFactor(const RealType loss) noexcept
85 {
86 if (loss > 1)
87 {
88 LOG(Level::INFO, "Using greater than unity antenna efficiency.");
89 }
90 _loss_factor = loss;
91 }
92
93 RealType Antenna::getAngle(const SVec3& angle, const SVec3& refangle) noexcept
94 {
95 SVec3 normangle(angle);
96 normangle.length = 1;
97 return std::acos(dotProduct(Vec3(normangle), Vec3(refangle)));
98 }
99
100 RealType Gaussian::getGain(const SVec3& angle, const SVec3& refangle, RealType /*wavelength*/) const noexcept
101 {
102 const SVec3 a = angle - refangle;
103 return std::exp(-a.azimuth * a.azimuth * _azscale) * std::exp(-a.elevation * a.elevation * _elscale);
104 }
105
106 RealType Sinc::getGain(const SVec3& angle, const SVec3& refangle, RealType /*wavelength*/) const noexcept
107 {
108 const RealType theta = getAngle(angle, refangle);
109 const RealType sinc_val = sinc(_beta * theta);
110 const RealType gain_pattern = std::pow(std::abs(sinc_val), _gamma);
111 return _alpha * gain_pattern * getEfficiencyFactor();
112 }
113
114 RealType SquareHorn::getGain(const SVec3& angle, const SVec3& refangle, const RealType wavelength) const noexcept
115 {
116 const RealType ge = 4 * PI * std::pow(_dimension, 2) / std::pow(wavelength, 2);
117 const RealType x = PI * _dimension * std::sin(getAngle(angle, refangle)) / wavelength;
118 return ge * std::pow(sinc(x), 2) * getEfficiencyFactor();
119 }
120
121 RealType Parabolic::getGain(const SVec3& angle, const SVec3& refangle, const RealType wavelength) const noexcept
122 {
123 const RealType ge = std::pow(PI * _diameter / wavelength, 2);
124 const RealType x = PI * _diameter * std::sin(getAngle(angle, refangle)) / wavelength;
125 return ge * std::pow(2 * j1C(x), 2) * getEfficiencyFactor();
126 }
127
128 RealType XmlAntenna::getGain(const SVec3& angle, const SVec3& refangle, RealType /*wavelength*/) const
129 {
130 const SVec3 delta_angle = angle - refangle;
131
132 const std::optional<RealType> azi_value = _azi_samples->getValueAt(std::abs(delta_angle.azimuth));
133
134 if (const std::optional<RealType> elev_value = _elev_samples->getValueAt(std::abs(delta_angle.elevation));
135 azi_value && elev_value)
136 {
137 return *azi_value * *elev_value * _max_gain * getEfficiencyFactor();
138 }
139
140 LOG(Level::FATAL, "Could not get antenna gain value");
141 throw std::runtime_error("Could not get antenna gain value");
142 }
143
144 void XmlAntenna::loadAntennaDescription(const std::string_view filename)
145 {
146 _filename = filename;
147 XmlDocument doc;
148 if (!doc.loadFile(std::string(filename)))
149 {
150 LOG(Level::FATAL, "Could not load antenna description {}", filename.data());
151 throw std::runtime_error("Could not load antenna description");
152 }
153
154 const XmlElement root(doc.getRootElement());
155 loadAntennaGainAxis(_elev_samples.get(), root.childElement("elevation", 0));
156 loadAntennaGainAxis(_azi_samples.get(), root.childElement("azimuth", 0));
157
158 _max_gain = std::max(_azi_samples->getMax(), _elev_samples->getMax());
159 _elev_samples->divide(_max_gain);
160 _azi_samples->divide(_max_gain);
161 }
162
163 RealType H5Antenna::getGain(const SVec3& angle, const SVec3& refangle, RealType /*wavelength*/) const
164 {
165 constexpr RealType two_pi = 2.0 * PI;
166
167 const SVec3& pattern_angle = angle - refangle;
168
169 const double ex1 = (pattern_angle.azimuth + PI) / two_pi;
170 const double ey1 = (pattern_angle.elevation + PI) / two_pi;
171
172 const auto calc_grid_point = [](const double value, const unsigned size)
173 {
174 const double x1 = std::floor(value * (size - 1)) / (size - 1);
175 const double x2 = std::min(x1 + 1.0 / size, 1.0);
176 return std::pair{x1, x2};
177 };
178
179 unsigned size_azi = _pattern.size();
180 unsigned size_elev = _pattern[0].size();
181
182 LOG(logging::Level::TRACE, "Size of pattern: {} x {}", size_azi, size_elev);
183
184 const auto [x1, x2] = calc_grid_point(ex1, size_azi);
185 const auto [y1, y2] = calc_grid_point(ey1, size_elev);
186
187 const double t = (ex1 - x1) / (x2 - x1);
188 const double u = (ey1 - y1) / (y2 - y1);
189
190 const auto calc_array_index = [](const double value, const unsigned size)
191 { return std::min(static_cast<unsigned>(std::floor(value * size)), size - 1); };
192
193 const unsigned arr_x = calc_array_index(x1, size_azi);
194 const unsigned arr_y = calc_array_index(y1, size_elev);
195
196 const RealType interp = (1.0 - t) * (1.0 - u) * _pattern[arr_x][arr_y] +
197 t * (1.0 - u) * _pattern[(arr_x + 1) % size_azi][arr_y] +
198 t * u * _pattern[(arr_x + 1) % size_azi][(arr_y + 1) % size_elev] +
199 (1.0 - t) * u * _pattern[arr_x][(arr_y + 1) % size_elev];
200
201 return interp * getEfficiencyFactor();
202 }
203}
Header file defining various types of antennas and their gain patterns.
Class for managing XML documents.
XmlElement getRootElement() const
Get the root element of the document.
bool loadFile(std::string_view filename)
Load an XML file into the document.
Class representing a node in an XML document.
XmlElement childElement(const std::string_view name="", const unsigned index=0) const noexcept
Retrieve a child element by name and index.
bool isValid() const noexcept
Check if the XML element is valid.
xmlNodePtr getNode() const noexcept
Get the underlying XML node pointer.
std::string getText() const
Get the text content of the XML element.
static RealType getAngle(const math::SVec3 &angle, const math::SVec3 &refangle) noexcept
Computes the angle between the input and reference angles.
void setEfficiencyFactor(RealType loss) noexcept
Sets the efficiency factor of the antenna.
RealType getEfficiencyFactor() const noexcept
Retrieves the efficiency factor of the antenna.
RealType getGain(const math::SVec3 &angle, const math::SVec3 &refangle, RealType wavelength) const noexcept override
Computes the gain of the Gaussian antenna.
RealType getGain(const math::SVec3 &angle, const math::SVec3 &refangle, RealType) const override
Computes the gain of the antenna based on the input angle and reference angle.
RealType getGain(const math::SVec3 &angle, const math::SVec3 &refangle, RealType wavelength) const noexcept override
Computes the gain of the parabolic antenna.
RealType getGain(const math::SVec3 &angle, const math::SVec3 &refangle, RealType wavelength) const noexcept override
Computes the gain of the sinc antenna based on the input parameters.
RealType getGain(const math::SVec3 &angle, const math::SVec3 &refangle, RealType wavelength) const noexcept override
Computes the gain of the square horn antenna.
RealType getGain(const math::SVec3 &angle, const math::SVec3 &refangle, RealType wavelength) const override
Computes the gain of the antenna based on the input angle and reference angle.
Wrapper class for managing interpolation sets using smart pointers.
A class representing a vector in spherical coordinates.
RealType elevation
The elevation angle of the vector.
RealType azimuth
The azimuth angle of the vector.
RealType length
The length of the vector.
A class representing a vector in rectangular coordinates.
Global configuration file for the project.
double RealType
Type for real numbers.
Definition config.h:27
constexpr RealType EPSILON
Machine epsilon for real numbers.
Definition config.h:51
constexpr RealType PI
Mathematical constant π (pi).
Definition config.h:43
Classes and operations for 3D geometry.
Wrapper for managing XML documents and elements using libxml2.
Header file for the logging system.
#define LOG(level,...)
Definition logging.h:19
RealType besselJ1(const RealType x) noexcept
Computes the Bessel function of the first kind (order 1) for a given value.
@ TRACE
Trace level for detailed debugging information.
Utility functions for mathematical and system operations.