mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 22:10:05 +00:00
776 lines
24 KiB
C++
776 lines
24 KiB
C++
#include <scwx/wsr88d/rda/digital_radar_data_generic.hpp>
|
|
#include <scwx/util/logger.hpp>
|
|
|
|
namespace scwx
|
|
{
|
|
namespace wsr88d
|
|
{
|
|
namespace rda
|
|
{
|
|
|
|
static const std::string logPrefix_ =
|
|
"scwx::wsr88d::rda::digital_radar_data_generic";
|
|
static const auto logger_ = util::Logger::Create(logPrefix_);
|
|
|
|
static const std::unordered_map<std::string, DataBlockType> strToDataBlock_ {
|
|
{"VOL", DataBlockType::Volume},
|
|
{"ELV", DataBlockType::Elevation},
|
|
{"RAD", DataBlockType::Radial},
|
|
{"REF", DataBlockType::MomentRef},
|
|
{"VEL", DataBlockType::MomentVel},
|
|
{"SW ", DataBlockType::MomentSw},
|
|
{"ZDR", DataBlockType::MomentZdr},
|
|
{"PHI", DataBlockType::MomentPhi},
|
|
{"RHO", DataBlockType::MomentRho},
|
|
{"CFP", DataBlockType::MomentCfp}};
|
|
|
|
class DigitalRadarDataGeneric::DataBlock::Impl
|
|
{
|
|
public:
|
|
explicit Impl(const std::string& dataBlockType,
|
|
const std::string& dataName) :
|
|
dataBlockType_ {dataBlockType}, dataName_ {dataName}
|
|
{
|
|
}
|
|
|
|
std::string dataBlockType_;
|
|
std::string dataName_;
|
|
};
|
|
|
|
DigitalRadarDataGeneric::DataBlock::DataBlock(const std::string& dataBlockType,
|
|
const std::string& dataName) :
|
|
p(std::make_unique<Impl>(dataBlockType, dataName))
|
|
{
|
|
}
|
|
DigitalRadarDataGeneric::DataBlock::~DataBlock() = default;
|
|
|
|
DigitalRadarDataGeneric::DataBlock::DataBlock(DataBlock&&) noexcept = default;
|
|
DigitalRadarDataGeneric::DataBlock&
|
|
DigitalRadarDataGeneric::DataBlock::operator=(DataBlock&&) noexcept = default;
|
|
|
|
class DigitalRadarDataGeneric::MomentDataBlock::Impl
|
|
{
|
|
public:
|
|
explicit Impl() {}
|
|
|
|
std::uint16_t numberOfDataMomentGates_ {0};
|
|
std::int16_t dataMomentRange_ {0};
|
|
std::uint16_t dataMomentRangeSampleInterval_ {0};
|
|
std::uint16_t tover_ {0};
|
|
std::int16_t snrThreshold_ {0};
|
|
std::uint8_t controlFlags_ {0};
|
|
std::uint8_t dataWordSize_ {0};
|
|
float scale_ {0.0f};
|
|
float offset_ {0.0f};
|
|
|
|
std::vector<std::uint8_t> momentGates8_ {};
|
|
std::vector<std::uint16_t> momentGates16_ {};
|
|
};
|
|
|
|
DigitalRadarDataGeneric::MomentDataBlock::MomentDataBlock(
|
|
const std::string& dataBlockType, const std::string& dataName) :
|
|
DataBlock(dataBlockType, dataName), p(std::make_unique<Impl>())
|
|
{
|
|
}
|
|
DigitalRadarDataGeneric::MomentDataBlock::~MomentDataBlock() = default;
|
|
|
|
DigitalRadarDataGeneric::MomentDataBlock::MomentDataBlock(
|
|
MomentDataBlock&&) noexcept = default;
|
|
DigitalRadarDataGeneric::MomentDataBlock&
|
|
DigitalRadarDataGeneric::MomentDataBlock::operator=(
|
|
MomentDataBlock&&) noexcept = default;
|
|
|
|
std::uint16_t
|
|
DigitalRadarDataGeneric::MomentDataBlock::number_of_data_moment_gates() const
|
|
{
|
|
return p->numberOfDataMomentGates_;
|
|
}
|
|
|
|
units::kilometers<float>
|
|
DigitalRadarDataGeneric::MomentDataBlock::data_moment_range() const
|
|
{
|
|
return units::kilometers<float> {p->dataMomentRange_ * 0.001f};
|
|
}
|
|
|
|
std::int16_t
|
|
DigitalRadarDataGeneric::MomentDataBlock::data_moment_range_raw() const
|
|
{
|
|
return p->dataMomentRange_;
|
|
}
|
|
|
|
units::kilometers<float>
|
|
DigitalRadarDataGeneric::MomentDataBlock::data_moment_range_sample_interval()
|
|
const
|
|
{
|
|
return units::kilometers<float> {p->dataMomentRangeSampleInterval_ * 0.001f};
|
|
}
|
|
|
|
std::uint16_t DigitalRadarDataGeneric::MomentDataBlock::
|
|
data_moment_range_sample_interval_raw() const
|
|
{
|
|
return p->dataMomentRangeSampleInterval_;
|
|
}
|
|
|
|
float DigitalRadarDataGeneric::MomentDataBlock::snr_threshold() const
|
|
{
|
|
return p->snrThreshold_ * 0.1f;
|
|
}
|
|
|
|
std::int16_t DigitalRadarDataGeneric::MomentDataBlock::snr_threshold_raw() const
|
|
{
|
|
return p->snrThreshold_;
|
|
}
|
|
|
|
std::uint8_t DigitalRadarDataGeneric::MomentDataBlock::data_word_size() const
|
|
{
|
|
return p->dataWordSize_;
|
|
}
|
|
|
|
float DigitalRadarDataGeneric::MomentDataBlock::scale() const
|
|
{
|
|
return p->scale_;
|
|
}
|
|
|
|
float DigitalRadarDataGeneric::MomentDataBlock::offset() const
|
|
{
|
|
return p->offset_;
|
|
}
|
|
|
|
const void* DigitalRadarDataGeneric::MomentDataBlock::data_moments() const
|
|
{
|
|
const void* dataMoments;
|
|
|
|
switch (p->dataWordSize_)
|
|
{
|
|
case 8:
|
|
dataMoments = p->momentGates8_.data();
|
|
break;
|
|
case 16:
|
|
dataMoments = p->momentGates16_.data();
|
|
break;
|
|
default:
|
|
dataMoments = nullptr;
|
|
break;
|
|
}
|
|
|
|
return dataMoments;
|
|
}
|
|
|
|
std::shared_ptr<DigitalRadarDataGeneric::MomentDataBlock>
|
|
DigitalRadarDataGeneric::MomentDataBlock::Create(
|
|
const std::string& dataBlockType,
|
|
const std::string& dataName,
|
|
std::istream& is)
|
|
{
|
|
std::shared_ptr<MomentDataBlock> p =
|
|
std::make_shared<MomentDataBlock>(dataBlockType, dataName);
|
|
|
|
if (!p->Parse(is))
|
|
{
|
|
p.reset();
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
bool DigitalRadarDataGeneric::MomentDataBlock::Parse(std::istream& is)
|
|
{
|
|
bool dataBlockValid = true;
|
|
|
|
is.seekg(4, std::ios_base::cur); // 4-7
|
|
is.read(reinterpret_cast<char*>(&p->numberOfDataMomentGates_), 2); // 8-9
|
|
is.read(reinterpret_cast<char*>(&p->dataMomentRange_), 2); // 10-11
|
|
is.read(reinterpret_cast<char*>(&p->dataMomentRangeSampleInterval_),
|
|
2); // 12-13
|
|
is.read(reinterpret_cast<char*>(&p->tover_), 2); // 14-15
|
|
is.read(reinterpret_cast<char*>(&p->snrThreshold_), 2); // 16-17
|
|
is.read(reinterpret_cast<char*>(&p->controlFlags_), 1); // 18
|
|
is.read(reinterpret_cast<char*>(&p->dataWordSize_), 1); // 19
|
|
is.read(reinterpret_cast<char*>(&p->scale_), 4); // 20-23
|
|
is.read(reinterpret_cast<char*>(&p->offset_), 4); // 24-27
|
|
|
|
p->numberOfDataMomentGates_ = ntohs(p->numberOfDataMomentGates_);
|
|
p->dataMomentRange_ = ntohs(p->dataMomentRange_);
|
|
p->dataMomentRangeSampleInterval_ = ntohs(p->dataMomentRangeSampleInterval_);
|
|
p->tover_ = ntohs(p->tover_);
|
|
p->snrThreshold_ = ntohs(p->snrThreshold_);
|
|
p->scale_ = awips::Message::SwapFloat(p->scale_);
|
|
p->offset_ = awips::Message::SwapFloat(p->offset_);
|
|
|
|
if (p->numberOfDataMomentGates_ <= 1840)
|
|
{
|
|
if (p->dataWordSize_ == 8)
|
|
{
|
|
p->momentGates8_.resize(p->numberOfDataMomentGates_);
|
|
is.read(reinterpret_cast<char*>(p->momentGates8_.data()),
|
|
p->numberOfDataMomentGates_);
|
|
}
|
|
else if (p->dataWordSize_ == 16)
|
|
{
|
|
p->momentGates16_.resize(p->numberOfDataMomentGates_);
|
|
is.read(reinterpret_cast<char*>(p->momentGates16_.data()),
|
|
p->numberOfDataMomentGates_ * 2);
|
|
awips::Message::SwapVector(p->momentGates16_);
|
|
}
|
|
else
|
|
{
|
|
logger_->warn("Invalid data word size: {}", p->dataWordSize_);
|
|
dataBlockValid = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
logger_->warn("Invalid number of data moment gates: {}",
|
|
p->numberOfDataMomentGates_);
|
|
dataBlockValid = false;
|
|
}
|
|
|
|
return dataBlockValid;
|
|
}
|
|
|
|
class DigitalRadarDataGeneric::VolumeDataBlock::Impl
|
|
{
|
|
public:
|
|
explicit Impl() {}
|
|
|
|
std::uint16_t lrtup_ {0};
|
|
std::uint8_t versionNumberMajor_ {0};
|
|
std::uint8_t versionNumberMinor_ {0};
|
|
float latitude_ {0.0f};
|
|
float longitude_ {0.0f};
|
|
std::int16_t siteHeight_ {0};
|
|
std::uint16_t feedhornHeight_ {0};
|
|
float calibrationConstant_ {0.0f};
|
|
float horizontaShvTxPower_ {0.0f};
|
|
float verticalShvTxPower_ {0.0f};
|
|
float systemDifferentialReflectivity_ {0.0f};
|
|
float initialSystemDifferentialPhase_ {0.0f};
|
|
std::uint16_t volumeCoveragePatternNumber_ {0};
|
|
std::uint16_t processingStatus_ {0};
|
|
};
|
|
|
|
DigitalRadarDataGeneric::VolumeDataBlock::VolumeDataBlock(
|
|
const std::string& dataBlockType, const std::string& dataName) :
|
|
DataBlock(dataBlockType, dataName), p(std::make_unique<Impl>())
|
|
{
|
|
}
|
|
DigitalRadarDataGeneric::VolumeDataBlock::~VolumeDataBlock() = default;
|
|
|
|
DigitalRadarDataGeneric::VolumeDataBlock::VolumeDataBlock(
|
|
VolumeDataBlock&&) noexcept = default;
|
|
DigitalRadarDataGeneric::VolumeDataBlock&
|
|
DigitalRadarDataGeneric::VolumeDataBlock::operator=(
|
|
VolumeDataBlock&&) noexcept = default;
|
|
|
|
float DigitalRadarDataGeneric::VolumeDataBlock::latitude() const
|
|
{
|
|
return p->latitude_;
|
|
}
|
|
|
|
float DigitalRadarDataGeneric::VolumeDataBlock::longitude() const
|
|
{
|
|
return p->longitude_;
|
|
}
|
|
|
|
std::uint16_t
|
|
DigitalRadarDataGeneric::VolumeDataBlock::volume_coverage_pattern_number() const
|
|
{
|
|
return p->volumeCoveragePatternNumber_;
|
|
}
|
|
|
|
std::shared_ptr<DigitalRadarDataGeneric::VolumeDataBlock>
|
|
DigitalRadarDataGeneric::VolumeDataBlock::Create(
|
|
const std::string& dataBlockType,
|
|
const std::string& dataName,
|
|
std::istream& is)
|
|
{
|
|
std::shared_ptr<VolumeDataBlock> p =
|
|
std::make_shared<VolumeDataBlock>(dataBlockType, dataName);
|
|
|
|
if (!p->Parse(is))
|
|
{
|
|
p.reset();
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
bool DigitalRadarDataGeneric::VolumeDataBlock::Parse(std::istream& is)
|
|
{
|
|
bool dataBlockValid = true;
|
|
|
|
is.read(reinterpret_cast<char*>(&p->lrtup_), 2); // 4-5
|
|
is.read(reinterpret_cast<char*>(&p->versionNumberMajor_), 1); // 6
|
|
is.read(reinterpret_cast<char*>(&p->versionNumberMinor_), 1); // 7
|
|
is.read(reinterpret_cast<char*>(&p->latitude_), 4); // 8-11
|
|
is.read(reinterpret_cast<char*>(&p->longitude_), 4); // 12-15
|
|
is.read(reinterpret_cast<char*>(&p->siteHeight_), 2); // 16-17
|
|
is.read(reinterpret_cast<char*>(&p->feedhornHeight_), 2); // 18-19
|
|
is.read(reinterpret_cast<char*>(&p->calibrationConstant_), 4); // 20-23
|
|
is.read(reinterpret_cast<char*>(&p->horizontaShvTxPower_), 4); // 24-27
|
|
is.read(reinterpret_cast<char*>(&p->verticalShvTxPower_), 4); // 28-31
|
|
is.read(reinterpret_cast<char*>(&p->systemDifferentialReflectivity_),
|
|
4); // 32-35
|
|
is.read(reinterpret_cast<char*>(&p->initialSystemDifferentialPhase_),
|
|
4); // 36-39
|
|
is.read(reinterpret_cast<char*>(&p->volumeCoveragePatternNumber_),
|
|
2); // 40-41
|
|
is.read(reinterpret_cast<char*>(&p->processingStatus_), 2); // 42-43
|
|
|
|
p->lrtup_ = ntohs(p->lrtup_);
|
|
p->latitude_ = awips::Message::SwapFloat(p->latitude_);
|
|
p->longitude_ = awips::Message::SwapFloat(p->longitude_);
|
|
p->siteHeight_ = ntohs(p->siteHeight_);
|
|
p->feedhornHeight_ = ntohs(p->feedhornHeight_);
|
|
p->calibrationConstant_ = awips::Message::SwapFloat(p->calibrationConstant_);
|
|
p->horizontaShvTxPower_ = awips::Message::SwapFloat(p->horizontaShvTxPower_);
|
|
p->verticalShvTxPower_ = awips::Message::SwapFloat(p->verticalShvTxPower_);
|
|
p->systemDifferentialReflectivity_ =
|
|
awips::Message::SwapFloat(p->systemDifferentialReflectivity_);
|
|
p->initialSystemDifferentialPhase_ =
|
|
awips::Message::SwapFloat(p->initialSystemDifferentialPhase_);
|
|
p->volumeCoveragePatternNumber_ = ntohs(p->volumeCoveragePatternNumber_);
|
|
p->processingStatus_ = ntohs(p->processingStatus_);
|
|
|
|
return dataBlockValid;
|
|
}
|
|
|
|
class DigitalRadarDataGeneric::ElevationDataBlock::Impl
|
|
{
|
|
public:
|
|
explicit Impl() {}
|
|
|
|
std::uint16_t lrtup_ {0};
|
|
std::int16_t atmos_ {0};
|
|
float calibrationConstant_ {0.0f};
|
|
};
|
|
|
|
DigitalRadarDataGeneric::ElevationDataBlock::ElevationDataBlock(
|
|
const std::string& dataBlockType, const std::string& dataName) :
|
|
DataBlock(dataBlockType, dataName), p(std::make_unique<Impl>())
|
|
{
|
|
}
|
|
DigitalRadarDataGeneric::ElevationDataBlock::~ElevationDataBlock() = default;
|
|
|
|
DigitalRadarDataGeneric::ElevationDataBlock::ElevationDataBlock(
|
|
ElevationDataBlock&&) noexcept = default;
|
|
DigitalRadarDataGeneric::ElevationDataBlock&
|
|
DigitalRadarDataGeneric::ElevationDataBlock::operator=(
|
|
ElevationDataBlock&&) noexcept = default;
|
|
|
|
std::shared_ptr<DigitalRadarDataGeneric::ElevationDataBlock>
|
|
DigitalRadarDataGeneric::ElevationDataBlock::Create(
|
|
const std::string& dataBlockType,
|
|
const std::string& dataName,
|
|
std::istream& is)
|
|
{
|
|
std::shared_ptr<ElevationDataBlock> p =
|
|
std::make_shared<ElevationDataBlock>(dataBlockType, dataName);
|
|
|
|
if (!p->Parse(is))
|
|
{
|
|
p.reset();
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
bool DigitalRadarDataGeneric::ElevationDataBlock::Parse(std::istream& is)
|
|
{
|
|
bool dataBlockValid = true;
|
|
|
|
is.read(reinterpret_cast<char*>(&p->lrtup_), 2); // 4-5
|
|
is.read(reinterpret_cast<char*>(&p->atmos_), 2); // 6-7
|
|
is.read(reinterpret_cast<char*>(&p->calibrationConstant_), 4); // 8-11
|
|
|
|
p->lrtup_ = ntohs(p->lrtup_);
|
|
p->atmos_ = ntohs(p->atmos_);
|
|
p->calibrationConstant_ = awips::Message::SwapFloat(p->calibrationConstant_);
|
|
|
|
return dataBlockValid;
|
|
}
|
|
|
|
class DigitalRadarDataGeneric::RadialDataBlock::Impl
|
|
{
|
|
public:
|
|
explicit Impl() {}
|
|
|
|
std::uint16_t lrtup_ {0};
|
|
std::uint16_t unambigiousRange_ {0};
|
|
float noiseLevelHorizontal_ {0.0f};
|
|
float noiseLevelVertical_ {0.0f};
|
|
std::uint16_t nyquistVelocity_ {0};
|
|
std::uint16_t radialFlags_ {0};
|
|
float calibrationConstantHorizontal_ {0.0f};
|
|
float calibrationConstantVertical_ {0.0f};
|
|
};
|
|
|
|
DigitalRadarDataGeneric::RadialDataBlock::RadialDataBlock(
|
|
const std::string& dataBlockType, const std::string& dataName) :
|
|
DataBlock(dataBlockType, dataName), p(std::make_unique<Impl>())
|
|
{
|
|
}
|
|
DigitalRadarDataGeneric::RadialDataBlock::~RadialDataBlock() = default;
|
|
|
|
DigitalRadarDataGeneric::RadialDataBlock::RadialDataBlock(
|
|
RadialDataBlock&&) noexcept = default;
|
|
DigitalRadarDataGeneric::RadialDataBlock&
|
|
DigitalRadarDataGeneric::RadialDataBlock::operator=(
|
|
RadialDataBlock&&) noexcept = default;
|
|
|
|
float DigitalRadarDataGeneric::RadialDataBlock::unambiguous_range() const
|
|
{
|
|
return p->unambigiousRange_ / 10.0f;
|
|
}
|
|
|
|
std::shared_ptr<DigitalRadarDataGeneric::RadialDataBlock>
|
|
DigitalRadarDataGeneric::RadialDataBlock::Create(
|
|
const std::string& dataBlockType,
|
|
const std::string& dataName,
|
|
std::istream& is)
|
|
{
|
|
std::shared_ptr<RadialDataBlock> p =
|
|
std::make_shared<RadialDataBlock>(dataBlockType, dataName);
|
|
|
|
if (!p->Parse(is))
|
|
{
|
|
p.reset();
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
bool DigitalRadarDataGeneric::RadialDataBlock::Parse(std::istream& is)
|
|
{
|
|
bool dataBlockValid = true;
|
|
|
|
is.read(reinterpret_cast<char*>(&p->lrtup_), 2); // 4-5
|
|
is.read(reinterpret_cast<char*>(&p->unambigiousRange_), 2); // 6-7
|
|
is.read(reinterpret_cast<char*>(&p->noiseLevelHorizontal_), 4); // 8-11
|
|
is.read(reinterpret_cast<char*>(&p->noiseLevelVertical_), 4); // 12-15
|
|
is.read(reinterpret_cast<char*>(&p->nyquistVelocity_), 2); // 16-17
|
|
is.read(reinterpret_cast<char*>(&p->radialFlags_), 2); // 18-19
|
|
is.read(reinterpret_cast<char*>(&p->calibrationConstantHorizontal_),
|
|
4); // 20-23
|
|
is.read(reinterpret_cast<char*>(&p->calibrationConstantVertical_),
|
|
4); // 24-27
|
|
|
|
p->lrtup_ = ntohs(p->lrtup_);
|
|
p->unambigiousRange_ = ntohs(p->unambigiousRange_);
|
|
p->noiseLevelHorizontal_ =
|
|
awips::Message::SwapFloat(p->noiseLevelHorizontal_);
|
|
p->noiseLevelVertical_ = awips::Message::SwapFloat(p->noiseLevelVertical_);
|
|
p->nyquistVelocity_ = ntohs(p->nyquistVelocity_);
|
|
p->radialFlags_ = ntohs(p->radialFlags_);
|
|
p->calibrationConstantHorizontal_ =
|
|
awips::Message::SwapFloat(p->calibrationConstantHorizontal_);
|
|
p->calibrationConstantVertical_ =
|
|
awips::Message::SwapFloat(p->calibrationConstantVertical_);
|
|
|
|
return dataBlockValid;
|
|
}
|
|
|
|
class DigitalRadarDataGeneric::Impl
|
|
{
|
|
public:
|
|
explicit Impl() {};
|
|
~Impl() = default;
|
|
|
|
std::string radarIdentifier_ {};
|
|
std::uint32_t collectionTime_ {0};
|
|
std::uint16_t modifiedJulianDate_ {0};
|
|
std::uint16_t azimuthNumber_ {0};
|
|
float azimuthAngle_ {0.0f};
|
|
std::uint8_t compressionIndicator_ {0};
|
|
std::uint16_t radialLength_ {0};
|
|
std::uint8_t azimuthResolutionSpacing_ {0};
|
|
std::uint8_t radialStatus_ {0};
|
|
std::uint8_t elevationNumber_ {0};
|
|
std::uint8_t cutSectorNumber_ {0};
|
|
float elevationAngle_ {0.0f};
|
|
std::uint8_t radialSpotBlankingStatus_ {0};
|
|
std::uint8_t azimuthIndexingMode_ {0};
|
|
std::uint16_t dataBlockCount_ {0};
|
|
std::array<std::uint32_t, 10> dataBlockPointer_ {0};
|
|
|
|
std::shared_ptr<VolumeDataBlock> volumeDataBlock_ {nullptr};
|
|
std::shared_ptr<ElevationDataBlock> elevationDataBlock_ {nullptr};
|
|
std::shared_ptr<RadialDataBlock> radialDataBlock_ {nullptr};
|
|
std::unordered_map<DataBlockType, std::shared_ptr<MomentDataBlock>>
|
|
momentDataBlock_ {};
|
|
};
|
|
|
|
DigitalRadarDataGeneric::DigitalRadarDataGeneric() :
|
|
GenericRadarData(), p(std::make_unique<Impl>())
|
|
{
|
|
}
|
|
DigitalRadarDataGeneric::~DigitalRadarDataGeneric() = default;
|
|
|
|
DigitalRadarDataGeneric::DigitalRadarDataGeneric(
|
|
DigitalRadarDataGeneric&&) noexcept = default;
|
|
DigitalRadarDataGeneric& DigitalRadarDataGeneric::operator=(
|
|
DigitalRadarDataGeneric&&) noexcept = default;
|
|
|
|
std::string DigitalRadarDataGeneric::radar_identifier() const
|
|
{
|
|
return p->radarIdentifier_;
|
|
}
|
|
|
|
std::uint32_t DigitalRadarDataGeneric::collection_time() const
|
|
{
|
|
return p->collectionTime_;
|
|
}
|
|
|
|
std::uint16_t DigitalRadarDataGeneric::modified_julian_date() const
|
|
{
|
|
return p->modifiedJulianDate_;
|
|
}
|
|
|
|
std::uint16_t DigitalRadarDataGeneric::azimuth_number() const
|
|
{
|
|
return p->azimuthNumber_;
|
|
}
|
|
|
|
units::degrees<float> DigitalRadarDataGeneric::azimuth_angle() const
|
|
{
|
|
return units::degrees<float> {p->azimuthAngle_};
|
|
}
|
|
|
|
std::uint8_t DigitalRadarDataGeneric::compression_indicator() const
|
|
{
|
|
return p->compressionIndicator_;
|
|
}
|
|
|
|
std::uint16_t DigitalRadarDataGeneric::radial_length() const
|
|
{
|
|
return p->radialLength_;
|
|
}
|
|
|
|
std::uint8_t DigitalRadarDataGeneric::azimuth_resolution_spacing() const
|
|
{
|
|
return p->azimuthResolutionSpacing_;
|
|
}
|
|
|
|
std::uint8_t DigitalRadarDataGeneric::radial_status() const
|
|
{
|
|
return p->radialStatus_;
|
|
}
|
|
|
|
std::uint16_t DigitalRadarDataGeneric::elevation_number() const
|
|
{
|
|
return p->elevationNumber_;
|
|
}
|
|
|
|
std::uint8_t DigitalRadarDataGeneric::cut_sector_number() const
|
|
{
|
|
return p->cutSectorNumber_;
|
|
}
|
|
|
|
units::degrees<float> DigitalRadarDataGeneric::elevation_angle() const
|
|
{
|
|
return units::degrees<float> {p->elevationAngle_};
|
|
}
|
|
|
|
std::uint8_t DigitalRadarDataGeneric::radial_spot_blanking_status() const
|
|
{
|
|
return p->radialSpotBlankingStatus_;
|
|
}
|
|
|
|
std::uint8_t DigitalRadarDataGeneric::azimuth_indexing_mode() const
|
|
{
|
|
return p->azimuthIndexingMode_;
|
|
}
|
|
|
|
std::uint16_t DigitalRadarDataGeneric::data_block_count() const
|
|
{
|
|
return p->dataBlockCount_;
|
|
}
|
|
|
|
std::uint16_t DigitalRadarDataGeneric::volume_coverage_pattern_number() const
|
|
{
|
|
std::uint16_t vcpNumber = 0;
|
|
|
|
if (p->volumeDataBlock_ != nullptr)
|
|
{
|
|
vcpNumber = p->volumeDataBlock_->volume_coverage_pattern_number();
|
|
}
|
|
|
|
return vcpNumber;
|
|
}
|
|
|
|
std::shared_ptr<DigitalRadarDataGeneric::ElevationDataBlock>
|
|
DigitalRadarDataGeneric::elevation_data_block() const
|
|
{
|
|
return p->elevationDataBlock_;
|
|
}
|
|
|
|
std::shared_ptr<DigitalRadarDataGeneric::RadialDataBlock>
|
|
DigitalRadarDataGeneric::radial_data_block() const
|
|
{
|
|
return p->radialDataBlock_;
|
|
}
|
|
|
|
std::shared_ptr<DigitalRadarDataGeneric::VolumeDataBlock>
|
|
DigitalRadarDataGeneric::volume_data_block() const
|
|
{
|
|
return p->volumeDataBlock_;
|
|
}
|
|
|
|
std::shared_ptr<GenericRadarData::MomentDataBlock>
|
|
DigitalRadarDataGeneric::moment_data_block(DataBlockType type) const
|
|
{
|
|
std::shared_ptr<MomentDataBlock> momentDataBlock = nullptr;
|
|
|
|
auto it = p->momentDataBlock_.find(type);
|
|
if (it != p->momentDataBlock_.end())
|
|
{
|
|
momentDataBlock = it->second;
|
|
}
|
|
|
|
return momentDataBlock;
|
|
}
|
|
|
|
bool DigitalRadarDataGeneric::Parse(std::istream& is)
|
|
{
|
|
logger_->trace("Parsing Digital Radar Data (Message Type 31)");
|
|
|
|
bool messageValid = true;
|
|
std::size_t bytesRead = 0;
|
|
|
|
std::streampos isBegin = is.tellg();
|
|
|
|
p->radarIdentifier_.resize(4);
|
|
|
|
is.read(&p->radarIdentifier_[0], 4); // 0-3
|
|
is.read(reinterpret_cast<char*>(&p->collectionTime_), 4); // 4-7
|
|
is.read(reinterpret_cast<char*>(&p->modifiedJulianDate_), 2); // 8-9
|
|
is.read(reinterpret_cast<char*>(&p->azimuthNumber_), 2); // 10-11
|
|
is.read(reinterpret_cast<char*>(&p->azimuthAngle_), 4); // 12-15
|
|
is.read(reinterpret_cast<char*>(&p->compressionIndicator_), 1); // 16
|
|
is.seekg(1, std::ios_base::cur); // 17
|
|
is.read(reinterpret_cast<char*>(&p->radialLength_), 2); // 18-19
|
|
is.read(reinterpret_cast<char*>(&p->azimuthResolutionSpacing_), 1); // 20
|
|
is.read(reinterpret_cast<char*>(&p->radialStatus_), 1); // 21
|
|
is.read(reinterpret_cast<char*>(&p->elevationNumber_), 1); // 22
|
|
is.read(reinterpret_cast<char*>(&p->cutSectorNumber_), 1); // 23
|
|
is.read(reinterpret_cast<char*>(&p->elevationAngle_), 4); // 24-27
|
|
is.read(reinterpret_cast<char*>(&p->radialSpotBlankingStatus_), 1); // 28
|
|
is.read(reinterpret_cast<char*>(&p->azimuthIndexingMode_), 1); // 29
|
|
is.read(reinterpret_cast<char*>(&p->dataBlockCount_), 2); // 30-31
|
|
|
|
p->collectionTime_ = ntohl(p->collectionTime_);
|
|
p->modifiedJulianDate_ = ntohs(p->modifiedJulianDate_);
|
|
p->azimuthNumber_ = ntohs(p->azimuthNumber_);
|
|
p->azimuthAngle_ = SwapFloat(p->azimuthAngle_);
|
|
p->radialLength_ = ntohs(p->radialLength_);
|
|
p->elevationAngle_ = SwapFloat(p->elevationAngle_);
|
|
p->dataBlockCount_ = ntohs(p->dataBlockCount_);
|
|
|
|
if (p->azimuthNumber_ < 1 || p->azimuthNumber_ > 720)
|
|
{
|
|
logger_->warn("Invalid azimuth number: {}", p->azimuthNumber_);
|
|
messageValid = false;
|
|
}
|
|
if (p->elevationNumber_ < 1 || p->elevationNumber_ > 32)
|
|
{
|
|
logger_->warn("Invalid elevation number: {}", p->elevationNumber_);
|
|
messageValid = false;
|
|
}
|
|
if (p->dataBlockCount_ < 4 || p->dataBlockCount_ > 10)
|
|
{
|
|
logger_->warn("Invalid number of data blocks: {}", p->dataBlockCount_);
|
|
messageValid = false;
|
|
}
|
|
if (p->compressionIndicator_ != 0)
|
|
{
|
|
logger_->warn("Compression not supported");
|
|
messageValid = false;
|
|
}
|
|
|
|
if (!messageValid)
|
|
{
|
|
p->dataBlockCount_ = 0;
|
|
}
|
|
|
|
is.read(reinterpret_cast<char*>(&p->dataBlockPointer_),
|
|
p->dataBlockCount_ * 4);
|
|
|
|
SwapArray(p->dataBlockPointer_, p->dataBlockCount_);
|
|
|
|
for (uint16_t b = 0; b < p->dataBlockCount_; ++b)
|
|
{
|
|
is.seekg(isBegin + std::streamoff(p->dataBlockPointer_[b]),
|
|
std::ios_base::beg);
|
|
|
|
std::string dataBlockType(1, 0);
|
|
std::string dataName(3, 0);
|
|
|
|
is.read(&dataBlockType[0], 1);
|
|
is.read(&dataName[0], 3);
|
|
|
|
DataBlockType dataBlock = DataBlockType::Unknown;
|
|
try
|
|
{
|
|
dataBlock = strToDataBlock_.at(dataName);
|
|
}
|
|
catch (const std::exception&)
|
|
{
|
|
}
|
|
|
|
switch (dataBlock)
|
|
{
|
|
case DataBlockType::Volume:
|
|
p->volumeDataBlock_ =
|
|
std::move(VolumeDataBlock::Create(dataBlockType, dataName, is));
|
|
break;
|
|
case DataBlockType::Elevation:
|
|
p->elevationDataBlock_ =
|
|
std::move(ElevationDataBlock::Create(dataBlockType, dataName, is));
|
|
break;
|
|
case DataBlockType::Radial:
|
|
p->radialDataBlock_ =
|
|
std::move(RadialDataBlock::Create(dataBlockType, dataName, is));
|
|
break;
|
|
case DataBlockType::MomentRef:
|
|
case DataBlockType::MomentVel:
|
|
case DataBlockType::MomentSw:
|
|
case DataBlockType::MomentZdr:
|
|
case DataBlockType::MomentPhi:
|
|
case DataBlockType::MomentRho:
|
|
case DataBlockType::MomentCfp:
|
|
p->momentDataBlock_[dataBlock] =
|
|
std::move(MomentDataBlock::Create(dataBlockType, dataName, is));
|
|
break;
|
|
default:
|
|
logger_->warn("Unknown data name: {}", dataName);
|
|
break;
|
|
}
|
|
}
|
|
|
|
is.seekg(isBegin, std::ios_base::beg);
|
|
if (!ValidateMessage(is, bytesRead))
|
|
{
|
|
messageValid = false;
|
|
}
|
|
|
|
return messageValid;
|
|
}
|
|
|
|
std::shared_ptr<DigitalRadarDataGeneric>
|
|
DigitalRadarDataGeneric::Create(Level2MessageHeader&& header, std::istream& is)
|
|
{
|
|
std::shared_ptr<DigitalRadarDataGeneric> message =
|
|
std::make_shared<DigitalRadarDataGeneric>();
|
|
message->set_header(std::move(header));
|
|
|
|
if (!message->Parse(is))
|
|
{
|
|
message.reset();
|
|
}
|
|
|
|
return message;
|
|
}
|
|
|
|
} // namespace rda
|
|
} // namespace wsr88d
|
|
} // namespace scwx
|