Search code examples
c++nested-loopslidar

How to avoid using nested loops in cpp?


I am working on digital sampling for sensor. I have following code to compute the highest amplitude and the corresponding time.

struct LidarPoints{
   float timeStamp;
   float Power;
}
std::vector<LidarPoints> measurement; // To store Lidar points of current measurement

enter image description here

Currently power and energy are the same (because of delta function)and vector is arranged in ascending order of time. I would like to change this to step function. Pulse duration is a constant 10ns.

enter image description here

uint32_t pulseDuration = 5;

The problem is to find any overlap between the samples and if any to add up the amplitudes.

enter image description here

I currently use following code:

for(auto i= 0; i< measurement.size(); i++){
   for(auto j=i+1; i< measurement.size(); j++){
      if(measurement[j].timeStamp - measurement[i].timeStamp) < pulseDuration){
          measurement[i].Power += measurement[j].Power;
          measurement[i].timeStamp = (measurement[i].timeStamp + measurement[j].timeStamp)/2.0f;
    } 
  }
}

Is it possible to code this without two for loops since I cannot afford the amount of time being taken by nested loops.


Solution

  • You can take advantage that the vector is sorted by timeStamp and find the next pulse with binary search, thus reducing the complexity from O(n^2) to O(n log n):

    #include <vector>
    #include <algorithm>
    #include <numeric>
    #include <iterator
    
    auto it = measurement.begin();
    auto end = measurement.end();
    
    while (it != end)
    {
        // next timestamp as in your code
        auto timeStampLower = it->timeStamp + pulseDuration;
    
        // next value in measurement with a timestamp >= timeStampLower
        auto lower_bound = std::lower_bound(it, end, timeStampLower, [](float a, const LidarPoints& b) {
                return a < b.timeStamp;
            });
    
        // sum over [timeStamp, timeStampLower)
        float sum = std::accumulate(it, lower_bound, 0.0f, [] (float a, const LidarPoints& b) {
                return a + b.timeStamp;
            });
    
        auto num = std::distance(it, lower_bound);
        // num should be >= since the vector is sorted and pulseDuration is positive
        // you should uncomment next line to catch unexpected error
        // Expects(num >= 1); // needs GSL library
        // assert(num >= 1); // or standard C if you don't want to use GSL
    
        // average over [timeStamp, timeStampLower)
        it->timeStamp = sum / num;
    
        // advance it
        it = lower_bound;
    }
    

    https://en.cppreference.com/w/cpp/algorithm/lower_bound https://en.cppreference.com/w/cpp/algorithm/accumulate

    Also please note that my algorithm will produce different result than yours because you don't really compute the average over multiple values with measurement[i].timeStamp = (measurement[i].timeStamp + measurement[j].timeStamp)/2.0f

    Also to consider: (I am by far not an expert in the field, so I am just throwing the ideea, it's up to you to know if its valid or not): with your code you just "squash" together close measurement, instead of having a vector of measurement with periodic time. It might be what you intend or not.

    Disclaimer: not tested beyond "it compiles". Please don't just copy-paste it. It could be incomplet and incorrekt. But I hope I gave you a direction to investigate.