基于CW32的仪表精度测量实现(三):标定与校准

cathy的头像
cathy 发布于:周四, 07/18/2024 - 17:53 ,关键词:

标定的概念

标定是一种校准过程,它通过与已知的标准或参考值进行比较来确保测量设备、仪器或系统的准确性和可靠性。这个过程涉及调整设备,以消除系统误差和提高测量结果与真实值的一致性,从而确保数据的精确度和可重复性。 

1.为什么去标定

我们使用单片机ADC读取的电压电流值由于制造公差、温度变化、时间老化、电源波动等因素引起的初始误差和漂移,我们需要对电压电流进行标定校准,使得我们得到的电压电流值是正确的。

2.标定的方法

标定的方法多种多样,我们需要根据自己的需求来选择相应的方法,常见的标定方法如下所示:

(1)直接比较法:

将待标定的测量设备与一个已知准确度的标准设备进行比较,直接读取并记录差异。

(2)多点标定法:

在多个已知的标准点上进行测量,收集数据点,然后通过数学模型(如多项式拟合)来确定设备输出与标准值之间的关系。

(3)线性回归法:

使用最小二乘法等统计技术,通过拟合最佳拟合线来确定设备输出与标准输入值之间的线性关系。

(4)分段线性标定:

当测量设备的响应在不同输入范围内呈现不同的线性度时,可以采用分段线性标定,即在不同的输入范围内使用不同的线性模型。 

(5)非线性标定:

对于非线性设备,使用非线性函数(如指数、对数或S形曲线)来描述输入与输出之间的关系。

标定的实现

1.CW32开发板的实物图和原理图

 1.png 2.png

2.软件代码讲解

(1)滤波算法

在做电压值的校准之前,我们根据传感器采集到的是连续性的时间序列信号,所以我们可以采用了均值滤波对单片机采集到的AD值进行滤波处理。

在程序中我首先初始化总和、最大值和最小值变量,然后在一个循环中累加数组 value 中所有元素的值,并同时更新最大值和最小值。循环结束后,从总和中减去最大值和最小值,以排除可能的异常数据点,最后将调整后的总和除以数组元素数减去2,得到并返回一个滤除极端值后的均值。这种方法有助于减少数据中的噪声,特别是当数据集中包含异常高值或低值时。代码如下所示:

uint32_t Mean_Value_Filter(uint16_t *value, uint32_t size)     //均值滤波
{  
    uint32_t sum = 0;         //ADC采样数据和  
    uint16_t max = 0;  
    uint16_t min = 0xffff;    //min初值取最大是为了将第一个数据记录  
    int      i;  
    for(i = 0; i < size; i++)    
    {        
        sum += value[i];        
        if(value[i] > max)        
        {            
            max = value[i];        
        }        
        if(value[i] < min)        
        {            
            min = value[i];        
        }    
    }    
    sum -= max + min;       //去除最大最小值    
    sum  = sum / (size - 2);    
    return sum;
}

(2)分段线性标定

在代码中定义了电压校准的相关变量X06和X12,分别代表着6V对应的AD代码值和12V对应的AD代码值。其中还定义了纵坐标的变量Y06和Y12,这个对应着电压值6V和12V。最后定义了坐标轴的斜率K,如下所示:

//5V与15V 校准
unsigned int X06=0;
unsigned int X12=0;

unsigned int Y06=6;
unsigned int Y12=12;
float K; //斜率

在标定校准之前,我们需要计算斜率,根据两点确定一条直线算出该区间内的斜率K,如下图所示:

void Count_K(void)
{  
    K = (Y12 - Y06);  
    K = K/(X12 - X06);
}

我们还需要存储校准值,我们在一个数组中存了三个数据,第一个数据是判断位(0xaa),判断当前是否存储过校准值。其中两个是6V对应的AD代码值和12V对应的AD代码值。存储之前需要擦除然后才能写入数据。代码如下所示:

void flash_calibration(void)
{  
    uint16_t dat[5];  
    dat[0]=0xaa;  
    dat[1]=X06;  
    dat[2]=X12;
    
   flash_erase();  
   flash_write(0,dat,5);
}

我们除了写入校准值还要读取校准值,先读取校准值,判断第一个数据是否为0xaa,如果不是0xaa,代表没校准过,需要赋一个初始化进行存储。例如

X06 = 6.0/23/1.5*4096;如果第一个值是0xaa,那就可以把存储过的值赋给我们的变量就可以了,代码如下所示。

void judge_calibration(void)
{  
    uint16_t dat[5];  
    flash_read(0,dat, 5);  
    if(dat[0]!=0xaa)  
    {    
        X06 = 6.0/23/1.5*4096;    
        X12 = 12.0/23/1.5*4096;    
        flash_calibration();  
    }  
    else  
    {    
        X06=dat[1];    
        X12=dat[2];  
    } 
}

我们可以通过按键对每一个区间的信号进行校准,比如说我们这次校准的是6~12V区间内的信号,初始化时可以通过按下一次按键对6V时候的数据校准,再按一次按键就可以对12V时候的数据校准,代码如下所示:

void button_select_calibration(void)
{  
    if(GPIO_ReadPin(CW_GPIOB,GPIO_PIN_12) == GPIO_Pin_RESET)//按键按下  
    {    
        mode++;    
        if(mode >2)      
            mode =0;    
        while(GPIO_ReadPin(CW_GPIOB,GPIO_PIN_12) == GPIO_Pin_RESET);  
    }   
    
    if(mode == 0)  
    {    
        DisPlay_dianya(V_Buffer);  
    }  
    else if(mode == 1)  
    {    
        X06=Mean_Value_Filter(Volt_Buffer,ADC_SAMPLE_SIZE);    
        flash_calibration();    
        Count_K();    
        Volt_Cal();    
        DisPlay_dianya(V_Buffer);  
    }  
    else if(mode == 2)  
    {    
        X12=Mean_Value_Filter(Volt_Buffer,ADC_SAMPLE_SIZE);    
        flash_calibration();    
        Count_K();    
        Volt_Cal();    
        DisPlay_dianya(V_Buffer);  
    }
}

3.分段线性标定分析和处理

在这个程序中,我们的思想是同时两路AD采集,一个是测量电压的,一个是测量电流的,同时读取AD数据,进而能对二者一起校准。代码如下所示:

void Get_ADC_Value(void)
{  
    static uint8_t cnt;  
    ADC_GetSqr0Result(&Volt_Buffer[cnt]);    
    ADC_GetSqr3Result(&Curr_Buffer[cnt]);    
    cnt++;  
    if(cnt >= ADC_SAMPLE_SIZE)    
    {        
        cnt = 0;    
    }
}

我们在电压电流表上测量了大量的数据,如下图所示:

 3.png

在上面图中可以看出实际的电压值和测量的电压值存在一定的偏差,我们将它们的偏差值做成一个折线图给大家看看,如下图所示。

4.png

常见标定的原理是:使用AD值作为X轴,电压(电流)值作为Y轴;在电压(电流)为0的时候标定为Xmin,在电压(电流)为最大量程的时候标定为Xmax,根据数学公式两点确定一条直线,可以得到这条直线的斜率K。根据Y=kx公式我们可以通过输出每一个AD值得到对应的电压(电流)值。

5.png

常见的标定是在只有最小值和最大值之间做了标定,如果这两个值的范围很大,使用中间的AD值也会出现误差,所以我们就需要多做几组标定,使得数据更加准确,这样就形成了分段线性标定。效果图如下所示。

6.png

如果我们求X3到X2之间的电压值,可以根据公式:Y=k×(Xad-X2)+5得到准确的电压值,在这条折线上标的点越多,测量得到的电压值就越准确。

4.标定的结果

标定之前的实验数据显示,误差在0.08V左右,数据如下所示:

7.png

误差的折线图如下所示:

8.png

实物的测量图显示误差在0.08左右,结果如下所示:

9.png

在6V标定之后实验数据显示误差在0.01V左右,数据如下所示:

10.png

标定校准后的误差的折线图如下所示,可以看出6V标定后的误差范围在0V到0.03V之间的,所以证明了多处标定,得到的测量值就越精确。

11.png

经过标定校准后的电压显示没有误差,结果如下所示:

12.png

来源:CW32生态社区

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 11