Sampling of Analog values

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Sampling of Analog values

1,169 Views
TVNAIDU
Contributor III

I am doing 24 plug port power strip with 3 input plugs (each input plug controls one group of 8 receptacles of 24 plugs)

 

Basically I am doing power strip with 50Hz/120V input and I have 24 receptcles (each group is 8), like that 3 groups of eight receptacles in each strip, I am reading currents back from 24 receptacle relays, also I am reading 3 voltages, one from each group of eight receptacles. I am using 5 GPIO pins to select one of the receptacle (24 currents + 3 volatges + few for temperature), basically I have to read 24 currents, 3 voltage. 24 Instaneous currents, 3 Instaneous voltages, then I have to VI (voltage * current), also I have to calculate average voltage and current: total readings are:

 

Three Vrms from Three groups

8 * 3 = 24 rms currents + 3 boards + 1 total

28 Powers

28 VA (V rms * I rms)

28 PF (P / VA)

 

I have to do 840 samples per second to measure Instantaneous current and Instantaneous voltage. using them I have to calculate RMS Current and RMS voltage, then actual power (instantaneous current * instantaneous voltage), apparent power (RMS Current * RMS voltage), then Power factor ( actual power / apparent power).

 

 

I am using 5 GPIO pins (AN0 - AN4) select one at a time and AN7 to read the value. Please throw some ideas about real-time sampling (how can I do exactly real-time 840 samples per second).

 

Thanks.

TV.

Labels (1)
0 Kudos
5 Replies

356 Views
admin
Specialist II

The constant interval between the samples can be arranged by interrupt of free-running PIT.

The simplest implementation of the ISR takes set of the samples and messages the set to the upper level.

 

The following sequence of samples in the set provides pseudo-simultaneous sampling of U and I for calculation of power factor:

U0 I0  I1  ... I7  I7  I6  ... I0  U0

U1 I8  I9  ... I15 I15 I14 ... I8  U1

U2 I16 I17 ... I23 I23 I22 ... I16 U2

The average value of the two samples of the channel is related to the same time.

These averages are used to calculate instantaneous U*I and the further power factor.

Either first or second half of each line is used for calculation of Irms and Urms.

 

Quantity of such a sets must represent integer number of ~50 Hz mains voltage.

 

In case of CPU time between the samples needs to be used, PIT ISR needs only to trigger the first sample in the set. ADC ISR needs to read the ready sample from the ADC and to trigger the next sample. By read of the last sample in the set, the ADC ISR needs to message the set to the task of the upper level.

 

0 Kudos

356 Views
TVNAIDU
Contributor III

Thanks yevgenit.

 

If I set PIT ISR for 1ms (1000 samples per second, 1 / 1000 = 1 ms), in PIT ISRE I have a BOOL flag measure_instantaneous_sample = TRUE, in my main task which reads Ui (Inst volt) and Ii (Inst current), I have to check for that flag measure_instantaneous_sample == TRUE, then collect One instantaneous sample (U0, I0, I1.....I7), then set flag to FALSE and wait till PIT ISR triggers again to measure next sample. also once collect half of total samples which is 500 (1000 / 2 = 500) then calculate RMS current and RMS voltage (accumulation of squares of Inst currents and inst voltages, then  average / 500 to get RMS) and then calculate powers and power factor. once calculated reset this count to zero again measure when this counter reached 500 again. earlier flag to take samples and this counter to calculate powers.

 

Now I have to see whether I can use one PIT for 1ms and just set the flag in PIT ISR, sothing doing except set the flag in ISR. the task resets this flag back and buffer those inst currents and voltages.

0 Kudos

356 Views
admin
Specialist II

TVNAIDU,

I'd recommend the following design. It is relatively sophisticated, but it provides more available CPU time.

 

Two buffers of 54 samples each are need: while the calculation task processes the granted buffer, the other buffer is fill with the samples in the background.

The complete set of samples in the just filled buffer is as the following:

U0 I0  I1  ... I7  I7  I6  ... I0  U0

U1 I8  I9  ... I15 I15 I14 ... I8  U1

U2 I16 I17 ... I23 I23 I22 ... I16 U2

Assuming constant time interval between samples in the set, the average value of the two samples of the channel is related to the same time.

 

PIT ISR triggers the ADC for first sample in the set. Then, PIT ISR returns.

ADC ISR reads first sample from ADC to the buffer. Then, ADC ISR triggers the ADC for the second sample. Then, PIT ISR returns.

Next ADC ISR reads second sample from ADC to the buffer. Then, ADC ISR triggers the ADC for third sample. Then, PIT ISR returns.

...

When ADC ISR reads and fills the last sample (54-th) of the set, it updates number of the just filled (and granted) buffer. Then, ADC ISR releases the semapfore, which locks the calculation task.

Such a way, the sampling is suspended until next PIT interrupt.

 

Unlocked calculation task must process the granted buffer before the next buffer is granted. After processing of the granted buffer, the calculation task again pends on the semaphore.

 

I'd recommend, that, the calculation task use the fixed quantity of ~50 Hz periods of the mains voltage, instead of the exact 0.5 seconds. Start of each ~50 Hz period of the mains voltage can be detected by zero crossing of one of the well filtered ~50 Hz voltages. Such the arrangement keeps the accuracy of the measurement for the actual mains frequency below 50 Hz. Moreover, natural automatic tuning to 60 Hz is implemented.

 

To further save CPU time I'd recommend to assign both the task stacks and the buffers in the SRAM.

 

0 Kudos

356 Views
TVNAIDU
Contributor III

Actually when I see above Three lines, I feel like I am sampling twice, I wanted to sample only once for every plug (measure PF twice in a second). I divided the above table into Half, I have to take minum 780 samples per second (60 * 7th harmonic is 420, double is 840), I wanted to go for 1000 samples per second, that is 1ms interval, I need to measure twice a second means for every 500 ms, then calculate powers.

 

U0 I0  I1  ... I7 

U1 I8  I9  ... I15

U2 I16 I17 ... I23

 

This is my prog, I want to use GPT for 1ms interval, after 500ms, I need to measure PF for every 500ms. here buffers numbered from 1 to 24, also accumulators 1 to 24, buffers gets reqritten for every instantaneous, where accumulator gets overwrittem for every 500ms, i.e., after calculated all powers. GPT ISR sets flag (timer_isr_take_samling_flag), oncetask reads ADC readings, resets flag back after every instant. for power calculations I have local counter cheacks whether it is equal to 500 or not.

 

(I divided below prog into Two postings because of size)

 

  • #define SAMPLES 1000
  • /* Buffer holds only instantaneous values - Total 24 current bufs */
  • int curr_buf1 =0;
  • ......
  • .....
  • int curr_buf24 =0;
  • /* Voltage bufs holds only instantaneous volt - total 3 for Three power boards */
  • int volt_buf1 = 0;
  • int volt_buf2 = 0;
  • int volt_buf3 = 0;
  • /* Total 24 accumlators for current - holds summation of squares of insta. for RMS */
  • int curr1_accu=0;
  • .....
  • ....
  • int curr24_accu=0;
  • /* Total 3 accumlators for voltage - holds summation of squares of insta. for RMS */
  • int volt1_accu = 0;
  • int volt2_accu = 0;
  • int volt3_accu = 0;
  • /* total 24 - actual power, instantaneous current of each board plug * that board voltage */
  • int power1_accu = 0;
  • .......
  • .......
  • int power24_accu = 0;
  • /* Total 3 RMS voltages, one for each 8 plug board */
  • float rms_volt1 = 0.0;
  • ........
  • ........
  • float rms_volt3 = 0.0;
  • /* Total 24 - rms currents */
  • float rms_curr1 = 0.0;
  • .........
  • ........
  • float rms_curr24 = 0.0;
  • /* Total 24 apparent powers */
  • float appa_pow1 = 0.0;
  • .....
  • .....
  • float appa_pow1 = 0.0;
  • /* Total 24 - power factors */
  • float power_fact1 = 0.0
  • ......
  • .....
  • float power_fact1 = 0.0
  • int measure_power_factor = 0;
  • /* These are accumulators, gets reset for every half-second */
  •         int curr_18_AT = 0;
  •         int curr_9_16_AT = 0;
  •         int curr_17_24_AT = 0;
  •         int curr_8_BT = 0;
  •         int curr_9_24_BT = 0;
  •         int curr_17_24_BT = 0;
  •         int pow_18_AT = 0;
  •         int pow_9_16_AT = 0;
  •         int pow_17_24_AT = 0;
  • main_task {
  •          if (timer_isr_take_sampling_flag == TRUE)
  •             set GPIO to select for volt;
  •             volt_buf1 = ADC value;
  •             volt1_accu = volt_buf1 * volt_buf1;
  •             set GPIO to select curr_count;
  •             curr_buf1 = ADC value;
  •             curr1_accu += curr_buf1 * curr_buf1;
  •         power1_accu += volt_buf1 * curr_buf1;
  •             set GPIO to select curr_count;
  •             curr_buf2 = ADC value;
  •             curr2_accu += curr_buf2 * curr_buf2;
  •         power2_accu += volt_buf1 * curr_buf2;
  • ...................... 
  •  ......................
  •             set GPIO to select curr_count;
  •             curr_buf7 = ADC value;
  •             curr7_accu += curr_buf7 * curr_buf7;
  •         power7_accu += volt_buf1 * curr_buf7;
  •             set GPIO to select curr_count;
  •             curr_buf8 = ADC value;
  •             curr8_accu += curr_buf8 * curr_buf8;
  •         power8_accu += volt_buf1 * curr_buf8;
  •         curr_18_BT = curr_buf1+curr_buf2 +curr_buf3+ curr_buf4 + curr_buf5 + curr_buf6 + curr_buf7  + curr_buf8;
  •         curr_18_AT += curr_18_BT * curr_18_BT;
  •         pow_18_AT += curr_18_AT * volt_buf1;
  •             set GPIO to select for volt;
  •             volt_buf2 = ADC value;
  •             volt2_accu += volt_buf2 * volt_buf2;
  •             set GPIO to select curr_count;
  •             curr_buf9 = ADC value;
  •             curr9_accu += curr_buf9 * curr_buf9;
  •         power9_accu += volt_buf2 * curr_buf9;
  •             set GPIO to select curr_count;
  •             curr_buf10 = ADC value;
  •             curr10_accu += curr_buf10 * curr_buf10;
  •         power10_accu += volt_buf2 * curr_buf10;
  • ................... 
  •  ...................
  •             set GPIO to select curr_count;
  •             curr_buf16 = ADC value;
  •             curr16_accu += curr_buf16 * curr_buf16;
  •         power16_accu += volt_buf2 * curr_buf16;
  •         curr_9_16_BT = curr_buf9+curr_buf10 +curr_buf11+ curr_buf12 + curr_buf13 + curr_buf14 + curr_buf15  + curr_buf16;
  •         curr_9_16_AT += curr_9_16_BT * curr_9_16_BT;
  •         pow_9_16_AT += curr_9_16_AT * volt_buf2;
  •             set GPIO to select for volt;
  •             volt_buf3 = ADC value;
  •             volt3_accu += volt_buf3 * volt_buf3;
  •             set GPIO to select curr_count;
  •             curr_buf17 = ADC value;
  •             curr17_accu += curr_buf17 * curr_buf17;
  •         power17_accu += volt_buf3 * curr_buf17;
  • .......................
  • ....................... 
  •             set GPIO to select curr_count;
  •             curr_buf23 = ADC value;
  •             curr23_accu += curr_buf23 * curr_buf23;
  •         power23_accu += volt_buf3 * curr_buf23;
  •             set GPIO to select curr_count;
  •             curr_buf24 = ADC value;
  •             curr24_accu += curr_buf24 * curr_buf24;
  •         power24_accu += volt_buf3 * curr_buf24;
  •         curr_17_24_BT = curr_buf17+curr_buf18+curr_buf19+curr_buf20+curr_buf21+curr_buf22+curr_buf23+curr_buf24;
  •         curr_17_24_AT += curr_17_24_BT * curr_17_24_BT;
  •         pow_17_24_AT += curr_17_24_AT * volt_buf3;
  •                 /* reste this flag, Timer ISR will this for next sampling */
  •                 timer_isr_take sampling_flag = FALSE
  •                 measure_power_factor ++;
  •            }    /* if (timer_isr_take_sampling_flag == TRUE) */
  •  
0 Kudos

356 Views
TVNAIDU
Contributor III

(continuation from previous page)


           if (measure_power_factor == 500) {
        rms_volt1 = sqrt( (volt1_accu / (SAMPLE/2) ));
        rms_curr1 = sqrt( curr1_accu / (SAMPLES/2) );
        rms_curr2 = sqrt( curr2_accu / (SAMPLES/2) );
        rms_curr3 = sqrt( curr3_accu / (SAMPLES/2) );
        rms_curr4 = sqrt( curr4_accu / (SAMPLES/2) );
        rms_curr5 = sqrt( curr5_accu / (SAMPLES/2) );
        rms_curr6 = sqrt( curr6_accu / (SAMPLES/2) );
        rms_curr7 = sqrt( curr7_accu / (SAMPLES/2) );
        rms_curr8 = sqrt( curr8_accu / (SAMPLES/2) );
        appa_pow1 = rms_curr1 * rms_volt1;
        appa_pow2 = rms_curr2 * rms_volt1;
        appa_pow3 = rms_curr3 * rms_volt1;
        appa_pow4 = rms_curr4 * rms_volt1;
        appa_pow5 = rms_curr5 * rms_volt1;
        appa_pow6 = rms_curr6 * rms_volt1;
        appa_pow7 = rms_curr7 * rms_volt1;
        appa_pow8 = rms_curr8 * rms_volt1;
        rms_volt2 = sqrt( (volt2_accu / (SAMPLE/2) ));
        rms_curr9  = sqrt( curr9_accu / (SAMPLES/2) );
        rms_curr10 = sqrt( curr10_accu / (SAMPLES/2) );
        rms_curr11 = sqrt( curr11_accu / (SAMPLES/2) );
        rms_curr12 = sqrt( curr12_accu / (SAMPLES/2) );
        rms_curr13 = sqrt( curr13_accu / (SAMPLES/2) );
        rms_curr14 = sqrt( curr14_accu / (SAMPLES/2) );
        rms_curr15 = sqrt( curr15_accu / (SAMPLES/2) );
        rms_curr16 = sqrt( curr16_accu / (SAMPLES/2) );
        appa_pow9 = rms_curr9 * rms_volt2;
        appa_pow10 = rms_curr10 * rms_volt2;
        appa_pow11 = rms_curr11 * rms_volt2;
        appa_pow12 = rms_curr12 * rms_volt2;
        appa_pow13 = rms_curr13 * rms_volt2;
        appa_pow14 = rms_curr14 * rms_volt2;
        appa_pow15 = rms_curr15 * rms_volt2;
        appa_pow16 = rms_curr16 * rms_volt2;
        rms_volt3 = sqrt( (volt3_accu / (SAMPLE/2) ));
        rms_curr17 = sqrt( curr17_accu / (SAMPLES/2) );
        rms_curr18 = sqrt( curr18_accu / (SAMPLES/2) );
        rms_curr19 = sqrt( curr19_accu / (SAMPLES/2) );
        rms_curr20 = sqrt( curr20_accu / (SAMPLES/2) );
        rms_curr21 = sqrt( curr21_accu / (SAMPLES/2) );
        rms_curr22 = sqrt( curr22_accu / (SAMPLES/2) );
        rms_curr23 = sqrt( curr23_accu / (SAMPLES/2) );
        rms_curr24 = sqrt( curr24_accu / (SAMPLES/2) );
        appa_pow17 = rms_curr17 * rms_volt3;
        appa_pow18 = rms_curr18 * rms_volt3;
        appa_pow19 = rms_curr19 * rms_volt3;
        appa_pow20 = rms_curr10 * rms_volt2;
        appa_pow21 = rms_curr11 * rms_volt2;
        appa_pow22 = rms_curr12 * rms_volt2;
        appa_pow23 = rms_curr13 * rms_volt2;
        appa_pow24 = rms_curr14 * rms_volt2;
        power_fact1 = power1_accu / appa_pow1;
        power_fact2 = power2_accu / appa_pow2;
        power_fact3 = power3_accu / appa_pow3;
        power_fact4 = power4_accu / appa_pow4;
        power_fact5 = power5_accu / appa_pow5;
        power_fact6 = power6_accu / appa_pow6;
        power_fact7 = power7_accu / appa_pow7;
        power_fact8 = power8_accu / appa_pow8;
        power_fact9 = power9_accu / appa_pow9;
        power_fact10= power10_accu / appa_pow10;
        power_fact11 = power11_accu / appa_pow11;
        power_fact12 = power12_accu / appa_pow12;
        power_fact13 = power13_accu / appa_pow13;
        power_fact14 = power14_accu / appa_pow14;
        power_fact15 = power15_accu / appa_pow15;
        power_fact16 = power16_accu / appa_pow16;
        power_fact17 = power17_accu / appa_pow17;
        power_fact18 = power18_accu / appa_pow18;
        power_fact19 = power19_accu / appa_pow19;
        power_fact20 = power20_accu / appa_pow20;
        power_fact21 = power21_accu / appa_pow21;
        power_fact22 = power22_accu / appa_pow22;
        power_fact23 = power23_accu / appa_pow23;
        power_fact24 = power24_accu / appa_pow24;
        /* set to zero, since 50 samples are equal to Half-Second */
               measure_power_factor = 0;
            /* reset all accumulatos */
        curr_18_AT = 0;
        curr_9_16_AT = 0;
        curr_17_24_AT = 0;
        pow_18_AT = 0;
        pow_9_16_AT = 0;
        pow_17_24_AT = 0;
            }     /*  if (measure_power_factor == 50) */
} /* main_task */
 

0 Kudos