AVR1631 - Energy Meter Reference Design with ATxmega32A4  Rev 1.0
 All Data Structures Files Functions Variables Typedefs Macros
meter_calculations.c
Go to the documentation of this file.
1 
2 /* This file has been prepared for Doxygen automatic documentation generation.*/
50 #include "meter.h"
51 
55 // STATIC VARIABLES DECLARATION
56 uint8_t gain_stage = 0;
57 uint32_t freq_sum = 0;
58 uint16_t frequency = 0, max_demand = 0;
59 uint16_t Vrms[5] = {0}, Irms[5] = {0}, Nrms = 0;
60 int16_t p_mean = 0, Vmean = 0, n_mean = 0;
61 int32_t phase_mean=0, neutral_mean=0, volt_mean=0;
62 uint64_t phase_sum = 0, volt_sum = 0, neutral_sum = 0;
63 int64_t watts_sum = 0, watts_sum_neutral = 0,watts_sum_calib = 0;
64 uint16_t adc_samples = 0;
65 int32_t active_energy_signed = 0, neutral_power = 0;
66 uint16_t active_power[5] = {0},apparent_power = 0;
67 int16_t power_factor, offset[7] = {0};
68 int32_t volt_temp,ct_temp, shunt_temp;
69 volatile int16_t adc_read_ch0, adc_read_ch1;
70 int16_t lp_phase[LP_ORDER] = {0}, lp_power[LP_ORDER] = {0}, lp_volt[LP_ORDER] = {0};
71 uint8_t freq_cnt,offset_cnt = 0;
72 const int16_t lp_coeff[LP_ORDER] ={5252, 5568, 5728, 5728, 5568, 5252};
73 float pulse_energy_2_5ms = 0;
74 uint8_t pulse_count = 0,On_Time_counter = 0;
75 float pulse_energy_acc = 0;
76 
85 ISR(TCC1_OVF_vect)
86 {
87  SLEEP.CTRL &= ~SLEEP_SEN_bm;
88  //ADC_Ch_Conversion_Start(&ADCA.CH0);
89  ADC_Conversions_Start(&ADCA,ADC_CH0START_bm | ADC_CH1START_bm);
90  pulse_count++;
91  if(pulse_count > 9)
92  {
93  pulse_count = 0;
94  pulse_energy_acc = pulse_energy_acc + pulse_energy_2_5ms ;
95  if(pulse_energy_acc >= ONE_PULSE_ENERGY_THRESHOLD)
96  {
97  pulse_energy_acc = pulse_energy_acc - ONE_PULSE_ENERGY_THRESHOLD;
98  // On the pulse LED
99  PORTD.OUTSET = PIN0_bm;
100  // On time counter
101  On_Time_counter = PULSE_ON_TIME;
102  }
103 
104  if(On_Time_counter !=0)
105  {
106  On_Time_counter--;
107  if(On_Time_counter == 0)
108  {
109  // Off the pulse LED
110  PORTD.OUTCLR = PIN0_bm;
111  }
112  }
113  }
114 }
115 
120 ISR(ADCA_CH0_vect) //Phase - Shunt
121 {
122  SLEEP.CTRL &= ~SLEEP_SEN_bm;
123  adc_read_ch0 = ADC_ResultCh_GetWord_Signed(&ADCA.CH0,offset[offset_cnt]);
124 }
125 
126 
133 ISR(ADCA_CH1_vect)
134 {
135  SLEEP.CTRL &= ~SLEEP_SEN_bm;
136  adc_read_ch1 = ADC_ResultCh_GetWord_Signed(&ADCA.CH1,offset[VOLT_GAIN]);
137  get_frequency();
138  ADC_Ch_Conversion_Start(&ADCA.CH2);
139 }
140 
155 ISR(ADCA_CH2_vect) //CT
156 {
157  SLEEP.CTRL &= ~SLEEP_SEN_bm;
158  int32_t i_temp, n_temp, v_temp;
159  int16_t lp_powerout = 0;
160  int16_t phase_read, neutral_read, volt_read, volt_read_filt1;
161  static int16_t volt_read_filt2 = 0;
162  neutral_read = ADC_ResultCh_GetWord_Signed(&ADCA.CH2, offset[1]);
163 
164  phase_mean += (int32_t)adc_read_ch0;
165  lp_phase[0] = adc_read_ch0 - p_mean;
166  // low pass filtering of the input signal
167  phase_read = lp_filter(lp_phase);
168 
169  //Removing DC offset from the ADC result.
170  volt_mean += (int32_t)adc_read_ch1;
171  lp_volt[0] = adc_read_ch1 - Vmean;
172 
173  //Phase angle correction
174  volt_read_filt1 = lp_filter(lp_volt);
175  volt_read = (int16_t)(meter.A1[gain_stage] * (volt_read_filt1 + meter.B1[gain_stage]*(float)volt_read_filt2));
176  volt_read_filt2 = volt_read_filt1;
177 
178  //multiply and accumulating the phase value for energy calculation
179  phase_sum += (uint64_t)((int32_t)phase_read * (int32_t)phase_read);
180 
181  //multiply and accumulating the volt value for energy calculation
182  volt_sum += (uint64_t)((int32_t)volt_read * (int32_t)volt_read);
183 
184 
185  //Removing DC offset from the ADC result.
186  neutral_mean += (int32_t)neutral_read;
187  neutral_read -= n_mean;
188  //multiply and accumulating the volt value for energy calculation
189  neutral_sum += (uint64_t)((int32_t)(neutral_read) * (int32_t)(neutral_read));
190 
191  //active energy calculation
192  i_temp = ((int32_t)meter.shunt_const[gain_stage] * (int32_t)phase_read);
193  n_temp = (1583 * (int32_t)neutral_read)>>16;
194  v_temp = ((int32_t)meter.volt_const * (int32_t)volt_read);
195  lp_power[0] = ((int64_t)i_temp * (int64_t)v_temp)>>32;
196  lp_powerout = lp_filter(lp_power);
197  watts_sum = watts_sum + lp_powerout;
198  watts_sum_neutral += (n_temp * v_temp);
199  adc_samples++;
200 }
201 
202 
208 int16_t lp_filter(int16_t *inp_array)
209 {
210  uint8_t i;
211  int16_t lp_output = 0;
212  //y(n)=h[0]*x[n]+..+h[N-1]x[n-(N-1)]
213  for (i = 0; i< LP_ORDER; i++)
214  lp_output += ((int32_t)lp_coeff[i] * (int32_t)*inp_array++)>>15;
215  //update sample data move "down"
216  for (i = LP_ORDER-1; i > 0; i--) //from bottom of buffer
217  {
218  *inp_array--;
219  *inp_array = *(inp_array-1);
220  }
221  return(lp_output);
222 }
223 
233 void calculate(void)
234 {
235  float kwh_temp=0;
236  for(int8_t avg_count = 1; avg_count <4; avg_count++)
237  {
238  Irms[avg_count] = Irms[avg_count+1];
239  Vrms[avg_count] = Vrms[avg_count+1];
240  active_power[avg_count] = active_power[avg_count+1];
241  }
242  //Current(rms) calculation on phase line
243  shunt_temp = (int32_t)((phase_sum/adc_samples)- meter.shunt_offset[offset_cnt]);
244  if (shunt_temp < 5)
245  { shunt_temp = 0; }
246  Irms[4] = ((meter.shunt_const[gain_stage] * (int32_t)(sqrt(shunt_temp)*1000))>>16);
247  //for smoothing the Irms
248  Irms[0] = ((int32_t)Irms[1] + (int32_t)Irms[2] + (int32_t)Irms[3] + (int32_t)Irms[4])>>2;
249  Irms[2] = Irms[0];
250 
251  //Voltage(rms) calculation
252  volt_temp = (int32_t)(volt_sum/adc_samples);
253  if(volt_temp < 35000)
254  volt_temp = 0;
255  Vrms[4] = ((meter.volt_const * (int32_t)(sqrt(volt_temp)*100))>>16);
256  //for smoothing the Vrms
257  Vrms[0] = ((int32_t)Vrms[1] + (int32_t)Vrms[2] + (int32_t)Vrms[3] + (int32_t)Vrms[4])>>2;
258  Vrms[2] = Vrms[0];
259 
260  //Current(rms) calculation on neutral line
261  ct_temp = (int32_t) (neutral_sum/adc_samples);
262  if (ct_temp < 5)
263  { ct_temp = 0; }
264  Nrms = ( 1583 * (int64_t)((sqrt(ct_temp))*1000))>>16;
265 
266  //apparent energy calculation
267  apparent_power = ((uint64_t)Vrms[0] * (uint64_t)Irms[0])/100000; //(Vrms/100) * (Irms/1000);
268  //active energy calculation
269  active_energy_signed = ((watts_sum + meter.watt_offset[offset_cnt]) / adc_samples);
270  watts_sum_calib = watts_sum;
271  watts_sum = 0;
272 
273  //for smoothing the active power
274  active_power[4] = (uint16_t)(meter.watt_const[gain_stage] * abs(active_energy_signed));
275  active_power[0] = ( (uint16_t)(active_power[1]) + (uint16_t)(active_power[2]) + (uint16_t)(active_power[3]) + (uint16_t)(active_power[4]) )>>2;
276  active_power[2] = active_power[0];
277 
278  // neutral power calculation
279  neutral_power = (watts_sum_neutral /adc_samples);
280 
281  // changing the gain dynamically
282  if(Irms[4] < 500 && gain_stage != 6)
283  {
284  gain_stage =6;
285  offset_cnt = 6;
287  ADC_CH_INPUTMODE_DIFFWGAIN_gc,
288  ADC_CH_GAIN_64X_gc);
289  }
290  else if(Irms[4] > 500 && Irms[4] < 1500 && gain_stage != 5)
291  {
292  gain_stage =5;
293  offset_cnt = 6;
295  ADC_CH_INPUTMODE_DIFFWGAIN_gc,
296  ADC_CH_GAIN_64X_gc);
297  }
298  else if(Irms[4] > 1500 && Irms[4] < 2500 && gain_stage != 4)
299  {
300  gain_stage =4;
301  offset_cnt = 6;
303  ADC_CH_INPUTMODE_DIFFWGAIN_gc,
304  ADC_CH_GAIN_64X_gc);
305  }
306  else if (Irms[4] > 2500 && Irms[4] < 4000 && gain_stage != 3)
307  {
308  gain_stage =3;
309  offset_cnt = 6;
311  ADC_CH_INPUTMODE_DIFFWGAIN_gc,
312  ADC_CH_GAIN_64X_gc);
313  }
314  else if (Irms[4] > 4000 && Irms[4] < 7000 && gain_stage != 2)
315  {
316  gain_stage = 2;
317  offset_cnt = 6;
319  ADC_CH_INPUTMODE_DIFFWGAIN_gc,
320  ADC_CH_GAIN_64X_gc);
321  }
322  else if (Irms[4] > 7000 && Irms[4] < 14500 && gain_stage != 1)
323  {
324  gain_stage = 1;
325  offset_cnt = 6;
327  ADC_CH_INPUTMODE_DIFFWGAIN_gc,
328  ADC_CH_GAIN_64X_gc);
329  }
330  else if (Irms[4] > 14500 && gain_stage !=0)
331  {
332  gain_stage = 0;
333  offset_cnt = 5;
335  ADC_CH_INPUTMODE_DIFFWGAIN_gc,
336  ADC_CH_GAIN_32X_gc);
337  }
338 
339 
340  if(active_energy_signed < 3 && active_energy_signed > -3)
341  {
342  active_power[0] = 0;
343  Irms[0] = 0;
344  apparent_power = 0;
345  }
346  if (Irms[0] < 10)
347  {
348  Irms[0] = 0;
349  Nrms = 0;
350  active_power[0] = 0;
351  neutral_power=0;
352  apparent_power = 0;
353  }
354 
355  //power factor calculation
356  power_factor = (int16_t)(1000 * (float)active_power[0]/(float)apparent_power);
357  if(power_factor >1000)
358  {
359  apparent_power = active_power[0];
360  power_factor = 1000;
361  }
362  else if(power_factor < 0)
363  {
364  power_factor = 0;
365  }
366 
367 
368  kwh_temp = ((float)(active_power[0])/3600000);
369  meter.kwh += kwh_temp;
370  pulse_energy_2_5ms = kwh_temp / 400;
371  calculate_freq();
372 
373  //Dc offset voltage calculation
374  Vmean = (int16_t)(volt_mean/adc_samples);
375  p_mean = (int16_t)(phase_mean/adc_samples);
376  n_mean = (int16_t)(neutral_mean/adc_samples);
377  phase_mean = 0;
378  volt_mean = 0;
379  n_mean = 0;
380 
381  adc_samples = 0;
382  volt_sum = 0;
383  phase_sum = 0;
384  neutral_sum = 0;
385  watts_sum = 0;
386  watts_sum_neutral = 0;
387 }
388 
389 
390 
396 void calculate_freq(void)
397 {
398 
399  uint16_t freq_avg;
400 
401  freq_avg = (uint16_t)(freq_sum/freq_cnt);
402  frequency = (uint16_t)((F_TIMER *100) /freq_avg);
403 
404  if(frequency > 10100 || frequency < 2000)
405  frequency = 0;
406  freq_sum = 0;
407  freq_cnt = 0;
408 }
409 
420 void get_frequency(void)
421 {
422  static uint8_t sign_flag = 0;
423  uint16_t freq_val;
424  if(adc_read_ch1 < 0 && sign_flag != 0)
425  {
426  sign_flag = 0;
427  }
428  else if(adc_read_ch1 >= 0 && sign_flag != 1)
429  {
430  sign_flag = 1;
431  freq_val = TCE0.CNT;
432  //*! freq measurement limited is from 20 to 100hz //freq_val > 9090 && freq_val < 11111
433  if(freq_val > FREQUENCY_MAX && freq_val < FREQUENCY_MIN)
434  {
435  freq_sum += freq_val;
436  freq_cnt++;
437  }
438  TCE0.CNT =0;
439  }
440 }
441 
442 
448 {
449  phase_mean = 0;
450  volt_mean = 0;
451  n_mean = 0;
452  for(int j=0; j < 5; j++)
453  {
454  Irms[j] = 0;
455  Vrms[j] = 0;
456  active_power[j] = 0;
457  }
458  phase_mean = 0;
459  volt_mean = 0;
460  n_mean = 0;
461  freq_sum = 0;
462  freq_cnt = 0;
463  adc_samples = 0;
464  volt_sum = 0;
465  phase_sum = 0;
466  neutral_sum = 0;
467  watts_sum = 0;
468  watts_sum_neutral = 0;
469 }
470