Community
OpenEnergyMonitor

Community

FIR-like phase error correction algorithm for stm32

Tags: #<Tag:0x00007fc9c4206008>

I’ve had an attempt at making a FIR-like algorithm for phase correction per CT channel. I’m thinking to post a few lines of code in a series which makes sense to the topic at hand, so it’s more legible, and so anyone could potentially discuss it better.

I’ve annotated this bit differently from the git so it’s easier to understand future code. I think what I could do is a series of posts going through the whole method.

First, the sample buffer is processed in the raw by this section. I thought it’d be a good starting point.

    // Processing DMA buffer.
    // a few things come before this line, including the check that the 'future' sample is ready.
    //----------------------------------------
    // Power
    //----------------------------------------
    // Cycle through channels, accumulating
    for (int ch = 0; ch < CTn; ch++) // CTn = number of channels.
    {
      channel_t *channel = &channels[ch];
      //----------------------------------------
      // Voltage
      //----------------------------------------
      // phase correction happen on voltage for higher resolution:
      // all the CTs use the voltage channel (single phase)
      int16_t sample_V_index = offset + i + ch + phase_corrections[ch];
      // offset relates to the buffer being in two halfs, for continuous sampling.
      // check for buffer overflow below:
      // the "+ phase_corrections[ch]" above can result in looking for 
      // a future sample that's in the next half of the buffer.
      if (sample_V_index >= adc_buff_size) sample_V_index -= adc_buff_size; 
      else if (sample_V_index < 0) sample_V_index += adc_buff_size; 
      
      sample_V = adc1_dma_buff[sample_V_index];
      //if (sample_V == 4095) Vclipped = true; // unlikely
      signed_V = sample_V - MID_ADC_READING; // 1st midrail removal, necessary?
      channel->sum_V += signed_V; 
      channel->sum_V_sq += signed_V * signed_V; // for Vrms
      //----------------------------------------
      // Current
      //----------------------------------------
      sample_I = adc2_dma_buff[offset + i + ch];
      if (sample_I == 4095) channel->Iclipped = true; // much more likely, useful safety information.
      signed_I = sample_I - MID_ADC_READING; // 1st midrail removal, necessary?
      channel->sum_I += signed_I;
      channel->sum_I_sq += signed_I * signed_I; // for Irms

. https://github.com/danbates2/STM32/blob/master/Software/Sombrero_VE_Working5%20for%20v0.9/Src/main.c