Simulink Model:
Interpolation Method: Linear point-slope 线性点斜式 插值(就是常见的计算斜率插值)
Extrapolation Method: Clip
Index search method: Binary search (二分法搜索) Linear search(线性搜索就是遍历搜索)
Code:
1. Binary search 和 Linear search 和 Linear point-slope 的代码基本例子
uint8_T look1_iu8lu32n24_binlcse(uint8_T u0, const uint8_T bp0[], const uint8_T table[], uint32_T maxIndex)
//函数返回是最终插值计算的值
//UO 是需要被查找的x轴数值
//bp0 数组 是X 轴整个数组
//table 数组是 y 轴 的整个数组
//maxIndex 是X 轴的数组的元素数
{
uint32_T frac;
uint32_T iLeft = 0U;
uint32_T iRght = maxIndex;
uint8_T bpLeftVar;
uint8_T y;
// 二分查找 找到输入在的X轴的区间
//
while (iRght - iLeft > 1U) {
frac = (iRght + iLeft) >> 1U; //>>1u 等同于 /2
if (u0 < bp0[frac]) {
iRght = frac;
} else {
iLeft = frac;
}
}
//只要区间右侧-左侧大于1,则先取中间位置数,与目标值比较大小,确定中间位置被定为左边还是右边
//直到或者相邻的两个元素位置。
// 计算分数值(如果u0在bp0范围内)
//二分法只适用于单调增、减的数组
if (u0 > bp0[0U] && u0 < bp0[maxIndex]) { //目标值在x轴范围内
bpLeftVar = bp0[iLeft];
frac = ((uint32_T)(uint8_T)((uint32_T)u0 - bpLeftVar) << 24) / (uint8_T)
((uint32_T)bp0[iLeft + 1U] - bpLeftVar);
} //插值计算: 分子为 目标位置-左边 分母 右边-左边 得到占的比例。
//此处<<24 即*2^24可提高精度
else if (u0 <= bp0[0U]) {
frac = 0U;
} else {
frac = 16777216U; // 2^24
}
// 一维线性插值
bpLeftVar = table[iLeft + 1U];
uint8_T yL_0d0 = table[iLeft];
if (bpLeftVar >= yL_0d0) {
y = (uint8_T)(((uint32_T)(bpLeftVar - yL_0d0) * frac) >> 24) + yL_0d0;
//比例有了那么就可计算y轴, 插值= (y右-y左)*比例+y左 注意上一步为提高精度<<24 最后要>>24 消除//掉
} else {
y = yL_0d0 - (uint8_T)(((uint32_T)(yL_0d0 - bpLeftVar) * frac) >> 24);
}
return y; //最终返回插值计算的y轴值
}
2. 现在看该模型Simulink 实际生成的code
A: 将X 轴 Y 轴进行数组化,1-D table 成为两个相同大小的数组
/* Definition for custom storage class: Global */
PRAGMA_MAPDATA const uint8_T Lookup1_X[5] = { 1U, 2U, 3U, 4U, 5U } ;
/* Referenced by: '<S3>/1-D Lookup Table' */
PRAGMA_MAPDATA const uint8_T Lookup1_Y[5] = { 10U, 20U, 30U, 40U, 50U } ;
/* Referenced by: '<S3>/1-D Lookup Table' */
PRAGMA_MAPDATA const uint8_T lookup2_X[5] = { 1U, 2U, 3U, 4U, 5U } ;
/* Referenced by: '<S3>/2-D Lookup Table' */
PRAGMA_MAPDATA const uint8_T lookup2_Y[5] = { 10U, 20U, 30U, 40U, 50U } ;
/* Referenced by: '<S3>/2-D Lookup Table' */
PRAGMA_MAPDATA const uint8_T lookup2_Z[25] = { 9U, 8U, 7U, 6U, 5U, 8U, 7U, 6U,
5U, 4U, 7U, 6U, 5U, 4U, 3U, 6U, 5U, 4U, 3U, 2U, 5U, 4U, 3U, 2U, 1U } ;
/* Referenced by: '<S3>/2-D Lookup Table' */
PRAGMA_MAPDATA const uint8_T lookuptableIN = 3U;/* Referenced by: '<S3>/Constant' */
PRAGMA_MAPDATA const uint8_T lookuptableIN2 = 5U;/* Referenced by: '<S3>/Constant1' */
B-生成计算线性插值的回调函数
uint8_T look1_iu8lu32n24_binlcse(uint8_T u0, const uint8_T bp0[], const uint8_T
table[], uint32_T maxIndex)
{
uint32_T frac;
uint32_T iLeft;
uint32_T iRght;
uint8_T bpLeftVar;
uint8_T y;
uint8_T yL_0d0;
if (u0 <= bp0[0U]) {//如果目标小于X轴范围 那么fac=0,那么会得到X轴最小值对应的数
iLeft = 0U;
frac = 0U;
} else if (u0 < bp0[maxIndex]) {//如果目标正常在X 范围,那么进行二分搜寻
/* Binary Search */
frac = maxIndex >> 1U; //取中
iLeft = 0U;
iRght = maxIndex;
while (iRght - iLeft > 1U) {
if (u0 < bp0[frac]) {
iRght = frac;
} else {
iLeft = frac;
}//重新限定范围
frac = (iRght + iLeft) >> 1U;//更新取中,直到找到X轴相邻的两个元素的区间
}
bpLeftVar = bp0[iLeft];
frac = ((uint32_T)(uint8_T)((uint32_T)u0 - bpLeftVar) << 24) / (uint8_T)
((uint32_T)bp0[iLeft + 1U] - bpLeftVar);
//计算 目标值在该区间内占得比例
} else {//如果目标值大于X 轴范围 会得到x轴最大值对应的Y值
iLeft = maxIndex - 1U;
frac = 16777216U;
}
//计算最终的插值 y
bpLeftVar = table[iLeft + 1U];
yL_0d0 = table[iLeft];//获得区间左右对应的y
if (bpLeftVar >= yL_0d0) {//如果是增函数
y = (uint8_T)((uint32_T)(uint8_T)(((uint8_T)((uint32_T)bpLeftVar - yL_0d0) *
frac) >> 24) + yL_0d0);
} else {//如果是减函数
y = (uint8_T)((uint32_T)yL_0d0 - (uint8_T)(((uint8_T)((uint32_T)yL_0d0 -
bpLeftVar) * frac) >> 24));
}
return y;
}
C-调用插值计算函数。
looktableOUT = (uint16_T)((uint32_T)((uint8_T)128U) * look1_iu8lu32n24_binlcse
(lookuptableIN, (&(Lookup1_X[0])), (&(Lookup1_Y[0])), 4U));