6.1.2. 控制器模型¶
为实现 Eq.3.1 中描述的控制器数学模型并与被控对象模型相连接,分解后的控制器原理框图如 图 6.2 。
模型头文件controller.h的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #ifndef CONTROLLER_H__
#define CONTROLLER_H__
//==================================================================/
// Milestone: A test case for fmi simulation tools
// Copyright (c) 2019, MA Yuhai
// All rights reserved.
//
// Version 1.0
//==================================================================/
#include "interface.h"
#define FMI_MODEL_AUTHOR "MA Yuhai" /* 模型作者 */
#define FMI_MODEL_NAME "controller" /* 模型名称 */
#define FMI_MODEL_DISCRIPTION "a controller model" /* 模型描述 */
#define FMI_PORT_POSTFIX "" /* 端口后缀 */
// resource file definition if any /* 外部资源文件需要放置在模型的resources目录下 */
#define FMI_RESOURCE_ITEM 2 /* 外部资源文件数量定义 */
#if FMI_RESOURCE_ITEM>0 && defined EN_RES_ACCESS
const char *resource_file_list[FMI_RESOURCE_ITEM] = {
"init_config.txt", "init_data.dat" }; /* 外部资源文件名称定义列表 */
#endif /* 列表中超出FMI_RESOURCE_ITEM的项目将被忽略 */
// task definition if any in the unit of [ms] /* 格式task_[period]ms_start_[offfset]ms */
#define FMI_TASK_ITEM 2 /* 计划任务数量定义 */
FMI_EXPORT void task_30ms_start_0ms(void); /* 计划任务触发函数1 */
FMI_EXPORT void task_100ms_start_1030ms(void); /* 计划任务触发函数2 */
// define interface variables by an fmi object
// one statement per line, no extra semicolons allowed
// do not modify internal variables
typedef struct st_fmi_object_t {
// internal variables /* 必须的内部变量,当前时间、步长和文件列表 */
FMI_IN double fmi_time_current;
FMI_IN double fmi_time_step;
#if FMI_RESOURCE_ITEM>0
FMI_PRM fmi_str_ptr fmi_file_list[FMI_RESOURCE_ITEM]; /* 运行时可用的外部资源文件名列表 */
#endif
// interface variables
FMI_IN Stru_Data_Plant_To_Controller st_data_plant_to_controller; /* 输入接口结构体 */
FMI_OUT Stru_Data_Controller_To_Plant st_data_controller_to_plant; /* 输出接口结构体 */
FMI_OUT double task_30ms_status; /* 自定义输出1,30ms任务监控 */
FMI_OUT double task_100ms_status; /* 自定义输出2,100ms任务监控 */
}st_fmi_object; /* 模型名称 */
#endif // CONTROLLER_H__
|
模型源文件controller.cpp中的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | #include "controller.h"
#include <iostream> /* 不限制模型内部的实现方式,可以使用C++的类、STL等特性 */
#include <fstream>
#include <string>
using namespace std;
double x; /* 可以在模型内部自定义全局变量 */
double v;
double F;
double x_0;
double v_0;
int task_30ms_trigger;
int task_100ms_trigger;
void load_initial_data(fmi_str_ptr fmi_file_list[]) /* 可以在模型内部自定义函数 */
{
ifstream init_file;
init_file.open(fmi_file_list[0]);
if (!init_file.is_open()) {
cout << "open data file error: " << fmi_file_list[0] << endl;
}
else {
string buff;
getline(init_file, buff);
cout << buff << endl; /* 打印资源文件中的内容 */
}
init_file.close();
init_file.open(fmi_file_list[1]);
if (!init_file.is_open()) {
cout << "open data file error: " << fmi_file_list[1] << endl;
}
else {
init_file >> x_0; /* 读取资源文件中的内容作为初始值传递给被控对象 */
init_file >> v_0; /* 注意!一般情况下这并不会生效,和求解器的实现方式有关 */
} /* 一般情况下,初始化阶段不会按照模型的连接关系按顺序执行,并交换接口变量 */
init_file.close();
return;
}
void task_30ms_start_0ms(void) /* 头文件中定义的定时任务触发函数必须实现 */
{
task_30ms_trigger = task_30ms_trigger ? 0 : 1;
}
void task_100ms_start_1030ms(void)
{
task_100ms_trigger = task_100ms_trigger ? 0 : 1;
}
void* fmi_instantiate(void) /* 实例化函数,在模型加载后被调用 */
{
st_fmi_object *p = /* 模板内容均为必须的操作,请勿删除 */
(st_fmi_object *)calloc(1, sizeof(st_fmi_object));
if (!p) {
fprintf(stderr, "fmi_instantiate failed in model controller!\n");
exit(EXIT_FAILURE);
}
/* 在模板代码后,可添加自定义的操作,如打印信息 */
return p;
}
int fmi_initialize(void *fmi_object) /* 初始化函数,在模型启动或重置时被调用 */
{
st_fmi_object *p = (st_fmi_object *)fmi_object;
load_initial_data(p->fmi_file_list); /* 可通过p指针访问接口上的所有变量及文件资源 */
p->st_data_controller_to_plant.x_0 = x_0;
p->st_data_controller_to_plant.v_0 = v_0;
return 0;
}
int fmi_doStep(void *fmi_object) /* 步进函数,每一个步长推进的周期被调用 */
{
st_fmi_object *p = (st_fmi_object *)fmi_object;
const double pi = 3.1416; /* 可在模型中自定义参数常量 */
const double r_x = 5;
const double m = 0.1;
const double zeta = 0.2; // let it oscillates
const double omega_n = 2*pi*0.5;
const double k_p = omega_n*omega_n*m;
const double k_d = 2*zeta*omega_n*m;
x = p->st_data_plant_to_controller.x; /* 可选择将接口内存变量赋值到较方便的名称 */
v = p->st_data_plant_to_controller.v;
F = k_p * (r_x - x) - k_d * v; /* 执行模型计算 */
p->st_data_controller_to_plant.F = F; /* 将计算后的结果发布到接口内存上 */
p->task_30ms_status = task_30ms_trigger;
p->task_100ms_status = task_100ms_trigger;
return 0;
}
int fmi_reset(void *fmi_object) /* 复位函数,在重置模型时被调用 */
{
st_fmi_object *p = (st_fmi_object *)fmi_object;
IO_PORT_FLUSH(Stru_Data_Controller_To_Plant, st_data_controller_to_plant); /* 清空输出接口内存 */
return 0;
}
void fmi_freeInstance(void *fmi_object) /* 释放函数,在模型卸载时被调用 */
{
st_fmi_object *p = (st_fmi_object *)fmi_object;
free(p);
}
|