Add Level 2 Message Type 1, Digital Radar Data

This commit is contained in:
Dan Paulat 2024-01-19 23:34:59 -06:00
parent bfd7963d4c
commit 68cca50ddf
4 changed files with 422 additions and 1 deletions

View file

@ -0,0 +1,62 @@
#pragma once
#include <scwx/wsr88d/rda/level2_message.hpp>
namespace scwx
{
namespace wsr88d
{
namespace rda
{
class DigitalRadarData : public Level2Message
{
public:
explicit DigitalRadarData();
~DigitalRadarData();
DigitalRadarData(const DigitalRadarData&) = delete;
DigitalRadarData& operator=(const DigitalRadarData&) = delete;
DigitalRadarData(DigitalRadarData&&) noexcept;
DigitalRadarData& operator=(DigitalRadarData&&) noexcept;
std::uint32_t collection_time() const;
std::uint16_t modified_julian_date() const;
std::uint16_t unambiguous_range() const;
std::uint16_t azimuth_angle() const;
std::uint16_t azimuth_number() const;
std::uint16_t radial_status() const;
std::uint16_t elevation_angle() const;
std::uint16_t elevation_number() const;
std::uint16_t surveillance_range() const;
std::uint16_t doppler_range() const;
std::uint16_t surveillance_range_sample_interval() const;
std::uint16_t doppler_range_sample_interval() const;
std::uint16_t number_of_surveillance_bins() const;
std::uint16_t number_of_doppler_bins() const;
std::uint16_t cut_sector_number() const;
float calibration_constant() const;
std::uint16_t surveillance_pointer() const;
std::uint16_t velocity_pointer() const;
std::uint16_t spectral_width_pointer() const;
std::uint16_t doppler_velocity_resolution() const;
std::uint16_t volume_coverage_pattern_number() const;
std::uint16_t nyquist_velocity() const;
std::uint16_t atmos() const;
std::uint16_t tover() const;
std::uint16_t radial_spot_blanking_status() const;
bool Parse(std::istream& is);
static std::shared_ptr<DigitalRadarData> Create(Level2MessageHeader&& header,
std::istream& is);
private:
class Impl;
std::unique_ptr<Impl> p;
};
} // namespace rda
} // namespace wsr88d
} // namespace scwx

View file

@ -0,0 +1,355 @@
#include <scwx/wsr88d/rda/digital_radar_data.hpp>
#include <scwx/util/logger.hpp>
namespace scwx
{
namespace wsr88d
{
namespace rda
{
static const std::string logPrefix_ = "scwx::wsr88d::rda::digital_radar_data";
static const auto logger_ = util::Logger::Create(logPrefix_);
class DigitalRadarData::Impl
{
public:
explicit Impl() {};
~Impl() = default;
std::uint32_t collectionTime_ {};
std::uint16_t modifiedJulianDate_ {};
std::uint16_t unambiguousRange_ {};
std::uint16_t azimuthAngle_ {};
std::uint16_t azimuthNumber_ {};
std::uint16_t radialStatus_ {};
std::uint16_t elevationAngle_ {};
std::uint16_t elevationNumber_ {};
std::uint16_t surveillanceRange_ {};
std::uint16_t dopplerRange_ {};
std::uint16_t surveillanceRangeSampleInterval_ {};
std::uint16_t dopplerRangeSampleInterval_ {};
std::uint16_t numberOfSurveillanceBins_ {};
std::uint16_t numberOfDopplerBins_ {};
std::uint16_t cutSectorNumber_ {};
float calibrationConstant_ {};
std::uint16_t surveillancePointer_ {};
std::uint16_t velocityPointer_ {};
std::uint16_t spectralWidthPointer_ {};
std::uint16_t dopplerVelocityResolution_ {};
std::uint16_t vcpNumber_ {};
std::uint16_t nyquistVelocity_ {};
std::uint16_t atmos_ {};
std::uint16_t tover_ {};
std::uint16_t radialSpotBlankingStatus_ {};
std::vector<std::uint8_t> reflectivity_ {};
std::vector<std::uint8_t> dopplerVelocity_ {};
std::vector<std::uint8_t> dopplerSpectrumWidth_ {};
};
DigitalRadarData::DigitalRadarData() :
Level2Message(), p(std::make_unique<Impl>())
{
}
DigitalRadarData::~DigitalRadarData() = default;
DigitalRadarData::DigitalRadarData(DigitalRadarData&&) noexcept = default;
DigitalRadarData&
DigitalRadarData::operator=(DigitalRadarData&&) noexcept = default;
std::uint32_t DigitalRadarData::collection_time() const
{
return p->collectionTime_;
}
std::uint16_t DigitalRadarData::modified_julian_date() const
{
return p->modifiedJulianDate_;
}
std::uint16_t DigitalRadarData::unambiguous_range() const
{
return p->unambiguousRange_;
}
std::uint16_t DigitalRadarData::azimuth_angle() const
{
return p->azimuthAngle_;
}
std::uint16_t DigitalRadarData::azimuth_number() const
{
return p->azimuthNumber_;
}
std::uint16_t DigitalRadarData::radial_status() const
{
return p->radialStatus_;
}
std::uint16_t DigitalRadarData::elevation_angle() const
{
return p->elevationAngle_;
}
std::uint16_t DigitalRadarData::elevation_number() const
{
return p->elevationNumber_;
}
std::uint16_t DigitalRadarData::surveillance_range() const
{
return p->surveillanceRange_;
}
std::uint16_t DigitalRadarData::doppler_range() const
{
return p->dopplerRange_;
}
std::uint16_t DigitalRadarData::surveillance_range_sample_interval() const
{
return p->surveillanceRangeSampleInterval_;
}
std::uint16_t DigitalRadarData::doppler_range_sample_interval() const
{
return p->dopplerRangeSampleInterval_;
}
std::uint16_t DigitalRadarData::number_of_surveillance_bins() const
{
return p->numberOfSurveillanceBins_;
}
std::uint16_t DigitalRadarData::number_of_doppler_bins() const
{
return p->numberOfDopplerBins_;
}
std::uint16_t DigitalRadarData::cut_sector_number() const
{
return p->cutSectorNumber_;
}
float DigitalRadarData::calibration_constant() const
{
return p->calibrationConstant_;
}
std::uint16_t DigitalRadarData::surveillance_pointer() const
{
return p->surveillancePointer_;
}
std::uint16_t DigitalRadarData::velocity_pointer() const
{
return p->velocityPointer_;
}
std::uint16_t DigitalRadarData::spectral_width_pointer() const
{
return p->spectralWidthPointer_;
}
std::uint16_t DigitalRadarData::doppler_velocity_resolution() const
{
return p->dopplerVelocityResolution_;
}
std::uint16_t DigitalRadarData::volume_coverage_pattern_number() const
{
return p->vcpNumber_;
}
std::uint16_t DigitalRadarData::nyquist_velocity() const
{
return p->nyquistVelocity_;
}
std::uint16_t DigitalRadarData::atmos() const
{
return p->atmos_;
}
std::uint16_t DigitalRadarData::tover() const
{
return p->tover_;
}
std::uint16_t DigitalRadarData::radial_spot_blanking_status() const
{
return p->radialSpotBlankingStatus_;
}
bool DigitalRadarData::Parse(std::istream& is)
{
logger_->trace("Parsing Digital Radar Data (Message Type 1)");
bool messageValid = true;
std::size_t bytesRead = 0;
std::streampos isBegin = is.tellg();
is.read(reinterpret_cast<char*>(&p->collectionTime_), 4); // 0-3
is.read(reinterpret_cast<char*>(&p->modifiedJulianDate_), 2); // 4-5
is.read(reinterpret_cast<char*>(&p->unambiguousRange_), 2); // 6-7
is.read(reinterpret_cast<char*>(&p->azimuthAngle_), 2); // 8-9
is.read(reinterpret_cast<char*>(&p->azimuthNumber_), 2); // 10-11
is.read(reinterpret_cast<char*>(&p->radialStatus_), 2); // 12-13
is.read(reinterpret_cast<char*>(&p->elevationAngle_), 2); // 14-15
is.read(reinterpret_cast<char*>(&p->elevationNumber_), 2); // 16-17
is.read(reinterpret_cast<char*>(&p->surveillanceRange_), 2); // 18-19
is.read(reinterpret_cast<char*>(&p->dopplerRange_), 2); // 20-21
is.read(reinterpret_cast<char*>(&p->surveillanceRangeSampleInterval_),
2); // 22-23
is.read(reinterpret_cast<char*>(&p->dopplerRangeSampleInterval_),
2); // 24-25
is.read(reinterpret_cast<char*>(&p->numberOfSurveillanceBins_), 2); // 26-27
is.read(reinterpret_cast<char*>(&p->numberOfDopplerBins_), 2); // 28-29
is.read(reinterpret_cast<char*>(&p->cutSectorNumber_), 2); // 30-31
is.read(reinterpret_cast<char*>(&p->calibrationConstant_), 4); // 32-35
is.read(reinterpret_cast<char*>(&p->surveillancePointer_), 2); // 36-37
is.read(reinterpret_cast<char*>(&p->velocityPointer_), 2); // 38-39
is.read(reinterpret_cast<char*>(&p->spectralWidthPointer_), 2); // 40-41
is.read(reinterpret_cast<char*>(&p->dopplerVelocityResolution_), 2); // 42-43
is.read(reinterpret_cast<char*>(&p->vcpNumber_), 2); // 44-45
is.seekg(14, std::ios_base::cur); // 46-59
is.read(reinterpret_cast<char*>(&p->nyquistVelocity_), 2); // 60-61
is.read(reinterpret_cast<char*>(&p->atmos_), 2); // 62-63
is.read(reinterpret_cast<char*>(&p->tover_), 2); // 64-65
is.read(reinterpret_cast<char*>(&p->radialSpotBlankingStatus_), 2); // 66-67
is.seekg(32, std::ios_base::cur); // 68-99
p->collectionTime_ = ntohl(p->collectionTime_);
p->modifiedJulianDate_ = ntohs(p->modifiedJulianDate_);
p->unambiguousRange_ = ntohs(p->unambiguousRange_);
p->azimuthAngle_ = ntohs(p->azimuthAngle_);
p->azimuthNumber_ = ntohs(p->azimuthNumber_);
p->radialStatus_ = ntohs(p->radialStatus_);
p->elevationAngle_ = ntohs(p->elevationAngle_);
p->elevationNumber_ = ntohs(p->elevationNumber_);
p->surveillanceRange_ = ntohs(p->surveillanceRange_);
p->dopplerRange_ = ntohs(p->dopplerRange_);
p->surveillanceRangeSampleInterval_ =
ntohs(p->surveillanceRangeSampleInterval_);
p->dopplerRangeSampleInterval_ = ntohs(p->dopplerRangeSampleInterval_);
p->numberOfSurveillanceBins_ = ntohs(p->numberOfSurveillanceBins_);
p->numberOfDopplerBins_ = ntohs(p->numberOfDopplerBins_);
p->cutSectorNumber_ = ntohs(p->cutSectorNumber_);
p->calibrationConstant_ = SwapFloat(p->calibrationConstant_);
p->surveillancePointer_ = ntohs(p->surveillancePointer_);
p->velocityPointer_ = ntohs(p->velocityPointer_);
p->spectralWidthPointer_ = ntohs(p->spectralWidthPointer_);
p->dopplerVelocityResolution_ = ntohs(p->dopplerVelocityResolution_);
p->vcpNumber_ = ntohs(p->vcpNumber_);
p->nyquistVelocity_ = ntohs(p->nyquistVelocity_);
p->atmos_ = ntohs(p->atmos_);
p->tover_ = ntohs(p->tover_);
p->radialSpotBlankingStatus_ = ntohs(p->radialSpotBlankingStatus_);
if (p->azimuthNumber_ < 1 || p->azimuthNumber_ > 400)
{
logger_->warn("Invalid azimuth number: {}", p->azimuthNumber_);
messageValid = false;
}
if (p->elevationNumber_ < 1 || p->elevationNumber_ > 25)
{
logger_->warn("Invalid elevation number: {}", p->elevationNumber_);
messageValid = false;
}
if (p->numberOfSurveillanceBins_ > 460)
{
logger_->warn("Invalid number of surveillance bins: {}",
p->numberOfSurveillanceBins_);
messageValid = false;
}
if (p->numberOfDopplerBins_ > 920)
{
logger_->warn("Invalid number of doppler bins: {}",
p->numberOfDopplerBins_);
messageValid = false;
}
if (p->surveillancePointer_ != 0 && p->surveillancePointer_ != 100)
{
logger_->warn("Invalid surveillance pointer: {}",
p->surveillancePointer_);
messageValid = false;
}
if (p->velocityPointer_ != 0 &&
(p->velocityPointer_ < 100 || p->velocityPointer_ > 560))
{
logger_->warn("Invalid velocity pointer: {}", p->velocityPointer_);
messageValid = false;
}
if (p->spectralWidthPointer_ != 0 &&
(p->spectralWidthPointer_ < 100 || p->spectralWidthPointer_ > 1480 ||
p->spectralWidthPointer_ > data_size()))
{
logger_->warn("Invalid spectral width pointer: {}",
p->spectralWidthPointer_);
messageValid = false;
}
if (messageValid && p->surveillancePointer_ != 0)
{
is.seekg(isBegin + std::streamoff(p->surveillancePointer_),
std::ios_base::beg);
p->reflectivity_.resize(p->numberOfSurveillanceBins_);
is.read(reinterpret_cast<char*>(p->reflectivity_.data()),
p->numberOfSurveillanceBins_);
}
if (messageValid && p->velocityPointer_ != 0)
{
is.seekg(isBegin + std::streamoff(p->velocityPointer_),
std::ios_base::beg);
p->dopplerVelocity_.resize(p->numberOfDopplerBins_);
is.read(reinterpret_cast<char*>(p->dopplerVelocity_.data()),
p->numberOfDopplerBins_);
}
if (messageValid && p->spectralWidthPointer_ != 0)
{
is.seekg(isBegin + std::streamoff(p->spectralWidthPointer_),
std::ios_base::beg);
p->dopplerSpectrumWidth_.resize(p->numberOfDopplerBins_);
is.read(reinterpret_cast<char*>(p->dopplerSpectrumWidth_.data()),
p->numberOfDopplerBins_);
}
is.seekg(isBegin, std::ios_base::beg);
if (!ValidateMessage(is, bytesRead))
{
messageValid = false;
}
return messageValid;
}
std::shared_ptr<DigitalRadarData>
DigitalRadarData::Create(Level2MessageHeader&& header, std::istream& is)
{
std::shared_ptr<DigitalRadarData> message =
std::make_shared<DigitalRadarData>();
message->set_header(std::move(header));
if (!message->Parse(is))
{
message.reset();
}
return message;
}
} // namespace rda
} // namespace wsr88d
} // namespace scwx

View file

@ -4,6 +4,7 @@
#include <scwx/util/vectorbuf.hpp>
#include <scwx/wsr88d/rda/clutter_filter_bypass_map.hpp>
#include <scwx/wsr88d/rda/clutter_filter_map.hpp>
#include <scwx/wsr88d/rda/digital_radar_data.hpp>
#include <scwx/wsr88d/rda/digital_radar_data_generic.hpp>
#include <scwx/wsr88d/rda/performance_maintenance_data.hpp>
#include <scwx/wsr88d/rda/rda_adaptation_data.hpp>
@ -29,7 +30,8 @@ typedef std::function<std::shared_ptr<Level2Message>(Level2MessageHeader&&,
CreateLevel2MessageFunction;
static const std::unordered_map<unsigned int, CreateLevel2MessageFunction>
create_ {{2, RdaStatusData::Create},
create_ {{1, DigitalRadarData::Create},
{2, RdaStatusData::Create},
{3, PerformanceMaintenanceData::Create},
{5, VolumeCoveragePatternData::Create},
{13, ClutterFilterBypassMap::Create},

View file

@ -102,6 +102,7 @@ set(SRC_WSR88D source/scwx/wsr88d/ar2v_file.cpp
source/scwx/wsr88d/wsr88d_types.cpp)
set(HDR_WSR88D_RDA include/scwx/wsr88d/rda/clutter_filter_bypass_map.hpp
include/scwx/wsr88d/rda/clutter_filter_map.hpp
include/scwx/wsr88d/rda/digital_radar_data.hpp
include/scwx/wsr88d/rda/digital_radar_data_generic.hpp
include/scwx/wsr88d/rda/level2_message.hpp
include/scwx/wsr88d/rda/level2_message_factory.hpp
@ -113,6 +114,7 @@ set(HDR_WSR88D_RDA include/scwx/wsr88d/rda/clutter_filter_bypass_map.hpp
include/scwx/wsr88d/rda/volume_coverage_pattern_data.hpp)
set(SRC_WSR88D_RDA source/scwx/wsr88d/rda/clutter_filter_bypass_map.cpp
source/scwx/wsr88d/rda/clutter_filter_map.cpp
source/scwx/wsr88d/rda/digital_radar_data.cpp
source/scwx/wsr88d/rda/digital_radar_data_generic.cpp
source/scwx/wsr88d/rda/level2_message.cpp
source/scwx/wsr88d/rda/level2_message_factory.cpp