PID控制器手动调节的环境
在这个项目中,我们建议您使用一个简约的环境来配置系统图形模型的PID控制。
系统描述
有一个模型定义为以下类型的传递函数:
任务是找到PID控制器的参数,在该参数处系统令人满意地执行单个分步动作。
解决步骤
如果这个模型在模型编辑器中求解,但没有演示我们感兴趣的过渡过程的参数,那么是时候进入下一阶段并尝试手动粗略选择参数了。
由于我们显然不知道必要参数的尺度,在本例中,PID控制器的每个参数都使用两个数字来选择。:
*最大值(无限),
*比例系数(从0到1)
该方法在方便性和所选参数的广度之间提供了一些折衷。 在不修改程序代码的情况下,设计人员可以设置调节器系数的任何比例,然后使用无级调节器平滑地选择更精确的值。
gr()
engee.open("pid_manual_tuning.engee")
using DataFrames, Statistics
all_runs = DataFrame[];
colors = [1, "skyblue", "lightblue", "powderblue", "lightblue1"];
下一个单元格的代码可以通过双击带有控件的表单来隐藏。 此外,将单元格输出放置在参数输入表单的右侧很方便(button<svg width="16"height="16"viewBox="0 0 18 18"fill="none"xmlns="http://www.w3.org/2000/svg "><path fill-rule="evenodd"clip-rule="evenodd"d="M0 3.9C0 3.40294 0.436522 3 0.975 3L17.025 3C17.5635 3 18 3.40294 18 3.9C18 4.39706 17.5635 4.8 17.025 4.8L0.975 4.8C0.436522 4.8 0 4.39706 0 3.9z"fill="#141519"><PATH FILL-RULE="EVENODD"CLIP-RULE="EVENODD"D="M0 0.9C0 0.402944 0.436522 0 0.975 0L17.025 0C17.5635 0 18 0.402944 18 0.9c18 1.39706 17.5635 1.8 17.025 1.8L0.975 1.8C0.436522 1.8 0 1.39706 0 0.9Z"FILL="#141519"><PATH FILL-RULE="EVENODD"CLIP-RULE="EVENODD"D="M1.95 9.17075V16.0976h16.05v9.17075h1.95zm1.5 7.26831C0.671573 7.26831 0 7.9235 0 8.73173V16.5366C0 17.3448 0.671573 18 1.5 18H16.5C17.3284 18 18 17.3448 18 16.5366v8.73172c18 7.9235 17.3284 7.26831 16.5 7.26831H1.5Z"FILL="#141519">)。
StopTime = 30 # @param {type:"slider",min:0,max:100,step:1}
P_max = 6.0 # @param {type:"number",placeholder:"1.0"}
I_max = 1.0 # @param {type:"number",placeholder:"1.0"}
D_max = 1.0 # @param {type:"number",placeholder:"1.0"}
P = 0.09 # @param {type:"slider",min:0,max:1,step:0.01}
I = 0.91 # @param {type:"slider",min:0,max:1,step:0.01}
D = 0 # @param {type:"slider",min:0,max:1,step:0.01}
engee.set_param!("pid_manual_tuning/ПИД-регулятор", "P"=>P*P_max, "I"=>I*I_max, "D"=>D*D_max)
engee.set_param!("pid_manual_tuning", "StopTime"=>StopTime)
# Запусти модель и получим результаты
data = engee.run("pid_manual_tuning")
x = collect(data["x"])
y = collect(data["y"])
# Удалим последний элемент если список переполнился
pushfirst!(all_runs, y)
if length(all_runs) > 5 pop!(all_runs); end;
# Анализ последнего переходного процесса
if length(all_runs) > 0
    last_run = all_runs[1]
    time_data = last_run.time
    value_data = last_run.value
    
    # Определяем установившееся значение (последние 10% данных)
    steady_state_idx = Int.(collect((round(0.9 * length(value_data)):length(value_data))))
    steady_state_value = mean(value_data[steady_state_idx])
    
    # Определяем начальное значение
    initial_value = value_data[1]
    
    # Целевое значение (берем из задания)
    target_value = x.value[end]  # предполагая, что x - это задание
    
    # Находим максимальное отклонение (перерегулирование)
    max_overshoot = maximum(value_data)
    overshoot_percentage = abs((max_overshoot - steady_state_value) / (target_value - initial_value)) * 100
    
    # Время установления (5%)
    tolerance = 0.05 * abs(target_value - initial_value)
    settling_time = nothing
    
    for i in length(value_data):-1:1
        if abs(value_data[i] - steady_state_value) > tolerance
            settling_time = time_data[i]
            break
        end
    end
    
    # Время нарастания (10%-90%)
    rise_time_10 = nothing
    rise_time_90 = nothing
    
    threshold_10 = initial_value + 0.1 * (steady_state_value - initial_value)
    threshold_90 = initial_value + 0.9 * (steady_state_value - initial_value)
    
    for i in 1:length(value_data)
        if value_data[i] >= threshold_10 && rise_time_10 === nothing
            rise_time_10 = time_data[i]
        end
        if value_data[i] >= threshold_90 && rise_time_90 === nothing
            rise_time_90 = time_data[i]
            break
        end
    end
    
    rise_time = rise_time_90 - rise_time_10
    
    # Выводим результаты анализа
    println("═"^50)
    println("АНАЛИЗ ПЕРЕХОДНОГО ПРОЦЕССА")
    println("═"^50)
    println("Установившееся значение: $(round(steady_state_value, digits=3))")
    println("Перерегулирование: $(round(overshoot_percentage, digits=1))%")
    
    if settling_time !== nothing
        println("Время установления (5%): $(round(settling_time, digits=2)) с")
    else
        println("Время установления: процесс не установился")
    end
    
    if rise_time !== nothing && rise_time_10 !== nothing
        println("Время нарастания (10%-90%): $(round(rise_time, digits=2)) с")
    end
    
    # Статическая ошибка (если есть)
    static_error = abs(target_value - steady_state_value)
    if static_error > 1e-6
        println("Статическая ошибка: $(round(static_error, digits=4))")
    else
        println("Статическая ошибка: отсутствует")
    end
    
    # Количество колебаний
    peaks = 0
    for i in 2:length(value_data)-1
        if value_data[i] > value_data[i-1] && value_data[i] > value_data[i+1] && 
           value_data[i] > steady_state_value
            peaks += 1
        end
    end
    println("Количество колебаний: $peaks")
    
    println("═"^50)
end
# Выведем графики
plot(x.time, x.value, c=:red, lw=1, size=(800,300), leg=false)
for i in length(all_runs):-1:1
    plot!(all_runs[i].time, all_runs[i].value, c=colors[i], lw=3)
end
plot!()
它是如何工作的
 
结论
我们已经实现了手动选择系数的相对粗略的方法,这将允许您调整非线性,物理,线性或线性化系统的参数。 引用最多的方法是齐格勒-尼科尔斯系数选择,它可以使用我们创建的环境来实现。
