mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 01:20: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
 | ||||
|                // (radar site origin)
 | ||||
|                logger_->error( | ||||
|                   "Smoothing enabled, gate should not start at zero"); | ||||
|                continue; | ||||
|             } | ||||
|          } | ||||
|  |  | |||
|  | @ -44,7 +44,8 @@ public: | |||
|    ~Impl() { threadPool_.join(); }; | ||||
| 
 | ||||
|    void ComputeCoordinates( | ||||
|       const std::shared_ptr<wsr88d::rpg::GenericRadialDataPacket>& radialData); | ||||
|       const std::shared_ptr<wsr88d::rpg::GenericRadialDataPacket>& radialData, | ||||
|       bool smoothingEnabled); | ||||
| 
 | ||||
|    Level3RadialView* self_; | ||||
| 
 | ||||
|  | @ -56,6 +57,8 @@ public: | |||
| 
 | ||||
|    std::shared_ptr<wsr88d::rpg::GenericRadialDataPacket> lastRadialData_ {}; | ||||
| 
 | ||||
|    bool prevSmoothingEnabled_ {false}; | ||||
| 
 | ||||
|    float         latitude_; | ||||
|    float         longitude_; | ||||
|    float         range_; | ||||
|  | @ -125,6 +128,7 @@ void Level3RadialView::ComputeSweep() | |||
| 
 | ||||
|    std::shared_ptr<manager::RadarProductManager> radarProductManager = | ||||
|       radar_product_manager(); | ||||
|    const bool smoothingEnabled = smoothing_enabled(); | ||||
| 
 | ||||
|    // Retrieve message from Radar Product Manager
 | ||||
|    std::shared_ptr<wsr88d::rpg::Level3Message> message; | ||||
|  | @ -155,7 +159,8 @@ void Level3RadialView::ComputeSweep() | |||
|       Q_EMIT SweepNotComputed(types::NoUpdateReason::InvalidData); | ||||
|       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
 | ||||
|       Q_EMIT SweepNotComputed(types::NoUpdateReason::NoChange); | ||||
|  | @ -163,6 +168,8 @@ void Level3RadialView::ComputeSweep() | |||
|    } | ||||
|    set_graphic_product_message(gpm); | ||||
| 
 | ||||
|    p->prevSmoothingEnabled_ = smoothingEnabled; | ||||
| 
 | ||||
|    // A message with radial data should have a Product Description Block and
 | ||||
|    // Product Symbology Block
 | ||||
|    std::shared_ptr<wsr88d::rpg::ProductDescriptionBlock> descriptionBlock = | ||||
|  | @ -267,11 +274,11 @@ void Level3RadialView::ComputeSweep() | |||
|    const std::vector<float>& coordinates = | ||||
|       (radialSize == common::RadialSize::NonStandard) ? | ||||
|          p->coordinates_ : | ||||
|          radarProductManager->coordinates(radialSize); | ||||
|          radarProductManager->coordinates(radialSize, smoothingEnabled); | ||||
| 
 | ||||
|    // There should be a positive number of range bins in radial data
 | ||||
|    const uint16_t gates = radialData->number_of_range_bins(); | ||||
|    if (gates < 1) | ||||
|    const uint16_t numberOfDataMomentGates = radialData->number_of_range_bins(); | ||||
|    if (numberOfDataMomentGates < 1) | ||||
|    { | ||||
|       logger_->warn("No range bins in radial data"); | ||||
|       Q_EMIT SweepNotComputed(types::NoUpdateReason::InvalidData); | ||||
|  | @ -293,13 +300,14 @@ void Level3RadialView::ComputeSweep() | |||
|    std::vector<float>& vertices = p->vertices_; | ||||
|    size_t              vIndex   = 0; | ||||
|    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
 | ||||
|    std::vector<uint8_t>& dataMoments8 = p->dataMoments8_; | ||||
|    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
 | ||||
|    const uint16_t snrThreshold = descriptionBlock->threshold(); | ||||
|  | @ -308,7 +316,7 @@ void Level3RadialView::ComputeSweep() | |||
|    std::uint16_t startRadial; | ||||
|    if (radialSize == common::RadialSize::NonStandard) | ||||
|    { | ||||
|       p->ComputeCoordinates(radialData); | ||||
|       p->ComputeCoordinates(radialData, smoothingEnabled); | ||||
|       startRadial = 0; | ||||
|    } | ||||
|    else | ||||
|  | @ -318,40 +326,95 @@ void Level3RadialView::ComputeSweep() | |||
|       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
 | ||||
|       const uint16_t dataMomentInterval = descriptionBlock->x_resolution_raw(); | ||||
|    for (std::uint16_t radial = 0; radial < radialData->number_of_radials(); | ||||
|         ++radial) | ||||
|    { | ||||
|       const auto& dataMomentsArray8 = radialData->level(radial); | ||||
| 
 | ||||
|       // Compute gate size (number of base gates per bin)
 | ||||
|       const uint16_t gateSize = std::max<uint16_t>( | ||||
|          1, | ||||
|          dataMomentInterval / | ||||
|             static_cast<uint16_t>(radarProductManager->gate_size())); | ||||
|       const std::uint16_t nextRadial = | ||||
|          (radial == radialData->number_of_radials() - 1) ? 0 : radial + 1; | ||||
|       const auto& nextDataMomentsArray8 = radialData->level(nextRadial); | ||||
| 
 | ||||
|       // Compute gate range [startGate, 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; | ||||
|       for (std::uint16_t gate = startGate, i = 0; gate + gateSize <= endGate; | ||||
|            gate += gateSize, ++i) | ||||
|       { | ||||
|          size_t vertexCount = (gate > 0) ? 6 : 3; | ||||
| 
 | ||||
|          // Store data moment value
 | ||||
|          uint8_t dataValue = | ||||
|             (i < dataMomentsArray8.size()) ? dataMomentsArray8[i] : 0; | ||||
|          if (dataValue < snrThreshold && dataValue != RANGE_FOLDED) | ||||
|          if (!smoothingEnabled) | ||||
|          { | ||||
|             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
 | ||||
|  | @ -376,8 +439,11 @@ void Level3RadialView::ComputeSweep() | |||
|             vertices[vIndex++] = coordinates[offset2]; | ||||
|             vertices[vIndex++] = coordinates[offset2 + 1]; | ||||
| 
 | ||||
|             vertices[vIndex++] = coordinates[offset3]; | ||||
|             vertices[vIndex++] = coordinates[offset3 + 1]; | ||||
|             vertices[vIndex++] = coordinates[offset4]; | ||||
|             vertices[vIndex++] = coordinates[offset4 + 1]; | ||||
| 
 | ||||
|             vertices[vIndex++] = coordinates[offset1]; | ||||
|             vertices[vIndex++] = coordinates[offset1 + 1]; | ||||
| 
 | ||||
|             vertices[vIndex++] = coordinates[offset3]; | ||||
|             vertices[vIndex++] = coordinates[offset3 + 1]; | ||||
|  | @ -385,9 +451,6 @@ void Level3RadialView::ComputeSweep() | |||
|             vertices[vIndex++] = coordinates[offset4]; | ||||
|             vertices[vIndex++] = coordinates[offset4 + 1]; | ||||
| 
 | ||||
|             vertices[vIndex++] = coordinates[offset2]; | ||||
|             vertices[vIndex++] = coordinates[offset2 + 1]; | ||||
| 
 | ||||
|             vertexCount = 6; | ||||
|          } | ||||
|          else | ||||
|  | @ -431,7 +494,8 @@ void Level3RadialView::ComputeSweep() | |||
| } | ||||
| 
 | ||||
| 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()"); | ||||
| 
 | ||||
|  | @ -455,12 +519,25 @@ void Level3RadialView::Impl::ComputeCoordinates( | |||
|    auto radials = boost::irange<std::uint32_t>(0u, numRadials); | ||||
|    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, | ||||
|                  radials.begin(), | ||||
|                  radials.end(), | ||||
|                  [&](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, | ||||
|                                   gates.begin(), | ||||
|  | @ -470,7 +547,8 @@ void Level3RadialView::Impl::ComputeCoordinates( | |||
|                                      const std::uint32_t radialGate = | ||||
|                                         radial * common::MAX_DATA_MOMENT_GATES + | ||||
|                                         gate; | ||||
|                                      const float range = (gate + 1) * gateSize; | ||||
|                                      const float range = | ||||
|                                         (gate + gateRangeOffset) * gateSize; | ||||
|                                      const std::size_t offset = radialGate * 2; | ||||
| 
 | ||||
|                                      double latitude; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat