【问题标题】:accurate sampling in c++C ++中的精确采样
【发布时间】:2017-02-20 14:50:18
【问题描述】:

我想以每秒 4000 次从 gpio 获得的值进行采样,目前我正在做这样的事情:

std::vector<int> sample_a_chunk(unsigned int rate, unsigned int block_size_in_seconds) {
    std::vector<std::int> data;
    constexpr unsigned int times = rate * block_size_in_seconds;
    constexpr unsigned int delay = 1000000 / rate; // microseconds
    for (int j=0; j<times; j++) {
      data.emplace_back(/* read the value from the gpio */);
      std::this_thread::sleep_for(std::chrono::microseconds(delay));
    }
    return data;
}

但根据参考,sleep_for 保证等待至少指定的时间量。

我怎样才能让我的系统等待准确的时间,或者至少达到可能的最佳准确性? 如何确定系统的时间分辨率?

【问题讨论】:

  • 您需要使用操作系统服务来完成您的要求。
  • 没有办法睡一个“确切”的时间。这不是计算机的工作方式。即使是 RTOS 也不能保证准确的睡眠。当您不知道有多好就足够好时,为什么不花时间尝试使其“更好”之前,看看您已经拥有的东西有多好。
  • 操作系统shmoperating system。你需要准确的时间,你需要一个确定性的系统,它用线程和中断写出任何东西。争取足够好的时间。确保你的定时器分辨率是你需要的 5-10 倍,并且上下文切换延迟足够低,以确保你永远不会过度睡眠,足以照顾。
  • 如果您想避免时间漂移,请使用绝对计时 (wait_until),这可能很有用:stackoverflow.com/questions/37240834/…
  • 高效的 4 kHz 采样?听起来像是声卡最好处理的任务。它们通常可以缓冲大量读数,几乎没有抖动,并且每个样本不需要太多 CPU。

标签: c++ sampling chrono


【解决方案1】:

我认为你能做到的最好的可能是使用 absolute 计时以避免漂移。

类似这样的:

std::vector<int> sample_a_chunk(unsigned int rate,
    unsigned int block_size_in_seconds)
{
    using clock = std::chrono::steady_clock;

    std::vector<int> data;

    const auto times = rate * block_size_in_seconds;
    const auto delay = std::chrono::microseconds{1000000 / rate};

    auto next_sample = clock::now() + delay;

    for(int j = 0; j < times; j++)
    {
        data.emplace_back(/* read the value from the gpio */);

        std::this_thread::sleep_until(next_sample);

        next_sample += delay; // don't refer back to clock, stay absolute
    }
    return data;
}

【讨论】:

  • 你以与我几乎相同的答案(+1)以 4 分钟的优势击败了我。 Nitpicks:我会使用steady_clock 而不是high_resolution_clock。在 gcc 上 high_resolution_clocksystem_clock 可能会被调整。另外我不认为sleep_until 可以提前返回,所以我没有费心循环来检查。但最重要的项目是使用sleep_until 来消除漂移,你已经找到了! :-)
  • @HowardHinnant 我从 stable_clock 开始,因为它在我的系统上足够快,但后来我看到 微秒 并想知道小型设备的时钟是否可能不同......?所以我选择了high_resolution。我会添加注释。
  • 不,毕竟我把它改成了steady。它需要准确的时间。
  • @HowardHinnant 在我的 Linux 系统上,只要进程收到信号,sleep_until 就会提前中断。这就是我做循环的原因。
  • @HowardHinnant 我从示例中删除了它,因为它显然是一个错误,我们不想为以防万一编译器有错误进行编码。最初我认为这是OS 的事情。
【解决方案2】:

我会使用boost::asio::deadline_timer

#include <vector>

#define BOOST_ERROR_CODE_HEADER_ONLY 1
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

std::vector<int> sample_a_chunk(unsigned int rate, unsigned int block_size_in_seconds) {
  std::vector<int> data;
  const unsigned int times = rate * block_size_in_seconds;
  auto expiration_time = boost::posix_time::microsec_clock::local_time();
  const auto delay = boost::posix_time::microseconds(1000000/rate);
  boost::asio::io_service io;
  boost::asio::deadline_timer t(io);

  for (unsigned int j=0; j < times; j++) {
    expiration_time += delay;
    data.emplace_back(/* read the value from the gpio */);
    t.expires_at(expiration_time);
    t.wait();
  }
  return data;
}

【讨论】:

  • 一旦链接失效,仅链接的答案就是无用的答案。 boost::asio::deadline_timer 链接可以,因为任何人都可以查看,但我建议扩展答案以总结教程的内容。
  • 谢谢@user4581301。我已经用示例代码替换了链接。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-28
  • 2022-11-13
  • 1970-01-01
  • 1970-01-01
  • 2014-12-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多