You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

150 lines
5.5 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DyeingComputer.UserClass
{
public class PID
{
private double Ts; // Sample period in seconds
private double K; // Rollup parameter
private double b0, b1, b2; // Rollup parameters
private double a0, a1, a2; // Rollup parameters
private double y0 = 0; // Current output
private double y1 = 0; // Output one iteration old
private double y2 = 0; // Output two iterations old
private double e0 = 0; // Current error
private double e1 = 0; // Error one iteration old
private double e2 = 0; // Error two iterations old
#region 构造函数
/// <summary>
/// PID构造器
/// </summary>
/// <param name="Kp">比例增益</param>
/// <param name="Ki">积分增益</param>
/// <param name="Kd">微分增益</param>
/// <param name="N">微分滤波系数</param>
/// <param name="OutputUpperLimit">控制器输出上限</param>
/// <param name="OutputLowerLimit">控制器输出下限</param>
public PID(double Kp, double Ki, double Kd, double N, double OutputUpperLimit, double OutputLowerLimit)
{
this.Kp = Kp;
this.Ki = Ki;
this.Kd = Kd;
this.N = N;
this.OutputUpperLimit = OutputUpperLimit;
this.OutputLowerLimit = OutputLowerLimit;
}
public PID()
{
this.Kp = 0.5;
this.Ki = 0.1;
this.Kd = 0.2;
this.N = 1;
this.OutputUpperLimit = 65530;
this.OutputLowerLimit = 0;
}
#endregion
/// <summary>
/// PID迭代器,在每个采样周期调用此函数以获取当前控制器输出。
/// 设定点和过程值应使用相同的单位。
/// </summary>
/// <param name="setPoint">设定目标值</param>
/// <param name="processValue">当前实际值</param>
/// <param name="ts">自上次迭代以来的时间跨度,对第一次调用使用默认采样周期</param>
/// <returns>Current Controller Output</returns>
public double PID_iterate(double setPoint, double processValue, TimeSpan ts)
{
// Ensure the timespan is not too small or zero.
Ts = (ts.TotalSeconds >= TsMin) ? ts.TotalSeconds : TsMin;
// Calculate rollup parameters
K = 2 / Ts;
b0 = Math.Pow(K, 2) * Kp + K * Ki + Ki * N + K * Kp * N + Math.Pow(K, 2) * Kd * N;
b1 = 2 * Ki * N - 2 * Math.Pow(K, 2) * Kp - 2 * Math.Pow(K, 2) * Kd * N;
b2 = Math.Pow(K, 2) * Kp - K * Ki + Ki * N - K * Kp * N + Math.Pow(K, 2) * Kd * N;
a0 = Math.Pow(K, 2) + N * K;
a1 = -2 * Math.Pow(K, 2);
a2 = Math.Pow(K, 2) - K * N;
// Age errors and output history
e2 = e1; // Age errors one iteration
e1 = e0; // Age errors one iteration
e0 = setPoint - processValue; // Compute new error
y2 = y1; // Age outputs one iteration
y1 = y0; // Age outputs one iteration
y0 = -a1 / a0 * y1 - a2 / a0 * y2 + b0 / a0 * e0 + b1 / a0 * e1 + b2 / a0 * e2; // Calculate current output
// Clamp output if needed
if (y0 > OutputUpperLimit)
{
y0 = OutputUpperLimit;
}
else if (y0 < OutputLowerLimit)
{
y0 = OutputLowerLimit;
}
return y0;
}
/// <summary>
/// 重置控制器历史记录,有效重置控制器。
/// </summary>
public void ResetController()
{
e2 = 0;
e1 = 0;
e0 = 0;
y2 = 0;
y1 = 0;
y0 = 0;
}
/// <summary>
/// 比例增益,如果此参数发生剧烈变化,请考虑重置控制器。
/// </summary>
public double Kp { get; set; }
/// <summary>
/// 积分增益,如果此参数发生剧烈变化,请考虑重置控制器。
/// </summary>
public double Ki { get; set; }
/// <summary>
/// 微分增益,如果此参数发生剧烈变化,请考虑重置控制器。
/// </summary>
public double Kd { get; set; }
/// <summary>
///微分滤波系数。
/// N越小,过滤效果越好
/// N越大,过滤效果越差
/// 如果此参数发生剧烈变化,请考虑重置控制器。
/// </summary>
public double N { get; set; }
/// <summary>
/// 避免除以零的最小允许采样周期!
/// Ts值可能会在第一次迭代时被错误地设置为过低的值或零。
/// TsMin默认设置为1毫秒。
/// </summary>
public double TsMin { get; set; } = 0.001;
/// <summary>
/// 控制器的输出上限。
/// 是一个比输出下限大的数值。
/// </summary>
public double OutputUpperLimit { get; set; }
/// <summary>
/// 控制器的输出下限。
/// 是一个比输出上限小的数值。
/// </summary>
public double OutputLowerLimit { get; set; }
}
}