mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 07:00:06 +00:00 
			
		
		
		
	Level 3 radial product smoothing
This commit is contained in:
		
							parent
							
								
									9f7026bf9c
								
							
						
					
					
						commit
						57f6b41a47
					
				
					 2 changed files with 119 additions and 39 deletions
				
			
		|  | @ -809,6 +809,8 @@ void Level2ProductView::ComputeSweep() | ||||||
|             { |             { | ||||||
|                // If smoothing is enabled, gate should never start at zero
 |                // If smoothing is enabled, gate should never start at zero
 | ||||||
|                // (radar site origin)
 |                // (radar site origin)
 | ||||||
|  |                logger_->error( | ||||||
|  |                   "Smoothing enabled, gate should not start at zero"); | ||||||
|                continue; |                continue; | ||||||
|             } |             } | ||||||
|          } |          } | ||||||
|  |  | ||||||
|  | @ -44,7 +44,8 @@ public: | ||||||
|    ~Impl() { threadPool_.join(); }; |    ~Impl() { threadPool_.join(); }; | ||||||
| 
 | 
 | ||||||
|    void ComputeCoordinates( |    void ComputeCoordinates( | ||||||
|       const std::shared_ptr<wsr88d::rpg::GenericRadialDataPacket>& radialData); |       const std::shared_ptr<wsr88d::rpg::GenericRadialDataPacket>& radialData, | ||||||
|  |       bool smoothingEnabled); | ||||||
| 
 | 
 | ||||||
|    Level3RadialView* self_; |    Level3RadialView* self_; | ||||||
| 
 | 
 | ||||||
|  | @ -56,6 +57,8 @@ public: | ||||||
| 
 | 
 | ||||||
|    std::shared_ptr<wsr88d::rpg::GenericRadialDataPacket> lastRadialData_ {}; |    std::shared_ptr<wsr88d::rpg::GenericRadialDataPacket> lastRadialData_ {}; | ||||||
| 
 | 
 | ||||||
|  |    bool prevSmoothingEnabled_ {false}; | ||||||
|  | 
 | ||||||
|    float         latitude_; |    float         latitude_; | ||||||
|    float         longitude_; |    float         longitude_; | ||||||
|    float         range_; |    float         range_; | ||||||
|  | @ -125,6 +128,7 @@ void Level3RadialView::ComputeSweep() | ||||||
| 
 | 
 | ||||||
|    std::shared_ptr<manager::RadarProductManager> radarProductManager = |    std::shared_ptr<manager::RadarProductManager> radarProductManager = | ||||||
|       radar_product_manager(); |       radar_product_manager(); | ||||||
|  |    const bool smoothingEnabled = smoothing_enabled(); | ||||||
| 
 | 
 | ||||||
|    // Retrieve message from Radar Product Manager
 |    // Retrieve message from Radar Product Manager
 | ||||||
|    std::shared_ptr<wsr88d::rpg::Level3Message> message; |    std::shared_ptr<wsr88d::rpg::Level3Message> message; | ||||||
|  | @ -155,7 +159,8 @@ void Level3RadialView::ComputeSweep() | ||||||
|       Q_EMIT SweepNotComputed(types::NoUpdateReason::InvalidData); |       Q_EMIT SweepNotComputed(types::NoUpdateReason::InvalidData); | ||||||
|       return; |       return; | ||||||
|    } |    } | ||||||
|    else if (gpm == graphic_product_message()) |    else if (gpm == graphic_product_message() && | ||||||
|  |             smoothingEnabled == p->prevSmoothingEnabled_) | ||||||
|    { |    { | ||||||
|       // Skip if this is the message we previously processed
 |       // Skip if this is the message we previously processed
 | ||||||
|       Q_EMIT SweepNotComputed(types::NoUpdateReason::NoChange); |       Q_EMIT SweepNotComputed(types::NoUpdateReason::NoChange); | ||||||
|  | @ -163,6 +168,8 @@ void Level3RadialView::ComputeSweep() | ||||||
|    } |    } | ||||||
|    set_graphic_product_message(gpm); |    set_graphic_product_message(gpm); | ||||||
| 
 | 
 | ||||||
|  |    p->prevSmoothingEnabled_ = smoothingEnabled; | ||||||
|  | 
 | ||||||
|    // A message with radial data should have a Product Description Block and
 |    // A message with radial data should have a Product Description Block and
 | ||||||
|    // Product Symbology Block
 |    // Product Symbology Block
 | ||||||
|    std::shared_ptr<wsr88d::rpg::ProductDescriptionBlock> descriptionBlock = |    std::shared_ptr<wsr88d::rpg::ProductDescriptionBlock> descriptionBlock = | ||||||
|  | @ -267,11 +274,11 @@ void Level3RadialView::ComputeSweep() | ||||||
|    const std::vector<float>& coordinates = |    const std::vector<float>& coordinates = | ||||||
|       (radialSize == common::RadialSize::NonStandard) ? |       (radialSize == common::RadialSize::NonStandard) ? | ||||||
|          p->coordinates_ : |          p->coordinates_ : | ||||||
|          radarProductManager->coordinates(radialSize); |          radarProductManager->coordinates(radialSize, smoothingEnabled); | ||||||
| 
 | 
 | ||||||
|    // There should be a positive number of range bins in radial data
 |    // There should be a positive number of range bins in radial data
 | ||||||
|    const uint16_t gates = radialData->number_of_range_bins(); |    const uint16_t numberOfDataMomentGates = radialData->number_of_range_bins(); | ||||||
|    if (gates < 1) |    if (numberOfDataMomentGates < 1) | ||||||
|    { |    { | ||||||
|       logger_->warn("No range bins in radial data"); |       logger_->warn("No range bins in radial data"); | ||||||
|       Q_EMIT SweepNotComputed(types::NoUpdateReason::InvalidData); |       Q_EMIT SweepNotComputed(types::NoUpdateReason::InvalidData); | ||||||
|  | @ -293,13 +300,14 @@ void Level3RadialView::ComputeSweep() | ||||||
|    std::vector<float>& vertices = p->vertices_; |    std::vector<float>& vertices = p->vertices_; | ||||||
|    size_t              vIndex   = 0; |    size_t              vIndex   = 0; | ||||||
|    vertices.clear(); |    vertices.clear(); | ||||||
|    vertices.resize(radials * gates * VERTICES_PER_BIN * VALUES_PER_VERTEX); |    vertices.resize(radials * numberOfDataMomentGates * VERTICES_PER_BIN * | ||||||
|  |                    VALUES_PER_VERTEX); | ||||||
| 
 | 
 | ||||||
|    // Setup data moment vector
 |    // Setup data moment vector
 | ||||||
|    std::vector<uint8_t>& dataMoments8 = p->dataMoments8_; |    std::vector<uint8_t>& dataMoments8 = p->dataMoments8_; | ||||||
|    size_t                mIndex       = 0; |    size_t                mIndex       = 0; | ||||||
| 
 | 
 | ||||||
|    dataMoments8.resize(radials * gates * VERTICES_PER_BIN); |    dataMoments8.resize(radials * numberOfDataMomentGates * VERTICES_PER_BIN); | ||||||
| 
 | 
 | ||||||
|    // Compute threshold at which to display an individual bin
 |    // Compute threshold at which to display an individual bin
 | ||||||
|    const uint16_t snrThreshold = descriptionBlock->threshold(); |    const uint16_t snrThreshold = descriptionBlock->threshold(); | ||||||
|  | @ -308,7 +316,7 @@ void Level3RadialView::ComputeSweep() | ||||||
|    std::uint16_t startRadial; |    std::uint16_t startRadial; | ||||||
|    if (radialSize == common::RadialSize::NonStandard) |    if (radialSize == common::RadialSize::NonStandard) | ||||||
|    { |    { | ||||||
|       p->ComputeCoordinates(radialData); |       p->ComputeCoordinates(radialData, smoothingEnabled); | ||||||
|       startRadial = 0; |       startRadial = 0; | ||||||
|    } |    } | ||||||
|    else |    else | ||||||
|  | @ -318,40 +326,95 @@ void Level3RadialView::ComputeSweep() | ||||||
|       startRadial = std::lroundf(startAngle * radialMultiplier); |       startRadial = std::lroundf(startAngle * radialMultiplier); | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    for (uint16_t radial = 0; radial < radialData->number_of_radials(); radial++) |    // Compute gate interval
 | ||||||
|  |    const std::uint16_t dataMomentInterval = | ||||||
|  |       descriptionBlock->x_resolution_raw(); | ||||||
|  | 
 | ||||||
|  |    // Compute gate size (number of base gates per bin)
 | ||||||
|  |    const std::uint16_t gateSize = std::max<std::uint16_t>( | ||||||
|  |       1, | ||||||
|  |       dataMomentInterval / | ||||||
|  |          static_cast<std::uint16_t>(radarProductManager->gate_size())); | ||||||
|  | 
 | ||||||
|  |    // Compute gate range [startGate, endGate)
 | ||||||
|  |    std::uint16_t       startGate = 0; | ||||||
|  |    const std::uint16_t endGate = | ||||||
|  |       std::min<std::uint16_t>(startGate + numberOfDataMomentGates * gateSize, | ||||||
|  |                               common::MAX_DATA_MOMENT_GATES); | ||||||
|  | 
 | ||||||
|  |    if (smoothingEnabled) | ||||||
|    { |    { | ||||||
|       const auto dataMomentsArray8 = radialData->level(radial); |       // If smoothing is enabled, the start gate is incremented by one, as we
 | ||||||
|  |       // are skipping the radar site origin. The end gate is unaffected, as
 | ||||||
|  |       // we need to draw one less data point.
 | ||||||
|  |       ++startGate; | ||||||
|  |    } | ||||||
| 
 | 
 | ||||||
|       // Compute gate interval
 |    for (std::uint16_t radial = 0; radial < radialData->number_of_radials(); | ||||||
|       const uint16_t dataMomentInterval = descriptionBlock->x_resolution_raw(); |         ++radial) | ||||||
|  |    { | ||||||
|  |       const auto& dataMomentsArray8 = radialData->level(radial); | ||||||
| 
 | 
 | ||||||
|       // Compute gate size (number of base gates per bin)
 |       const std::uint16_t nextRadial = | ||||||
|       const uint16_t gateSize = std::max<uint16_t>( |          (radial == radialData->number_of_radials() - 1) ? 0 : radial + 1; | ||||||
|          1, |       const auto& nextDataMomentsArray8 = radialData->level(nextRadial); | ||||||
|          dataMomentInterval / |  | ||||||
|             static_cast<uint16_t>(radarProductManager->gate_size())); |  | ||||||
| 
 | 
 | ||||||
|       // Compute gate range [startGate, endGate)
 |       for (std::uint16_t gate = startGate, i = 0; gate + gateSize <= endGate; | ||||||
|       const uint16_t startGate = 0; |  | ||||||
|       const uint16_t endGate   = std::min<uint16_t>( |  | ||||||
|          startGate + gates * gateSize, common::MAX_DATA_MOMENT_GATES); |  | ||||||
| 
 |  | ||||||
|       for (uint16_t gate = startGate, i = 0; gate + gateSize <= endGate; |  | ||||||
|            gate += gateSize, ++i) |            gate += gateSize, ++i) | ||||||
|       { |       { | ||||||
|          size_t vertexCount = (gate > 0) ? 6 : 3; |          size_t vertexCount = (gate > 0) ? 6 : 3; | ||||||
| 
 | 
 | ||||||
|          // Store data moment value
 |          if (!smoothingEnabled) | ||||||
|          uint8_t dataValue = |  | ||||||
|             (i < dataMomentsArray8.size()) ? dataMomentsArray8[i] : 0; |  | ||||||
|          if (dataValue < snrThreshold && dataValue != RANGE_FOLDED) |  | ||||||
|          { |          { | ||||||
|             continue; |             // Store data moment value
 | ||||||
|          } |             uint8_t dataValue = | ||||||
|  |                (i < dataMomentsArray8.size()) ? dataMomentsArray8[i] : 0; | ||||||
|  |             if (dataValue < snrThreshold && dataValue != RANGE_FOLDED) | ||||||
|  |             { | ||||||
|  |                continue; | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|          for (size_t m = 0; m < vertexCount; m++) |             for (size_t m = 0; m < vertexCount; m++) | ||||||
|  |             { | ||||||
|  |                dataMoments8[mIndex++] = dataValue; | ||||||
|  |             } | ||||||
|  |          } | ||||||
|  |          else if (gate > 0) | ||||||
|          { |          { | ||||||
|             dataMoments8[mIndex++] = dataValue; |             // Validate indices are all in range
 | ||||||
|  |             if (i + 1 >= numberOfDataMomentGates) | ||||||
|  |             { | ||||||
|  |                continue; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             const std::uint8_t& dm1 = dataMomentsArray8[i]; | ||||||
|  |             const std::uint8_t& dm2 = dataMomentsArray8[i + 1]; | ||||||
|  |             const std::uint8_t& dm3 = nextDataMomentsArray8[i]; | ||||||
|  |             const std::uint8_t& dm4 = nextDataMomentsArray8[i + 1]; | ||||||
|  | 
 | ||||||
|  |             if (dm1 < snrThreshold && dm1 != RANGE_FOLDED && | ||||||
|  |                 dm2 < snrThreshold && dm2 != RANGE_FOLDED && | ||||||
|  |                 dm3 < snrThreshold && dm3 != RANGE_FOLDED && | ||||||
|  |                 dm4 < snrThreshold && dm4 != RANGE_FOLDED) | ||||||
|  |             { | ||||||
|  |                // Skip only if all data moments are hidden
 | ||||||
|  |                continue; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // The order must match the store vertices section below
 | ||||||
|  |             dataMoments8[mIndex++] = dm1; | ||||||
|  |             dataMoments8[mIndex++] = dm2; | ||||||
|  |             dataMoments8[mIndex++] = dm4; | ||||||
|  |             dataMoments8[mIndex++] = dm1; | ||||||
|  |             dataMoments8[mIndex++] = dm3; | ||||||
|  |             dataMoments8[mIndex++] = dm4; | ||||||
|  |          } | ||||||
|  |          else | ||||||
|  |          { | ||||||
|  |             // If smoothing is enabled, gate should never start at zero
 | ||||||
|  |             // (radar site origin)
 | ||||||
|  |             logger_->error("Smoothing enabled, gate should not start at zero"); | ||||||
|  |             continue; | ||||||
|          } |          } | ||||||
| 
 | 
 | ||||||
|          // Store vertices
 |          // Store vertices
 | ||||||
|  | @ -376,8 +439,11 @@ void Level3RadialView::ComputeSweep() | ||||||
|             vertices[vIndex++] = coordinates[offset2]; |             vertices[vIndex++] = coordinates[offset2]; | ||||||
|             vertices[vIndex++] = coordinates[offset2 + 1]; |             vertices[vIndex++] = coordinates[offset2 + 1]; | ||||||
| 
 | 
 | ||||||
|             vertices[vIndex++] = coordinates[offset3]; |             vertices[vIndex++] = coordinates[offset4]; | ||||||
|             vertices[vIndex++] = coordinates[offset3 + 1]; |             vertices[vIndex++] = coordinates[offset4 + 1]; | ||||||
|  | 
 | ||||||
|  |             vertices[vIndex++] = coordinates[offset1]; | ||||||
|  |             vertices[vIndex++] = coordinates[offset1 + 1]; | ||||||
| 
 | 
 | ||||||
|             vertices[vIndex++] = coordinates[offset3]; |             vertices[vIndex++] = coordinates[offset3]; | ||||||
|             vertices[vIndex++] = coordinates[offset3 + 1]; |             vertices[vIndex++] = coordinates[offset3 + 1]; | ||||||
|  | @ -385,9 +451,6 @@ void Level3RadialView::ComputeSweep() | ||||||
|             vertices[vIndex++] = coordinates[offset4]; |             vertices[vIndex++] = coordinates[offset4]; | ||||||
|             vertices[vIndex++] = coordinates[offset4 + 1]; |             vertices[vIndex++] = coordinates[offset4 + 1]; | ||||||
| 
 | 
 | ||||||
|             vertices[vIndex++] = coordinates[offset2]; |  | ||||||
|             vertices[vIndex++] = coordinates[offset2 + 1]; |  | ||||||
| 
 |  | ||||||
|             vertexCount = 6; |             vertexCount = 6; | ||||||
|          } |          } | ||||||
|          else |          else | ||||||
|  | @ -431,7 +494,8 @@ void Level3RadialView::ComputeSweep() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Level3RadialView::Impl::ComputeCoordinates( | void Level3RadialView::Impl::ComputeCoordinates( | ||||||
|    const std::shared_ptr<wsr88d::rpg::GenericRadialDataPacket>& radialData) |    const std::shared_ptr<wsr88d::rpg::GenericRadialDataPacket>& radialData, | ||||||
|  |    bool smoothingEnabled) | ||||||
| { | { | ||||||
|    logger_->debug("ComputeCoordinates()"); |    logger_->debug("ComputeCoordinates()"); | ||||||
| 
 | 
 | ||||||
|  | @ -455,12 +519,25 @@ void Level3RadialView::Impl::ComputeCoordinates( | ||||||
|    auto radials = boost::irange<std::uint32_t>(0u, numRadials); |    auto radials = boost::irange<std::uint32_t>(0u, numRadials); | ||||||
|    auto gates   = boost::irange<std::uint32_t>(0u, numRangeBins); |    auto gates   = boost::irange<std::uint32_t>(0u, numRangeBins); | ||||||
| 
 | 
 | ||||||
|  |    const float gateRangeOffset = (smoothingEnabled) ? | ||||||
|  |                                     // Center of the first gate is half the gate
 | ||||||
|  |                                     // size distance from the radar site
 | ||||||
|  |                                     0.5f : | ||||||
|  |                                     // Far end of the first gate is the gate
 | ||||||
|  |                                     // size distance from the radar site
 | ||||||
|  |                                     1.0f; | ||||||
|  | 
 | ||||||
|    std::for_each(std::execution::par_unseq, |    std::for_each(std::execution::par_unseq, | ||||||
|                  radials.begin(), |                  radials.begin(), | ||||||
|                  radials.end(), |                  radials.end(), | ||||||
|                  [&](std::uint32_t radial) |                  [&](std::uint32_t radial) | ||||||
|                  { |                  { | ||||||
|                     const float angle = radialData->start_angle(radial); |                     float angle = radialData->start_angle(radial); | ||||||
|  | 
 | ||||||
|  |                     if (smoothingEnabled) | ||||||
|  |                     { | ||||||
|  |                        angle += radialData->delta_angle(radial) * 0.5f; | ||||||
|  |                     } | ||||||
| 
 | 
 | ||||||
|                     std::for_each(std::execution::par_unseq, |                     std::for_each(std::execution::par_unseq, | ||||||
|                                   gates.begin(), |                                   gates.begin(), | ||||||
|  | @ -470,7 +547,8 @@ void Level3RadialView::Impl::ComputeCoordinates( | ||||||
|                                      const std::uint32_t radialGate = |                                      const std::uint32_t radialGate = | ||||||
|                                         radial * common::MAX_DATA_MOMENT_GATES + |                                         radial * common::MAX_DATA_MOMENT_GATES + | ||||||
|                                         gate; |                                         gate; | ||||||
|                                      const float range = (gate + 1) * gateSize; |                                      const float range = | ||||||
|  |                                         (gate + gateRangeOffset) * gateSize; | ||||||
|                                      const std::size_t offset = radialGate * 2; |                                      const std::size_t offset = radialGate * 2; | ||||||
| 
 | 
 | ||||||
|                                      double latitude; |                                      double latitude; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat