3

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.

Baran
  • 101
  • 1
  • 10
Skanda
  • 135
  • 13
  • The problem here is not the nested loop, but the fact that it is not interrupted once timestamp goes out of bounds. Iterating all the way up to `measurement.size()` every time is just a waste of resources. – user7860670 Sep 04 '19 at 10:12
  • 7
    you are asking the wrong question: "two nested loops or 1 single loop or 3 nested loops" doesn't matter. It might seem counter-intuitive, but what really matters is **complexity**. You might associate 2 nesed loops with `O(n^2)` complexity, but that is definetely not always the case. Plus you can easily have `O(n^2)` or worst complexity (more or less hidden) in a single loop. – bolov Sep 04 '19 at 10:14
  • I am really sorry for the naming convention. "timeStamp" is not timeStamp anymore in the project but the deltaTime between transmission and reception of Lidar pulse. It is always under the limit. I need to reduce the overhead caused by two for loops for 56000 points. – Skanda Sep 04 '19 at 10:19
  • @bolov Thank you. All I need to know is that how I can reduce the time taken by the code and I do not have any worries on the memory. – Skanda Sep 04 '19 at 10:21
  • Did you consider something like vector operations to speed up the calculation? – JulianH Sep 04 '19 at 10:24
  • 1
    Yes, two nested loops here is a logically-flawed approach. This should be done as a single, simple loop. Unfortunately, the complete specification for how to combine samples, with respect to the timestamp, is not clear so no further suggestion can be made. – Sam Varshavchik Sep 04 '19 at 10:39
  • Combining samples is as simple as adding the power of overlapped samples with immediate neighbor samples and time is the average value as seen in the code. – Skanda Sep 04 '19 at 11:32

3 Answers3

3

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.

bolov
  • 58,757
  • 13
  • 108
  • 182
1

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

Red.Wave
  • 1,427
  • 6
  • 8
  • Jitters and noises are modeled already and in this piece of code I just have to assume that the power remains the same over the interval of time where overlap happened and the time of strongest signal should just be the middle point of overlap – Skanda Sep 04 '19 at 11:28
  • So basically you want to combine too-close-timestamped samples into one sample? How do you model the samples if you have a few samples which are too close to both samples **a** and **b**, while **a** and **b** are well-apart? – Red.Wave Sep 04 '19 at 13:34
0

If your values are in ascending order of timeStamp adding else break to the if statement shouldn't effect the result but should be a lot quicker.

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;
    } else {
      break;
    }
  }
}
Isaac Clancy
  • 409
  • 2
  • 7