求助均方根计算公式,用于计算交流有效电压值
用单片机的ADC采样128个点,现在程序已经采样到128个点,通过串口输出至电脑看波形也正常,现在要如何计算出电压值?也就是均方根公式,要如何计算?用的STC15W4K32S4的单片机。 均方根要什么公式?直接算就是了。平方和在平均再开方。调用C库函数。 我以前用EFM32 计算过交流电流。 要求不高的话直接绝对值求和取平均乘个系数就是有效值。 AWEN2000 发表于 2020-10-22 21:34要求不高的话直接绝对值求和取平均乘个系数就是有效值。
这样不准的,还是均方根值比较准确。 BOERLBH 发表于 2020-10-22 21:25
均方根要什么公式?直接算就是了。平方和在平均再开方。调用C库函数。 我以前用EFM32 计算过交流电流。 ...
我之前就在坛内看过该公式,找了好久没有找到。 很久很久以前做的,电压中心值在VDD/2左右,用整形计算
void calcOutputVoltage(void)
{
int8 i;
int32 tempV,OutVoltageSum;
if (!OutputVoltageCalcDone)
{
OutVoltageSum = 0;
for(i = 0;i<OutVoltageSumCounter; i++)
{
if (tempOutVoltage> adcValueZeroOutVoltage)
{
tempV = tempOutVoltage - adcValueZeroOutVoltage;
}
else
{
tempV = adcValueZeroOutVoltage - tempOutVoltage;
}
tempV = tempV * tempV;
OutVoltageSum +=tempV;
}
OutVoltageSum = (OutVoltageSum /MAX_ADC_SAMPLE_TIMES);
OutVoltageSum = sqrt(OutVoltageSum);
OutVoltage = (OutVoltageSum* 2075)>>8;
OutVoltageSumCounter = 0;
OutputVoltageCalcDone = 1;
}
} 冈板日川 发表于 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 = 0;
ADC_ADV = 0;
ADC_RMS = 0;
for(cm = 0; cm < 128; cm++) // 采集128次 求均方根值
{
adv = ADC_ARR - adc_init_val;
ADC_ADV += adv * adv;
}
ADC_ADV = ADC_ADV >> 7;
ADC_RMS = isqrt32((uint32_t)ADC_ADV);
iav = (float)ADC_RMS / 4095 * 2.5 / RK / IK ; // 电流 单位 mA
current = (int)iav;
}
}
//开根号的函数
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;
} BOERLBH 发表于 2020-10-22 22:16
//开根号的函数
uint16_t isqrt32(uint32_t x)
{
我用的是51啊。{:cry:} BOERLBH 发表于 2020-10-22 22:15
void adc_process(void)
{
uint8_t cha = 0, cm = 0;
采集到的数据是10位的,不是8位的数据。要怎么处理? 本帖最后由 AWEN2000 于 2020-10-22 22:47 编辑
冈板日川 发表于 2020-10-22 21:53
这样不准的,还是均方根值比较准确。
不准?还可以吧。普通万用表就是测的也是平均值。
计算一般市电交流电压足够了,如果波形畸变厉害是不够准的。
也用不了128次采样的,32次都够了。
但是老大,你是51啊,算开根号?开玩笑吧 AWEN2000 发表于 2020-10-22 22:46
不准?还可以吧。普通万用表就是测的也是平均值。
计算一般市电交流电压足够了,如果波形畸变厉害是不够 ...
就是因为波形有畸变,所以才需要用均方根计算。 AWEN2000 发表于 2020-10-22 22:46
不准?还可以吧。普通万用表就是测的也是平均值。
计算一般市电交流电压足够了,如果波形畸变厉害是不够 ...
没毛病啊。整数开平方根很容易的。先猜根,当最高位1后面有偶数个位时,丢一半,就是假根,如果是奇数,丢一半+1个(即留一半-1个),把最高位1后面添个0。然后用这个猜出来的假根做两次牛顿迭代,就可以得到精度+-1的整数二次方根。这个算法已经验证了的。
不仅仅是这个算法,以2为底的指数对数都有快速计算公式。整数部分直接数位,小数部分直接查表。对log2(x),最高位位置-1即为整数值,小数直接查表。对2^x,整数部分直接移位,溢出另外处理,然后小数部分查表,然后直接和整数部分相乘。精度和你的表。项有关,表越细精度越高。 奇怪了,用上面的公式,计算出来的结果和实际相差非常的大。 以下是完整的采样以及计算公式,两个开平方返回的结果是一样的,说明公式应该没有问题,主要是我自己写的这部分程序哪里不对,平均值是正确的,就是均方根值不正确,两种公式得出的结果是一样的,但是结果不正确。
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 intisqrt32(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 intxdata a;
unsigned long b=0,p=0;
for(i=138;i>0;i--)//清空数组内数据
{
a=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=ADC_RES;
DL=ADC_RESL;
a<<=2;
a|=DL;
ADC_CONTR = 0xc0; //清除ADC
a>>=1;
if(i<139)
{
i++;
}
Delay_Read();//延时
Dat++;
}
Send_ASCII("共计采样:",0);
WR_DAT(Dat);
DL=i;
for(i=0;i<DL;i++)
{
b+=(a*a);//计算平方和
p+=a;//累加
}
b/=DL;//计算平方和后再平均
Dat=insqrt(b);//开平方
a=isqrt32(b);
Send_ASCII("均方根值1:",0);//第一种均方根计算方式
WR_DAT(Dat);
Send_ASCII("均方根值2:",0);//第二种均方根计算方式
WR_DAT(a);
Dat=p/DL;//直接平均
Send_ASCII("平均值:",0);
WR_DAT(Dat);
ENT();ENT();
}
这样是不行的,电网的频率是变化的,你需要等时采样后均方根才最准,0.1V没有问题
electricit 发表于 2020-10-23 00:57
这样是不行的,电网的频率是变化的,你需要等时采样后均方根才最准,0.1V没有问题
...
等时?现在的采样时间是固定的20毫秒,你说的等时是指需要与电网的频率同步?那要怎么做? 数据错误的问题解决了
for(i=0;i<DL;i++)
{
d=a;//强制将数据转换为long类型
b+=d*d;
p+=a;//累加
} 冈板日川 发表于 2020-10-23 01:28
等时?现在的采样时间是固定的20毫秒,你说的等时是指需要与电网的频率同步?那要怎么做? ...
哈,你一个周期采一个点?
那不各点基本一样的,周期波形哪里来呢。
冈板日川 发表于 2020-10-22 22:44
采集到的数据是10位的,不是8位的数据。要怎么处理?
我的 ADC是 12位采集8个通道。 产品都用了5年了。 你照着改一下肯定能用。 四倍频采样法,可直接计算出幅度 冈板日川 发表于 2020-10-23 01:28
等时?现在的采样时间是固定的20毫秒,你说的等时是指需要与电网的频率同步?那要怎么做? ...
做过交流电压表,先计算出电压的频率(如果频率固定可省略),例如50HZ那么一个周期20mS在20ms内采集128个点(间隔20mS/128可以不用等待过零随时开始)每个点先计算平方数在相加等待取完128个点时累加和/128 再开方 就得到结果 还有交流有正负周期 算两个幅值128个点的数据只算一半就可以了, 如果要精确的算正周期/负周期 就要做过零了
简易的方式 二极管取半波 电阻分压 直接送入单片机ADC取128个点数据平均时/64 因为没有负半周{:lol:}{:lol:}{:lol:} 虽然两个词是通用的,还是建议使用“方均根”,这里面是有计算顺序的 liujian6f 发表于 2020-10-23 08:22
做过交流电压表,先计算出电压的频率(如果频率固定可省略),例如50HZ那么一个周期20mS在20ms内采集 ...
如果不是50HZ,要如何处理? AWEN2000 发表于 2020-10-22 22:46
不准?还可以吧。普通万用表就是测的也是平均值。
计算一般市电交流电压足够了,如果波形畸变厉害是不够 ...
STC8浮点数开根号也就几十微秒,算市电交流电也足够了 软件不行,就硬件上,速度不快就直接硬件转换,, 冈板日川 发表于 2020-10-23 09:09
如果不是50HZ,要如何处理?
定频就好办例如60Hz周期就是16.6666mS 如果用的是 例如发电机上时 频率都是有误差的 所以要先计算频率 s1j2h3 发表于 2020-10-23 08:21
四倍频采样法,可直接计算出幅度
那样太占系统时间和资源了。 liujian6f 发表于 2020-10-23 09:42
定频就好办例如60Hz周期就是16.6666mS 如果用的是 例如发电机上时 频率都是有误差的 所以要先计 ...
是用在工业设备里的,正常的情况下,国内的电网频率都是50HZ的吧,变化应该不会太大的吧。这个主要是用来测量电机电流是不是失衡,是不是过流等。 冈板日川 发表于 2020-10-23 09:56
是用在工业设备里的,正常的情况下,国内的电网频率都是50HZ的吧,变化应该不会太大的吧。这个主要是用来 ...
电机过流?精度应该要求不高吧,似乎没必要用真有效值 AWEN2000 发表于 2020-10-23 09:59
电机过流?精度应该要求不高吧,似乎没必要用真有效值
系统还要做PID调整,对电流有一定的精度要求。 冈板日川 发表于 2020-10-23 01:28
等时?现在的采样时间是固定的20毫秒,你说的等时是指需要与电网的频率同步?那要怎么做? ...
过零检测一个周波的时长,采样32点时将时长32等份写入定时器,定时器触发采样,每个周波都要更新一下定时器溢出值,然后均方根非常准 冈板日川 发表于 2020-10-23 09:09
如果不是50HZ,要如何处理?
过零时开始,下次或N次过零时结束,之后计算,
或用一个很长的时间平均下减少不是整周期的误差
页:
[1]