1.题目要求
本题要求设计并制作一个根据电源线电流的电参量信息分析在用电器类别的装置。该装置具有学习和分析识别两种工作模式。在学习模式下,测试并存储用于识别各单件电器的特征参量;在分析识别模式下,实时指示在用电器的类别。
其中重点与难点为:
- 电网在不同时间与不同地点会有较大波动,会对大功率用电器测量造成影响,以至于其功率波动可达 ±50W之高,给用电器的准确识别带来极大困难。
- 在测量大功率电器与小功率电器组合时,大功率用电器的频谱特性将会掩盖小功率频谱特性,给识别工作带来极大困难。
- 如何对电流大小相同而阻抗特性不同的用电器进行鉴别。
- 用电器的选择需要再三斟酌,好的用电器组合搭配会让你的初测效果好很多。
2.方案介绍
2.1系统组成
本系统方案主要采用STM32 F407单片机作为系统主控,通过串口同SUI-101A电能计量模块进行通讯,获取有功功率、电压、电流等电参数,并通过这些参数进行用电器识别功能。其中SUI-101A模块通过电流互感器接入插座,监测用电器参数。
2.2硬件电路
原定方案为搭建CS5463模块,但是尝试画了几块板子后模块都无法正常使用,所以紧急购买了SUI-101A模块。 故本系统主要采用了SUI-101A模块获取电能参数。 模块总体布局如下图,模块通过电流与电压互感器分别从负载线路上获取电流与电压信号,并送入24位高精度ADC中进行处理,再将波形数据送入STM8单片机中计算出电流、电压等参数值,最后通过串口传输至STM32 F407中进行数据的分析与用电器的识别。
3.具体设计
3.1程序设计
程序设计的比较简单,具体流程如下:
- 识别部分:由于在测量取得的参数中仅有有功功率可满足线性叠加,故我只使用了有功功率作为识别判据。首先将用电器的参数存进相应用电器的结构体中,并且通过循环取余穷举七位二进制编码生成不同用电器组合,随后将当前负载电路上的有功功率与生成的128种用电器组合功率进行比较,倘若有某组合的误差小于阈值,则断定该组合为当前负载电路上的用电器组合,然后对该组合的二进制编码进行解码得到用电器组合。
- 学习部分:首先将所有用电器结构体中的参数进行清零,随后在红外遥控器上下按下要学习的用电器编号,即可将用电器参数记录到对应用电器编号的结构体中,至此完成学习。
3.2核心代码如下:
u8 SUI_101A_Get(u8 adder,float *vol,float *cur,float *pow,float *pf,float *fre){
u8 t=20;
u8 rxlen=0;
u8 i=0;
u8 sum=0;
u8 n=0;
u8 CmdTxBuf[]={0x55,0x55,0x01,0x02,0x00,0x00,0xAD};
CmdTxBuf[2]=adder;
Uart2_RxCnt=0;
char buf[6];
CmdTxBuf[6]=CmdTxBuf[0]+CmdTxBuf[1]+CmdTxBuf[2]+CmdTxBuf[3]+CmdTxBuf[4]+CmdTxBuf[5];//重新计算校验和
USART_SendBuf(USART2,CmdTxBuf,7);
delay_ms(10); //等待10ms,等待数据返回
while(t){
t--;
rxlen=Uart2_RxCnt;
delay_ms(30); //等待5ms,连续超过5ms没有接收到一个数据,则认为接收结束
if((rxlen==Uart2_RxCnt)&&(rxlen!=0)){//接收到了数据,且接收完成了
if(rxlen==(Uart2_RxBuf[5]+7)){
//数据长度正确
}
else{
return 3;//异常,数据长度错误
}
sum=0;
rxlen-=1;//除去校验位的长度
for(i=0;i<rxlen;i++){
sum+=Uart2_RxBuf[i];
}
if(sum==Uart2_RxBuf[rxlen]){//校验和正确
*vol=(double)(((u32)Uart2_RxBuf[6] <<24)|((u32)Uart2_RxBuf[7] <<16)|((u32)Uart2_RxBuf[8] <<8)|((u32)Uart2_RxBuf[9] <<0))/1000.0;
*cur=(double)(((u32)Uart2_RxBuf[10]<<24)|((u32)Uart2_RxBuf[11]<<16)|((u32)Uart2_RxBuf[12]<<8)|((u32)Uart2_RxBuf[13]<<0))/1000.0;
*pow=(double)(((u32)Uart2_RxBuf[14]<<24)|((u32)Uart2_RxBuf[15]<<16)|((u32)Uart2_RxBuf[16]<<8)|((u32)Uart2_RxBuf[17]<<0))/1000.0;
n=18;
*pf=(double)(s32)(((s32)Uart2_RxBuf[n++]<<24)|((s32)Uart2_RxBuf[n++]<<16)|((s32)Uart2_RxBuf[n++]<<8)|((s32)Uart2_RxBuf[n++]<<0))/10000.0;
*fre=(double)(((u32)Uart2_RxBuf[n++]<<24)|((u32)Uart2_RxBuf[n++]<<16)|((u32)Uart2_RxBuf[n++]<<8)|((u32)Uart2_RxBuf[n++]<<0))/1000.0;
// W_KWH=(double)(((u32)Uart2_RxBuf[n++]<<24)|((u32)Uart2_RxBuf[n++]<<16)|((u32)Uart2_RxBuf[n++]<<8)|((u32)Uart2_RxBuf[n++]<<0))/10000.0;
}
else{//数据校验错误
return 1;
}
break;
}
}
if(t==0){//接收超时,超过100ms未接收到数据
return 2;
}
// printf(" | V:%10.05f | I:%10.05f | P:%10.05f | PF:%10.05f | F:%10.05f | W:%10.05f |\r\n",Vrms,Irms,PActive,PowerFactor,Frequency,W_KWH);
return 0;
}
//学习模式
void learn_mode(void)
{
char tbuf[32];
float voltage; //测量电压
float Current; //测量电流
float Pow_fac; //功率因数
float Pactive_pow; //有功功率
float frequency;
if(learn_flag_0==1){
learn_flag_0=0;
app1.Pactive_pow=0;
app2.Pactive_pow=0;
app3.Pactive_pow=0;
app4.Pactive_pow=0;
app5.Pactive_pow=0;
app6.Pactive_pow=0;
app7.Pactive_pow=0;
if(SUI_101A_Get(1,&Current_proper.voltage,&Current_proper.Current,&Current_proper.Pactive_pow,&Current_proper.Pow_fac,&Current_proper.frequency)==0){
//LCD_ShowString(20,60,200,16,16,"Learning...Please wait.");
if(app_num==1)
{
app1.Current =Current_proper.Current;
app1.voltage =Current_proper.voltage;
app1.Pactive_pow =Current_proper.Pactive_pow;
app1.Pow_fac =Current_proper.Pow_fac;
}
if(app_num==2)
{
app2.Current =Current_proper.Current;
app2.voltage =Current_proper.voltage;
app2.Pactive_pow =Current_proper.Pactive_pow;
app2.Pow_fac =Current_proper.Pow_fac;
}
if(app_num==3)
{
app3.Current =Current_proper.Current;
app3.voltage =Current_proper.voltage;
app3.Pactive_pow =Current_proper.Pactive_pow;
app3.Pow_fac =Current_proper.Pow_fac;
}
if(app_num==4)
{
app4.Current =Current_proper.Current;
app4.voltage =Current_proper.voltage;
app4.Pactive_pow =Current_proper.Pactive_pow;
app4.Pow_fac =Current_proper.Pow_fac;
}
if(app_num==5)
{
app5.Current =Current_proper.Current;
app5.voltage =Current_proper.voltage;
app5.Pactive_pow =Current_proper.Pactive_pow;
app5.Pow_fac =Current_proper.Pow_fac;
}
if(app_num==6)
{
app6.Current =Current_proper.Current;
app6.voltage =Current_proper.voltage;
app6.Pactive_pow =Current_proper.Pactive_pow;
app6.Pow_fac =Current_proper.Pow_fac;
}
if(app_num==7)
{
app7.Current =Current_proper.Current;
app7.voltage =Current_proper.voltage;
app7.Pactive_pow =Current_proper.Pactive_pow;
app7.Pow_fac =Current_proper.Pow_fac;
}
}
}
}
void JudgeSta(void)
{
int ElectricalSta[7]={0};
int len=7;
int i=0,j=0;
float p_sta[7]; //用电器工作状态
float p_sum; //总功率
float current;
float power[7]={app1.Pactive_pow,app2.Pactive_pow,app3.Pactive_pow,app4.Pactive_pow,app5.Pactive_pow,app6.Pactive_pow,app7.Pactive_pow};
int times=0,timestmp=0;
for( i=0;i<7;i++)
{
switch(i)
{
case 0:app1.sta="off"; break;
case 1:app2.sta="off"; break;
case 2:app3.sta="off"; break;
case 3:app4.sta="off"; break;
case 4:app5.sta="off"; break;
case 5:app6.sta="off"; break;
case 6:app7.sta="off"; break;
}
}
for(times=0;times<128;times++)
{
timestmp=times;
for(i=0;i<7;i++)
ElectricalSta[i]=0;
i=0;
while(timestmp)
{
ElectricalSta[i]=timestmp%2;
timestmp=timestmp/2;
i++;
}
for(i = 0; i < len; i ++)//遍历数组。
{
p_sta[i] = ElectricalSta[i]*power[i];
}
for(i=0;i<7;i++)
{
p_sum+=p_sta[i];
}
if(p_sum<1000){
if(fabsf(p_sum-Current_proper.Pactive_pow)<0.2) //进行匹配 假设匹配PowerSum
{
for( i=0;i<7;i++)
{
if(ElectricalSta[i]==1)
{
switch(i)
{
case 0:app1.sta="on"; break;
case 1:app2.sta="on"; break;
case 2:app3.sta="on"; break;
case 3:app4.sta="on"; break;
case 4:app5.sta="on"; break;
case 5:app6.sta="on"; break;
case 6:app7.sta="on"; break;
}
}
}
p_sum=0;
break;
}
p_sum=0;
}
else
{
if(fabsf(p_sum-Current_proper.Pactive_pow)<0.2) //进行匹配 假设匹配PowerSum
{
for( i=0;i<7;i++)
{
if(ElectricalSta[i]==1)
{
switch(i)
{
case 0:app1.sta="on"; break;
case 1:app2.sta="on"; break;
case 2:app3.sta="on"; break;
case 3:app4.sta="on"; break;
case 4:app5.sta="on"; break;
case 5:app6.sta="on"; break;
case 6:app7.sta="on"; break;
}
}
}
p_sum=0;
break;
}
p_sum=0;
}
}
}
4.测试结果
具体测试结果放在了视频里,感兴趣的话可以看看
5.总结
这题说来运气成分也大,因为暑假训练时就已经做过2017年的K题了,当时也是第一次接触220V的电压,出了几次事故,并且采用FFT方案的成品实际效果实在一般,基波幅度不稳定,甚至会有高达±10%的抖动,而且除了基波之外其余谐波的分析价值实在不大,想了半天也没想到该怎么处理,最后换了电能计量模块并使用单参数判据,最后发现效果不错。只能说,大道至简,能完成任务的方案就是好方案! 啧,回想了一下今年比赛延期时的状况,疫情卷土重来,搞得整个实验室人心惶惶,当时一心只想着跑路,没想到现在已经国一了...另外,赛后复盘发现,这次国一实在是运气爆表,大多数使用FFT方案分析电器谐波的队伍在测试时都有着不同的问题,把我们这种用现成模块而且只使用了单个参数作为判据的队伍抬上了国一,而且就连最关键的生成二进制编码组合的代码也是从CSDN上找到的,因此这个国一实在是受之有愧。但是不得不说,作为一个从小到大得到的唯一一个奖项,实在是秦始皇摸电线-赢麻了!