一、基於Excel的查表插值計算工具
二維查表算法是控制器軟件開發中最爲基礎的算法之一,同時進行二維查表計算也是標定開發過程中常見操作。
通常一維線性插值算法可以採用手工計算的方式;二維查表插值算法則多采用Matlab、Origin等軟件實現,但上述軟件體積較大,操作複雜,並不適合日常辦公使用。
爲此製作了基於Excel的查表插值計算工具,其操作界面如下:
其使用方法如下:
1、將INCA中的二維MAP表格的X軸座標值、Y座標值、MAP值分別填入Excel中對應的位置。
注意
- 本工具X軸最大長度爲25,Y軸最大長度20
- X軸與Y軸座標值務必是單調遞增趨勢
2、填寫Y軸取值點以及X軸取值點(X軸可選取多個點),按下計算按鍵後,藍色框區會自動顯示查表插值算法的結果。
二、查表插值算法詳解
1、舉例計算X=18,Y=850時,Z點的取值 ?
二維查表函數如下:
// 查表函數 x = 橫座標取點值 y = 縱座標取點值 z =返回查表結果
public float GetElementAt(float x, float y)
{
uint x_index, y_index;
float x_offset, y_offset;
float x_distance, y_distance, result;
// 計算X軸 起始座標索引、偏移量、起始座標索引至下一個座標索引點的距離
SearchDistrX(x, out x_index, out x_offset, out x_distance);
// 計算Y軸 起始座標索引、偏移量、起始座標索引至下一個座標索引點的距離
SearchDistrY(y, out y_index, out y_offset, out y_distance);
// 根據X,Y軸座標信息計算MAP插值
return result = GetDeltaAt(x_index, x_offset, x_distance, y_index, y_offset, y_distance);
}
獲取 X=18,Y=850時,Z點的取值?
float Z = GetElementAt(18.00 , 850)
2、首先計算X在起始座標索引、偏移量、起始座標索引至下一個座標索引點的距離,out關鍵字類似指針的效果,表示此處輸出參數值
SearchDistrX(x, out x_index, out x_offset, out x_distance);
運算結果 SearchDistrX(18, 3, 3, 5);
如圖所示,將x=18帶入函數可得( x 值在[15,20]的座標區間中)
x_index = 3; 區間起始座標點對應的下標值(X3)
x_offset = 3; x值(18) - 區間起始座標點(15)
x_distance = 5;區間結束座標點(20) - 區間起始座標點(15)
3、同理計算Y在起始座標索引、偏移量、起始座標索引至下一個座標索引點的距離
SearchDistrY(y, out y_index, out y_offset, out y_distance);
運算結果 SearchDistrY(850, 1, 422.5, 427.25);
4、將上述計算結果帶入MAP插值計算函數中
// 根據X,Y軸座標信息計算MAP插值
result = GetDeltaAt(3, 3, 5, 1, 422.5, 427.25);
public float GetDeltaAt(uint x_index, float x_offset, float x_distance, uint y_index, float y_offset, float y_distance)
{
float v00, v01, v10, v11, v0, v1, result;
// 獲取需查詢的MAP值所在的左上角單元格數值
v00 = this.zMapValue[y_index, x_index]; /* base value at vMat[x1,y1]*/
// 需查詢的MAP值在二維數組範圍內
if ((x_index < (this.xAxisLen - 1)) && (y_index < (this.yAxisLen - 1)))
{
// 獲取需查詢的MAP值所在的右上角單元格數值
v01 = this.zMapValue[y_index, x_index + 1];
// 獲取需查詢的MAP值所在的左下角單元格數值
v10 = this.zMapValue[y_index + 1, x_index];
// 獲取需查詢的MAP值所在的右下角單元格數值
v11 = this.zMapValue[y_index + 1, x_index + 1];
}
// 如果需查詢的MAP值Y座標超過最大邊界
else if ((x_index < (this.xAxisLen - 1)) && (y_index == (this.yAxisLen - 1)))
{
// // 獲取需查詢的MAP值所在的右上角單元格數值
v01 = this.zMapValue[y_index, x_index + 1];
// 因爲Y軸超邊界, 左下角單元格數值 == 左上角單元格數值
v10 = v00;
// 因爲Y軸超邊界, 右下角單元格數值 == 右上角單元格數值
v11 = v01;
}
// 如果需查詢的MAP值X座標超過最大邊界
else if ((x_index == (this.xAxisLen - 1)) && (y_index < (this.yAxisLen - 1)))
{
// 獲取需查詢的MAP值所在的左下角單元格數值
v10 = this.zMapValue[y_index + 1, x_index];
// 因爲X軸超邊界, 右上角單元格數值 == 左上角單元格數值
v01 = v00;
// 因爲X軸超邊界, 右下角單元格數值 == 左下角單元格數值
v11 = v10;
}
// 如果需查詢的MAP值X座標和Y座標超過最小邊界
else
{
// 四個單元格的值都等於左上角單元格數值
v01 = v00;
v10 = v00;
v11 = v00;
}
// 獲取需查詢的Y點座標值在左上角與右上角單元格之間的差值
v0 = Interpolate(v00, v01, x_offset, x_distance);
// 獲取需查詢的Y點座標值在左下角與右下角單元格之間的差值
v1 = Interpolate(v10, v11, x_offset, x_distance);
// 獲取需查詢的X點座標值在 差值點v0,v1的之間的差值
return result = Interpolate(v0, v1, y_offset, y_distance);
}
5、上述函數的第一步是根據計算出的X,Y值座標索引值(x_index,y_index),可知當X=18,Y=850時,Z值務必在四個黃色單元格內:
分別對應函數的v00(左上1150),v01(左下1275),v10(右上1175),v11(右下1300)
6、選取四個單元格完成後,根據x_offset和x_distance之間的比值,計算出左上角與右上角之間的v0值,計算出左下角與右下角之間的v1值
插值公式:
配圖說明:
// 獲取需查詢的Y點座標值在左上角與右上角單元格之間的差值
v0 = Interpolate(1150, 1175, 3, 5)
v0 =1165
// 獲取需查詢的Y點座標值在左下角與右下角單元格之間的差值
v1 = Interpolate(1275, 1300, 422.5, 427.25);
v1 = 1290
7、使用y_offset,y_distance值在計算出來的v0,v1值之間在進行最後一次插值計算
// 獲取需查詢的X點座標值在 差值點v0,v1的之間的差值
result = Interpolate(v0, v1, y_offset, y_distance);
result = 1288.61
最終二維查表插值結果:
1288.61 = GetElementAt(18.00 , 850)
工具下載地址(含插值算法源代碼):