STM32 distortion meter and oscilloscope

The reason for putting the distortion meter and the oscilloscope together is that the two projects need to do very similar things, only a small number of problems are different. So put the two together, and I will mark the differences between the two.

"Distortion" in a signal system is defined as the square root of the ratio of all harmonic energy to fundamental energy. There are many kinds of distortion: harmonic distortion, intermodulation distortion, phase distortion and so on. The technical term for the degree of distortion we usually refer to is Total Harmonic Distortion , or THD for short.

Distortion measurement method

1. Fundamental wave suppression method

2. Harmonic analysis

3. Simulation method

4. Digital approach

The digital method refers to a measurement method in which the signal is digitized and sent to a computer, and then the degree of distortion is calculated by the computer. According to the calculation method of distortion, it can be divided into FFT method and curve fitting method .

The use of stm32 must be measured using FFT (fast Fourier transform).

1. The basic definition formula of THD: The
basic definition of THD is the power ratio relationship, expressed as a percentage of the ratio between the power value of each harmonic and the power of the fundamental wave

2. THD Equivalent Relational Formula:

3. THD approximate measurement formula:

In digital signal processing, it is a very important concept to learn that FFT is one of the most basic methods in time domain-frequency domain transformation analysis. There is no more introduction to FFT here.

The overall idea of ​​the distortion meter code

Using STM32 to collect 64 or 256 or 1024 points of a sine wave must ensure that at least one full cycle is collected. The reason why 64 or 256 or 1024 points are collected is that st officially provides a library for FFT transformation. Link: https ://pan.baidu.com/s/1rVO6uYRk7eL2yID2U8IF9Q Extraction code: mhsr, now the official download is no longer available, I will share the file of this library with everyone.

After picking a good point, use DMA transmission (reduce the CPU burden), do FFT transformation, and directly apply the THD calculation formula to calculate the distortion degree after finishing.

The overall idea of ​​the oscilloscope code

The work of an oscilloscope is very similar to that of a distortion meter. After collecting points, use DMA transfer to perform FFT, and then get some desired values, such as maximum value, minimum value, signal frequency and so on.

It should be noted that the AD acquisition here needs to be configured as a timer trigger, so that the timer timing time can be the sampling time of the adc, and the sampling frequency>2*signal frequency. Later, adjust the sampling rate by pressing the button, so that the 2021 e-sports A question will come out (TI board used for the e-sports).

Gossip less, let's go to the code

Distortion meter:

adc configuration

 #include "adc.h"

//Initialize timer                                                               
void Adc_Init(void)
{     
    ADC_InitTypeDef ADC_InitStructure; 
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE ); //Enable ADC1 channel clock
 

    RCC_ADCCLKConfig(RCC_PCLK2_Div6); //Set ADC frequency division factor 6 72M/6=12, ADC maximum time cannot exceed 14M

    //PA6 is used as an analog channel input pin                         
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //Analog input
    GPIO_InitStructure.GPIO_Speed ​​= GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);    

    ADC_DeInit(ADC1); //Reset ADC1, reset all registers of peripheral ADC1 to default values

    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC working mode: ADC1 works in independent mode
    ADC_InitStructure.ADC_ScanConvMode = DISABLE; //Analog-to-digital conversion works in single-channel mode
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //Analog-to-digital conversion works in discontinuous conversion mode
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2; //The conversion is triggered by channel 2 of timer 2 (it can only be triggered on the rising edge)
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC data is right aligned
    ADC_InitStructure.ADC_NbrOfChannel = 1; //Sequence for regular conversion The number of ADC channels
    ADC_Init(ADC1, &ADC_InitStructure); //Initialize the registers of the peripheral ADCx according to the parameters specified in ADC_InitStruct   

    ADC_Cmd(ADC1, ENABLE); //Enable the specified ADC1
    
    ADC_DMACmd(ADC1, ENABLE); //ADC DMA function enable
    
    ADC_ResetCalibration(ADC1); //Enable reset calibration  
     
    ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 1, ADC_SampleTime_1Cycles5 ) ;//ADC1 channel 6, the sampling time is 239.5 cycles     
     
    ADC_ResetCalibration(ADC1);//Reset the calibration register
     
    while(ADC_GetResetCalibrationStatus(ADC1)); //Wait for the reset calibration to end
    
    ADC_StartCalibration(ADC1); //Open AD calibration
 
    while(ADC_GetCalibrationStatus (ADC1)); //Wait for the calibration to end
 
    ADC_SoftwareStartConvCmd(ADC1, ENABLE); //Enable the software conversion start function of the specified ADC1

}            

 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2; //The conversion is triggered by channel 2 of timer 2 (it can only be triggered on the rising edge)

Be sure to pay attention to this sentence, configure it as a timer trigger.

Use the collected values ​​as an array to call the above function for FFT transformation, and then apply the formula to calculate the degree of distortion

// Calculate the total resonance distortion function
void GetTHD()
{     unsigned short i=20;     float Uo1,Uo2,Uo3,Uo4,Uo5;     double THD,thd_fz=0,thd_fm=0;     Uo1=Mag[100];     Uo2=Mag [200];     Uo3=Mag[300];     Uo4=Mag[400];     Uo5=Mag[500];     thd_fm     =Uo1;     thd_fz=Uo2*Uo2 + Uo3*Uo3 + Uo4*Uo4 + Uo5*Uo5; (thd_fz);     THD=thd_fz/thd_fm*100;     sprintf((unsigned char *)temp1,"THD:%5lf%%",THD); }













Next, let’s talk about adjusting the sampling rate, set the button as an interrupt line, and press the button to enter the interrupt. In the interrupt service function, changing the timer timing time will change the sampling rate. In the standard library, there is such a function:

void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode)
{
  /* Check the parameters */
  assert_param(IS_TIM_ALL_PERIPH(TIMx));
  assert_param(IS_TIM_PRESCALER_RELOAD(TIM_PSCReloadMode));
  /* Set the Prescaler value */
  TIMx->PSC = Prescaler;
  /* Set or reset the UG Bit */
  TIMx->EGR = TIM_PSCReloadMode;
}

Obviously, this function can change the pre of the timer, that is, the sampling rate of the adc.

To sum up, adc uses timer triggers to set the sampling rate, and DMA transfers for FFT transformation, but the official FFT library provided by ST only has 64 points, 256 points and 1024 points. What if I want to do 32 points? What if I want to do 512 points? At this time, the official library is no longer applicable. I can only write a function of FFT transformation. I wrote a function of butterfly transformation. You can set the number of points yourself, as long as it is to the power of 2^n.

void Mfft(double pr[], double pi[], int n, int k, double fr[], double fi[])

//pr[] input real part
// pi[] input imaginary part (Fourier transform is not performed in time domain, there is no imaginary part, this array is all assigned as 0) //
n sampling points
// k: k of 2 Power = n The number of sampling points can be customized
// fr[] transforms the real part
// fi[] transforms the imaginary part

{     int it,m,is,i,j,nv,l0;     double p,q,s,vr,vi,poddr,poddi;     for (it=0; it<=n-1; it++) //put pr [0] and pi[0] are assigned to fr[] and fi[]     {         m=it;         is=0;         for(i=0; i<=k-1; i++)         {             j=m/2;             is =2*is+(m-2*j);             m=j;         }         fr[it]=pr[is];         fi[it]=pi[is];      }      pr[0]=1.0;      pi[0]= 0.0;      p=6.283185306/(1.0*n);      pr[1]=cos(p); //w=e^-j2pi/n Euler's formula table      pi[1]=-sin(p);



















     for (i=2; i<=n-1; i++)  //计算pr[]
     {
         p=pr[i-1]*pr[1];
         q=pi[i-1]*pi[1];
         s=(pr[i-1]+pi[i-1])*(pr[1]+pi[1]);
         pr[i]=p-q; pi[i]=s-p-q;
     }
     for (it=0; it<=n-2; it=it+2)
     {
          vr=fr[it];
          vi=fi[it];
          fr[it]=vr+fr[it+1];
          fi[it]=vi+fi[it+1];
          fr[it+1]=vr-fr[it+1];
          fi[it+1]=vi-fi[it+1];
     }
     m=n/2;
     nv=2;
     for (l0=k-2; l0>=0; l0--) //蝶形计算
     {
          m=m/2;
          nv=2*nv;
          for (it=0; it<=(m-1)*nv; it=it+nv)
              for (j=0; j<=(nv/2)-1; j++)
              {
                    p=pr[m*j]*fr[it+j+nv/2];
                    q=pi[m*j]*fi[it+j+nv/2];
                    s=pr[m*j]+pi[m*j];
                    s=s*(fr[it+j+nv/2]+fi[it+j+nv/2]);
                    poddr=p-q;
                    poddi=s-p-q;
                    fr[it+j+nv/2]=fr[it+j]-poddr;
                    fi[it+j+nv/2]=fi[it+j]-poddi;
                    fr[it+j]=fr[it+j]+poddr;
                    fi[it+j]=fi[it+j]+poddi;
               }
       }
       for (i=0; i<=n-1; i++)
       {
           pr[i]=sqrt(fr[i]*fr[i]+fi[i]*fi[i]);  //计算幅值
       }

       return;
}
Afterwards, the self-written FFT transformation was improved and optimized, link https://pan.baidu.com/s/1V0vs6tk6bd9VdooRwo4iZw 
Extraction code: pea8

Supongo que te gusta

Origin blog.csdn.net/qq_52838784/article/details/122726863
Recomendado
Clasificación