19#include <highfive/highfive.hpp>
38 if (value.has_value())
40 file.createAttribute(name, *value);
46 const std::optional<T>& value)
48 if (value.has_value())
50 file.createAttribute(name,
static_cast<unsigned long long>(*value));
56 file.createAttribute(
"fers_metadata_schema_version", 1U);
58 file.createAttribute(
"receiver_id",
static_cast<unsigned long long>(metadata.
receiver_id));
60 file.createAttribute(
"data_mode", metadata.
mode);
65 file.createAttribute(
"total_samples",
static_cast<unsigned long long>(metadata.
total_samples));
66 file.createAttribute(
"sample_start",
static_cast<unsigned long long>(metadata.
sample_start));
67 file.createAttribute(
"sample_end_exclusive",
69 file.createAttribute(
"streaming_segment_count",
71 file.createAttribute(
"fmcw_source_count",
static_cast<unsigned long long>(metadata.
fmcw_sources.size()));
158 if (
segment.first_chirp_start_time.has_value())
162 if (
segment.emitted_chirp_count.has_value())
165 static_cast<unsigned long long>(*
segment.emitted_chirp_count));
167 if (
segment.first_triangle_start_time.has_value())
171 if (
segment.emitted_triangle_count.has_value())
174 static_cast<unsigned long long>(*
segment.emitted_triangle_count));
179 auto attr =
file.createAttribute<
RealType>(
"streaming_first_chirp_start_time",
185 auto attr =
file.createAttribute<
unsigned long long>(
191 auto attr =
file.createAttribute<
RealType>(
"streaming_first_triangle_start_time",
197 auto attr =
file.createAttribute<
unsigned long long>(
205 if (!metadata.
fmcw.has_value())
226 if (!std::filesystem::exists(name))
228 LOG(Level::FATAL,
"File '{}' not found", name);
229 throw std::runtime_error(
"File " + name +
" not found.");
232 LOG(Level::TRACE,
"Opening file '{}'", name);
233 const HighFive::File
file(name, HighFive::File::ReadOnly);
251 LOG(Level::TRACE,
"Reading dataset 'I' from file '{}'", name);
256 LOG(Level::TRACE,
"Reading dataset 'Q' from file '{}'", name);
259 LOG(Level::FATAL,
"Dataset 'Q' is not the same size as dataset 'I' in file '{}'", name);
260 throw std::runtime_error(R
"(Dataset "Q" is not the same size as dataset "I" in file )" + name);
264 for (
size_t i = 0; i <
size; ++i)
268 LOG(Level::TRACE,
"Read dataset successfully");
276 const std::size_t
size =
data.size();
278 const std::string
base_chunk_name =
"chunk_" + std::format(
"{:06}", count);
282 std::vector<RealType> i(
size), q(
size);
283 std::ranges::transform(
data, i.begin(), [](
const ComplexType&
c) { return c.real(); });
284 std::ranges::transform(
data, q.begin(), [](
const ComplexType&
c) { return c.imag(); });
294 catch (
const HighFive::Exception&
err)
296 LOG(Level::FATAL,
"Error while writing data to HDF5 file: {}",
err.what());
297 throw std::runtime_error(
"Error while writing data to HDF5 file: " +
chunkName +
" - " +
err.what());
306 dataset.createAttribute(
"time", time);
308 dataset.createAttribute(
"fullscale", fullscale);
309 if (metadata !=
nullptr)
312 dataset.createAttribute(
"sample_count",
static_cast<unsigned long long>(metadata->
sample_count));
313 dataset.createAttribute(
"sample_start",
static_cast<unsigned long long>(metadata->
sample_start));
314 dataset.createAttribute(
"sample_end_exclusive",
318 catch (
const HighFive::Exception&
err)
320 LOG(Level::FATAL,
"Error while setting attributes on chunk: {}",
err.what());
321 throw std::runtime_error(
"Error while setting attributes on chunk: " +
chunkName +
" - " +
err.what());
337 LOG(Level::TRACE,
"Reading dataset '{}' from file '{}'",
datasetName, name);
338 const HighFive::File
file(name, HighFive::File::ReadOnly);
345 if (
dims.size() != 2)
347 LOG(Level::FATAL,
"Invalid dataset dimensions for '{}' in file '{}'",
datasetName, name);
348 throw std::runtime_error(
349 std::format(R
"(Invalid dataset dimensions for "{}" in file "{}")", datasetName, name));
352 LOG(Level::TRACE, "Reading dataset with dimensions {}x{}",
dims[0],
dims[1]);
354 std::vector
data(
dims[0], std::vector<RealType>(
dims[1]));
357 LOG(Level::TRACE,
"Read dataset successfully");
361 catch (
const HighFive::Exception&
err)
363 LOG(Level::FATAL,
"Error handling HDF5 file: {}",
err.what());
364 throw std::runtime_error(
"Error handling HDF5 file: " + std::string(
err.what()));
double RealType
Type for real numbers.
std::complex< RealType > ComplexType
Type for complex numbers.
Header file for HDF5 data export and import functions.
Header file for the logging system.
std::string outputFileMetadataToJsonString(const OutputFileMetadata &metadata)
Serializes one output-file metadata entry to JSON.
RealType rate() noexcept
Get the rendering sample rate.
std::mutex hdf5_global_mutex
Global mutex to protect all HDF5 C-library calls, which are not thread-safe.
void writeOutputFileMetadataAttributes(HighFive::File &file, const core::OutputFileMetadata &metadata)
Writes additive FERS output metadata attributes to an open HDF5 file.
void addChunkToFile(HighFive::File &file, const std::vector< ComplexType > &data, const RealType time, const RealType fullscale, const unsigned count, const core::PulseChunkMetadata *metadata)
Adds a chunk of data to an HDF5 file.
void readPulseData(const std::string &name, std::vector< ComplexType > &data)
Reads pulse data from an HDF5 file.
std::vector< std::vector< RealType > > readPattern(const std::string &name, const std::string &datasetName)
Reads a 2D antenna gain pattern from the named dataset.
Defines the Parameters struct and provides methods for managing simulation parameters.