Engee 文档
Notebook

设计智能手机摄像头焦点 SAU

让我们连接必要的库。

In [ ]:
import Pkg; 
Pkg.add(["ControlSystemIdentification", "ControlSystems"])
In [ ]:
using ControlSystems                # основная библиотека для работы с САУ
using ControlSystemIdentification   # библиотека для оценки динамических моделей на основе данных 

控制对象

下面的模型模拟了智能手机摄像头的自动对焦控制系统。

image.png

考虑一下智能手机的自动对焦模式。智能手机电子设备通过摄像头的反馈来控制电机。让我们从技术角度抽象一下,从接收到对焦指令开始,我们需要瞬时过程不超过 0.6 秒。让我们尝试使用 PID 控制器来实现这样一个系统。

我们的电机-透镜系统是非线性的,因此首先要将模型线性化。

控制对象的线性化

让我们使用控制指令运行模型。结果,在工作区中我们得到了变量data ,其中包含模拟结果。

In [ ]:
modelName = "Линза_ОУ"
if !(modelName in [m.name for m in engee.get_all_models()]) engee.load( "$(@__DIR__)/$(modelName).engee"); end;
data = engee.run( modelName )
Out[0]:
SimulationResult(
    "Преобразование единиц измерения.1" => WorkspaceArray{Float64}("Линза_ОУ/Преобразование единиц измерения.1")
,
    "Ступенчатая функция.1" => WorkspaceArray{Float64}("Линза_ОУ/Ступенчатая функция.1")

)

我们将输入和输出信号的数据写入变量并绘制成图表。

In [ ]:
dataIn = collect(data["Ступенчатая функция.1"]).value;
dataOut = collect(data["Преобразование единиц измерения.1"]).value;
data_t = collect(data["Преобразование единиц измерения.1"]).time;

plot( data_t, [dataIn dataOut], label=["Входной сигнал" "Выходной сигнал"] )
Out[0]:

我们继续对模型进行线性化处理。ControlSystemIdentification 库中的所有模型识别方法都将 AbstractIdData 类型的对象作为输入。要获取时域识别数据对象,可以使用函数iddata 。然后,使用subspaceid 方法,我们可以获得状态空间形式的系统描述。

In [ ]:
Ts = data_t[2] - data_t[1]                     # Получим частоту дискретизации системы из вектора времени
d  = iddata(dataOut, dataIn, Ts);              # создаем объект идентификации данных во временном пространстве 
sys_d = subspaceid(d, :auto);                  # запускаем метод идентификации модели пространства состояний

让我们将获得的模型描述与建模环境中收集的模型进行比较。为此,我们将使用块Пространство состояний ,并将所获得的值 A、B、C、D 写成矩阵值。

In [ ]:
sys = d2c(sys_d);   # перейдем к непрерывной модели
A = sys.A;          # находим матрицу A
B = sys.B;          # находим матрицу B
C = sys.C;          # находим матрицу C
D = sys.D;          # находим матрицу D
Warning: d2c does not handle a non-zero cross covariance S, S will be set to zero
@ ControlSystemIdentification /usr/local/ijulia-demos/packages/ControlSystemIdentification/KM4Nc/src/ControlSystemIdentification.jl:359

系数选择:函数 pid()

为了评估所选系数值是否合适,我们将绘制 LFCC、LFCC 和奈奎斯特霍德图。我们还将评估瞬态过程的质量。为方便显示频率响应图,下面将使用pid_marginplot 函数。它将在电路板上获得的系统值代入绘制频率特性图的函数:marginplotnyquistplot ,并将其显示在图形上。

In [ ]:
function pid_marginplot(C)
    f1 = marginplot(sys_tf * C, w)
    f2 = nyquistplot(sys_tf * C, xlims=(-10,1), ylims=(-2, 10), title="")
    plot(f1,f2, titlefontsize=10)
end
Out[0]:
pid_marginplot (generic function with 1 method)

让我们设置附加变量。将系统表示转换为传递函数的形式,并设置我们将绘制时间和频率特性的频率。

In [ ]:
sys_tf = tf(sys);
w = exp10.(LinRange(-2.5, 3, 500));

我们将使用单元格掩码设置系数。通过移动滑块,可以设置变量的新值。如果更改一个系数,掩码下的代码将重新计算。如果想同时更改多个参数,请关闭单元格启动按钮下的自动刷新,然后手动启动单元格。

系数的选择是迭代式的,因此我们首先要评估没有调节器时的系统特性,然后开始逐一更改,并评估更改对系统的影响。

In [ ]:
kp = 0.4 # @param {type:"slider", min:0.1, max:5, step:0.1}
ki = 1.322 # @param {type:"slider", min:0.0, max:20, step:0.001}
kd = 0.03 # @param {type:"slider", min:0.0, max:0.5, step:0.01}
Tf = 0.012 # @param {type:"slider", min:0.0, max:1, step:0.001}

C0 = pid(kp, ki, kd; Tf, form=:parallel, filter_order=2)
pid_marginplot(C0)
Out[0]:

让我们检查一下系统是否稳定。这可以通过函数isstable 来实现。

In [ ]:
isstable(feedback(sys_tf * C0))     # Проверка: устойчива ли система с полученным ПИД регулятором
Out[0]:
true

然后,如果系统是稳定的,且稳定裕度满足我们的要求,我们就构建一个瞬态过程,并评估其特性的质量。

In [ ]:
plot(stepinfo(step(feedback(sys_tf * C0), 5)))      # Оценка переходного процесса САУ
Out[0]:

获得的控制器数据可用于仿真环境中的模型。为此,我们可以从工作区域中提取系数值,并将其指定到 PID 调节器模块中。

系数选择:函数 loopshapingPID()

使用loopshapingPID 函数进行系数选择是基于环路整形方法,通过该方法可以指定所需的开环频率响应形状,从而提供所需的闭环特性。因此,如果已知系统所需的频率特性(如所需的带宽或干扰抑制水平),这种方法就非常方便。

让我们尝试将此方法应用到我们的示例中,并获得所需的特性。

该函数以传递函数的形式对系统进行描述,并给出希望实现开环系统统一增益的频率。此外,该函数还接受附加灵敏度函数 Mt 和所需相移 ϕt 的参数值。默认情况下,这些参数具有最佳值,但也可以更改。还可以调整合成 PID 控制器的形状,并显示有助于评估所获得控制系统质量的图表。

In [ ]:
ω  = 17
Tf = 1/1000ω   
C0, kp, ki, kd, fig, CF = loopshapingPID(sys_tf, ω; Mt = 1.3, ϕt = 75, form=:parallel, doplot = true)
Out[0]:
(C = TransferFunction{Continuous, ControlSystemsBase.SisoRational{Float64}}
0.0493284587237057s^2 + 1.0063456913621145s + 6.26737143322893
--------------------------------------------------------------
                             1.0s

Continuous-time transfer function model, kp = 1.0063456913621145, ki = 6.26737143322893, kd = 0.0493284587237057, fig = Plot{Plots.PlotlyJSBackend() n=18}, CF = TransferFunction{Continuous, ControlSystemsBase.SisoRational{Float64}}
0.0493284587237057s^2 + 1.0063456913621145s + 6.26737143322893
--------------------------------------------------------------
   3.4602076124567474e-9s^3 + 8.31890330807703e-5s^2 + 1.0s

Continuous-time transfer function model)

让我们尝试改变频率。如果我们分析奈奎斯特图,就会发现该特性非常接近临界点。让我们试着修正这一点,并设置ω = 17 。现在,修正后系统的特性将在ω = 17 处以ϕt = 75 的角度触及圆 Mt。

In [ ]:
plot(fig)
Out[0]:

让我们验证一下所得到系统的稳定性。

In [ ]:
isstable(feedback(CF*sys_tf))
Out[0]:
true

让我们绘制出系统的 LFC 和 LFCC,并反映出稳定性储备。

In [ ]:
marginplot([sys_tf, CF*sys_tf])
Out[0]:

我们还构建了所获 ACS 的暂态过程。我们可以看到,瞬态时间约为 0.4 秒,满足我们的要求。

In [ ]:
plot(stepinfo(step(feedback(CF * sys_tf), 1)))
Out[0]:

使用获得的 PID 调节器,我们在仿真环境中模拟了系统。并将结果绘制在图表上。