如何在C+&#x2B中进行数值集成的基本示例

发布于 2025-01-27 00:42:15 字数 702 浏览 4 评论 0 原文

我认为大多数人都知道如何在计算机编程中执行数值派生(如限制 - > 0;阅读:“限制接近零”)。

//example code for derivation of position over time to obtain velocity

float currPosition, prevPosition, currTime, lastTime, velocity;

while (true)
{
    prevPosition = currPosition;
    currPosition = getNewPosition();

    lastTime = currTime;
    currTime = getTimestamp();

    // Numerical derivation of position over time to obtain velocity
    velocity = (currPosition - prevPosition)/(currTime - lastTime);
}

// since the while loop runs at the shortest period of time, we've already
// achieved limit --> 0;

这是大多数推导编程的基本构建块。

我该如何使用积分进行操作?我将用于循环并添加或什么?

I think most people know how to do numerical derivation in computer programming, (as limit --> 0; read: "as the limit approaches zero").

//example code for derivation of position over time to obtain velocity

float currPosition, prevPosition, currTime, lastTime, velocity;

while (true)
{
    prevPosition = currPosition;
    currPosition = getNewPosition();

    lastTime = currTime;
    currTime = getTimestamp();

    // Numerical derivation of position over time to obtain velocity
    velocity = (currPosition - prevPosition)/(currTime - lastTime);
}

// since the while loop runs at the shortest period of time, we've already
// achieved limit --> 0;

This is the basic building block for most derivation programming.

How can I do this with integrals? Do I use a for loop and add or what?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

心欲静而疯不止 2025-02-03 00:42:15

在物理,映射,机器人技术,游戏,死刑和控制的代码中的数值派生和集成

请注意我在下面使用“估算“ VS”测量”一词。差异很重要。

  1. 测量是传感器的直接读数。
    1. ex:GPS测量位置(仪表),直接速度计测量 speed (m/s)。
  2. 估计值计算的投影您可以通过集成和衍生(派生)测量值获得。
    例如:您可以在获得速度或速度(m/s)估计的时间上 der 位置测量(M),并且您可以集成相对于获得位置或位移(M)估计的速度或速度测量(M/s)。
  3. 等等,不是所有“测量”实际上只是在某些基本层面上只是“估计”吗?
    1. 是的 - 非常重要!但是,它们不一定是通过针对时间的推导或集成而产生的,因此有点不同。
    2. 还要注意,从技术上讲,几乎没有什么可以直接衡量的。所有传感器都会降低到电压或电流,并猜测您如何测量电流? - 电压! - 作为横跨微小电阻的电压下降,或者是由于电流流动引起的电压诱导的电压。因此,一切都归结为电压。甚至“直接测量速度”的设备也可以使用压力(飞机上的皮托静态管),多普勒/相移(雷达或声纳),或者随着时间的时间观察距离,然后观察距离。甚至可以通过测量将热线保持在固定温度或测量热线的温度变化所需的电流来测量的流体速度或相对于空气或水等流体(例如空气或水)的速度固定电流。如何测量该温度?温度只是热电产生的电压,或二极管或其他电阻的电压下降。
    3. 您可以看到,所有这些“测量”和“估计值”在低级别上都是交织在一起的。但是,如果已经生产,测试和校准给定的设备以输出给定的“测量”,则您可以将其作为所有实际目的的“真实来源”接受,并将其称为“测量”。然后,您从该测量中得出的任何内容,相对于时间或其他变量,您可以考虑一个“估计”。具有讽刺意味的是,如果您校准设备并派生或集成的估计值,那么其他人可以将您的输出“估计”视为其系统中的输入“测量”,并以一种永无止境的链条向下行。但是,那是ped的。让我们暂时使用上面的简化定义。

例如,下表是正确的。例如,阅读第二行,例如:“如果您采用速度测量的导数,则会获得加速度估计,如果您进行它积分,您将获得一个位置估计。”

Derivatives and integrals of position

Measurement, y              Derivative                  Integral
                            Estimate (dy/dt)            Estimate (dy*dt)
-----------------------     -----------------------     -----------------------
position        [m]         velocity        [m/s]       -               [m*s]
velocity        [m/s]       acceleration    [m/s^2]     position        [m]      
acceleration    [m/s^2]     jerk            [m/s^3]     velocity        [m/s]
jerk            [m/s^3]     snap            [m/s^4]     acceleration    [m/s^2]
snap            [m/s^4]     crackle         [m/s^5]     jerk            [m/s^3]
crackle         [m/s^5]     pop             [m/s^6]     snap            [m/s^4]
pop             [m/s^6]     -               [m/s^7]     crackle         [m/s^5]

有关混蛋,快照或浮游,crack和流行音乐,请参阅:

1。数值派生

记住,派生在XY图上获得该行的 slope dy/dx 。常规表格为(y_new -y_old)/(x_new -x_old)

为了从您获得重复位置测量的系统中获取速度估计(例如时间。您的 y轴是位置,而您的 x轴是时间,因此 dy/dx 是简单的(position_new-position_old) /(time_new -time_old)。单位检查显示这可能是米/sec ,这确实是速度的单位。

在代码中,这将是这样的,对于仅在1维中测量位置的系统:

double position_new_m = getPosition(); // m = meters
double position_old_m;
// `getNanoseconds()` should return a `uint64_t timestamp in nanoseconds, for
// instance
double time_new_sec = NS_TO_SEC((double)getNanoseconds());
double time_old_sec;

while (true)
{
    position_old_m = position_new_m;
    position_new_m = getPosition();

    time_old_sec = time_new_sec;
    time_new_sec = NS_TO_SEC((double)getNanoseconds());

    // Numerical derivation of position measurements over time to obtain
    // velocity in meters per second (mps)
    double velocity_mps = 
        (position_new_m - position_old_m)/(time_new_sec - time_old_sec);
}

2。数值集成

数值集成在曲线下获得 dy*dx下的区域,在XY图上。做到这一点的最佳方法之一称为梯形集成,在其中您将平均 dy 读取并乘以 dx 。看起来像这样:(y_old + y_new)/2 *(x_new -x_old)

为了从您获得重复的速度测量的系统中获得位置估计(例如:您正在尝试估算旅行的距离,而仅读取汽车上的速度表) ,您必须随着时间的推移将速度测量值集成。您的 y轴是速度,而您的 X轴是时间,所以(y___old + y_new)/2 *(x_new-x_new-x_old)>仅是 velocity_old + velocity_new)/2 *(time_new -time_old)。单位检查显示这可能是米/sec * sec =米,这确实是距离的单位。

在代码中,看起来像这样。请注意,数值集成获得了一个小时间隔的距离。要获得对旅行的总距离的估计值,您必须总和所有的距离估计值。

double velocity_new_mps = getVelocity(); // mps = meters per second
double velocity_old_mps;
// `getNanoseconds()` should return a `uint64_t timestamp in nanoseconds, for
// instance
double time_new_sec = NS_TO_SEC((double)getNanoseconds());
double time_old_sec;

// Total meters traveled
double distance_traveled_m_total = 0;

while (true)
{
    velocity_old_mps = velocity_new_mps;
    velocity_new_mps = getVelocity();

    time_old_sec = time_new_sec;
    time_new_sec = NS_TO_SEC((double)getNanoseconds());

    // Numerical integration of velocity measurements over time to obtain 
    // a distance estimate (in meters) over this time interval
    double distance_traveled_m = 
        (velocity_old_mps + velocity_new_mps)/2 * (time_new_sec - time_old_sec);
    distance_traveled_m_total += distance_traveled_m;
}

另请参见: https://en.wikipedia.org/wiki/wiki/numerical_integration_integration

进一步:

高分辨率时间戳

要执行以上操作,您需要一种获得时间戳的好方法。我使用以下各种技术:

在C ++中,使用我的 uint64_t nanos()

如果在C C ++中使用Linux,请使用我的 uint64_t nanos()使用 clock_getTime()在此处。更好的是,我将其包装到了一个不错的 timinglib linux的库中,在我的回购在这里:

  1. href =“ https://github.com/electricrcaircraftguy/ercaguy_hello_world/blob/blob/master/master/c/timinglib.h”
  2. < a href =“ https://github.com/electricrcaircraftguy/ercaguy_hello_world/blob/blob/master/c/timinglib.c” rel =“ nofollow noreferrer”> timinglib.c

这里代码>来自Timing.h的宏:

#define NS_PER_SEC (1000000000L)
/// Convert nanoseconds to seconds
#define NS_TO_SEC(ns)   ((ns)/NS_PER_SEC)

如果使用微控制器,则需要从计时器或计数器寄存器中读取一个递增的定期计数器,或者您已配置为以稳定的固定速率增量。例如:在arduino上:使用 micros() 获得具有4-US分辨率的微秒时间戳(默认情况下,可以更改)。在STM32或其他上,您需要配置自己的计时器/计数器。

使用数据样本速率

在样本循环中尽快采取数据样本是一个好主意,因为这样您就可以平均得出的许多样本要实现:

  1. 降低噪声:平均许多原始样品会降低传感器的噪声。
  2. 高分辨率:平均许多原始样本实际上在测量系统中添加了一些分辨率。这被称为过采样。
    1. 我在我的个人网站上写了有关它的文章: electricRcairCraftGuy.com:使用Arduino Uno的内置10位至16+-bit ADC(对数字转换器的模拟)
    2. 和Atmel/Microchip在此处的白纸上写了有关它的文章:注意AN8003:AVR121:通过过采样来增强ADC分辨率
    3. 服用 4^n 样品通过 n 分辨率提高了样本分辨率。例如:
        4^0 = 1分辨率下的样品 - &gt; 1个10位样品
      4^1 = 4位分辨率的4个样品 - &gt; 1个11位样品
      4^2 = 10位分辨率的16个样品 - &gt; 1个12位样品
      4^3 = 64个分辨率的样品 - &gt; 1个13位样品
      4^4 = 256个分辨率的样品 - &gt; 1 14位样本
      4^5 = 1024个分辨率的样品 - &gt; 1 15位样品
      4^6 = 4096个分辨率的样品 - &gt; 1个16位样品
       

      请参阅:


https://1.bp.blogspot.com/srndpqdiemu/u3hbqfdowii/aaaaaaaaaaaaaa2q/1c45z1unsfc/s1600600以高样本速率采样很好。您可以对这些样品进行基本过滤。

如果您以高速率处理原始样品,则在高样本原始样本上进行数值推导最终将衍生出大量噪声,从而产生噪声衍生估计。这不是很好。最好对过滤样品进行推导:例如:100或1000个快速样本的平均值。但是,在高样本原始样品上进行数值集成,但是,因为正如Edgar Bonet所说的,“集成在整合时,您得到的样本越多,噪音平均越好。”这与我上面的笔记有关。

但是,仅使用过滤后的样品进行数值集成和数值推导就可以了。

使用合理的控制回路速率

控制回路速率不应太快。 样本率越高越好,因为您可以过滤它们以减少噪声。但是,控制回路速率不是一定越好,因为控制回路速率有一个最佳位置。如果您的控制循环速率太慢,则系统的频率响应速度较慢,并且对环境的响应不会足够快,并且控制循环速率太快了,最终它只是对示例噪声的响应< /em>而不是在测量数据中进行实际更改。

因此,即使您有1 kHz的样本率,也不需要快速地进行过度采样和过滤数据,也不需要快速,因为读数的噪声在很小的时间间隔内的真实传感器太大。使用 10 Hz〜100 Hz 的任何地方使用控制环,也许最多可用于具有干净数据的简单系统。在某些情况下,您可以更快地走,但是 50 Hz 在控制系统中非常普遍。更复杂的系统和/或更无偿的传感器测量值通常慢> 必须是,控制回路必须为 1〜10 Hz 左右。例如,自动驾驶汽车非常复杂,经常在仅10 Hz的控制循环

方法

为了完成上述,独立的测量和滤波循环和控制循环,您需要一种执行精确有效的环时时间的 和多任务。

如果需要在C或C ++ 中进行Linux中的重复循环,请使用上面的我的 timinglib 。我有一个 sleep_until_us()在linux中使用重复loop的演示。代码> 1 kHz至100 kHz 在这里

如果在微控制器上使用裸机(无操作系统)作为计算平台,请使用基于 timestamp的合作多任务执行您的控制循环和其他循环,例如测量环路,根据需要。在此处查看我的详细答案:如何进行高分辨率,基于时间戳,非块,单线读取的合作多任务

完整的数字集成和多任务示例

我有一个数值集成的深入示例 和合作多任务在裸机系统上使用我的 create> create_task_timer()宏中观点。

卡尔曼(Kalman)

进行了良好的测量过滤器,您可能需要一个Kalman过滤器,也许是“无知的Kalman过滤器”或UKF,因为显然它们是“无知的”,因为它们“不臭”。

另请参阅

  1. 我的答案基于物理的控件和控制系统:控制的许多层

Numerical derivation and integration in code for physics, mapping, robotics, gaming, dead-reckoning, and controls

Pay attention to where I use the words "estimate" vs "measurement" below. The difference is important.

  1. Measurements are direct readings from a sensor.
    1. Ex: a GPS measures position (meters) directly, and a speedometer measures speed (m/s) directly.
  2. Estimates are calculated projections you can obtain through integrating and derivating (deriving) measured values.
    Ex: you can derive position measurements (m) with respect to time to obtain speed or velocity (m/s) estimates, and you can integrate speed or velocity measurements (m/s) with respect to time to obtain position or displacement (m) estimates.
  3. Wait, aren't all "measurements" actually just "estimates" at some fundamental level?
    1. Yeah--pretty much! But, they are not necessarily produced through derivations or integrations with respect to time, so that is a bit different.
    2. Also note that technically, virtually nothing can truly be measured directly. All sensors get reduced down to a voltage or a current, and guess how you measure a current?--a voltage!--either as a voltage drop across a tiny resistance, or as a voltage induced through an inductive coil due to current flow. So, everything boils down to a voltage. Even devices which "measure speed directly" may be using pressure (pitot-static tube on airplane), doppler/phase shift (radar or sonar), or looking at distance over time and then outputting speed. Fluid speed, or speed with respect to fluid such as air or water, can even be measured via a hot wire anemometer by measuring the current required to keep a hot wire at a fixed temperature, or by measuring the temperature change of the hot wire at a fixed current. And how is that temperature measured? Temperature is just a thermo-electrically-generated voltage, or a voltage drop across a diode or other resistance.
    3. As you can see, all of these "measurements" and "estimates", at the low level, are intertwined. However, if a given device has been produced, tested, and calibrated to output a given "measurement", then you can accept it as a "source of truth" for all practical purposes and call it a "measurement". Then, anything you derive from that measurement, with respect to time or some other variable, you can consider an "estimate". The irony of this is that if you calibrate your device and output derived or integrated estimates, someone else could then consider your output "estimates" as their input "measurements" in their system, in a sort of never-ending chain down the line. That's being pedantic, however. Let's just go with the simplified definitions I have above for the time being.

The following table is true, for example. Read the 2nd line, for instance, as: "If you take the derivative of a velocity measurement with respect to time, you get an acceleration estimate, and if you take its integral, you get a position estimate."

Derivatives and integrals of position

Measurement, y              Derivative                  Integral
                            Estimate (dy/dt)            Estimate (dy*dt)
-----------------------     -----------------------     -----------------------
position        [m]         velocity        [m/s]       -               [m*s]
velocity        [m/s]       acceleration    [m/s^2]     position        [m]      
acceleration    [m/s^2]     jerk            [m/s^3]     velocity        [m/s]
jerk            [m/s^3]     snap            [m/s^4]     acceleration    [m/s^2]
snap            [m/s^4]     crackle         [m/s^5]     jerk            [m/s^3]
crackle         [m/s^5]     pop             [m/s^6]     snap            [m/s^4]
pop             [m/s^6]     -               [m/s^7]     crackle         [m/s^5]

For jerk, snap or jounce, crackle, and pop, see: https://en.wikipedia.org/wiki/Fourth,_fifth,_and_sixth_derivatives_of_position.

1. numerical derivation

Remember, derivation obtains the slope of the line, dy/dx, on an x-y plot. The general form is (y_new - y_old)/(x_new - x_old).

In order to obtain a velocity estimate from a system where you are obtaining repeated position measurements (ex: you are taking GPS readings periodically), you must numerically derivate your position measurements over time. Your y-axis is position, and your x-axis is time, so dy/dx is simply (position_new - position_old)/(time_new - time_old). A units check shows this might be meters/sec, which is indeed a unit for velocity.

In code, that would look like this, for a system where you're only measuring position in 1-dimension:

double position_new_m = getPosition(); // m = meters
double position_old_m;
// `getNanoseconds()` should return a `uint64_t timestamp in nanoseconds, for
// instance
double time_new_sec = NS_TO_SEC((double)getNanoseconds());
double time_old_sec;

while (true)
{
    position_old_m = position_new_m;
    position_new_m = getPosition();

    time_old_sec = time_new_sec;
    time_new_sec = NS_TO_SEC((double)getNanoseconds());

    // Numerical derivation of position measurements over time to obtain
    // velocity in meters per second (mps)
    double velocity_mps = 
        (position_new_m - position_old_m)/(time_new_sec - time_old_sec);
}

2. numerical integration

Numerical integration obtains the area under the curve, dy*dx, on an x-y plot. One of the best ways to do this is called trapezoidal integration, where you take the average dy reading and multiply by dx. This would look like this: (y_old + y_new)/2 * (x_new - x_old).

In order to obtain a position estimate from a system where you are obtaining repeated velocity measurements (ex: you are trying to estimate distance traveled while only reading the speedometer on your car), you must numerically integrate your velocity measurements over time. Your y-axis is velocity, and your x-axis is time, so (y_old + y_new)/2 * (x_new - x_old) is simply velocity_old + velocity_new)/2 * (time_new - time_old). A units check shows this might be meters/sec * sec = meters, which is indeed a unit for distance.

In code, that would look like this. Notice that the numerical integration obtains the distance traveled over that one tiny time interval. To obtain an estimate of the total distance traveled, you must sum all of the individual estimates of distance traveled.

double velocity_new_mps = getVelocity(); // mps = meters per second
double velocity_old_mps;
// `getNanoseconds()` should return a `uint64_t timestamp in nanoseconds, for
// instance
double time_new_sec = NS_TO_SEC((double)getNanoseconds());
double time_old_sec;

// Total meters traveled
double distance_traveled_m_total = 0;

while (true)
{
    velocity_old_mps = velocity_new_mps;
    velocity_new_mps = getVelocity();

    time_old_sec = time_new_sec;
    time_new_sec = NS_TO_SEC((double)getNanoseconds());

    // Numerical integration of velocity measurements over time to obtain 
    // a distance estimate (in meters) over this time interval
    double distance_traveled_m = 
        (velocity_old_mps + velocity_new_mps)/2 * (time_new_sec - time_old_sec);
    distance_traveled_m_total += distance_traveled_m;
}

See also: https://en.wikipedia.org/wiki/Numerical_integration.

Going further:

high-resolution timestamps

To do the above, you'll need a good way to obtain timestamps. Here are various techniques I use:

In C++, use my uint64_t nanos() function here.

If using Linux in C or C++, use my uint64_t nanos() function which uses clock_gettime() here. Even better, I have wrapped it up into a nice timinglib library for Linux, in my eRCaGuy_hello_world repo here:

  1. timinglib.h
  2. timinglib.c

Here is the NS_TO_SEC() macro from timing.h:

#define NS_PER_SEC (1000000000L)
/// Convert nanoseconds to seconds
#define NS_TO_SEC(ns)   ((ns)/NS_PER_SEC)

If using a microcontroller, you'll need to read an incrementing periodic counter from a timer or counter register which you have configured to increment at a steady, fixed rate. Ex: on Arduino: use micros() to obtain a microsecond timestamp with 4-us resolution (by default, it can be changed). On STM32 or others, you'll need to configure your own timer/counter.

use high data sample rates

Taking data samples as fast as possible in a sample loop is a good idea, because then you can average many samples to achieve:

  1. Reduced noise: averaging many raw samples reduces noise from the sensor.
  2. Higher-resolution: averaging many raw samples actually adds bits of resolution in your measurement system. This is known as oversampling.
    1. I write about it on my personal website here: ElectricRCAircraftGuy.com: Using the Arduino Uno’s built-in 10-bit to 16+-bit ADC (Analog to Digital Converter).
    2. And Atmel/Microchip wrote about it in their white-paper here: Application Note AN8003: AVR121: Enhancing ADC resolution by oversampling.
    3. Taking 4^n samples increases your sample resolution by n bits of resolution. For example:
      4^0 = 1    sample  at 10-bits resolution --> 1 10-bit sample
      4^1 = 4    samples at 10-bits resolution --> 1 11-bit sample
      4^2 = 16   samples at 10-bits resolution --> 1 12-bit sample
      4^3 = 64   samples at 10-bits resolution --> 1 13-bit sample
      4^4 = 256  samples at 10-bits resolution --> 1 14-bit sample
      4^5 = 1024 samples at 10-bits resolution --> 1 15-bit sample
      4^6 = 4096 samples at 10-bits resolution --> 1 16-bit sample
      

      See:

So, sampling at high sample rates is good. You can do basic filtering on these samples.

If you process raw samples at a high rate, doing numerical derivation on high-sample-rate raw samples will end up derivating a lot of noise, which produces noisy derivative estimates. This isn't great. It's better to do the derivation on filtered samples: ex: the average of 100 or 1000 rapid samples. Doing numerical integration on high-sample-rate raw samples, however, is fine, because as Edgar Bonet says, "when integrating, the more samples you get, the better the noise averages out." This goes along with my notes above.

Just using the filtered samples for both numerical integration and numerical derivation, however, is just fine.

use reasonable control loop rates

Control loop rates should not be too fast. The higher the sample rates, the better, because you can filter them to reduce noise. The higher the control loop rate, however, not necessarily the better, because there is a sweet spot in control loop rates. If your control loop rate is too slow, the system will have a slow frequency response and won't respond to the environment fast enough, and if the control loop rate is too fast, it ends up just responding to sample noise instead of to real changes in the measured data.

Therefore, even if you have a sample rate of 1 kHz, for instance, to oversample and filter the data, control loops that fast are not needed, as the noise from readings of real sensors over very small time intervals will be too large. Use a control loop anywhere from 10 Hz ~ 100 Hz, perhaps up to 400+ Hz for simple systems with clean data. In some scenarios you can go faster, but 50 Hz is very common in control systems. The more-complicated the system and/or the more-noisy the sensor measurements, generally, the slower the control loop must be, down to about 1~10 Hz or so. Self-driving cars, for instance, which are very complicated, frequently operate at control loops of only 10 Hz.

loop timing and multi-tasking

In order to accomplish the above, independent measurement and filtering loops, and control loops, you'll need a means of performing precise and efficient loop timing and multi-tasking.

If needing to do precise, repetitive loops in Linux in C or C++, use the sleep_until_ns() function from my timinglib above. I have a demo of my sleep_until_us() function in-use in Linux to obtain repetitive loops as fast as 1 KHz to 100 kHz here.

If using bare-metal (no operating system) on a microcontroller as your compute platform, use timestamp-based cooperative multitasking to perform your control loop and other loops such as measurements loops, as required. See my detailed answer here: How to do high-resolution, timestamp-based, non-blocking, single-threaded cooperative multi-tasking.

full, numerical integration and multi-tasking example

I have an in-depth example of both numerical integration and cooperative multitasking on a bare-metal system using my CREATE_TASK_TIMER() macro in my Full coulomb counter example in code. That's a great demo to study, in my opinion.

Kalman filters

For robust measurements, you'll probably need a Kalman filter, perhaps an "unscented Kalman Filter," or UKF, because apparently they are "unscented" because they "don't stink."

See also

  1. My answer on Physics-based controls, and control systems: the many layers of control
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文