我認為大多數人都知道如何在計算機編程中進行數值推導(作為限制 --> 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;
這是大多數派生編程的基本構建塊。
我怎樣才能用積分做到這一點?我是使用 for 回圈并添加還是什么?
uj5u.com熱心網友回復:
物理、地圖、機器人、游戲、航位推算和控制代碼中的數值推導和集成
請注意我在下面使用“估計”與“測量”這兩個詞的位置。區別很重要。
1.數值推導
請記住,推導獲得xy 圖上直線的斜率。dy/dx
一般形式是(y_new - y_old)/(x_new - x_old)
。
為了從您正在獲得重復位置測量(例如:您定期獲取 GPS 讀數)的系統中獲得速度估計,您必須隨時間對您的位置測量進行數值推導。你的y 軸是 position,你的x 軸是 time,所以是 simple 。單位檢查顯示這可能是,這確實是速度單位。dy/dx
(position_new - position_old)/(time_new - time_old)
meters/sec
在代碼中,對于只測量一維位置的系統,這看起來像這樣:
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.數值積分
數值積分獲得xy 圖上曲線,下的面積。dy*dx
做到這一點的最佳方法之一稱為梯形積分,您可以在其中獲取平均dy
讀數并乘以dx
. 這看起來像這樣(y_old y_new)/2 * (x_new - x_old)
:
為了從您獲得重復速度測量的系統中獲得位置估計(例如:您試圖估計行駛距離,同時僅讀取汽車上的速度計),您必須隨時間對速度測量進行數值積分。你的y 軸是 velocity,你的x 軸是 time,所以是 simple 。單位檢查顯示這可能是,這確實是距離單位。(y_old y_new)/2 * (x_new - x_old)
velocity_old velocity_new)/2 * (time_new - time_old)
meters/sec * sec = meters
在代碼中,它看起來像這樣。請注意,數值積分獲得了在那個微小的時間間隔內行進的距離。要獲得總行駛距離的估計值,您必須將所有單獨的行駛距離估計值相加。
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/Numerical_integration 。
更進一步:
高解析度時間戳
要執行上述操作,您需要一種獲取時間戳的好方法。以下是我使用的各種技術:
在 C 中,在這里使用我的uint64_t nanos()
函式。
如果在 C或C 中使用 Linux ,請使用我在此處使用的uint64_t nanos()
函式clock_gettime()
。更好的是,我已經將它打包成一個不錯timinglib
的 Linux 庫,在我的eRCaGuy_hello_world 存盤庫中:
- 計時庫.h
- 計時庫.c
這是NS_TO_SEC()
來自timing.h的宏:
#define NS_PER_SEC (1000000000L)
/// Convert nanoseconds to seconds
#define NS_TO_SEC(ns) ((ns)/NS_PER_SEC)
回圈計時和多任務處理
如果需要在 Linux 中使用 C 或 C 執行精確、重復的回圈,請使用sleep_until_ns()
我timinglib
上面的函式。我有一個我在 Linux 中使用的函式的演示,以像這里一樣快sleep_until_us()
地獲得重復回圈。1 KHz to 100 kHz
然而,實際上,不需要快速的控制回路,并且在如此短的時間間隔內真實傳感器讀數的噪聲將太大。在10 Hz ~ 100 Hz的任何地方使用控制回路。有些人走得更快,但50 Hz在控制系統中很常見。系統越復雜和/或傳感器測量的噪聲越大,通常控制回路必須越慢,低至大約 10 Hz 左右。
如果在微控制器上使用裸機(無作業系統)作為計算平臺,請根據需要使用基于時間戳的協作多任務處理來執行控制回圈和其他回圈,例如測量回圈。在這里查看我的詳細答案:如何進行高解析度、基于時間戳、非阻塞、單執行緒協作多任務。
完整的數值積分和多任務示例
我在代碼中的完整庫侖計數器示例中使用我的宏在裸機系統上進行了數值積分和協作多任務處理的深入示例。CREATE_TASK_TIMER()
在我看來,這是一個很好的學習演示。
卡爾曼濾波器
對于穩健的測量,您可能需要卡爾曼濾波器,也許是“無味卡爾曼濾波器”或 UKF,因為它們顯然是“無味的”,因為它們“不臭”。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/470841.html
上一篇:使用線性插值改變影像范圍
下一篇:賦值時C 向量下標超出范圍