【问题标题】:How to avoid using nested loops in cpp?如何避免在 cpp 中使用嵌套循环?
【发布时间】:2020-01-07 05:08:47
【问题描述】:

我正在为传感器进行数字采样。我有以下代码来计算最高振幅和相应的时间。

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

目前功率和能量是相同的(因为delta函数)并且向量是按时间升序排列的。我想将其更改为步进功能。脉冲持续时间是恒定的 10ns。

uint32_t pulseDuration = 5;

问题是找到样本之间的任何重叠,如果有的话,将幅度相加。

我目前使用以下代码:

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;
    } 
  }
}

是否可以在没有两个 for 循环的情况下编写此代码,因为我无法承受嵌套循环所花费的时间。

【问题讨论】:

  • 这里的问题不是嵌套循环,而是一旦时间戳超出范围就不会中断。每次迭代一直到measurement.size() 只是浪费资源。
  • 您问错了问题:“两个嵌套循环或 1 个单循环或 3 个嵌套循环”无关紧要。这似乎违反直觉,但真正重要的是复杂性。您可能会将 2 个嵌套循环与 O(n^2) 复杂性相关联,但情况并非总是如此。此外,您可以在单个循环中轻松拥有O(n^2) 或最差复杂性(或多或少隐藏)。
  • 我真的很抱歉命名约定。 “timeStamp”在项目中不再是timeStamp,而是激光雷达脉冲传输和接收之间的deltaTime。它总是在限制之下。我需要为 56000 个点减少两个 for 循环造成的开销。
  • @bolov 谢谢。我只需要知道如何减少代码花费的时间,并且我对内存没有任何担忧。
  • 是的,这里的两个嵌套循环是一种逻辑上有缺陷的方法。这应该作为一个简单的循环来完成。不幸的是,关于如何组合样本的完整规范(关于时间戳)尚不清楚,因此无法提出进一步的建议。

标签: c++ nested-loops lidar


【解决方案1】:

您可以利用向量按timeStamp排序,并通过二分查找找到下一个脉冲,从而将复杂度从O(n^2)降低到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

另外请注意,我的算法将产生与您的不同的结果,因为您并没有真正使用 measurement[i].timeStamp = (measurement[i].timeStamp + measurement[j].timeStamp)/2.0f 计算多个值的平均值

还要考虑:(我目前还不是该领域的专家,所以我只是提出想法,由您决定它是否有效):使用您的代码,您只需将代码“挤压”在一起即可测量,而不是具有周期性时间的测量向量。这可能是你想要的,也可能不是。

免责声明:未经过“它编译”之外的测试。请不要只是复制粘贴。它可能是不完整和不正确的。但我希望我给了你一个调查的方向。

【讨论】:

    【解决方案2】:

    由于抖动和其他时序复杂性,您需要切换到[数值积分][1](例如Trapezoidal Integration.. .).

    【讨论】:

    • 抖动和噪声已经建模,在这段代码中,我只需要假设功率在重叠发生的时间间隔内保持不变,最强信号的时间应该只是中间重叠点
    • 所以基本上你想将时间戳太接近的样本合并到一个样本中?如果有几个样本太接近样本 ab,而 a b 相隔甚远?
    【解决方案3】:

    如果您的值按 timeStamp 的升序排列,则将 else break 添加到 if 语句不应影响结果,但应该更快。

    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;
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-02
      • 1970-01-01
      • 2012-06-25
      • 2021-08-19
      • 1970-01-01
      • 2017-09-20
      • 1970-01-01
      相关资源
      最近更新 更多