Engee 文档
Notebook

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

本演示展示了Engee模型的开发,用于在整个输入信号范围内测试模糊控制器,并将输出输出到MIK32V2微控制器的DAC。

导言

该示例的目的是测试具有两个输入和一个输出的模糊控制器的操作。 模糊控制器模型由Engee基础库的单独块组装而成,便于熟悉控制器的功能特性。 本演示中使用的目标设备是MIK32NUKE v0调试板。3基于微控制器*[K1948VK018MIK32Amur](https://mikron.ru/products/mikrokontrollery/mk32-amur /)。 代码通过PlatformIO扩展从VS Code*编译并上传到微控制器。

模型描述

模型的一般视图如下图所示。

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 它包括改变值的范围和控制器的输出信号的数据类型: :

mik32_output_model.png

信号限制在0到4095之间,因为MIC32Dac具有12位比特率,数据格式为整数、无符号、2字节。

模糊控制器的结构

模糊控制器根据Mamdani算法构建,由相同的模糊化和聚合块,激活块(min函数),累积块(max函数)和去模糊化块(单点集的重心法,COGS)组成。

mik32_fuzzy_controller_model_2.png

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

模糊化和聚集

输入变量有三个语言项,它们接受范围为"低"的非零真值。: ,"平均": ,"高": . 在聚合阶段,对输入信号应用相对于零对称的三角隶属函数(AF)。 在子系统中 fuzzyfication OP以块[1-D查找表](https://engee.com/helpcenter/stable/ru/base-lib-tables/1d-lookup-table.html )。 下面给出了输入变量项的AF计算。

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 定义了所有术语组合的结论。 激活由最小函数执行:

积累

在子系统中 accumulation 以下规则库被再现:

  1. 如果( "低" "低" "平均"))然后 "低"
  2. 如果( "低" "高")
    ( "平均" "低" "平均"))
    ( "高" "低")然后 "平均"
  3. 如果( "平均" "高")
    ( "高" "平均" "高")) "高"

为了清楚起见,让我们以表格的形式呈现它。:

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]:

输出项的真实程度是根据表达式从结论中确定的最大函数:

脱雾化;脱雾化

在子系统中 defuzzyfication 实现了单点集(COGS)的重心法。 输出项的隶属函数的中点: . 计算是在不将隶属度降低到总和的情况下实现的( )和一个演员( ). 对于建模和测试,我们进一步使用第一种方法。

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]:

该信号包含在加载到控制器中的程序中,并将被传输到数模转换器。

代码生成和项目汇编

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

带有模型的项目在IDE中组装VS Code+PlatformIO,组装过程类似于示例中的过程*[MIC32:锯齿信号发生器](https://engee.com/community/ru/catalogs/projects/mik32-generator-piloobraznykh-signalov )*。
唯一的例外是编译的程序不是加载到控制器的RAM中,而是通过SPIFI接口加载到闪存中。 配置文件附加到示例中的配置PlatformIO。 platformio.ini. 让我们继续在微控制器上执行代码。

在MIK32上执行代码

在成功组装和编译项目后,我们将一个示波器连接到P1.12微控制器通道并显示示波器。

mik32_fuzzy_results.gif

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

结论

在这个例子中,我们检查了Engee模型中模糊控制器的结构,模拟了其测试,并在从模型生成代码后在MIC32Amur微控制器上测试了控制器。 控制器上的仿真和测试结果完全相同,并与指定的算法相对应。