mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 05:10: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(); | ||||
| 
 | ||||
|    auto radialData0 = radarData0->radial_data_block(); | ||||
|    auto volumeData0 = radarData0->volume_data_block(); | ||||
|    p->latitude_     = volumeData0->latitude(); | ||||
|    p->longitude_    = volumeData0->longitude(); | ||||
|  | @ -782,24 +781,209 @@ void Level2ProductViewImpl::ComputeCoordinates( | |||
| std::optional<std::uint16_t> | ||||
| Level2ProductView::GetBinLevel(const common::Coordinate& coordinate) const | ||||
| { | ||||
|    // TODO
 | ||||
|    Q_UNUSED(coordinate); | ||||
|    return std::nullopt; | ||||
|    auto radarData     = p->elevationScan_; | ||||
|    auto dataBlockType = p->dataBlockType_; | ||||
| 
 | ||||
|    if (radarData == nullptr) | ||||
|    { | ||||
|       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> | ||||
| Level2ProductView::GetDataLevelCode(std::uint16_t level) const | ||||
| { | ||||
|    // TODO
 | ||||
|    Q_UNUSED(level); | ||||
|    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: | ||||
|       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; | ||||
| } | ||||
| 
 | ||||
| std::optional<float> Level2ProductView::GetDataValue(std::uint16_t level) const | ||||
| { | ||||
|    // TODO
 | ||||
|    Q_UNUSED(level); | ||||
|    return std::nullopt; | ||||
|    const float   offset    = p->momentDataBlock0_->offset(); | ||||
|    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 (level - offset) / scale; | ||||
| } | ||||
| 
 | ||||
| std::shared_ptr<Level2ProductView> Level2ProductView::Create( | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat