搜索
bottom↓
回复: 33

求助均方根计算公式,用于计算交流有效电压值

[复制链接]

出0入0汤圆

发表于 2020-10-22 21:12:48 | 显示全部楼层 |阅读模式
用单片机的ADC采样128个点,现在程序已经采样到128个点,通过串口输出至电脑看波形也正常,现在要如何计算出电压值?也就是均方根公式,要如何计算?用的STC15W4K32S4的单片机。

出0入79汤圆

发表于 2020-10-22 21:25:20 | 显示全部楼层
均方根要什么公式?直接算就是了。平方和在平均再开方。调用C库函数。 我以前用EFM32 计算过交流电流。

出0入162汤圆

发表于 2020-10-22 21:34:31 来自手机 | 显示全部楼层
要求不高的话直接绝对值求和取平均乘个系数就是有效值。

出0入0汤圆

 楼主| 发表于 2020-10-22 21:53:48 | 显示全部楼层
AWEN2000 发表于 2020-10-22 21:34
要求不高的话直接绝对值求和取平均乘个系数就是有效值。

这样不准的,还是均方根值比较准确。

出0入0汤圆

 楼主| 发表于 2020-10-22 21:54:57 | 显示全部楼层
BOERLBH 发表于 2020-10-22 21:25
均方根要什么公式?直接算就是了。平方和在平均再开方。调用C库函数。 我以前用EFM32 计算过交流电流。 ...

我之前就在坛内看过该公式,找了好久没有找到。

出0入16汤圆

发表于 2020-10-22 22:06:42 | 显示全部楼层
很久很久以前做的,电压中心值在VDD/2左右,用整形计算
void calcOutputVoltage(void)
{
        int8 i;
        int32 tempV,OutVoltageSum;
        if (!OutputVoltageCalcDone)
        {
                OutVoltageSum = 0;
                for(i = 0;i<OutVoltageSumCounter; i++)
                {
                        if (tempOutVoltage[i]  > adcValueZeroOutVoltage)
                        {
                                tempV = tempOutVoltage[i] - adcValueZeroOutVoltage;
                        }
                        else
                        {
                                tempV = adcValueZeroOutVoltage - tempOutVoltage[i];
                        }
                        tempV = tempV * tempV;
                        OutVoltageSum +=  tempV;
                }
                OutVoltageSum = (OutVoltageSum /MAX_ADC_SAMPLE_TIMES);
                OutVoltageSum = sqrt(OutVoltageSum);
                OutVoltage = (OutVoltageSum* 2075)>>8;
                OutVoltageSumCounter = 0;
                OutputVoltageCalcDone = 1;       
        }
}

出0入79汤圆

发表于 2020-10-22 22:15:59 | 显示全部楼层
冈板日川 发表于 2020-10-22 21:54
我之前就在坛内看过该公式,找了好久没有找到。

void adc_process(void)
{
    uint8_t cha = 0, cm = 0;

    int adv = 0;
    float iav = 0;

    // 计算电流
    for(cha = 0; cha < CHANNEL_SUM; cha++)
    {
        ADC_ZER[cha] = 0;
        ADC_ADV[cha] = 0;
        ADC_RMS[cha] = 0;
                       
        for(cm = 0; cm < 128; cm++)                                 // 采集128次 求均方根值
        {
            adv = ADC_ARR[cha][cm] - adc_init_val[7-cha];
            ADC_ADV[cha] += adv * adv;
        }
        ADC_ADV[cha] = ADC_ADV[cha] >> 7;
        ADC_RMS[cha] = isqrt32((uint32_t)ADC_ADV[cha]);
        iav = (float)ADC_RMS[cha] / 4095 * 2.5 / RK / IK ;     // 电流 单位 mA
        current[7-cha] = (int)iav;
    }
}

出0入79汤圆

发表于 2020-10-22 22:16:33 | 显示全部楼层
//开根号的函数
uint16_t isqrt32(uint32_t x)
{
    uint32_t m, y, b;
    m = 0x40000000;
    y = 0;
    while (m != 0)
    {
        b = y | m;
        y = y >> 1;
        if (x >= b)
        {
            x = x - b;
            y = y | m;
        }
        m >>= 2;
    }
    return y;
}

出0入0汤圆

 楼主| 发表于 2020-10-22 22:40:48 | 显示全部楼层
BOERLBH 发表于 2020-10-22 22:16
//开根号的函数
uint16_t isqrt32(uint32_t x)
{

我用的是51啊。

出0入0汤圆

 楼主| 发表于 2020-10-22 22:44:03 | 显示全部楼层
BOERLBH 发表于 2020-10-22 22:15
void adc_process(void)
{
    uint8_t cha = 0, cm = 0;

采集到的数据是10位的,不是8位的数据。要怎么处理?

出0入162汤圆

发表于 2020-10-22 22:46:12 来自手机 | 显示全部楼层
本帖最后由 AWEN2000 于 2020-10-22 22:47 编辑
冈板日川 发表于 2020-10-22 21:53
这样不准的,还是均方根值比较准确。


不准?还可以吧。普通万用表就是测的也是平均值。
计算一般市电交流电压足够了,如果波形畸变厉害是不够准的。
也用不了128次采样的,32次都够了。
但是老大,你是51啊,算开根号?开玩笑吧

出0入0汤圆

 楼主| 发表于 2020-10-22 22:51:51 | 显示全部楼层
AWEN2000 发表于 2020-10-22 22:46
不准?还可以吧。普通万用表就是测的也是平均值。
计算一般市电交流电压足够了,如果波形畸变厉害是不够 ...

就是因为波形有畸变,所以才需要用均方根计算。

出0入442汤圆

发表于 2020-10-22 23:09:19 来自手机 | 显示全部楼层
AWEN2000 发表于 2020-10-22 22:46
不准?还可以吧。普通万用表就是测的也是平均值。
计算一般市电交流电压足够了,如果波形畸变厉害是不够 ...

没毛病啊。整数开平方根很容易的。先猜根,当最高位1后面有偶数个位时,丢一半,就是假根,如果是奇数,丢一半+1个(即留一半-1个),把最高位1后面添个0。然后用这个猜出来的假根做两次牛顿迭代,就可以得到精度+-1的整数二次方根。这个算法已经验证了的。

不仅仅是这个算法,以2为底的指数对数都有快速计算公式。整数部分直接数位,小数部分直接查表。对log2(x),最高位位置-1即为整数值,小数直接查表。对2^x,整数部分直接移位,溢出另外处理,然后小数部分查表,然后直接和整数部分相乘。精度和你的表。项有关,表越细精度越高。

出0入0汤圆

 楼主| 发表于 2020-10-23 00:22:10 | 显示全部楼层
奇怪了,用上面的公式,计算出来的结果和实际相差非常的大。

出0入0汤圆

 楼主| 发表于 2020-10-23 00:37:26 | 显示全部楼层
以下是完整的采样以及计算公式,两个开平方返回的结果是一样的,说明公式应该没有问题,主要是我自己写的这部分程序哪里不对,平均值是正确的,就是均方根值不正确,两种公式得出的结果是一样的,但是结果不正确。
unsigned int insqrt(unsigned long a)
{
    unsigned long i,c;
    unsigned long b=0;
    unsigned int dat;
    for(i=0x40000000;i!=0;i>>=2)
    {
        c =i+b;
        b>>=1;
        if(c<= a)
        {
            a-=c;
            b+=i;
        }
    }
    dat=b;
    return dat;
}


unsigned int  isqrt32(unsigned long x)
{
    unsigned long m, y, b;
    m = 0x40000000;
    y = 0;
    while (m != 0)
    {
        b = y | m;
        y = y >> 1;
        if (x >= b)
        {
            x = x - b;
            y = y | m;
        }
        m >>= 2;
    }
    return y;
}

void READ_SYS_Voltage(void)//读取系统电压
{
    unsigned char i,DL;
    unsigned int Dat=0;
    unsigned int  xdata a[140];
    unsigned long b=0,p=0;
    for(i=138;i>0;i--)//清空数组内数据
    {
        a[i]=0;   
    }
    TF1 = 0;       //清除TF1标志
    ET1 = 0;       //关闭定时器1中断
    TR1 = 0;       //定时器1关闭计时   
    TH1 = 0x00;    //初始化计时值
    TH1 = 0xb8;       //初始化计时值 定时20毫秒@11.0592M外置晶振
    TF1 = 0;       //清除TF1标志   
    ET1 = 1;       //使能定时器1中断
    TR1 = 1;       //定时器1开始计时
    READ_Voltage_EN=1;//将定时时间到置1
    Dat=0;
    while(READ_Voltage_EN)//到达20毫秒后,此变量通过定时器1中断置0,退出采样
    {
        ADC_CONTR = 0xc0; //清除ADC    180个时钟转换一次
        ADC_CONTR = 0Xcc; //P1.4
        while(!(ADC_CONTR&0x10));
        a[i]=ADC_RES;
        DL=ADC_RESL;
        a[i]<<=2;
        a[i]|=DL;
        ADC_CONTR = 0xc0; //清除ADC
        a[i]>>=1;
        if(i<139)
        {
            i++;
        }
        Delay_Read();//延时        
        Dat++;   
    }
    Send_ASCII("共计采样:",0);
    WR_DAT(Dat);
   
    DL=i;
    for(i=0;i<DL;i++)
    {
        b+=(a[i]*a[i]);//计算平方和
        p+=a[i];//累加        
    }
    b/=DL;//计算平方和后再平均
    Dat=insqrt(b);//开平方
    a[0]=isqrt32(b);

    Send_ASCII("均方根值1:",0);//第一种均方根计算方式
    WR_DAT(Dat);

    Send_ASCII("均方根值2:",0);//第二种均方根计算方式
    WR_DAT(a[0]);

    Dat=p/DL;//直接平均
    Send_ASCII("平均值:",0);
    WR_DAT(Dat);
    ENT();ENT();
}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入4汤圆

发表于 2020-10-23 00:57:26 | 显示全部楼层
这样是不行的,电网的频率是变化的,你需要等时采样后均方根才最准,0.1V没有问题

出0入0汤圆

 楼主| 发表于 2020-10-23 01:28:19 | 显示全部楼层
electricit 发表于 2020-10-23 00:57
这样是不行的,电网的频率是变化的,你需要等时采样后均方根才最准,0.1V没有问题
...

等时?现在的采样时间是固定的20毫秒,你说的等时是指需要与电网的频率同步?那要怎么做?

出0入0汤圆

 楼主| 发表于 2020-10-23 01:30:35 | 显示全部楼层
数据错误的问题解决了
        for(i=0;i<DL;i++)
        {
                d=a[i];//强制将数据转换为long类型
                b+=d*d;
                p+=a[i];//累加               
        }

出0入42汤圆

发表于 2020-10-23 08:02:24 | 显示全部楼层
冈板日川 发表于 2020-10-23 01:28
等时?现在的采样时间是固定的20毫秒,你说的等时是指需要与电网的频率同步?那要怎么做? ...

哈,你一个周期采一个点?
那不各点基本一样的,周期波形哪里来呢。

出0入79汤圆

发表于 2020-10-23 08:12:17 | 显示全部楼层
冈板日川 发表于 2020-10-22 22:44
采集到的数据是10位的,不是8位的数据。要怎么处理?

我的 ADC是 12位  采集8个通道。 产品都用了5年了。 你照着改一下肯定能用。

出0入0汤圆

发表于 2020-10-23 08:21:13 | 显示全部楼层
四倍频采样法,可直接计算出幅度

出0入0汤圆

发表于 2020-10-23 08:22:06 | 显示全部楼层
冈板日川 发表于 2020-10-23 01:28
等时?现在的采样时间是固定的20毫秒,你说的等时是指需要与电网的频率同步?那要怎么做? ...

做过交流电压表,先计算出电压的频率(如果频率固定可省略),例如50HZ  那么一个周期20mS  在20ms内采集128个点(间隔20mS/128  可以不用等待过零随时开始)每个点先计算平方数  在相加  等待取完128个点时  累加和/128 再开方 就得到结果

出0入0汤圆

发表于 2020-10-23 08:40:32 | 显示全部楼层
还有交流有正负周期 算两个幅值  128个点的数据只算一半就可以了, 如果要精确的算正周期/负周期 就要做过零了
简易的方式 二极管取半波 电阻分压 直接送入单片机ADC  取128个点数据  平均时/64 因为没有负半周

出0入0汤圆

发表于 2020-10-23 08:54:20 来自手机 | 显示全部楼层
虽然两个词是通用的,还是建议使用“方均根”,这里面是有计算顺序的

出0入0汤圆

 楼主| 发表于 2020-10-23 09:09:02 | 显示全部楼层
liujian6f 发表于 2020-10-23 08:22
做过交流电压表,先计算出电压的频率(如果频率固定可省略),例如50HZ  那么一个周期20mS  在20ms内采集 ...

如果不是50HZ,要如何处理?

出0入0汤圆

发表于 2020-10-23 09:10:23 | 显示全部楼层
AWEN2000 发表于 2020-10-22 22:46
不准?还可以吧。普通万用表就是测的也是平均值。
计算一般市电交流电压足够了,如果波形畸变厉害是不够 ...


STC8浮点数开根号也就几十微秒,算市电交流电也足够了

出50入4汤圆

发表于 2020-10-23 09:13:24 | 显示全部楼层
软件不行,就硬件上,速度不快就直接硬件转换,,

出0入0汤圆

发表于 2020-10-23 09:42:06 | 显示全部楼层
冈板日川 发表于 2020-10-23 09:09
如果不是50HZ,要如何处理?

定频就好办  例如60Hz  周期就是16.6666mS     如果用的是 例如发电机上时 频率都是有误差的 所以要先计算频率

出0入0汤圆

 楼主| 发表于 2020-10-23 09:54:17 | 显示全部楼层
s1j2h3 发表于 2020-10-23 08:21
四倍频采样法,可直接计算出幅度

那样太占系统时间和资源了。

出0入0汤圆

 楼主| 发表于 2020-10-23 09:56:04 | 显示全部楼层
liujian6f 发表于 2020-10-23 09:42
定频就好办  例如60Hz  周期就是16.6666mS     如果用的是 例如发电机上时 频率都是有误差的 所以要先计 ...

是用在工业设备里的,正常的情况下,国内的电网频率都是50HZ的吧,变化应该不会太大的吧。这个主要是用来测量电机电流是不是失衡,是不是过流等。

出0入162汤圆

发表于 2020-10-23 09:59:27 来自手机 | 显示全部楼层
冈板日川 发表于 2020-10-23 09:56
是用在工业设备里的,正常的情况下,国内的电网频率都是50HZ的吧,变化应该不会太大的吧。这个主要是用来 ...

电机过流?精度应该要求不高吧,似乎没必要用真有效值

出0入0汤圆

 楼主| 发表于 2020-10-23 10:00:56 | 显示全部楼层
AWEN2000 发表于 2020-10-23 09:59
电机过流?精度应该要求不高吧,似乎没必要用真有效值

系统还要做PID调整,对电流有一定的精度要求。

出0入4汤圆

发表于 2020-10-23 18:34:26 | 显示全部楼层
冈板日川 发表于 2020-10-23 01:28
等时?现在的采样时间是固定的20毫秒,你说的等时是指需要与电网的频率同步?那要怎么做? ...

过零检测一个周波的时长,采样32点时将时长32等份写入定时器,定时器触发采样,每个周波都要更新一下定时器溢出值,然后均方根非常准

出0入0汤圆

发表于 2020-10-24 17:15:53 | 显示全部楼层
冈板日川 发表于 2020-10-23 09:09
如果不是50HZ,要如何处理?

过零时开始,下次或N次过零时结束,之后计算,
或用一个很长的时间平均下减少不是整周期的误差
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-19 10:10

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表