mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 12:00:04 +00:00 
			
		
		
		
	Level 2 data level function implementations
This commit is contained in:
		
							parent
							
								
									36f8f73b0f
								
							
						
					
					
						commit
						e96808d14d
					
				
					 3 changed files with 208 additions and 9 deletions
				
			
		|  | @ -468,7 +468,6 @@ void Level2ProductView::ComputeSweep() | ||||||
| 
 | 
 | ||||||
|    const uint32_t gates = momentData0->number_of_data_moment_gates(); |    const uint32_t gates = momentData0->number_of_data_moment_gates(); | ||||||
| 
 | 
 | ||||||
|    auto radialData0 = radarData0->radial_data_block(); |  | ||||||
|    auto volumeData0 = radarData0->volume_data_block(); |    auto volumeData0 = radarData0->volume_data_block(); | ||||||
|    p->latitude_     = volumeData0->latitude(); |    p->latitude_     = volumeData0->latitude(); | ||||||
|    p->longitude_    = volumeData0->longitude(); |    p->longitude_    = volumeData0->longitude(); | ||||||
|  | @ -782,26 +781,211 @@ void Level2ProductViewImpl::ComputeCoordinates( | ||||||
| std::optional<std::uint16_t> | std::optional<std::uint16_t> | ||||||
| Level2ProductView::GetBinLevel(const common::Coordinate& coordinate) const | Level2ProductView::GetBinLevel(const common::Coordinate& coordinate) const | ||||||
| { | { | ||||||
|    // TODO
 |    auto radarData     = p->elevationScan_; | ||||||
|    Q_UNUSED(coordinate); |    auto dataBlockType = p->dataBlockType_; | ||||||
|  | 
 | ||||||
|  |    if (radarData == nullptr) | ||||||
|  |    { | ||||||
|       return std::nullopt; |       return std::nullopt; | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|  |    auto         radarProductManager = radar_product_manager(); | ||||||
|  |    auto         radarSite           = radarProductManager->radar_site(); | ||||||
|  |    const double radarLatitude       = radarSite->latitude(); | ||||||
|  |    const double radarLongitude      = radarSite->longitude(); | ||||||
|  | 
 | ||||||
|  |    // Determine distance and azimuth of coordinate relative to radar location
 | ||||||
|  |    double s12;  // Distance (meters)
 | ||||||
|  |    double azi1; // Azimuth (degrees)
 | ||||||
|  |    double azi2; // Unused
 | ||||||
|  |    util::GeographicLib::DefaultGeodesic().Inverse(radarLatitude, | ||||||
|  |                                                   radarLongitude, | ||||||
|  |                                                   coordinate.latitude_, | ||||||
|  |                                                   coordinate.longitude_, | ||||||
|  |                                                   s12, | ||||||
|  |                                                   azi1, | ||||||
|  |                                                   azi2); | ||||||
|  | 
 | ||||||
|  |    if (std::isnan(azi1)) | ||||||
|  |    { | ||||||
|  |       // If a problem occurred with the geodesic inverse calculation
 | ||||||
|  |       return std::nullopt; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    // Azimuth is returned as [-180, 180) from the geodesic inverse, we need a
 | ||||||
|  |    // range of [0, 360)
 | ||||||
|  |    while (azi1 < 0.0) | ||||||
|  |    { | ||||||
|  |       azi1 += 360.0; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    // Find Radial
 | ||||||
|  |    const std::uint16_t numRadials = | ||||||
|  |       static_cast<std::uint16_t>(radarData->size()); | ||||||
|  |    auto radials = boost::irange<std::uint32_t>(0u, numRadials); | ||||||
|  | 
 | ||||||
|  |    auto radial = std::find_if( //
 | ||||||
|  |       std::execution::par_unseq, | ||||||
|  |       radials.begin(), | ||||||
|  |       radials.end(), | ||||||
|  |       [&](std::uint32_t i) | ||||||
|  |       { | ||||||
|  |          bool        found      = false; | ||||||
|  |          const float startAngle = (*radarData)[i]->azimuth_angle(); | ||||||
|  |          const float nextAngle = | ||||||
|  |             (*radarData)[(i + 1) % numRadials]->azimuth_angle(); | ||||||
|  | 
 | ||||||
|  |          if (startAngle < nextAngle) | ||||||
|  |          { | ||||||
|  |             if (startAngle <= azi1 && azi1 < nextAngle) | ||||||
|  |             { | ||||||
|  |                found = true; | ||||||
|  |             } | ||||||
|  |          } | ||||||
|  |          else | ||||||
|  |          { | ||||||
|  |             // If the bin crosses 0/360 degrees, special handling is needed
 | ||||||
|  |             if (startAngle <= azi1 || azi1 < nextAngle) | ||||||
|  |             { | ||||||
|  |                found = true; | ||||||
|  |             } | ||||||
|  |          } | ||||||
|  | 
 | ||||||
|  |          return found; | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |    if (radial == radials.end()) | ||||||
|  |    { | ||||||
|  |       // No radial was found (not likely to happen without a gap in data)
 | ||||||
|  |       return std::nullopt; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    // Compute gate interval
 | ||||||
|  |    auto momentData = (*radarData)[*radial]->moment_data_block(dataBlockType); | ||||||
|  |    const std::uint16_t dataMomentRange = momentData->data_moment_range_raw(); | ||||||
|  |    const std::uint16_t dataMomentInterval = | ||||||
|  |       momentData->data_moment_range_sample_interval_raw(); | ||||||
|  |    const std::uint16_t dataMomentIntervalH = dataMomentInterval / 2; | ||||||
|  | 
 | ||||||
|  |    // Compute gate size (number of base 250m gates per bin)
 | ||||||
|  |    const std::uint16_t gateSizeMeters = | ||||||
|  |       static_cast<std::uint16_t>(radarProductManager->gate_size()); | ||||||
|  | 
 | ||||||
|  |    // Compute gate range [startGate, endGate)
 | ||||||
|  |    const std::uint16_t startGate = | ||||||
|  |       (dataMomentRange - dataMomentIntervalH) / gateSizeMeters; | ||||||
|  |    const std::uint16_t numberOfDataMomentGates = | ||||||
|  |       momentData->number_of_data_moment_gates(); | ||||||
|  | 
 | ||||||
|  |    const std::uint16_t gate = s12 / dataMomentInterval - startGate; | ||||||
|  | 
 | ||||||
|  |    if (gate > numberOfDataMomentGates || gate > common::MAX_DATA_MOMENT_GATES) | ||||||
|  |    { | ||||||
|  |       // Coordinate is beyond radar range
 | ||||||
|  |       return std::nullopt; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    // Compute threshold at which to display an individual bin (minimum of 2)
 | ||||||
|  |    const std::uint16_t snrThreshold = | ||||||
|  |       std::max<std::int16_t>(2, momentData->snr_threshold_raw()); | ||||||
|  |    std::uint16_t level; | ||||||
|  | 
 | ||||||
|  |    if (momentData->data_word_size() == 8) | ||||||
|  |    { | ||||||
|  |       level = | ||||||
|  |          reinterpret_cast<const uint8_t*>(momentData->data_moments())[gate]; | ||||||
|  |    } | ||||||
|  |    else | ||||||
|  |    { | ||||||
|  |       level = | ||||||
|  |          reinterpret_cast<const uint16_t*>(momentData->data_moments())[gate]; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    if (level < snrThreshold && level != RANGE_FOLDED) | ||||||
|  |    { | ||||||
|  |       return std::nullopt; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    return level; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| std::optional<wsr88d::DataLevelCode> | std::optional<wsr88d::DataLevelCode> | ||||||
| Level2ProductView::GetDataLevelCode(std::uint16_t level) const | Level2ProductView::GetDataLevelCode(std::uint16_t level) const | ||||||
| { | { | ||||||
|    // TODO
 |    switch (p->product_) | ||||||
|    Q_UNUSED(level); |    { | ||||||
|  |    case common::Level2Product::Reflectivity: | ||||||
|  |    case common::Level2Product::Velocity: | ||||||
|  |    case common::Level2Product::SpectrumWidth: | ||||||
|  |    case common::Level2Product::DifferentialReflectivity: | ||||||
|  |    case common::Level2Product::DifferentialPhase: | ||||||
|  |    case common::Level2Product::CorrelationCoefficient: | ||||||
|  |       if (level == RANGE_FOLDED) | ||||||
|  |       { | ||||||
|  |          return wsr88d::DataLevelCode::RangeFolded; | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|  | 
 | ||||||
|  |    case common::Level2Product::ClutterFilterPowerRemoved: | ||||||
|  |       switch (level) | ||||||
|  |       { | ||||||
|  |       case 0: | ||||||
|  |          return wsr88d::DataLevelCode::ClutterFilterNotApplied; | ||||||
|  |       case 1: | ||||||
|  |          return wsr88d::DataLevelCode::ClutterFilterApplied; | ||||||
|  |       case 2: | ||||||
|  |          return wsr88d::DataLevelCode::DualPolVariablesFiltered; | ||||||
|  |       case 3: | ||||||
|  |       case 4: | ||||||
|  |       case 5: | ||||||
|  |       case 6: | ||||||
|  |       case 7: | ||||||
|  |          return wsr88d::DataLevelCode::Reserved; | ||||||
|  |       default: | ||||||
|  |          break; | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|  | 
 | ||||||
|  |    default: | ||||||
|  |       break; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|    return std::nullopt; |    return std::nullopt; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::optional<float> Level2ProductView::GetDataValue(std::uint16_t level) const | std::optional<float> Level2ProductView::GetDataValue(std::uint16_t level) const | ||||||
| { | { | ||||||
|    // TODO
 |    const float   offset    = p->momentDataBlock0_->offset(); | ||||||
|    Q_UNUSED(level); |    const float   scale     = p->momentDataBlock0_->scale(); | ||||||
|  |    std::uint16_t threshold = std::numeric_limits<std::uint16_t>::max(); | ||||||
|  | 
 | ||||||
|  |    switch (p->product_) | ||||||
|  |    { | ||||||
|  |    case common::Level2Product::Reflectivity: | ||||||
|  |    case common::Level2Product::Velocity: | ||||||
|  |    case common::Level2Product::SpectrumWidth: | ||||||
|  |    case common::Level2Product::DifferentialReflectivity: | ||||||
|  |    case common::Level2Product::DifferentialPhase: | ||||||
|  |    case common::Level2Product::CorrelationCoefficient: | ||||||
|  |       threshold = 2; | ||||||
|  |       break; | ||||||
|  | 
 | ||||||
|  |    case common::Level2Product::ClutterFilterPowerRemoved: | ||||||
|  |       threshold = 8; | ||||||
|  |       break; | ||||||
|  | 
 | ||||||
|  |    default: | ||||||
|  |       break; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    if (level < threshold) | ||||||
|  |    { | ||||||
|       return std::nullopt; |       return std::nullopt; | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|  |    return (level - offset) / scale; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| std::shared_ptr<Level2ProductView> Level2ProductView::Create( | std::shared_ptr<Level2ProductView> Level2ProductView::Create( | ||||||
|    common::Level2Product                         product, |    common::Level2Product                         product, | ||||||
|    std::shared_ptr<manager::RadarProductManager> radarProductManager) |    std::shared_ptr<manager::RadarProductManager> radarProductManager) | ||||||
|  |  | ||||||
|  | @ -50,6 +50,11 @@ enum class DataLevelCode | ||||||
|    Z8, |    Z8, | ||||||
|    SI, |    SI, | ||||||
| 
 | 
 | ||||||
|  |    // Clutter Filter Power Removed
 | ||||||
|  |    ClutterFilterNotApplied, | ||||||
|  |    ClutterFilterApplied, | ||||||
|  |    DualPolVariablesFiltered, | ||||||
|  | 
 | ||||||
|    Unknown |    Unknown | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -50,6 +50,11 @@ static const std::unordered_map<DataLevelCode, std::string> dataLevelCodeName_ { | ||||||
|    {DataLevelCode::Z8, "R(Z) * 0.8"}, |    {DataLevelCode::Z8, "R(Z) * 0.8"}, | ||||||
|    {DataLevelCode::SI, "R(Z) * multiplier"}, |    {DataLevelCode::SI, "R(Z) * multiplier"}, | ||||||
| 
 | 
 | ||||||
|  |    // Clutter Filter Power Removed
 | ||||||
|  |    {DataLevelCode::ClutterFilterNotApplied, "Clutter Filter Not Applied"}, | ||||||
|  |    {DataLevelCode::ClutterFilterApplied, "Clutter Filter Applied"}, | ||||||
|  |    {DataLevelCode::DualPolVariablesFiltered, "Dual Pol Variables Filtered"}, | ||||||
|  | 
 | ||||||
|    {DataLevelCode::Unknown, "?"}}; |    {DataLevelCode::Unknown, "?"}}; | ||||||
| 
 | 
 | ||||||
| static const std::unordered_map<DataLevelCode, std::string> | static const std::unordered_map<DataLevelCode, std::string> | ||||||
|  | @ -95,6 +100,11 @@ static const std::unordered_map<DataLevelCode, std::string> | ||||||
|       {DataLevelCode::Z8, "Z8"}, |       {DataLevelCode::Z8, "Z8"}, | ||||||
|       {DataLevelCode::SI, "SI"}, |       {DataLevelCode::SI, "SI"}, | ||||||
| 
 | 
 | ||||||
|  |       // Clutter Filter Power Removed
 | ||||||
|  |       {DataLevelCode::ClutterFilterNotApplied, ""}, | ||||||
|  |       {DataLevelCode::ClutterFilterApplied, ""}, | ||||||
|  |       {DataLevelCode::DualPolVariablesFiltered, ""}, | ||||||
|  | 
 | ||||||
|       {DataLevelCode::Unknown, "?"}}; |       {DataLevelCode::Unknown, "?"}}; | ||||||
| 
 | 
 | ||||||
| const std::string& GetDataLevelCodeName(DataLevelCode dataLevelCode) | const std::string& GetDataLevelCodeName(DataLevelCode dataLevelCode) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat