容易出错的测量样本的平均值,没有缓冲

时间:2017-04-30 10:18:49

标签: c average microcontroller adc

我得到了一个μC,它用一个带有ADC的传感器测量温度。由于各种情况,可能会发生读数为0(-30°C)或不可能的大值(500-1500°C)。我无法解决为什么这些读数如此糟糕(时间要求严格的ISR,有时候接线不良)的原因,所以我必须用一段聪明的代码修复它。

我想出了这个(代码在ISR中被称为OVERSAMPLENR-times):

#define OVERSAMPLENR 16 //read value 16 times
#define TEMP_VALID_CHANGE 0.15 //15% change in reading is possible
//float raw_tem_bed_value = <sum of all readings>;
//ADC = <AVR ADC reading macro>;
if(temp_count > 1) { //temp_count = amount of samples read, gets increased elsewhere
  float avgRaw = raw_temp_bed_value / temp_count;
  float diff = (avgRaw > ADC ? avgRaw - ADC : ADC - avgRaw) / (avgRaw == 0 ? 1 : avgRaw); //pulled out to shorten the line for SO
  if (diff > TEMP_VALID_CHANGE * ((OVERSAMPLENR - temp_count) / OVERSAMPLENR)) //subsequent readings have a smaller tollerance
    raw_temp_bed_value += avgRaw;
  else
    raw_temp_bed_value += ADC;
} else {
  raw_temp_bed_value = ADC;
}

raw_temp_bed_value是一个静态全局变量,稍后会被读取和处理,当ISR被触发16次时。

如您所见,我检查当前平均值与新读数之间的差异是否小于15%。如果是这样我接受阅读,如果没有,我拒绝它并添加当前的平均值。 但如果第一次阅读是不可能的事情,这会破坏性的。

我的一个解决方案是: 在最后一行中,raw_temp_bed_value被重置为第一个ADC读数。最好将其重置为raw_temp_bed_value/OVERSAMPLENR。所以我没有遇到“第一次阅读错误”。

你有更好的解决方案吗?我虽然有一些移动平均线的解决方案并使用移动平均线的平均值,但这需要我们想要防止的额外阵列/ RAM /周期。

1 个答案:

答案 0 :(得分:0)

我经常使用我称之为采样率的变化率。使用一个变量来表示达到某个值所需的样本数量,例如20.然后继续将样本差异添加到变量除以变化率。您仍然可以使用阈值来过滤掉不太可能的值。

float RateOfChange = 20;
float PreviousAdcValue = 0;
float filtered = FILTER_PRESET;

while(1)
{
    //isr gets adc value here        
    filtered = filtered + ((AdcValue - PreviousAdcValue)/RateOfChange);
    PreviousAdcValue = AdcValue;
    sleep();
}

请注意,这与低通滤波器不完全相同,它响应更快,最后添加的值具有最重要的意义。但是,如果一个单一的价值出现过多,根据变化的速度,它不会发生太大的变化。

您还可以将过滤后的值预设为合理的值。这可以防止野外启动行为。

RateOfChange样本需要达到稳定值。您可能需要确保在此之前不使用过滤后的值,例如使用计数器来计算采样的数量。如果计数器低于RateOfChange,则跳过处理温度控制。

对于更高级(温度)控制程序,我强烈建议您研究PID控制回路。这些功能增加了大量功能,可以获得快速,稳定的响应,并有效地保持某些温度,并将振荡降至最低。我在我自己的项目中使用了Marlin固件中使用的那个,效果很好。