FERS 1.0.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
serial Namespace Reference

Namespaces

namespace  kml_generator_utils
 
namespace  rotation_angle_utils
 
namespace  rotation_warning_utils
 
namespace  xml_parser_utils
 
namespace  xml_serializer_utils
 

Classes

class  KmlGenerator
 Generates KML files from FERS simulation scenarios for geographical visualization. More...
 
class  Response
 Manages radar signal responses from a transmitter. More...
 

Functions

std::vector< std::vector< RealType > > readPattern (const std::string &name, const std::string &datasetName)
 Reads a 2D pattern dataset from an HDF5 file.
 
void writeOutputFileMetadataAttributes (HighFive::File &file, const core::OutputFileMetadata &metadata)
 Writes additive FERS output metadata attributes to an open HDF5 file.
 
void readPulseData (const std::string &name, std::vector< ComplexType > &data)
 Reads pulse data from an HDF5 file.
 
void addChunkToFile (HighFive::File &file, const std::vector< ComplexType > &data, RealType time, RealType fullscale, unsigned count, const core::PulseChunkMetadata *metadata=nullptr)
 Adds a chunk of data to an HDF5 file.
 
std::unique_ptr< antenna::Antennaparse_antenna_from_json (const nlohmann::json &j)
 Parses an Antenna from JSON.
 
std::unique_ptr< fers_signal::RadarSignalparse_waveform_from_json (const nlohmann::json &j)
 Parses a Waveform from JSON.
 
std::unique_ptr< timing::PrototypeTimingparse_timing_from_json (const nlohmann::json &j, SimId id)
 Parses a timing prototype from JSON.
 
void update_parameters_from_json (const nlohmann::json &j, std::mt19937 &masterSeeder)
 Updates global simulation parameters from JSON.
 
void update_antenna_from_json (const nlohmann::json &j, antenna::Antenna *ant, core::World &world)
 Updates an antenna from JSON without full context recreation.
 
void update_platform_paths_from_json (const nlohmann::json &j, radar::Platform *plat)
 Updates a platform's motion and rotation paths from JSON.
 
void update_transmitter_from_json (const nlohmann::json &j, radar::Transmitter *tx, core::World &world, std::mt19937 &masterSeeder)
 Updates a transmitter from JSON without full context recreation.
 
void update_receiver_from_json (const nlohmann::json &j, radar::Receiver *rx, core::World &world, std::mt19937 &masterSeeder)
 Updates a receiver from JSON without full context recreation.
 
void update_monostatic_from_json (const nlohmann::json &j, radar::Transmitter *tx, radar::Receiver *rx, core::World &world, std::mt19937 &masterSeeder)
 Updates a monostatic radar from JSON without full context recreation.
 
void update_target_from_json (const nlohmann::json &j, radar::Target *tgt, core::World &world, std::mt19937 &masterSeeder)
 Updates a target from JSON without full context recreation.
 
void update_timing_from_json (const nlohmann::json &j, core::World &world, SimId id)
 Updates a timing source from JSON without full context recreation.
 
nlohmann::json world_to_json (const core::World &world)
 Serializes the entire simulation world into a nlohmann::json object.
 
void json_to_world (const nlohmann::json &j, core::World &world, std::mt19937 &masterSeeder)
 Deserializes a nlohmann::json object and reconstructs the simulation world.
 
std::unique_ptr< RadarSignalloadWaveformFromFile (const std::string &name, const std::string &filename, RealType power, RealType carrierFreq, const SimId id=0)
 Loads a radar waveform from a file and returns a RadarSignal object.
 
void parseSimulation (const std::string &filename, core::World *world, bool validate, std::mt19937 &masterSeeder)
 Parses a simulation configuration from an XML file.
 
void parseSimulationFromString (const std::string &xmlContent, core::World *world, bool validate, std::mt19937 &masterSeeder)
 Parses a simulation configuration directly from an XML string in memory.
 
std::string world_to_xml_string (const core::World &world)
 Serializes the entire simulation world into an XML formatted string.
 

Variables

std::mutex hdf5_global_mutex
 Global mutex to protect all HDF5 C-library calls, which are not thread-safe.
 

Function Documentation

◆ addChunkToFile()

void serial::addChunkToFile ( HighFive::File &  file,
const std::vector< ComplexType > &  data,
RealType  time,
RealType  fullscale,
unsigned  count,
const core::PulseChunkMetadata metadata = nullptr 
)

Adds a chunk of data to an HDF5 file.

Parameters
fileThe HDF5 file where the chunk is written.
dataA vector of complex data to be written.
timeThe time attribute associated with the chunk.
fullscaleThe fullscale attribute for the chunk.
countThe sequential count number for chunk naming.
Exceptions
std::runtime_errorIf there is an error writing data or setting attributes.

Definition at line 92 of file hdf5_handler.cpp.

94 {
95 std::scoped_lock lock(hdf5_global_mutex);
96
97 const std::size_t size = data.size();
98
99 const std::string base_chunk_name = "chunk_" + std::format("{:06}", count);
100 const std::string i_chunk_name = base_chunk_name + "_I";
101 const std::string q_chunk_name = base_chunk_name + "_Q";
102
103 std::vector<RealType> i(size), q(size);
104 std::ranges::transform(data, i.begin(), [](const ComplexType& c) { return c.real(); });
105 std::ranges::transform(data, q.begin(), [](const ComplexType& c) { return c.imag(); });
106
107 auto write_chunk = [&](const std::string& chunkName, const std::vector<RealType>& chunkData)
108 {
109 try
110 {
111 HighFive::DataSet dataset =
112 file.createDataSet<RealType>(chunkName, HighFive::DataSpace::From(chunkData));
113 dataset.write(chunkData);
114 }
115 catch (const HighFive::Exception& err)
116 {
117 LOG(Level::FATAL, "Error while writing data to HDF5 file: {}", err.what());
118 throw std::runtime_error("Error while writing data to HDF5 file: " + chunkName + " - " + err.what());
119 }
120 };
121
122 auto set_chunk_attributes = [&](const std::string& chunkName)
123 {
124 try
125 {
126 HighFive::DataSet dataset = file.getDataSet(chunkName);
127 dataset.createAttribute("time", time);
128 dataset.createAttribute("rate", params::rate());
129 dataset.createAttribute("fullscale", fullscale);
130 if (metadata != nullptr)
131 {
132 dataset.createAttribute("chunk_index", metadata->chunk_index);
133 dataset.createAttribute("sample_count", static_cast<unsigned long long>(metadata->sample_count));
134 dataset.createAttribute("sample_start", static_cast<unsigned long long>(metadata->sample_start));
135 dataset.createAttribute("sample_end_exclusive",
136 static_cast<unsigned long long>(metadata->sample_end_exclusive));
137 }
138 }
139 catch (const HighFive::Exception& err)
140 {
141 LOG(Level::FATAL, "Error while setting attributes on chunk: {}", err.what());
142 throw std::runtime_error("Error while setting attributes on chunk: " + chunkName + " - " + err.what());
143 }
144 };
145
146 write_chunk(i_chunk_name, i);
147 write_chunk(q_chunk_name, q);
148
149 set_chunk_attributes(i_chunk_name);
150 set_chunk_attributes(q_chunk_name);
151 }
double RealType
Type for real numbers.
Definition config.h:27
std::complex< RealType > ComplexType
Type for complex numbers.
Definition config.h:35
#define LOG(level,...)
Definition logging.h:19
RealType rate() noexcept
Get the rendering sample rate.
Definition parameters.h:121
std::uint64_t sample_end_exclusive

References core::PulseChunkMetadata::chunk_index, hdf5_global_mutex, LOG, params::rate(), core::PulseChunkMetadata::sample_count, core::PulseChunkMetadata::sample_end_exclusive, and core::PulseChunkMetadata::sample_start.

Referenced by processing::runPulsedFinalizer().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ json_to_world()

void serial::json_to_world ( const nlohmann::json &  j,
core::World world,
std::mt19937 &  masterSeeder 
)

Deserializes a nlohmann::json object and reconstructs the simulation world.

This function is the counterpart to world_to_json. It performs a full state replacement by clearing the existing world and rebuilding it from the provided JSON. This "replace" strategy simplifies state management, guaranteeing that the C++ core is always perfectly synchronized with the state provided by the UI without requiring complex diffing or patching logic. It also handles re-seeding the master random number generator to ensure that loading a state also restores its deterministic behavior.

Parameters
jThe json object to deserialize.
worldThe world object to populate.
masterSeederA reference to the master random number generator, which will be re-seeded.

Definition at line 1574 of file json_serializer.cpp.

1575 {
1576 // 1. Clear the existing world state. This function always performs a full
1577 // replacement to ensure the C++ state is a perfect mirror of the UI state.
1578 world.clear();
1579
1580 const auto& sim = j.at("simulation");
1581
1582 parse_parameters(sim, masterSeeder);
1583 parse_assets(sim, world);
1584
1585 // 3. Restore platforms and their components.
1586 if (sim.contains("platforms"))
1587 {
1588 for (const auto& plat_json : sim.at("platforms"))
1589 {
1590 parse_platform(plat_json, world, masterSeeder);
1591 }
1592 }
1593
1594 // 4. Finalize world state after all objects are loaded.
1595
1596 // Prepare CW receiver buffers before starting simulation
1597 const RealType start_time = params::startTime();
1598 const RealType end_time = params::endTime();
1599 const RealType dt_sim = 1.0 / (params::rate() * params::oversampleRatio());
1600 const auto num_samples = static_cast<size_t>(std::ceil((end_time - start_time) / dt_sim));
1601
1602 for (const auto& receiver : world.getReceivers())
1603 {
1604 if (receiver->getMode() == radar::OperationMode::CW_MODE)
1605 {
1606 receiver->prepareCwData(num_samples);
1607 }
1608 }
1609
1610 // Schedule initial events after all objects are loaded.
1611 world.scheduleInitialEvents();
1612 }
void scheduleInitialEvents()
Populates the event queue with the initial events for the simulation.
Definition world.cpp:256
void clear() noexcept
Clears all objects and assets from the simulation world.
Definition world.cpp:243
RealType endTime() noexcept
Get the end time for the simulation.
Definition parameters.h:109
RealType startTime() noexcept
Get the start time for the simulation.
Definition parameters.h:103
unsigned oversampleRatio() noexcept
Get the oversampling ratio.
Definition parameters.h:151
@ CW_MODE
The component operates in a continuous-wave mode.

References core::World::clear(), radar::CW_MODE, params::endTime(), core::World::getReceivers(), params::oversampleRatio(), params::rate(), core::World::scheduleInitialEvents(), and params::startTime().

Referenced by fers_update_scenario_from_json().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ loadWaveformFromFile()

std::unique_ptr< fers_signal::RadarSignal > serial::loadWaveformFromFile ( const std::string &  name,
const std::string &  filename,
RealType  power,
RealType  carrierFreq,
const SimId  id = 0 
)

Loads a radar waveform from a file and returns a RadarSignal object.

Parameters
nameThe name of the radar signal.
filenameThe path to the file containing the waveform data.
powerThe power of the radar signal in the waveform.
carrierFreqThe carrier frequency of the radar signal.
Returns
A unique pointer to a RadarSignal object loaded with the waveform data.
Exceptions
std::runtime_errorIf the file cannot be opened or the file format is unrecognized.

Definition at line 155 of file waveform_factory.cpp.

157 {
158 const std::filesystem::path filepath = filename;
159 const auto extension = filepath.extension().string();
160
161 if (hasExtension(extension, ".csv"))
162 {
163 auto wave = loadWaveformFromCsvFile(name, filepath, power, carrierFreq, id);
164 wave->setFilename(filename);
165 return wave;
166 }
167 if (hasExtension(extension, ".h5"))
168 {
169 auto wave = loadWaveformFromHdf5File(name, filepath, power, carrierFreq, id);
170 wave->setFilename(filename);
171 return wave;
172 }
173
174 LOG(logging::Level::FATAL, "Unrecognized file extension '{}' for file: '{}'", extension, filename);
175 throw std::runtime_error("Unrecognized file extension '" + extension + "' for file: " + filename);
176 }
@ FATAL
Fatal level for severe error events.

References logging::FATAL, and LOG.

Referenced by serial::xml_parser_utils::createDefaultAssetLoaders(), and fers_signal::from_json().

+ Here is the caller graph for this function:

◆ parse_antenna_from_json()

std::unique_ptr< antenna::Antenna > serial::parse_antenna_from_json ( const nlohmann::json &  j)

Parses an Antenna from JSON.

Definition at line 1113 of file json_serializer.cpp.

1114 {
1115 std::unique_ptr<antenna::Antenna> ant;
1116 antenna::from_json(j, ant);
1117 return ant;
1118 }
void from_json(const nlohmann::json &j, std::unique_ptr< Antenna > &ant)

References antenna::from_json().

Referenced by update_antenna_from_json().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_timing_from_json()

std::unique_ptr< timing::PrototypeTiming > serial::parse_timing_from_json ( const nlohmann::json &  j,
const SimId  id 
)

Parses a timing prototype from JSON.

Definition at line 1127 of file json_serializer.cpp.

1128 {
1129 auto timing = std::make_unique<timing::PrototypeTiming>(j.at("name").get<std::string>(), id);
1130 j.get_to(*timing);
1131 return timing;
1132 }

Referenced by update_timing_from_json().

+ Here is the caller graph for this function:

◆ parse_waveform_from_json()

std::unique_ptr< fers_signal::RadarSignal > serial::parse_waveform_from_json ( const nlohmann::json &  j)

Parses a Waveform from JSON.

Definition at line 1120 of file json_serializer.cpp.

1121 {
1122 std::unique_ptr<fers_signal::RadarSignal> wf;
1124 return wf;
1125 }
void from_json(const nlohmann::json &j, std::unique_ptr< RadarSignal > &rs)

References fers_signal::from_json().

Referenced by fers_update_waveform_from_json().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parseSimulation()

void serial::parseSimulation ( const std::string &  filename,
core::World world,
bool  validate,
std::mt19937 &  masterSeeder 
)

Parses a simulation configuration from an XML file.

This function acts as the primary facade for the simulator's XML loading pipeline. It performs the following steps:

  1. Resets the target World and global parameters (params::params).
  2. Loads the main XML file.
  3. Recursively finds and merges any <include> files into the main document.
  4. Optionally validates the combined document against the built-in DTD and XSD schemas.
  5. Uses the internal parser utilities to instantiate simulation objects.
  6. Updates the global params::params with the parsed context parameters.
Parameters
filenameThe filesystem path to the main XML simulation script.
worldA pointer to the World object to be populated with parsed components.
validateA boolean indicating whether to perform strict XML schema validation.
masterSeederA reference to the master random number generator used for assigning independent seeds to components.
Exceptions
XmlExceptionif the XML is malformed, fails schema validation, or contains invalid scenario logic.
std::runtime_errorfor file I/O errors or other critical setup issues.

Definition at line 25 of file xml_parser.cpp.

27 {
28 world->clear();
30
31 XmlDocument main_doc;
32 if (!main_doc.loadFile(filename))
33 {
34 throw XmlException("Failed to load main XML file: " + filename);
35 }
36
37 const std::filesystem::path main_dir = std::filesystem::path(filename).parent_path();
38 const bool did_combine = xml_parser_utils::addIncludeFilesToMainDocument(main_doc, main_dir);
39
40 if (validate)
41 {
42 xml_parser_utils::validateXml(did_combine, main_doc);
43 }
44 else
45 {
46 LOG(logging::Level::DEBUG, "Skipping XML validation.");
47 }
48
49 xml_parser_utils::ParserContext ctx;
50 ctx.world = world;
51 ctx.master_seeder = &masterSeeder;
52 ctx.base_dir = main_dir;
53 ctx.loaders = xml_parser_utils::createDefaultAssetLoaders();
54
55 xml_parser_utils::processParsedDocument(main_doc, ctx);
56
57 // Push the isolated context parameters into global application parameters
58 params::params = ctx.parameters;
59 }
Class for managing XML documents.
bool loadFile(std::string_view filename)
Load an XML file into the document.
Exception class for handling XML-related errors.
@ DEBUG
Debug level for general debugging information.
Parameters params
Definition parameters.h:85
void reset() noexcept
Resets the parameters to their default-constructed state.
Definition parameters.h:82

References serial::xml_parser_utils::addIncludeFilesToMainDocument(), serial::xml_parser_utils::ParserContext::base_dir, core::World::clear(), serial::xml_parser_utils::createDefaultAssetLoaders(), logging::DEBUG, serial::xml_parser_utils::ParserContext::loaders, XmlDocument::loadFile(), LOG, serial::xml_parser_utils::ParserContext::master_seeder, serial::xml_parser_utils::ParserContext::parameters, params::params, serial::xml_parser_utils::processParsedDocument(), params::Parameters::reset(), serial::xml_parser_utils::validateXml(), and serial::xml_parser_utils::ParserContext::world.

Referenced by fers_load_scenario_from_xml_file().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parseSimulationFromString()

void serial::parseSimulationFromString ( const std::string &  xmlContent,
core::World world,
bool  validate,
std::mt19937 &  masterSeeder 
)

Parses a simulation configuration directly from an XML string in memory.

Similar to parseSimulation, but operates on a raw string instead of a file. Because it does not load from the filesystem, <include> tags are ignored, and any relative paths for file-backed assets (like waveforms or antennas) will be resolved against the current working directory (.).

Parameters
xmlContentThe raw XML string containing the scenario definition.
worldA pointer to the World object to be populated with parsed components.
validateA boolean indicating whether to perform strict XML schema validation.
masterSeederA reference to the master random number generator used for assigning independent seeds to components.
Exceptions
XmlExceptionif the XML string is malformed, fails schema validation, or contains invalid scenario logic.

Definition at line 61 of file xml_parser.cpp.

63 {
64 world->clear();
66
67 XmlDocument doc;
68 if (!doc.loadString(xmlContent))
69 {
70 throw XmlException("Failed to parse XML from memory string.");
71 }
72
73 if (validate)
74 {
75 // Note: <include> tags are not processed when loading from a string.
76 xml_parser_utils::validateXml(false, doc);
77 }
78 else
79 {
80 LOG(logging::Level::DEBUG, "Skipping XML validation.");
81 }
82
83 // When loading from a string, there's no base directory for relative asset paths.
84 // The UI/caller is responsible for ensuring any paths in the XML are absolute or resolvable.
85 const std::filesystem::path base_dir = ".";
86
87 xml_parser_utils::ParserContext ctx;
88 ctx.world = world;
89 ctx.master_seeder = &masterSeeder;
90 ctx.base_dir = base_dir;
91 ctx.loaders = xml_parser_utils::createDefaultAssetLoaders();
92
93 xml_parser_utils::processParsedDocument(doc, ctx);
94
95 // Push the isolated context parameters into global application parameters
96 params::params = ctx.parameters;
97 }
bool loadString(const std::string &content)
Load an XML document from a string in memory.

References serial::xml_parser_utils::ParserContext::base_dir, core::World::clear(), serial::xml_parser_utils::createDefaultAssetLoaders(), logging::DEBUG, serial::xml_parser_utils::ParserContext::loaders, XmlDocument::loadString(), LOG, serial::xml_parser_utils::ParserContext::master_seeder, serial::xml_parser_utils::ParserContext::parameters, params::params, serial::xml_parser_utils::processParsedDocument(), params::Parameters::reset(), serial::xml_parser_utils::validateXml(), and serial::xml_parser_utils::ParserContext::world.

Referenced by fers_load_scenario_from_xml_string().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ readPattern()

std::vector< std::vector< RealType > > serial::readPattern ( const std::string &  name,
const std::string &  datasetName 
)

Reads a 2D pattern dataset from an HDF5 file.

Parameters
nameThe name of the HDF5 file.
datasetNameThe name of the dataset to be read.
Returns
A 2D vector containing the pattern data.
Exceptions
std::runtime_errorIf there is an error handling the file or if the dataset dimensions are invalid.

Definition at line 153 of file hdf5_handler.cpp.

154 {
155 std::scoped_lock lock(hdf5_global_mutex);
156 try
157 {
158 LOG(Level::TRACE, "Reading dataset '{}' from file '{}'", datasetName, name);
159 const HighFive::File file(name, HighFive::File::ReadOnly);
160
161 const auto dataset = file.getDataSet(datasetName);
162
163 const auto dataspace = dataset.getSpace();
164 const auto dims = dataspace.getDimensions();
165
166 if (dims.size() != 2)
167 {
168 LOG(Level::FATAL, "Invalid dataset dimensions for '{}' in file '{}'", datasetName, name);
169 throw std::runtime_error(
170 std::format(R"(Invalid dataset dimensions for "{}" in file "{}")", datasetName, name));
171 }
172
173 LOG(Level::TRACE, "Reading dataset with dimensions {}x{}", dims[0], dims[1]);
174
175 std::vector data(dims[0], std::vector<RealType>(dims[1]));
176 dataset.read(data);
177
178 LOG(Level::TRACE, "Read dataset successfully");
179
180 return data;
181 }
182 catch (const HighFive::Exception& err)
183 {
184 LOG(Level::FATAL, "Error handling HDF5 file: {}", err.what());
185 throw std::runtime_error("Error handling HDF5 file: " + std::string(err.what()));
186 }
187 }

References hdf5_global_mutex, and LOG.

◆ readPulseData()

void serial::readPulseData ( const std::string &  name,
std::vector< ComplexType > &  data 
)

Reads pulse data from an HDF5 file.

Parameters
nameThe name of the HDF5 file.
dataA reference to a vector where the complex data will be stored.
Exceptions
std::runtime_errorIf the file does not exist or the datasets "I" and "Q" have mismatched sizes.

Definition at line 43 of file hdf5_handler.cpp.

44 {
45 std::scoped_lock lock(hdf5_global_mutex);
46
47 if (!std::filesystem::exists(name))
48 {
49 LOG(Level::FATAL, "File '{}' not found", name);
50 throw std::runtime_error("File " + name + " not found.");
51 }
52
53 LOG(Level::TRACE, "Opening file '{}'", name);
54 const HighFive::File file(name, HighFive::File::ReadOnly);
55
56 // Helper lambda to open group and read dataset
57 auto read_dataset = [&file](const std::string& groupName, std::vector<double>& buffer) -> size_t
58 {
59 const auto group = file.getGroup("/" + groupName);
60
61 const auto dataset = group.getDataSet("value");
62
63 const auto dimensions = dataset.getSpace().getDimensions();
64 const auto size = dimensions[0];
65
66 buffer.resize(size);
67 dataset.read(buffer);
68
69 return size;
70 };
71
72 LOG(Level::TRACE, "Reading dataset 'I' from file '{}'", name);
73 std::vector<double> buffer_i;
74 const auto size = read_dataset("I", buffer_i);
75
76 std::vector<double> buffer_q;
77 LOG(Level::TRACE, "Reading dataset 'Q' from file '{}'", name);
78 if (read_dataset("Q", buffer_q) != size)
79 {
80 LOG(Level::FATAL, "Dataset 'Q' is not the same size as dataset 'I' in file '{}'", name);
81 throw std::runtime_error(R"(Dataset "Q" is not the same size as dataset "I" in file )" + name);
82 }
83
84 data.resize(size);
85 for (size_t i = 0; i < size; ++i)
86 {
87 data[i] = ComplexType(buffer_i[i], buffer_q[i]);
88 }
89 LOG(Level::TRACE, "Read dataset successfully");
90 }

References hdf5_global_mutex, and LOG.

◆ update_antenna_from_json()

void serial::update_antenna_from_json ( const nlohmann::json &  j,
antenna::Antenna ant,
core::World world 
)

Updates an antenna from JSON without full context recreation.

Definition at line 1141 of file json_serializer.cpp.

1142 {
1143 auto new_pattern = j.value("pattern", "isotropic");
1144 bool type_changed = false;
1145
1146 const auto parse_required_antenna = [&j]()
1147 {
1148 auto parsed = parse_antenna_from_json(j);
1149 if (parsed == nullptr)
1150 {
1151 const auto name = j.value("name", std::string{});
1152 const auto pattern = j.value("pattern", "isotropic");
1153 throw std::runtime_error("Cannot update antenna '" + name + "' to pattern '" + pattern +
1154 "' without a filename.");
1155 }
1156 return parsed;
1157 };
1158
1159 if (new_pattern == "isotropic" && (dynamic_cast<antenna::Isotropic*>(ant) == nullptr))
1160 type_changed = true;
1161 else if (new_pattern == "sinc" && (dynamic_cast<antenna::Sinc*>(ant) == nullptr))
1162 type_changed = true;
1163 else if (new_pattern == "gaussian" && (dynamic_cast<antenna::Gaussian*>(ant) == nullptr))
1164 type_changed = true;
1165 else if (new_pattern == "squarehorn" && (dynamic_cast<antenna::SquareHorn*>(ant) == nullptr))
1166 type_changed = true;
1167 else if (new_pattern == "parabolic" && (dynamic_cast<antenna::Parabolic*>(ant) == nullptr))
1168 type_changed = true;
1169 else if (new_pattern == "xml" && (dynamic_cast<antenna::XmlAntenna*>(ant) == nullptr))
1170 type_changed = true;
1171 else if (new_pattern == "file" && (dynamic_cast<antenna::H5Antenna*>(ant) == nullptr))
1172 type_changed = true;
1173
1174 if (type_changed)
1175 {
1176 world.replace(parse_required_antenna());
1177 return;
1178 }
1179
1180 ant->setName(j.at("name").get<std::string>());
1181 ant->setEfficiencyFactor(j.value("efficiency", 1.0));
1182
1183 if (auto* sinc = dynamic_cast<antenna::Sinc*>(ant))
1184 {
1185 sinc->setAlpha(j.value("alpha", 1.0));
1186 sinc->setBeta(j.value("beta", 1.0));
1187 sinc->setGamma(j.value("gamma", 2.0));
1188 }
1189 else if (auto* gauss = dynamic_cast<antenna::Gaussian*>(ant))
1190 {
1191 gauss->setAzimuthScale(j.value("azscale", 1.0));
1192 gauss->setElevationScale(j.value("elscale", 1.0));
1193 }
1194 else if (auto* horn = dynamic_cast<antenna::SquareHorn*>(ant))
1195 {
1196 horn->setDimension(j.value("diameter", 0.5));
1197 }
1198 else if (auto* para = dynamic_cast<antenna::Parabolic*>(ant))
1199 {
1200 para->setDiameter(j.value("diameter", 0.5));
1201 }
1202 else if (auto* xml = dynamic_cast<antenna::XmlAntenna*>(ant))
1203 {
1204 if (xml->getFilename() != j.value("filename", ""))
1205 {
1206 world.replace(parse_required_antenna());
1207 }
1208 }
1209 else if (auto* h5 = dynamic_cast<antenna::H5Antenna*>(ant))
1210 {
1211 if (h5->getFilename() != j.value("filename", ""))
1212 {
1213 world.replace(parse_required_antenna());
1214 }
1215 }
1216 }
void setEfficiencyFactor(RealType loss) noexcept
Sets the efficiency factor of the antenna.
void setName(std::string name) noexcept
Sets the name of the antenna.
Represents a Gaussian-shaped antenna gain pattern.
Represents an antenna whose gain pattern is loaded from a HDF5 file.
Represents an isotropic antenna with uniform gain in all directions.
Represents a parabolic reflector antenna.
Represents a sinc function-based antenna gain pattern.
Represents a square horn antenna.
Represents an antenna whose gain pattern is defined by an XML file.
void replace(std::unique_ptr< radar::Target > target)
Replaces an existing target, updating internal pointers.
Definition world.cpp:128
std::unique_ptr< antenna::Antenna > parse_antenna_from_json(const nlohmann::json &j)
Parses an Antenna from JSON.

References parse_antenna_from_json(), core::World::replace(), antenna::Antenna::setEfficiencyFactor(), and antenna::Antenna::setName().

Referenced by fers_update_antenna_from_json().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_monostatic_from_json()

void serial::update_monostatic_from_json ( const nlohmann::json &  j,
radar::Transmitter tx,
radar::Receiver rx,
core::World world,
std::mt19937 &  masterSeeder 
)

Updates a monostatic radar from JSON without full context recreation.

Definition at line 1418 of file json_serializer.cpp.

1420 {
1421 update_transmitter_from_json(j, tx, world, masterSeeder);
1422
1423 if (j.contains("name"))
1424 rx->setName(j.at("name").get<std::string>());
1425 rx->setMode(tx->getMode());
1426 if (rx->getMode() == radar::OperationMode::PULSED_MODE && j.contains("pulsed_mode"))
1427 {
1428 const auto& mode_json = j.at("pulsed_mode");
1429 rx->setWindowProperties(mode_json.value("window_length", 0.0), tx->getPrf(),
1430 mode_json.value("window_skip", 0.0));
1431 }
1432 if (j.contains("noise_temp"))
1433 rx->setNoiseTemperature(j.value("noise_temp", 0.0));
1434 if (j.contains("nodirect"))
1435 {
1436 if (j.value("nodirect", false))
1438 else
1440 }
1441 if (j.contains("nopropagationloss"))
1442 {
1443 if (j.value("nopropagationloss", false))
1445 else
1447 }
1448 if (j.contains("antenna"))
1449 rx->setAntenna(world.findAntenna(parse_json_id(j, "antenna", "Monostatic")));
1450 if (j.contains("timing"))
1451 {
1452 auto timing_id = parse_json_id(j, "timing", "Monostatic");
1453 if (auto* const timing_proto = world.findTiming(timing_id))
1454 {
1455 unsigned seed = rx->getTiming() ? rx->getTiming()->getSeed() : 0;
1456 auto rx_timing = std::make_shared<timing::Timing>(timing_proto->getName(), seed, timing_proto->getId());
1457 rx_timing->initializeModel(timing_proto);
1458 rx->setTiming(rx_timing);
1459 }
1460 else
1461 {
1462 rx->setTiming(nullptr);
1463 }
1464 }
1465 if (j.contains("schedule"))
1466 {
1467 auto raw = j.at("schedule").get<std::vector<radar::SchedulePeriod>>();
1468 RealType pri = 0.0;
1470 pri = 1.0 / tx->getPrf();
1471 auto processed_schedule = radar::processRawSchedule(
1472 std::move(raw), tx->getName(), tx->getMode() == radar::OperationMode::PULSED_MODE, pri);
1473 tx->setSchedule(processed_schedule);
1474 rx->setSchedule(processed_schedule);
1475 }
1476 }
timing::PrototypeTiming * findTiming(const SimId id)
Finds a timing source by ID.
Definition world.cpp:88
antenna::Antenna * findAntenna(const SimId id)
Finds an antenna by ID.
Definition world.cpp:82
const std::string & getName() const noexcept
Retrieves the name of the object.
Definition object.h:79
void setName(std::string name) noexcept
Sets the name of the object.
Definition object.h:86
void setAntenna(const antenna::Antenna *ant)
Sets the antenna for the radar.
Definition radar_obj.cpp:46
std::shared_ptr< timing::Timing > getTiming() const
Retrieves the timing source for the radar.
Definition radar_obj.cpp:66
void setTiming(const std::shared_ptr< timing::Timing > &tim)
Sets the timing source for the radar.
Definition radar_obj.cpp:36
void setMode(OperationMode mode) noexcept
Sets the operational mode of the receiver.
Definition receiver.h:178
void setFlag(RecvFlag flag) noexcept
Sets a receiver flag.
Definition receiver.h:216
void clearFlag(RecvFlag flag) noexcept
Clears a receiver flag.
Definition receiver.h:223
void setSchedule(std::vector< SchedulePeriod > schedule)
Sets the active schedule for the receiver.
Definition receiver.cpp:130
OperationMode getMode() const noexcept
Gets the operational mode of the receiver.
Definition receiver.h:160
void setWindowProperties(RealType length, RealType prf, RealType skip) noexcept
Sets the properties for radar windows.
Definition receiver.cpp:90
void setNoiseTemperature(RealType temp)
Sets the noise temperature of the receiver.
Definition receiver.cpp:80
RealType getPrf() const noexcept
Retrieves the pulse repetition frequency (PRF).
Definition transmitter.h:64
OperationMode getMode() const noexcept
Gets the operational mode of the transmitter.
Definition transmitter.h:85
void setSchedule(std::vector< SchedulePeriod > schedule)
Sets the active schedule for the transmitter.
std::vector< SchedulePeriod > processRawSchedule(std::vector< SchedulePeriod > periods, const std::string &ownerName, const bool isPulsed, const RealType pri)
Processes a raw list of schedule periods.
@ PULSED_MODE
The component operates in a pulsed mode.
void update_transmitter_from_json(const nlohmann::json &j, radar::Transmitter *tx, core::World &world, std::mt19937 &)
Updates a transmitter from JSON without full context recreation.

References radar::Receiver::clearFlag(), core::World::findAntenna(), core::World::findTiming(), radar::Receiver::FLAG_NODIRECT, radar::Receiver::FLAG_NOPROPLOSS, radar::Receiver::getMode(), radar::Transmitter::getMode(), radar::Object::getName(), radar::Transmitter::getPrf(), radar::Radar::getTiming(), radar::processRawSchedule(), radar::PULSED_MODE, radar::Radar::setAntenna(), radar::Receiver::setFlag(), radar::Receiver::setMode(), radar::Object::setName(), radar::Receiver::setNoiseTemperature(), radar::Receiver::setSchedule(), radar::Transmitter::setSchedule(), radar::Radar::setTiming(), radar::Receiver::setWindowProperties(), and update_transmitter_from_json().

Referenced by fers_update_monostatic_from_json().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_parameters_from_json()

void serial::update_parameters_from_json ( const nlohmann::json &  j,
std::mt19937 &  masterSeeder 
)

Updates global simulation parameters from JSON.

Definition at line 1134 of file json_serializer.cpp.

1135 {
1136 nlohmann::json sim;
1137 sim["parameters"] = j;
1138 parse_parameters(sim, masterSeeder);
1139 }

Referenced by fers_update_parameters_from_json().

+ Here is the caller graph for this function:

◆ update_platform_paths_from_json()

void serial::update_platform_paths_from_json ( const nlohmann::json &  j,
radar::Platform plat 
)

Updates a platform's motion and rotation paths from JSON.

Definition at line 1218 of file json_serializer.cpp.

1219 {
1220 if (j.contains("motionpath"))
1221 {
1222 auto path = std::make_unique<math::Path>();
1223 j.at("motionpath").get_to(*path);
1224 plat->setMotionPath(std::move(path));
1225 }
1226 if (j.contains("rotationpath"))
1227 {
1228 auto rot_path = std::make_unique<math::RotationPath>();
1229 const auto& rotation_json = j.at("rotationpath");
1230 rot_path->setInterp(rotation_json.at("interpolation").get<math::RotationPath::InterpType>());
1231 unsigned waypoint_index = 0;
1232 for (const auto& waypoint_json : rotation_json.at("rotationwaypoints"))
1233 {
1234 const RealType azimuth = waypoint_json.at("azimuth").get<RealType>();
1235 const RealType elevation = waypoint_json.at("elevation").get<RealType>();
1236 const RealType time = waypoint_json.at("time").get<RealType>();
1237 const std::string owner =
1238 std::format("platform '{}' rotation waypoint {}", plat->getName(), waypoint_index);
1239
1240 rotation_warning_utils::maybe_warn_about_rotation_value(azimuth, params::rotationAngleUnit(),
1241 rotation_warning_utils::ValueKind::Angle,
1242 "JSON", owner, "azimuth");
1243 rotation_warning_utils::maybe_warn_about_rotation_value(elevation, params::rotationAngleUnit(),
1244 rotation_warning_utils::ValueKind::Angle,
1245 "JSON", owner, "elevation");
1246
1247 rot_path->addCoord(rotation_angle_utils::external_rotation_to_internal(azimuth, elevation, time,
1249 ++waypoint_index;
1250 }
1251 rot_path->finalize();
1252 plat->setRotationPath(std::move(rot_path));
1253 }
1254 else if (j.contains("fixedrotation"))
1255 {
1256 auto rot_path = std::make_unique<math::RotationPath>();
1257 const auto& fixed_json = j.at("fixedrotation");
1258 const RealType start_az_deg = fixed_json.at("startazimuth").get<RealType>();
1259 const RealType start_el_deg = fixed_json.at("startelevation").get<RealType>();
1260 const RealType rate_az_deg_s = fixed_json.at("azimuthrate").get<RealType>();
1261 const RealType rate_el_deg_s = fixed_json.at("elevationrate").get<RealType>();
1262 const std::string owner = std::format("platform '{}' fixedrotation", plat->getName());
1263
1264 rotation_warning_utils::maybe_warn_about_rotation_value(start_az_deg, params::rotationAngleUnit(),
1265 rotation_warning_utils::ValueKind::Angle, "JSON",
1266 owner, "startazimuth");
1267 rotation_warning_utils::maybe_warn_about_rotation_value(start_el_deg, params::rotationAngleUnit(),
1268 rotation_warning_utils::ValueKind::Angle, "JSON",
1269 owner, "startelevation");
1270 rotation_warning_utils::maybe_warn_about_rotation_value(rate_az_deg_s, params::rotationAngleUnit(),
1271 rotation_warning_utils::ValueKind::Rate, "JSON",
1272 owner, "azimuthrate");
1273 rotation_warning_utils::maybe_warn_about_rotation_value(rate_el_deg_s, params::rotationAngleUnit(),
1274 rotation_warning_utils::ValueKind::Rate, "JSON",
1275 owner, "elevationrate");
1276
1278 start_az_deg, start_el_deg, 0.0, params::rotationAngleUnit());
1280 rate_az_deg_s, rate_el_deg_s, 0.0, params::rotationAngleUnit());
1281 rot_path->setConstantRate(start, rate);
1282 rot_path->finalize();
1283 plat->setRotationPath(std::move(rot_path));
1284 }
1285 }
InterpType
Enumeration for types of interpolation.
const std::string & getName() const noexcept
Gets the name of the platform.
Definition platform.h:90
void setMotionPath(std::unique_ptr< math::Path > path) noexcept
Sets the motion path of the platform.
Definition platform.h:111
void setRotationPath(std::unique_ptr< math::RotationPath > path) noexcept
Sets the rotation path of the platform.
Definition platform.h:104
RotationAngleUnit rotationAngleUnit() noexcept
Definition parameters.h:286
math::RotationCoord external_rotation_to_internal(const RealType azimuth, const RealType elevation, const RealType time, const params::RotationAngleUnit unit) noexcept
math::RotationCoord external_rotation_rate_to_internal(const RealType azimuth_rate, const RealType elevation_rate, const RealType time, const params::RotationAngleUnit unit) noexcept

References serial::rotation_warning_utils::Angle, serial::rotation_angle_utils::external_rotation_rate_to_internal(), serial::rotation_angle_utils::external_rotation_to_internal(), radar::Platform::getName(), serial::rotation_warning_utils::maybe_warn_about_rotation_value(), serial::rotation_warning_utils::Rate, params::rotationAngleUnit(), radar::Platform::setMotionPath(), and radar::Platform::setRotationPath().

Referenced by fers_update_platform_from_json().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_receiver_from_json()

void serial::update_receiver_from_json ( const nlohmann::json &  j,
radar::Receiver rx,
core::World world,
std::mt19937 &   
)

Updates a receiver from JSON without full context recreation.

Definition at line 1347 of file json_serializer.cpp.

1349 {
1350 if (j.contains("name"))
1351 rx->setName(j.at("name").get<std::string>());
1352
1353 if (j.contains("pulsed_mode"))
1354 {
1356 const auto& mode_json = j.at("pulsed_mode");
1357 rx->setWindowProperties(mode_json.value("window_length", 0.0), mode_json.value("prf", 0.0),
1358 mode_json.value("window_skip", 0.0));
1359 }
1360 else if (j.contains("cw_mode"))
1361 {
1363 }
1364
1365 if (j.contains("noise_temp"))
1366 rx->setNoiseTemperature(j.value("noise_temp", 0.0));
1367
1368 if (j.contains("nodirect"))
1369 {
1370 if (j.value("nodirect", false))
1372 else
1374 }
1375 if (j.contains("nopropagationloss"))
1376 {
1377 if (j.value("nopropagationloss", false))
1379 else
1381 }
1382
1383 if (j.contains("antenna"))
1384 {
1385 auto id = parse_json_id(j, "antenna", "Receiver");
1386 auto* ant = world.findAntenna(id);
1387 if (ant == nullptr)
1388 throw std::runtime_error("Antenna ID " + std::to_string(id) + " not found.");
1389 rx->setAntenna(ant);
1390 }
1391
1392 if (j.contains("timing"))
1393 {
1394 auto timing_id = parse_json_id(j, "timing", "Receiver");
1395 if (auto* const timing_proto = world.findTiming(timing_id))
1396 {
1397 unsigned seed = rx->getTiming() ? rx->getTiming()->getSeed() : 0;
1398 auto timing = std::make_shared<timing::Timing>(timing_proto->getName(), seed, timing_proto->getId());
1399 timing->initializeModel(timing_proto);
1400 rx->setTiming(timing);
1401 }
1402 else
1403 {
1404 throw std::runtime_error("Timing ID " + std::to_string(timing_id) + " not found.");
1405 }
1406 }
1407 if (j.contains("schedule"))
1408 {
1409 auto raw = j.at("schedule").get<std::vector<radar::SchedulePeriod>>();
1410 RealType pri = 0.0;
1412 pri = 1.0 / rx->getWindowPrf();
1413 rx->setSchedule(radar::processRawSchedule(std::move(raw), rx->getName(),
1415 }
1416 }
RealType getWindowPrf() const noexcept
Retrieves the pulse repetition frequency (PRF) of the radar window.
Definition receiver.h:116

References radar::Receiver::clearFlag(), radar::CW_MODE, core::World::findAntenna(), core::World::findTiming(), radar::Receiver::FLAG_NODIRECT, radar::Receiver::FLAG_NOPROPLOSS, radar::Receiver::getMode(), radar::Object::getName(), radar::Radar::getTiming(), radar::Receiver::getWindowPrf(), radar::processRawSchedule(), radar::PULSED_MODE, radar::Radar::setAntenna(), radar::Receiver::setFlag(), radar::Receiver::setMode(), radar::Object::setName(), radar::Receiver::setNoiseTemperature(), radar::Receiver::setSchedule(), radar::Radar::setTiming(), and radar::Receiver::setWindowProperties().

Referenced by fers_update_receiver_from_json().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_target_from_json()

void serial::update_target_from_json ( const nlohmann::json &  j,
radar::Target existing_tgt,
core::World world,
std::mt19937 &   
)

Updates a target from JSON without full context recreation.

Definition at line 1478 of file json_serializer.cpp.

1480 {
1481 auto* plat = existing_tgt->getPlatform();
1482 const auto& rcs_json = j.at("rcs");
1483 const auto rcs_type = rcs_json.at("type").get<std::string>();
1484 std::unique_ptr<radar::Target> target_obj;
1485
1486 const auto target_id = existing_tgt->getId();
1487 const auto name = j.value("name", existing_tgt->getName());
1488 unsigned seed = existing_tgt->getSeed();
1489
1490 if (rcs_type == "isotropic")
1491 {
1492 target_obj = radar::createIsoTarget(plat, name, rcs_json.value("value", 1.0), seed, target_id);
1493 }
1494 else if (rcs_type == "file")
1495 {
1496 const auto filename = rcs_json.value("filename", "");
1497 target_obj = radar::createFileTarget(plat, name, filename, seed, target_id);
1498 }
1499 else
1500 {
1501 throw std::runtime_error("Unsupported target RCS type: " + rcs_type);
1502 }
1503
1504 if (j.contains("model"))
1505 {
1506 const auto& model_json = j.at("model");
1507 const auto model_type = model_json.at("type").get<std::string>();
1508 if (model_type == "chisquare" || model_type == "gamma")
1509 {
1510 auto model =
1511 std::make_unique<radar::RcsChiSquare>(target_obj->getRngEngine(), model_json.value("k", 1.0));
1512 target_obj->setFluctuationModel(std::move(model));
1513 }
1514 else if (model_type == "constant")
1515 {
1516 target_obj->setFluctuationModel(std::make_unique<radar::RcsConst>());
1517 }
1518 }
1519
1520 world.replace(std::move(target_obj));
1521 }
Platform * getPlatform() const noexcept
Retrieves the associated platform of the object.
Definition object.h:65
unsigned getSeed() const noexcept
Gets the initial seed used for the target's RNG.
Definition target.h:174
SimId getId() const noexcept
Gets the unique ID of the target.
Definition target.h:153
std::unique_ptr< Target > createIsoTarget(Platform *platform, std::string name, RealType rcs, unsigned seed, const SimId id=0)
Creates an isotropic target.
Definition target.h:282
std::unique_ptr< Target > createFileTarget(Platform *platform, std::string name, const std::string &filename, unsigned seed, const SimId id=0)
Creates a file-based target.
Definition target.h:297

References radar::createFileTarget(), radar::createIsoTarget(), radar::Target::getId(), radar::Object::getName(), radar::Object::getPlatform(), radar::Target::getSeed(), and core::World::replace().

Referenced by fers_update_target_from_json().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_timing_from_json()

void serial::update_timing_from_json ( const nlohmann::json &  j,
core::World world,
const SimId  id 
)

Updates a timing source from JSON without full context recreation.

Definition at line 1523 of file json_serializer.cpp.

1524 {
1525 auto* existing = world.findTiming(id);
1526 if (existing == nullptr)
1527 {
1528 throw std::runtime_error("Timing ID " + std::to_string(id) + " not found.");
1529 }
1530
1531 auto patched = j;
1532 if (!patched.contains("name"))
1533 {
1534 patched["name"] = existing->getName();
1535 }
1536
1537 world.replace(parse_timing_from_json(patched, id));
1538 }
std::unique_ptr< timing::PrototypeTiming > parse_timing_from_json(const nlohmann::json &j, const SimId id)
Parses a timing prototype from JSON.

References core::World::findTiming(), parse_timing_from_json(), and core::World::replace().

Referenced by fers_update_timing_from_json().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_transmitter_from_json()

void serial::update_transmitter_from_json ( const nlohmann::json &  j,
radar::Transmitter tx,
core::World world,
std::mt19937 &   
)

Updates a transmitter from JSON without full context recreation.

Definition at line 1287 of file json_serializer.cpp.

1289 {
1290 if (j.contains("name"))
1291 tx->setName(j.at("name").get<std::string>());
1292
1293 if (j.contains("pulsed_mode"))
1294 {
1296 tx->setPrf(j.at("pulsed_mode").value("prf", 0.0));
1297 }
1298 else if (j.contains("cw_mode"))
1299 {
1301 }
1302
1303 if (j.contains("waveform"))
1304 {
1305 auto id = parse_json_id(j, "waveform", "Transmitter");
1306 auto* wf = world.findWaveform(id);
1307 if (wf == nullptr)
1308 throw std::runtime_error("Waveform ID " + std::to_string(id) + " not found.");
1309 tx->setWave(wf);
1310 }
1311
1312 if (j.contains("antenna"))
1313 {
1314 auto id = parse_json_id(j, "antenna", "Transmitter");
1315 auto* ant = world.findAntenna(id);
1316 if (ant == nullptr)
1317 throw std::runtime_error("Antenna ID " + std::to_string(id) + " not found.");
1318 tx->setAntenna(ant);
1319 }
1320
1321 if (j.contains("timing"))
1322 {
1323 auto timing_id = parse_json_id(j, "timing", "Transmitter");
1324 if (auto* const timing_proto = world.findTiming(timing_id))
1325 {
1326 unsigned seed = tx->getTiming() ? tx->getTiming()->getSeed() : 0;
1327 auto timing = std::make_shared<timing::Timing>(timing_proto->getName(), seed, timing_proto->getId());
1328 timing->initializeModel(timing_proto);
1329 tx->setTiming(timing);
1330 }
1331 else
1332 {
1333 throw std::runtime_error("Timing ID " + std::to_string(timing_id) + " not found.");
1334 }
1335 }
1336 if (j.contains("schedule"))
1337 {
1338 auto raw = j.at("schedule").get<std::vector<radar::SchedulePeriod>>();
1339 RealType pri = 0.0;
1341 pri = 1.0 / tx->getPrf();
1342 tx->setSchedule(radar::processRawSchedule(std::move(raw), tx->getName(),
1344 }
1345 }
fers_signal::RadarSignal * findWaveform(const SimId id)
Finds a radar signal by ID.
Definition world.cpp:76
void setWave(fers_signal::RadarSignal *pulse) noexcept
Sets the radar signal wave to be transmitted.
Definition transmitter.h:99
void setMode(OperationMode mode) noexcept
Sets the operational mode of the transmitter.
Definition transmitter.h:92
void setPrf(RealType mprf) noexcept
Sets the pulse repetition frequency (PRF) of the transmitter.

References radar::CW_MODE, core::World::findAntenna(), core::World::findTiming(), core::World::findWaveform(), radar::Transmitter::getMode(), radar::Object::getName(), radar::Transmitter::getPrf(), radar::Radar::getTiming(), radar::processRawSchedule(), radar::PULSED_MODE, radar::Radar::setAntenna(), radar::Transmitter::setMode(), radar::Object::setName(), radar::Transmitter::setPrf(), radar::Transmitter::setSchedule(), radar::Radar::setTiming(), and radar::Transmitter::setWave().

Referenced by fers_update_transmitter_from_json(), and update_monostatic_from_json().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ world_to_json()

nlohmann::json serial::world_to_json ( const core::World world)

Serializes the entire simulation world into a nlohmann::json object.

This function traverses the core::World object model and constructs a JSON representation. It is designed to produce a format that is convenient for the frontend to consume. This involves translating internal data formats (e.g., angles in radians) to a more UI-friendly format (e.g., compass degrees) and restructuring complex object relationships (like monostatic radars) into simpler representations.

Parameters
worldThe world object to serialize.
Returns
A nlohmann::json object representing the world.

Definition at line 1540 of file json_serializer.cpp.

1541 {
1542 nlohmann::json sim_json;
1543
1544 sim_json["name"] = params::params.simulation_name;
1545 sim_json["parameters"] = params::params;
1546
1547 sim_json["waveforms"] = nlohmann::json::array();
1548 for (const auto& waveform : world.getWaveforms() | std::views::values)
1549 {
1550 sim_json["waveforms"].push_back(*waveform);
1551 }
1552
1553 sim_json["antennas"] = nlohmann::json::array();
1554 for (const auto& antenna : world.getAntennas() | std::views::values)
1555 {
1556 sim_json["antennas"].push_back(*antenna);
1557 }
1558
1559 sim_json["timings"] = nlohmann::json::array();
1560 for (const auto& timing : world.getTimings() | std::views::values)
1561 {
1562 sim_json["timings"].push_back(*timing);
1563 }
1564
1565 sim_json["platforms"] = nlohmann::json::array();
1566 for (const auto& p : world.getPlatforms())
1567 {
1568 sim_json["platforms"].push_back(serialize_platform(p.get(), world));
1569 }
1570
1571 return {{"simulation", sim_json}};
1572 }
std::string simulation_name
The name of the simulation, from the XML.
Definition parameters.h:74

References core::World::getAntennas(), core::World::getPlatforms(), core::World::getTimings(), core::World::getWaveforms(), params::params, and params::Parameters::simulation_name.

Referenced by fers_get_scenario_as_json().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ world_to_xml_string()

std::string serial::world_to_xml_string ( const core::World world)

Serializes the entire simulation world into an XML formatted string.

This function serves as the reverse of the XML parser. It is essential for allowing users to modify a scenario in a UI and then export their changes back into a valid FERS XML file that can be used by the CLI or shared. It iterates through the in-memory core::World object and reconstructs the corresponding XML structure.

Parameters
worldThe world object to serialize.
Returns
A string containing the XML representation of the world.

Definition at line 26 of file xml_serializer.cpp.

27 {
28 XmlDocument doc;
29 xmlNodePtr sim_node = xmlNewNode(nullptr, reinterpret_cast<const xmlChar*>("simulation"));
30 XmlElement root(sim_node);
31 doc.setRootElement(root);
32
33 const auto& p = params::params;
34
35 if (!p.simulation_name.empty())
36 {
37 root.setAttribute("name", p.simulation_name);
38 }
39 else
40 {
41 root.setAttribute("name", "FERS Scenario");
42 }
43
44 const XmlElement params_elem = root.addChild("parameters");
45 xml_serializer_utils::serializeParameters(params_elem, p);
46
47 for (const auto& waveform : world.getWaveforms() | std::views::values)
48 {
49 XmlElement waveform_elem = root.addChild("waveform");
50 xml_serializer_utils::serializeWaveform(*waveform, waveform_elem);
51 }
52 for (const auto& timing : world.getTimings() | std::views::values)
53 {
54 XmlElement timing_elem = root.addChild("timing");
55 xml_serializer_utils::serializeTiming(*timing, timing_elem);
56 }
57 for (const auto& antenna : world.getAntennas() | std::views::values)
58 {
59 XmlElement antenna_elem = root.addChild("antenna");
60 xml_serializer_utils::serializeAntenna(*antenna, antenna_elem);
61 }
62 for (const auto& platform : world.getPlatforms())
63 {
64 XmlElement plat_elem = root.addChild("platform");
65 xml_serializer_utils::serializePlatform(*platform, world, plat_elem);
66 }
67
68 return doc.dumpToString();
69 }
void setRootElement(const XmlElement &root) const
Set the root element of the document.
std::string dumpToString() const
Dumps the document to a string.
Class representing a node in an XML document.
XmlElement addChild(const std::string_view name) const noexcept
Add a child element to the current node.

References XmlElement::addChild(), XmlDocument::dumpToString(), core::World::getAntennas(), core::World::getPlatforms(), core::World::getTimings(), core::World::getWaveforms(), params::params, serial::xml_serializer_utils::serializeAntenna(), serial::xml_serializer_utils::serializeParameters(), serial::xml_serializer_utils::serializePlatform(), serial::xml_serializer_utils::serializeTiming(), serial::xml_serializer_utils::serializeWaveform(), XmlElement::setAttribute(), and XmlDocument::setRootElement().

Referenced by fers_get_scenario_as_xml().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writeOutputFileMetadataAttributes()

void serial::writeOutputFileMetadataAttributes ( HighFive::File &  file,
const core::OutputFileMetadata metadata 
)

Writes additive FERS output metadata attributes to an open HDF5 file.

The caller must hold hdf5_global_mutex.

Definition at line 31 of file hdf5_handler.cpp.

32 {
33 file.createAttribute("fers_metadata_schema_version", 1U);
34 file.createAttribute("fers_metadata_json", core::outputFileMetadataToJsonString(metadata));
35 file.createAttribute("receiver_id", static_cast<unsigned long long>(metadata.receiver_id));
36 file.createAttribute("receiver_name", metadata.receiver_name);
37 file.createAttribute("data_mode", metadata.mode);
38 file.createAttribute("total_samples", static_cast<unsigned long long>(metadata.total_samples));
39 file.createAttribute("sample_start", static_cast<unsigned long long>(metadata.sample_start));
40 file.createAttribute("sample_end_exclusive", static_cast<unsigned long long>(metadata.sample_end_exclusive));
41 }
std::string outputFileMetadataToJsonString(const OutputFileMetadata &metadata)
std::uint64_t sample_end_exclusive

References core::OutputFileMetadata::mode, core::outputFileMetadataToJsonString(), core::OutputFileMetadata::receiver_id, core::OutputFileMetadata::receiver_name, core::OutputFileMetadata::sample_end_exclusive, core::OutputFileMetadata::sample_start, and core::OutputFileMetadata::total_samples.

Referenced by processing::pipeline::exportCwToHdf5(), and processing::runPulsedFinalizer().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ hdf5_global_mutex

std::mutex serial::hdf5_global_mutex

Global mutex to protect all HDF5 C-library calls, which are not thread-safe.

Definition at line 29 of file hdf5_handler.cpp.

Referenced by addChunkToFile(), processing::pipeline::exportCwToHdf5(), readPattern(), readPulseData(), and processing::runPulsedFinalizer().