基于重复控制方法的逆变器的仿真学习笔记

重复控制器的传递函数

重复控制器(Repetitive Controller,RC)是一种基于"内模原理"(Internal Model Principle)设计的控制器,用于消除周期性参考信号或周期性扰动下的稳态误差。逆变器具有周期性参考信号的特征,采用重复控制器进行控制,可以获得更稳定的控制性能。

重复控制器的基本传递函数为:

\[G(z)=\frac{z^{-N}}{1-z^{-N}} \]

其中,\(N\) 表示在一个周期内的采样数。意思是采用一个重复周期之前的采样样本作为环路的反馈值进行计算。

通常,重复控制器更为实用的传递函数是:

\[G(z)=\frac{z^m Q(z) z^{-N}}{1-Q(z) z^{-N}} \]

其中,\(Q(z)\) 是一个低通滤波器,用于消减高频处的增益,增加相位裕量。\(z^m\) 是一个超前相位补偿器,\(m\) 表示超前的采样数。

重复控制逆变器的仿真调试

仿真过程中将搭建一个逆变器电路,并使用重复控制器对输出电压进行控制,观察其性能。仿真软件使用的 GeckoCircuits 。

步骤1:搭建逆变器电路

搭建一个全桥逆变器电路,母线电压设为 \(400V\),输出电压有效值 \(230V\),频率 \(50Hz\),负载电阻 \(200 \Omega\)。

其中,LC 滤波器参数的估算过程:LC 滤波器截止频率计算公式为 \(f_c = 1/2\pi \sqrt{LC}\),该频率应远高于 \(10\) 倍基波频率,远低于开关频率 \(10\%\),开关频率取\(32kHz\),即 \(500Hz << f_c << 3200Hz\)。输出峰值电流 \(I_{pk} = U_{rms}*1.414/R = 230V*1.414/200 \Omega \approx 1.6A\)。电感纹波电流取峰值电流的 \(10\% ~~ 30\%\),即 \(\Delta I = I_{pk}*0.3 = 0.53A\)。根据伏秒定理计算电感值 \(L = (V_{dc}*T_s*D)/(\Delta I*2) \approx 1.6mH\)。根据截止频率的取值范围,电容值取 \(2.2 \mu F\)。

步骤2:搭建控制环路及驱动

控制环路采用了重复控制器和比例控制器并联的方式。

其中,重复控制器的代码内容如下:

java 复制代码
public class tmpJav393624554 implements java.io.Serializable, ch.technokrat.gecko.ControlCalculatable { 
// variables: 
	private final double sampleRate = 32000;
	private final double frequency = 50;
	private final double vRMS = 230;
	private final int indexMAX = (int)(sampleRate / frequency);
	private final double PI = Math.PI;
	private final double TWOPI = 2.0*PI;
	private final double thetaStep = TWOPI / indexMAX;
	private double[] bufferIN = new double[indexMAX];
	private double[] bufferOUT = new double[indexMAX];
	private int bufferIndex;
	private double error;
	private int count;
	private int countMAX;
	private boolean initialized;
	private double vSet;
	private double theta;
	private double vIN;
	private double vOUT;
	private double gain, gain1;
	private double q_b0, q_b1, q_a1;
	private double y, y0, y1, y2;
	private double x, x0, x1, x2;
	private double rc0, rc1, rc2;
	private double lpf_b0, lpf_b1, lpf_a1;
	private int m;
	private double[] yOUT = new double[2];

	@Override
	public void init() {
		initialized = false;
		bufferIndex = 0;
		count = 0;
		theta = 0;
		gain = 0.0035;
		q_b0 = 0.07246376811594202;
		q_b1 = 0.07246376811594202;
		q_a1 = -0.855072463768116;
		lpf_b0 = 0.23809523809523814;
		lpf_b1 = 0.23809523809523814;
		lpf_a1 = -0.5238095238095238;
		m = 3;
	}

    @Override
    public double[] calculateYOUT(final double[] xIN, final double time, final double dt) throws Exception {
// ****************** your code segment **********************
		if (initialized){
		    count ++;
		    if (count >= countMAX){
		        count = 0;
		        
		        vIN = xIN[0];
		        vSet = 1.414*vRMS*Math.sin(theta);
		        error = (vSet - vIN);
		        
		        y0 = bufferOUT[bufferIndex];
		        y = y0*q_b0 + y1*q_b1 - y2*q_a1;
		        y1 = y0;
		        y2 = y;
		        
		        if (bufferIndex+m < indexMAX){
		            x0 = bufferIN[bufferIndex+m];
		        }
		        else{
		            x0 = bufferIN[bufferIndex+m-indexMAX];
		        }
		        
		        x = x0*q_b0 + x1*q_b1 - x2*q_a1;
		        x1 = x0;
		        x2 = x;
		    
		        rc0 = x + y;
		        bufferIN[bufferIndex] = error;
		        bufferOUT[bufferIndex] = rc0;
		        
		        vOUT = rc0*lpf_b0 + rc1*lpf_b1 - rc2*lpf_a1;
		        vOUT = vOUT*gain;
		
		        if (vOUT >= 0.980){
		            vOUT = 0.980;
		        }
		        else if (vOUT < -0.980){
		            vOUT = -0.980;
		        }
		        
		        if (vSet >= 0){
		            if (vOUT < 0){
		            vOUT = 0;
		            }
		        }
		        else{
		            if (vOUT > 0){
		                vOUT = 0;
		            }
		        }
		        
		        lpf_b1 = lpf_b0;
		        lpf_a1 = vOUT;
		        
		        bufferIndex ++;
		        if (bufferIndex >= indexMAX){
		            bufferIndex = 0;
		        }
		        theta += thetaStep;
		        if (theta >= TWOPI){
		            theta = 0;
		        }
		    }
		}
		else{
		    countMAX = (int)(1/(sampleRate*dt));
		    initialized = true;
		    vOUT = 0;
		}
		
		yOUT[0] = vOUT;
		yOUT[1] = vSet;
		
		return yOUT;
// ****************** end of code segment **********************
    }
}

H 桥驱动器的代码内容如下:

java 复制代码
public class tmpJav1901723632 implements java.io.Serializable, ch.technokrat.gecko.ControlCalculatable { 
// variables: 
	
	private double[] yOUT = new double[4];

	@Override
	public void init() {
	}

    @Override
    public double[] calculateYOUT(final double[] xIN, final double time, final double dt) throws Exception {
// ****************** your code segment **********************
		
		if (xIN[1] >= 0)
		{
		    yOUT[0] = xIN[0];
		    yOUT[1] = 1 - xIN[0];
		    yOUT[2] = 1;
		    yOUT[3] = 0;
		}
		else
		{
		    yOUT[1] = xIN[0];
		    yOUT[0] = 1 - xIN[0];
		    yOUT[3] = 1;
		    yOUT[2] = 0;
		}
		
		return yOUT;
// ****************** end of code segment **********************
    }
}

步骤3:运行结果

运行仿真,查看输出电压波形:

转载请注明文章出处:https://www.cnblogs.com/CIB27149/p/19656366