此示例显示了使用C函数块将C代码集成到AnyMath模型中的各种方法。
在开始工作之前,我们将连接库以与MATLAB进行比较。:
using MATLAB
使用宏 @__DIR__
demoroot = @__DIR__
让我们来看看使用C函数块的简单示例,说明将C代码集成到AnyMath模型中的基础知识。
1. 处理多维信号,传递参数并使用#define指令
进入模型 cCodeIntegration_basics.engeein
假设我们要增加正弦波的振幅 ingainbiasout = gain * in + bias
让我们转到C函数块的设置,在选项卡中的位置 Ports
- 标量变量
像x 与第一输入端口通信double ;in - 向量(3个元素)变量
像y 与所述第一输出端口连通double .out
.png)
阵列 gainParameters
.png)
值得注意的是,将变量作为参数传递后,它变成:
- 全球至
您可以从源代码编辑器的任何选项卡访问它。;gain - 用限定符
-尝试更改值时const 将收到错误。gain
位移量 bias#define biasBuild options
.png)
在此示例中,偏移量为 5
我们去弗拉卡吧 MainOutputCode
.png)
在循环中 fory
让我们为系统建模:
cCodeIntegration_basics = engee.load("$demoroot/models/cCodeIntegration_basics.engee", force = true)
simulationResults_basics = engee.run(cCodeIntegration_basics)
关闭模型:
engee.close(cCodeIntegration_basics, force = true);
导入模拟结果:
cCodeIntegration_basics_t = simulationResults_basics["out"].time;
cCodeIntegration_basics_y1 = [y[1] for y in simulationResults_basics["out"].value];
cCodeIntegration_basics_y2 = [y[2] for y in simulationResults_basics["out"].value];
cCodeIntegration_basics_y3 = [y[3] for y in simulationResults_basics["out"].value];
让我们建立一个图表:
plot(cCodeIntegration_basics_t, cCodeIntegration_basics_y1)
plot!(cCodeIntegration_basics_t, cCodeIntegration_basics_y2)
plot!(cCodeIntegration_basics_t, cCodeIntegration_basics_y3)
title!("C功能块的输出信号 <br> (多维信号,参数和#define)")
xlabel!("时间,[s]")
ylabel!("的振幅")
2. 使用整数数据类型和静态变量
在模型中 cCodeIntegration_integers.engee
让我们分析一下选项卡的内容 PortsBuild Options
.png)
.png)
C函数块中整数数据类型的名称根据[头文件]设置(https://ru.wikipedia.org/wiki/Stdint.h ) <stdint.h>HeadersBuild options
在标签中 Portsoutuint64_tlong<stdint.h>
在标签中 Output code
.png)
静态变量 counter1out
让我们为系统建模:
cCodeIntegration_integers = engee.load("$demoroot/models/cCodeIntegration_integers.engee", force = true)
simulationResults_integers = engee.run(cCodeIntegration_integers)
关闭模型:
engee.close(cCodeIntegration_integers, force = true);
导入模拟结果:
cCodeIntegration_integers_t = simulationResults_integers["counter"].time;
cCodeIntegration_integers_y = simulationResults_integers["counter"].value;
让我们建立一个图表:
plot(cCodeIntegration_integers_t, cCodeIntegration_integers_y, legend = false)
title!("C功能块的输出信号 <br> (整数类型和静态变量)")
xlabel!("时间,[s]")
ylabel!("迭代次数")
有关源代码编辑器选项卡的用途、构建功能和可用数据类型的更多详细信息,请参阅[文档](https://engee.com/helpcenter/stable/base-lib-user-defined-function/c-function.html )AnyMath。
设置任务
让我们考虑一个更有趣的工程问题。
假设考虑到测量噪声,我们需要控制二阶的稳定对象,该对象受外部扰动的影响。 因此,我们将需要解决过滤控制对象的输出信号的问题,幸运的是,AnyMath有一个非常适合这个的工具!
在档案中 alphabetafilter.calphabetafilter.h
文件内容 alphabetafilter.c
#include "alphabetafilter.h"
#include <math.h>
double dt = 0.01;
static double xk_1, vk_1;
Parameters determineAlphaBeta(double processNoiseVariance, double measurementNoiseVariance)
{
double lambda, r;
Parameters p;
lambda = (processNoiseVariance * pow(dt, 2)) / measurementNoiseVariance;
r = (4 + lambda - sqrt(8 * lambda + pow(lambda, 2))) / 4;
p.alpha = 1 - pow(r, 2);
p.beta = 2 * (2 - p.alpha) - 4 * sqrt(1 - p.alpha);
return p;
}
double alphaBetaFilter(double value, Parameters p)
{
double xk, vk, rk;
xk = xk_1 + (vk_1 * dt);
vk = vk_1;
rk = value - xk;
xk += p.alpha * rk;
vk += (p.beta * rk) / dt;
xk_1 = xk;
vk_1 = vk;
return xk;
}
void initializeStaticVariables()
{
xk_1 = 0;
vk_1 = 0;
}
文件内容 alphabetafilter.h
typedef struct {
double alpha;
double beta;
} Parameters;
Parameters determineAlphaBeta(double, double);
double alphaBetaFilter(double, Parameters);
void initializeStaticVariables();
我们将此源代码集成到我们的AnyMath模型中。
模型分析
模型 cCodeIntegration_source.engee
该模型由:
- 管理对象
Plant - 实现二阶PID控制器的子系统
;Controller - 块带限白噪声
和ProcessNoise 模拟外部冲击和测量噪声;MeasurementNoise - C功能块
,其中实现了alpha-beta过滤器。Filter
参数 Sample TimeFilterTs
.png)
让我们分析一下选项卡的内容 Build optionsFilter
.png)
在此选项卡的行中:
-源代码文件已连接Source files ;alphabetafilter.c -设置包含头文件的文件夹的路径。;Iinclude directories -头文件已连接Headers .alphabetafilter.h
在标签中 PortsFilter
块的源代码中 FilterOutputCode
.png)
在模型计算的每个步骤中,函数按顺序调用 determineAlphaBeta()alphabetafilter()outxFilter
运行模拟
让我们为系统建模:
cCodeIntegration_source = engee.load("$demoroot/models/cCodeIntegration_source.engee", force = true)
simulationResults_source = engee.run(cCodeIntegration_source)
关闭模型:
engee.close(cCodeIntegration_source, force = true);
模拟结果
导入模拟结果:
cCodeIntegration_source_noisy_t = simulationResults_source["noisy"].time;
cCodeIntegration_source_noisy_y = simulationResults_source["noisy"].value;
cCodeIntegration_source_filtered_t = simulationResults_source["filtered"].time;
cCodeIntegration_source_filtered_y = simulationResults_source["filtered"].value;
让我们建立一个图表:
plot(cCodeIntegration_source_noisy_t, cCodeIntegration_source_noisy_y, label = "原始信号")
plot!(cCodeIntegration_source_filtered_t, cCodeIntegration_source_filtered_y, label = "滤波信号")
plot!(legend = :bottomright)
title!("Α-β过滤器 <br> (集成外部源代码)")
xlabel!("时间,[s]")
ylabel!("的振幅")
设置任务
源代码通常不是显式提供的,而是作为静态或动态库的一部分提供的。 具有C API接口的库与外部源代码一样容易地集成到AnyMath模型中!
编译一个静态(alphabetafilter.aalphabetafilter.soalphabetafilter.calphabetafilter.hMakeFile
文件内容 Makefile
all: alphabetafilter.a alphabetafilter.so
alphabetafilter.o: alphabetafilter.c
alphabetafilter.a: alphabetafilter.o
ar rcs ^
alphabetafilter.so: alphabetafilter.o
^ -o $@
clean:
rm -f *.o *.a *.so
让我们开始编译库:
run(`make -C $demoroot/source`)
将静态和动态库集成到我们的AnyMath模型中。
静态库:模型分析
通过它的结构,模型 cCodeIntegration_library_static.engeecCodeIntegration_source.engeeBuild optionsFilter
.png)
此处定义了以下构造选项:
-设置包含头文件的文件夹的路径。;Include directories -设置包含静态库的文件夹的路径。;Library directories -头文件已连接Headers ;alphabetafilter.h -静态库已连接Libraries .alphabetafilter.a
静态库:运行模拟
让我们为系统建模:
cCodeIntegration_library_static = engee.load("$demoroot/models/cCodeIntegration_library_static.engee", force = true)
simulationResults_library_static = engee.run(cCodeIntegration_library_static)
关闭模型:
engee.close(cCodeIntegration_library_static, force = true);
静态库:仿真结果
导入模拟结果:
cCodeIntegration_library_static_noisy_t = simulationResults_library_static["noisy"].time;
cCodeIntegration_library_static_noisy_y = simulationResults_library_static["noisy"].value;
cCodeIntegration_library_static_filtered_t = simulationResults_library_static["filtered"].time;
cCodeIntegration_library_static_filtered_y = simulationResults_library_static["filtered"].value;
让我们建立一个图表:
plot(cCodeIntegration_library_static_noisy_t, cCodeIntegration_library_static_noisy_y, label = "原始信号")
plot!(cCodeIntegration_library_static_filtered_t, cCodeIntegration_library_static_filtered_y, label = "滤波信号")
plot!(legend = :bottomright)
title!("Α-β过滤器 <br> (静态库集成)")
xlabel!("时间,[s]")
ylabel!("的振幅")
动态库:模型分析
通过它的结构,模型 cCodeIntegration_library_dynamic.engeecCodeIntegration_source.engeeBuild optionsFilter
.png)
此处定义了以下构造选项:
-设置包含头文件的文件夹的路径。;Include directories -设置包含动态库的文件夹的路径。;Library directories -头文件已连接Headers ;alphabetafilter.h -启用了动态库Libraries .alphabetafilter.so
在块源代码编辑器的开始代码选项卡中 FilterinitializeStaticVariables()
功能 initializeStaticVariables()alphabetafilter.hxk_1vk_10
动态库:运行模拟
让我们为系统建模:
cCodeIntegration_library_dynamic = engee.load("$demoroot/models/cCodeIntegration_library_dynamic.engee", force = true)
simulationResults_library_dynamic = engee.run(cCodeIntegration_library_dynamic)
关闭模型:
engee.close(cCodeIntegration_library_dynamic, force = true);
动态库:仿真结果
导入模拟结果:
cCodeIntegration_library_dynamic_noisy_t = simulationResults_library_dynamic["noisy"].time;
cCodeIntegration_library_dynamic_noisy_y = simulationResults_library_dynamic["noisy"].value;
cCodeIntegration_library_dynamic_filtered_t = simulationResults_library_dynamic["filtered"].time;
cCodeIntegration_library_dynamic_filtered_y = simulationResults_library_dynamic["filtered"].value;
让我们建立一个图表:
plot(cCodeIntegration_library_dynamic_noisy_t, cCodeIntegration_library_dynamic_noisy_y, label = "原始信号")
plot!(cCodeIntegration_library_dynamic_filtered_t, cCodeIntegration_library_dynamic_filtered_y, label = "滤波信号")
plot!(legend = :bottomright)
title!("Α-β过滤器 <br> (动态库集成)")
xlabel!("时间,[s]")
ylabel!("的振幅")
设置任务
从Simulink模型生成C代码 alphabetafilter.slxcCodeIntegration_cg_simulink.engee
模型 alphabetafilter.slxdetermineAlphaBetafilterInputSignal
模型的上层:
.png)
子系统 determineAlphaBeta
.png)
子系统 filterInputSignal
.png)
使用Simulink Embedded Coder生成代码:
cgPath = joinpath(demoroot,"cg/simulink")
cgModel = joinpath(demoroot,"cg/simulink/alphabetafilter")
mat"""
model = load_system($cgModel);
path = $cgPath;
set_param(0, 'CacheFolder', path)
set_param(0, 'CodeGenFolder', path)
slbuild(model)
set_param(0, 'CacheFolder', '')
set_param(0, 'CodeGenFolder', '')
"""
模型分析
通过它的结构,模型 cCodeIntegration_cg_simulink.engeecCodeIntegration_source.engeeBuild optionsFilter
.png)
此处定义了以下构造选项:
-源代码文件已连接Source files 和alphabetafilter.c ;alphabetafilter_data.c -包含头文件的文件夹的路径设置;Include directories -头文件已连接Headers ,alphabetafilter.h 和alphabetafilter_types.h .rtwtypes.h
循环执行的代码显示在选项卡上 Output codeFilter
.png)
在模型计算的每个步骤中,执行以下操作:
*结构的初始化 alphabetafilter_UinprocessNoiseVariancemeasurementNoiseVariance
*函数调用 alphabetafilter_step()
*分配变量 outxalphabetafilter_Y
在块源代码编辑器的开始代码选项卡中 Filteralphabetafilter_initialize()
.png)
在块源代码编辑器的终止代码选项卡中 Filteralphabetafilter_terminate()
.png)
运行模拟
让我们为系统建模:
cCodeIntegration_cg_simulink = engee.load("$demoroot/models/cCodeIntegration_cg_simulink.engee", force = true)
simulationResults_cg_simulink = engee.run(cCodeIntegration_cg_simulink)
关闭模型:
engee.close(cCodeIntegration_cg_simulink, force = true);
模拟结果
导入模拟结果:
cCodeIntegration_cg_simulink_noisy_t = simulationResults_cg_simulink["noisy"].time;
cCodeIntegration_cg_simulink_noisy_y = simulationResults_cg_simulink["noisy"].value;
cCodeIntegration_cg_simulink_filtered_t = simulationResults_cg_simulink["filtered"].time;
cCodeIntegration_cg_simulink_filtered_y = simulationResults_cg_simulink["filtered"].value;
让我们建立一个图表:
plot(cCodeIntegration_cg_simulink_noisy_t, cCodeIntegration_cg_simulink_noisy_y, label = "原始信号")
plot!(cCodeIntegration_cg_simulink_filtered_t, cCodeIntegration_cg_simulink_filtered_y, label = "滤波信号")
plot!(legend = :bottomright)
title!("Α-β过滤器 <br> (集成从Simulink模型生成的代码)")
xlabel!("时间,[s]")
ylabel!("的振幅")
设置任务
从AnyMath模型生成C代码 alphabetafilter.engeecCodeIntegration_cg_engee.engee
模型的上层:
子系统 determineAlphaBeta
子系统 filterInputSignal
让我们使用AnyMath代码生成器生成代码:
engee.generate_code("$demoroot/cg/engee/alphabetafilter.engee", "$demoroot/cg/engee/alphabetafilter_cg")
模型分析
通过它的结构,模型 cCodeIntegration_cg_engee.engeecCodeIntegration_source.engeeBuild optionsFilter
.png)
此处定义了以下构造选项:
-源代码文件已连接Source files ;alphabetafilter.c -包含头文件的文件夹的路径已设置;Include directories -头文件已连接Headers .alphabetafilter.h
循环执行的代码显示在选项卡上 Output codeFilter
.png)
在模型计算的每个步骤中,执行以下操作:
*结构的初始化 alphabetafilter_UinprocessNoiseVariancemeasurementNoiseVariance
*函数调用 alphabetafilter_step()
*分配变量 outxalphabetafilter_Y
在块源代码编辑器的开始代码选项卡中 Filteralphabetafilter_init()
在块源代码编辑器的终止代码选项卡中 Filteralphabetafilter_term()
运行模拟
让我们为系统建模:
cCodeIntegration_cg_engee = engee.load("$demoroot/models/cCodeIntegration_cg_engee.engee", force = true)
simulationResults_cg_engee = engee.run(cCodeIntegration_cg_engee)
关闭模型:
engee.close(cCodeIntegration_cg_engee, force = true);
模拟结果
导入模拟结果:
cCodeIntegration_cg_engee_noisy_t = simulationResults_cg_engee["noisy"].time;
cCodeIntegration_cg_engee_noisy_y = simulationResults_cg_engee["noisy"].value;
cCodeIntegration_cg_engee_filtered_t = simulationResults_cg_engee["filtered"].time;
cCodeIntegration_cg_engee_filtered_y = simulationResults_cg_engee["filtered"].value;
让我们建立一个图表:
plot(cCodeIntegration_cg_engee_noisy_t, cCodeIntegration_cg_engee_noisy_y, label = "原始信号")
plot!(cCodeIntegration_cg_engee_filtered_t, cCodeIntegration_cg_engee_filtered_y, label = "滤波信号")
plot!(legend = :bottomright)
title!("Α-β过滤器 <br> (从AnyMath模型生成的代码的集成)")
xlabel!("时间,[s]")
ylabel!("的振幅")
此示例演示了使用C函数块的功能以及将C代码集成到AnyMath模型中的各种方法。:
- 集成外部源代码;
- 静态和动态库的集成;
- 集成从Simulink模型生成的代码;
- 从AnyMath模型生成的代码的集成。