你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

线性插值---通用的ADC数据处理子程序

[复制链接]
radio2radio 发布时间:2018-11-25 23:46
本帖最后由 radio2radio 于 2018-11-26 15:51 编辑

虽然这个话题是程序员的基本功,但是,每一次实际使用时都要“重新编程+除错”折腾一番。
于是,萌发了搞一个“通用的”,目的是,下次用到时,拿过来就用。
大家看看我的方法是不是最佳的,欢迎提出改进方案。

由MCU的ADC读到的“真实世界”的数据,0~1023对应10bit的ADC,0~4095对应12bit,0~65535对应16bit。通常,这些数据都要通过简单的数据处理,变换成电压/电流/温度/压力/等等意义明确的数值,用于传输或者显示。

线性插值,就是最最常用的数据处理方法。 直线函数公式:
My Formula.jpg


应用实例,某电池的“电压—容量”测量估算结果,大致如下图所示:
BatteryCap vs Data.JPG

由曲线上面可以看出,虽然已经有了10组实测数据,但是只要取其中黄色的4组数据,也就是用3段直线进行线性插值,就可以得到很好的“近似结果”。
下图,就是用我的“通用线性插值程序”得到的计算结果,看图形,基本上一样的。
(注意,ADC数据所对应的电池电压值,只是测量ADC数据时用可调电源代替电池的外加电压,它们并不参与运算。 直接由ADC数据插值出电池的剩余电量。)
Test result-1.JPG



正弦曲线测试实例,使用37个X轴等间隔的数据(每10度一个),线性插值出0-360度的范围一段正弦曲线的结果:
(为了提高转换精度,合理的做法是在曲线变化剧烈的部分,密集取点;线性好的部分,少量取点。而不是采用等间隔的方式取点。)
Test result-2.JPG



最后,给出子程序:
需要说明的是,笔者对有符号的整数(int)和浮点数(float)有“原始的抵触”,喜欢使用无符号整数类型(uint)。所以只做出了整数类型的。


  1. //General integer Linear Interpolation
  2. //
  3. //setup: uint16_t Y[size] = {Y0, Y1, Y2, , , Ysize-1};
  4. //setup: uint16_t X[size] = {X0, X1, X2, , , Xsize-1};
  5. // - Two Arrays in integer format, Unsigned, no negative values.
  6. // - X[0]<X[1]<X[2]......<Xn, must increasing.

  7. //Test data-1, battery capacity:
  8. const uint16_t X[] = {31778, 33442, 39398, 40421};
  9. const uint16_t Y[] = {0,     29,    94,    100  };

  10. //Test data-2, sine wave:
  11. //const uint16_t X[] = {0,10,20,30,40,50,60,70,80,90,
  12. //                      100,110,120,130,140,150,160,170,180,190,
  13. //                      200,210,220,230,240,250,260,270,280,290,
  14. //                      300,310,320,330,340,350,360};
  15. //const uint16_t Y[] = {2000,2174,2342,2500,2643,2766,2866,2940,2985,3000,
  16. //                      2985,2940,2866,2766,2643,2500,2342,2174,2000,1826,
  17. //                      1658,1500,1357,1234,1134,1060,1015,1000,1015,1060,
  18. //                      1134,1234,1357,1500,1658,1826,2000};


  19. uint16_t u16LinearInterpolation(uint16_t xdata)
  20. {
  21.   uint32_t u32Temp;
  22.   int i,size;
  23.   
  24.   size = sizeof(X)/2; //get the array numbers, uint16_t occupied 2 bytes.
  25.   
  26.   if (xdata <= X[0]) return Y[0];
  27.   if (xdata >= X[size-1]) return Y[size-1];
  28.   
  29.   for (i=0; i<(size-1); i++)
  30.   {
  31.     if ((xdata >= X[i]) && (xdata < X[i+1])) break;   
  32.   }
  33.   
  34.   if ((xdata == X[i]) || (Y[i] == Y[i+1])) return Y[i];
  35.   
  36.   //Y(x)=[Yi*(Xi+1-x)+Yi+1*(x-Xi)]/(Xi+1-Xi)
  37.   u32Temp = Y[i]*(X[i+1]-xdata);
  38.   u32Temp += Y[i+1]*(xdata-X[i]);
  39.   u32Temp /= X[i+1]-X[i];

  40.   return (uint16_t) u32Temp;
  41. }
复制代码





收藏 2 评论3 发布时间:2018-11-25 23:46

举报

3个回答
STM1024 回答时间:2018-11-26 10:11:41
尽量避免使用有符号整数和浮点数是比较明智的做法~~甚至不要去假定int就是32位的
zjczm 回答时间:2018-11-26 10:36:30
很不错。
legenderw 回答时间:2019-1-31 14:11:23
不错!收了

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版