Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 333
Skanda Avatar asked Feb 12 '26 21:02

Skanda


2 Answers

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.

like image 160
bolov Avatar answered Feb 14 '26 10:02

bolov


Due to jitter and other timing complexities, instead of simple summation, you need to switch to [Numerical Integration][۱] (eg. Trapezoidal Integration...).

like image 39
Red.Wave Avatar answered Feb 14 '26 11:02

Red.Wave



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!