Engee 文档
Notebook

为 MIC32 生成代码(模糊控制器测试)

该演示介绍了Engee模型的开发过程,该模型用于测试一个模糊调节器,测试范围包括全部输入信号以及输出到MIK32V2微控制器 DAC 的信号。

介绍

本例的目的是测试具有两个输入和一个输出的模糊调节器的运行情况。模糊调节器模型由 Engee 基本库的各个模块构建而成,便于熟悉调节器的功能。本演示使用的目标设备是基于 K1948VK018 MIK32 Amur 微控制器的 MIK32 NUKE V0.3 调试板。代码的编译和加载是通过 VS CodePlatformIO 扩展完成的。

型号说明

模型概览如下图所示。

mik32_fuzzy_model.png

它由两个输入分配块、测试信号、一个具有两个输入和一个输出的模糊控制器子系统、一个输出缩放子系统以及 HAL 库中的 MIC32 外设块组成。

控制器输入和输出

来自 [重复序列楼梯] 单元 (https://engee.com/helpcenter/stable/ru/base-lib-sources/repeating-sequence-stair.html) 的重复变量二进制信号被输入到控制器输入端:

In [ ]:
# Входные сигналы:
x1_data = Vector(range(-2,2,105))
x2_data = Vector(range(-2,2,21))

# Шаг дискретизации:
Ts = 0.01

using Plots
gr()
plot([x1_data,x2_data]; label=["x1_data" "x2_data"],
     st=:step, title = "Входные сигналы", aspect_ratio=10)
Out[0]:
No description has been provided for this image

这样设置输入信号,就可以在一个信号和另一个信号的整个数值范围内检查控制器输出计算的结果。

子系统scaling 的工作包括更改调节器输出信号的数值范围和数据类型:$dac\_val = 2048\cdot (y+1)$:

mik32_output_model.png

由于 MIC32 DAC 为 12 位,数据格式为整数、无符号、2 字节,因此信号范围限制在 0 至 4095 之间。

模糊控制器的结构

模糊控制器以 Mamdani 算法为基础,由相同的分阶段和聚合块、激活块(最小函数)、累积块(最大函数)、去模糊化块(单点集重心法,COGS)组成。

mik32_fuzzy_controller_model_2.png

输入信号的语言术语数为 3,输出信号为 3。

分阶段和聚合

输入变量有三个语言项,其真值范围均为非零 - "LOW"(低):$x_S \in(-\infty;\ 0)$中":$x_M \in(-1;\ 1)$高":$x_L \in(0;\ \infty)$ 。在汇总阶段,与零对称的三角形成员函数(FP)被应用于输入信号。在fuzzyfication 子系统中,FP 由 1-D 查找表 块复制。输入变量项的 TPs 计算如下。

In [ ]:
# ФП для x1
μ_S_x1 = -x1_data;
μ_M_x1 = 1.0.-abs.(x1_data);
μ_L_x1 = copy(x1_data);

μ_x1 = [μ_S_x1, μ_M_x1, μ_L_x1];

# ФП для x2
μ_S_x2 = -x2_data;
μ_M_x2 = 1.0.-abs.(x2_data);
μ_L_x2 = copy(x2_data);

μ_x2 = [μ_S_x2, μ_M_x2, μ_L_x2];

термы = ["низкое" "среднее" "высокое"];

输入信号的饱和函数:

In [ ]:
function насыщение(μ)
    for i in 1:length(μ) 
        if μ[i] > 1
            μ[i] = 1.0
        end
        if μ[i] < 0
            μ[i] = 0.0
        end
    end 
end;

将饱和度应用于项,构建成员函数:

In [ ]:
for i in 1:3
    насыщение(μ_x1[i])
end

for i in 1:3
    насыщение(μ_x2[i])
end

график1 = plot(x1_data, μ_x1; title = "ФП для x1", label = термы, xlabel = "x1")
график2 = plot(x2_data, μ_x2; title = "ФП для x2", label = :none, xlabel = "x2")
plot(график1, график2;
     ylabel = "Степень принадлежености, μ", legend = :right, aspect_ratio=3)
Out[0]:
No description has been provided for this image

激活

在激活步骤中,子系统activation 中定义了所有术语组合的子结论。激活由最小函数完成:

$$\mu_{SS} = \min(\mu_{1S},\mu_{2S}),\ \mu_{SM} = \min(\mu_{1S},\mu_{2M}),\ \mu_{SL} = \min(\mu_{1S},\mu_{2L})$$ $$\mu_{MS} = \min(\mu_{1M},\mu_{2S}),\ \mu_{MM} = \min(\mu_{1M},\mu_{2M}),\ \mu_{ML} = \min(\mu_{1M},\mu_{2L})$$ $$\mu_{LS} = \min(\mu_{1L},\mu_{2S}),\ \mu_{LM} = \min(\mu_{1L},\mu_{2M}),\ \mu_{LL} = \min(\mu_{1L},\mu_{2L})$$

积累

accumulation 子系统中复制了以下规则库:

1.if ($x_{1}=$ "low" and ( "low" or "medium"))and ($x_{2}=$ "low" or$x_{2}=$ "medium"))则***$y =$ "低"。 2.if** ($x_{1}=$ "低" and$x_{2}=$ "高") or
($x_{1}=$ "中等"。and ($x_{2}=$ "low" or$x_{2}=$ "medium") ))
($x_{1}=$ "高" ** 和$x_{2}=$ "低") **到$y =$ "中"。 3.
如果** ($x_{1}=$ "中" ** 和$x_{2}=$ "高") **or
($x_{1}=$ "高"and ($x_{2}=$ "medium" or$x_{2}=$ "high"))TO$y =$ "高"

为了清楚起见,我们用表格的形式来表示:

In [ ]:
колонки = ["низкое", "среднее", "высокое"];
строки = copy(колонки);
база_правил = [
                "низкое" "среднее" "среднее";
                "низкое" "среднее" "высокое";
                "среднее" "высокое" "высокое"
               ];
(n,m) = size(база_правил)

heatmap(база_правил, fc = cgrad([:blue; :red; :green]), leg=false, xticks=(1:3,колонки), yticks=(1:3,строки))
title!("База правил")
xlabel!("Термы x1")
ylabel!("Термы x2")
annotate!( [(j, i, база_правил[i,j]) for i in 1:n for j in 1:m])
vline!(0.5:(n+0.5), c=:black)
hline!(0.5:(m+0.5), c=:black)
Out[0]:

根据表达式,输出项的真度定义在子结论的最大函数中:

$$\mu_{y_S} = \max(\mu_{SS},\ \mu_{SM}),$$ $$\mu_{y_M} = \max(\mu_{SL},\ \mu_{MS},\ \mu_{MM},\ \mu_{LS}),$$ $$\mu_{y_L} = \max(\mu_{ML},\ \mu_{LM},\ \mu_{LL})$$

模糊化

子系统defuzzyfication 采用单点集重心法 (COGS)。输出项成员函数的中点为:$y_S= -1;\ y_M= 0;\ y_L= 1$ 。计算在没有 ($y$ ) 和有 ($y_1$ ) 的情况下进行。我们使用第一种方法进行建模和测试。

mik32_defuzzy_model.png

建模结果

让我们加载并运行示例模型:

In [ ]:
# @markdown **Программное управление моделированием:**  
# @markdown Требуется ввести только имя модели
имя_модели = "mik32_fuzzy_reg" # @param {type:"string"}
if имя_модели in [m.name for m in engee.get_all_models()]
    модель = engee.open( имя_модели );
else
    модель = engee.load( "$(@__DIR__)/"*имя_модели*".engee" );
end
данные = engee.run(модель);

绘制输出变量的图表

In [ ]:
plot(данные["dac_val"].time, данные["dac_val"].value;
     label="y", title="Выходной сигнал", xlims=(0,1.1))
Out[0]:

将程序中的信号加载到控制器中,并将其发送到数模转换器。

模型中控制器的外围由C 函数块实现,正如在 MIC32 的 DAC 早期示例中实现的那样:锯齿信号Engee 徽标

代码生成和项目组装

In [ ]:
# @markdown **Генерация кода:**  
# @markdown Папка для результатов генерации кода будет создана в папке скрипта:
папка = "code" # @param {type:"string"}

# @markdown Генерация кода для подсистемы:
включить = false # @param {type:"boolean"}
if(включить)
    подсистема = "" # @param {type:"string"}
    engee.generate_code( "$(@__DIR__)/"*имя_модели*".engee", "$(@__DIR__)/"*папка;
                     subsystem_name = подсистема)
else
    engee.generate_code( "$(@__DIR__)/"*имя_модели*".engee", "$(@__DIR__)/"*папка)
end
[ Info: Generated code and artifacts: /user/start/examples/codegen/mik32_fuzzy/code

包含模型的项目在集成开发环境 VS Code+PlatformIO 中构建,构建过程与示例 MIC32: 锯齿波信号发生器中的过程类似。
唯一不同的是,编译后的程序不是加载到控制器的 RAM 中,而是通过 SPIFI 接口加载到闪存中。在示例中配置 PlatformIO 时,配置文件platformio.ini 附后。下面我们继续在微控制器上执行代码。

在 MIK 32 上执行代码

成功组装和编译项目后,将示波器连接到微控制器的 P1.12 频道并显示示波器图。

mik32_fuzzy_results.gif

从振荡图中可以看出,DAC 通道再现了被测模糊控制器的模拟输出信号的形状。

结论

在本示例中,我们考虑了 Engee 模型中模糊控制器的结构,模拟了其测试,并在根据模型生成代码后在 MIC32 Amur 微控制器上测试了控制器。控制器的建模和测试结果与指定算法完全一致。