6.1.2. 控制器模型

为实现 Eq.3.1 中描述的控制器数学模型并与被控对象模型相连接,分解后的控制器原理框图如 图 6.2

../_images/sys_controller.png

图 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);
}