三、MPC算法应用与仿真

1、MPC的Simulink模型

(1)Simulink模块库提供了MPC工具箱,其中有自适应MPC控制模块、显式MPC控制模块、基本MPC控制模块、多重显式MPC控制模块、多重MPC控制模块,本节主要介绍基本MPC控制模块的使用。

(2)默认的基本MPC控制模块提供了三个输入端口和一个输出端口:

①mo端口(Measured Outputs):从被控对象传感器测量到的当前输出信号,或者状态观测器估计出的当前状态信号(如位置、速度等)。

②ref端口(References):输入系统的设定值或参考轨迹,即希望被控量达到的目标值(如指令位置)。

③md端口(Measured Disturbances):输入系统中可测量的前馈扰动信号,该端口是可选项,用于抑制干扰,通过在模块对话框中取消勾选“Measured disturbance(md)”可禁用该端口。(需要说明的是,此端口输入的是可计算的扰动信号,与三要素中的“反馈校正”无关)

④mv端口(Manipulated Variable):此端口输出通过内部求解器计算出的最优操作变量,即实际作用于被控对象的控制信号。

(3)双击基本MPC控制模块,可进入参数设置页面。

①Parameters一栏可对MPC控制器的参数和初始状态进行设置。

②General选项卡主要用于配置附加的输入输出端口,如果勾选最后一条,mo端口会变为x[k|k]端口,用于输入由用户自定义状态观测器(如自己设计的卡尔曼滤波器)估计出的状态。

③Online Features选项卡主要用于配置约束条件、权重参数(即代价函数的QRSF,如下为代价函数的“完全体”,其中△u为操作变量变化率权重),勾选相应的选项,相应的参数即可从模型端口输入。

[1]输出变量权重(Output Weights):定义了希望系统以多快的速度、多高的精度跟踪设定值。权重增加,控制器对输出误差的惩罚变大,会更加“积极地”消除误差,但可能会让控制动作更剧烈;反之,跟踪精度会下降。

[2]操作变量权重(MV Weights):体现了对控制动作本身消耗(比如能耗、机构磨损)的重视程度。权重增加,控制器的动作会更“吝啬”、更平缓,有利于节能,但代价是可能牺牲响应速度,系统会变“迟钝”。

[3]操作变量变化率权重(MV Rate Weights):用来抑制控制信号的剧烈跳变,也称为“阻尼项”。权重增加,控制信号变化更平滑,能有效避免超调,但如果过大,系统可能对误差反应迟钝。

④Default Conditions选项卡主要用于配置默认条件,如采样时间间隔、预测周期、系统输入信号大小及系统输出信号大小(或者说变量个数)。

(4)示例模型搭建(需要说明的是,以下例程仅仅演示如何配置MPC,在设计上并没有太多实际参考价值):

①首先按照下图所示进行模型搭建,禁用MPC控制器的md端口(简单起见,不考虑干扰抑制)。

②被控系统就是专题——基于临界阻尼二阶系统的响应调节器中介绍的系统,直接借用即可。

(5)使用MPC Designer设计MPC控制器:

①端口及仿真参数配置:

[1]双击MPC控制器模块,点击“Design”→“MPC Structure”,在弹出的对话框中可设置MPC控制器的结构。

[2]基于上一步,点击“Change I/O Sizes”,可以设置系统输入输出参数的个数。

[3]基于第一步,还可以设置采样时间和仿真信号,这里设置采样时间为0.1s,仿真信号在模型搭建完成后会自动选取,一般无需额外手动配置。

[4]配置完成后,点击“Define and Linearize”,MPC Designer将被控对象的数学模型导入Data Browser中,如下图所示,“mpc1(current)”是系统作为内部模型创建的默认MPC控制器,“scenario1”是系统默认的模拟场景,MPC Designer在默认场景中运行默认MPC控制器,然后在右侧更新输入输出响应曲线图。(需注意,如果要更改MPC控制器的结构,修改结构后需重新打开会话窗口)

[5]点击“I/O Attributes”,在弹出的对话框中可以配置输入输出信号的名称、单位、标称值和比例因子,后两者一般保持默认值即可。

[6]双击“scenario1”,在弹出的对话框中可以配置仿真时间,以及参考信号、输出扰动和负载扰动,配置完成后点击“OK”即可。

②控制器参数配置:

[1]切换至TUNING选项卡,点击“Constraints”,可以配置输入输出约束,也即上下限。在实际控制工程中,输入输出约束可能是会动态变化的,可以在配置Online Features选项卡的参数时增加系统限制相关的输入端口。

[2]点击“Weights”,可以配置代价函数中的权重系数,不过MPC Designer的界面只能填写对角线元素(每个变量对应一个权重参数),如果希望配置非对角权重,需要从模块外部输入完整的权重矩阵。

        通常建议先确定输出权重(最主要的目标)与输入/输入变化率权重(能耗、平顺性)之间的相对比例,这个比例比设置的绝对数值更重要

        跟踪精度不足或响应慢:优先增加输出变量权重

        控制动作过猛、振荡或超调:可以增加操作变量变化率权重

        系统稳态误差大:考虑增加输出变量权重,或者检查状态估计是否准确

[3]如果实际调试过程中发现上一步的调试规则不适用,很可能是预测时域过短导致的,需要保证预测时域大于控制时域,且比控制时域长得多,比如控制时域为2步,预测时域可以设置为50步;除此之外,还需要注意采样时间不能过大、输出权重与变化率权重的比例不能失调,如果增长预测时域不管用,就需要考虑这些原因。

[4]MPC Designer提供了一个方便的功能——“Review Design”按钮,点击它,应用会自动检查当前的权重、约束等参数设置是否合理,并会给出清晰的警告或建议,快速定位问题。

③MPC控制器代入Simulink模型:

[1]点击“Store Controller”,即可将MPC控制器保存到系统的工作区内。

②右键保存的控制器,选择“Update Block”,即可将设计的控制器更新到Simulink的MPC模块中。

(6)如下为上面设计的MPC模块应用示例效果展示,当然,这只是简单的展示,实际工程中远比这复杂得多。

2、C语言实现MPC算法

(1)C语言实现MPC算法,可以包含osqp.h文件,当然,二次规划求解器库不止OSQP一个,比如还有HPIPM、qpSWIFT、HiGHS。

(2)以下为示例代码,适用于类似于小车在直线上运动的控制系统,其中mpc_set_constraints函数可以动态调整约束边界,mpc_compute函数用于求解最优控制输入。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "osqp.h"

/* 系统参数 */
#define NX 2      /* 状态维度: [位置, 速度] */
#define NU 1      /* 控制维度: 加速度 */
#define N 5       /* 预测时域 */

/* MPC工作区 */
typedef struct {
    /* 系统矩阵 */
    double A[NX][NX];   /* 状态转移矩阵 */
    double B[NX][NU];   /* 输入矩阵 */
    double Q[NX][NX];   /* 状态代价矩阵 */
    double R[NU][NU];   /* 输入代价矩阵 */
    double Qf[NX][NX];  /* 终端代价矩阵 */
    
    /* 当前状态 */
    double x0[NX];
    double x_ref[NX];
    
    /* 动态约束边界 */
    double u_min, u_max;
    double x1_min, x1_max;   /* 位置约束 */
    double x2_min, x2_max;   /* 速度约束 */
    
    /* QP矩阵 (紧凑形式: 只优化控制序列, 状态通过动态模型传递) */
    double H[N*NU][N*NU];    /* 目标函数的Hessian矩阵 */
    double f[N*NU];             /* 目标函数的线性项 */
    double A_ineq[2*N*NX + 2*N*NU][N*NU]; /* 不等式约束矩阵 */
    double l_ineq[2*N*NX + 2*N*NU];         /* 下界 */
    double u_ineq[2*N*NX + 2*N*NU];        /* 上界 */
    int n_ineq;               /* 不等式约束数量 */
    
    /* 工作区 */
    OSQPSolver* solver;
    OSQPCscMatrix P, A;
    OSQPData data;
    OSQPSettings settings;
    
    int horizon;
} MPCWorkspace;

/* 辅助函数: 矩阵乘法 */
void mat_mul(int m, int n, int p, double* A, double* B, double* C) {
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < p; j++) {
            C[i*p + j] = 0.0;
            for (int k = 0; k < n; k++) {
                C[i*p + j] += A[i*n + k] * B[k*p + j];
            }
        }
    }
}

/* 计算收缩矩阵的乘积: M * M^T */
void mat_mul_trans(int m, int n, double* A, double* C) {
    double* AT = (double*)malloc(n * m * sizeof(double));
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            AT[j*m + i] = A[i*n + j];
        }
    }
    mat_mul(m, n, m, A, AT, C);
    free(AT);
}

/* 构建QP问题的Hessian矩阵和线性项
   H = B'*Q*B + R, 其中B是扩展后的控制传递矩阵
   f = B'*Q*(A*x0 - x_ref) 的修正项 */
void build_qp(MPCWorkspace* mpc) {
    int nu = NU, nx = NX, Np = mpc->horizon;
    int n_vars = nu * Np;
    
    /* 构建扩展控制传递矩阵 Phi = [B, AB, A^2B, ...] 
       用于将初始状态和输入序列映射到状态轨迹 */
    double* Phi = (double*)calloc(nx * (Np+1) * n_vars, sizeof(double));
    double* Apow = (double*)calloc((Np+1) * nx * nx, sizeof(double));
    
    /* A的幂: Apow[0] = I */
    for (int i = 0; i < nx; i++) Apow[i*nx + i] = 1.0;
    
    /* 构建Phi矩阵块 */
    double* temp = (double*)calloc(nx * nx, sizeof(double));
    for (int k = 0; k < Np; k++) {
        /* Phi的第k个块: A^k * B */
        double* block = Phi + k * nx * n_vars;
        if (k == 0) {
            /* k=0: 直接复制B */
            for (int i = 0; i < nx; i++) {
                for (int j = 0; j < nu; j++) {
                    block[i*n_vars + j] = mpc->B[i][j];
                }
            }
        } 
        else {
            /* k>0: Apow[k] * B */
            mat_mul(nx, nx, nu, Apow + k * nx * nx, (double*)mpc->B, block);
        }
        
        /* 更新A的幂: 计算A^(k+1) */
        if (k < Np-1) {
            mat_mul(nx, nx, nx, (double*)mpc->A, Apow + k * nx * nx, temp);
            memcpy(Apow + (k+1) * nx * nx, temp, nx * nx * sizeof(double));
        }
    }
    
    /* 计算 H = Phi' * Q_bar * Phi + R_bar
       其中Q_bar是扩展的状态代价矩阵(块对角,包含终端代价)
       这里简化处理,使用块对角权重 */
    double* Q_bar = (double*)calloc(nx * (Np+1) * nx * (Np+1), sizeof(double));
    for (int k = 0; k < Np; k++) {
        for (int i = 0; i < nx; i++) {
            for (int j = 0; j < nx; j++) {
                Q_bar[k*nx*nx*(Np+1) + i*nx + j] = mpc->Q[i][j];
            }
        }
    }
    for (int i = 0; i < nx; i++) {
        for (int j = 0; j < nx; j++) {
            Q_bar[Np*nx*nx*(Np+1) + i*nx + j] = mpc->Qf[i][j];
        }
    }
    
    /* 计算 Phi' * Q_bar * Phi */
    double* tmp = (double*)calloc(n_vars * nx*(Np+1), sizeof(double));
    mat_mul(nx*(Np+1), nx, n_vars, Q_bar, Phi, tmp);
    
    double H_full[20][20] = {0};
    for (int i = 0; i < n_vars; i++) {
        for (int j = 0; j < n_vars; j++) {
            for (int k = 0; k < nx*(Np+1); k++) {
                H_full[i][j] += tmp[k*n_vars + i] * Phi[k*n_vars + j];
            }
        }
    }
    
    /* 添加R_bar项 */
    double R_bar[N*NU][N*NU] = {0};
    for (int k = 0; k < Np; k++) {
        for (int i = 0; i < NU; i++) {
            R_bar[k*NU + i][k*NU + i] = mpc->R[i][i];
        }
    }
    for (int i = 0; i < n_vars; i++) {
        for (int j = 0; j < n_vars; j++) {
            H_full[i][j] += R_bar[i][j];
        }
    }
    
    /* 复制到mpc->H */
    for (int i = 0; i < n_vars; i++) {
        for (int j = 0; j < n_vars; j++) {
            mpc->H[i][j] = H_full[i][j];
        }
    }
    
    /* 计算f向量: f = (A*x0 - x_ref)' * Q * Phi */
    /* 构建预测状态偏差向量 */
    double* X_pred = (double*)calloc(nx * (Np+1), sizeof(double));
    double* x_k = (double*)calloc(nx, sizeof(double));
    memcpy(x_k, mpc->x0, nx * sizeof(double));
    
    /* 计算状态轨迹(无控制输入时) */
    for (int k = 0; k <= Np; k++) {
        memcpy(X_pred + k*nx, x_k, nx * sizeof(double));
        /* 将x_k减去参考值 */
        for (int i = 0; i < nx; i++) {
            X_pred[k*nx + i] -= mpc->x_ref[i];
        }
        /* 更新x_{k+1} = A * x_k */
        double* x_next = (double*)calloc(nx, sizeof(double));
        for (int i = 0; i < nx; i++) {
            for (int j = 0; j < nx; j++) {
                x_next[i] += mpc->A[i][j] * x_k[j];
            }
        }
        memcpy(x_k, x_next, nx * sizeof(double));
        free(x_next);
    }
    
    /* f = x0偏差 * Q_bar * Phi */
    double tmpf[20] = {0};
    mat_mul(1, nx*(Np+1), n_vars, X_pred, tmp, tmpf);
    for (int i = 0; i < n_vars; i++) {
        mpc->f[i] = tmpf[i];
    }
    
    free(Phi);
    free(Apow);
    free(temp);
    free(Q_bar);
    free(tmp);
    free(X_pred);
    free(x_k);
}

/* 构建动态约束(状态和控制边界) */
void build_constraints(MPCWorkspace* mpc) {
    int nu = NU, nx = NX, Np = mpc->horizon;
    int n_vars = nu * Np;
    int n_ineq = 2 * Np * nx + 2 * Np * nu;  /* 每个控制有上下界,每个状态有上下界 */
    mpc->n_ineq = n_ineq;
    
    /* 构建扩展控制传递矩阵Phi(用于状态预测) */
    double* Phi = (double*)calloc(nx * (Np+1) * n_vars, sizeof(double));
    double* Apow = (double*)calloc((Np+1) * nx * nx, sizeof(double));
    
    for (int i = 0; i < nx; i++) Apow[i*nx + i] = 1.0;
    
    double* temp = (double*)calloc(nx * nx, sizeof(double));
    for (int k = 0; k < Np; k++) {
        double* block = Phi + k * nx * n_vars;
        if (k == 0) {
            for (int i = 0; i < nx; i++) {
                for (int j = 0; j < nu; j++) {
                    block[i*n_vars + j] = mpc->B[i][j];
                }
            }
        } 
        else {
            mat_mul(nx, nx, nu, Apow + k * nx * nx, (double*)mpc->B, block);
        }
        if (k < Np-1) {
            mat_mul(nx, nx, nx, (double*)mpc->A, Apow + k * nx * nx, temp);
            memcpy(Apow + (k+1) * nx * nx, temp, nx * nx * sizeof(double));
        }
    }
    
    /* 构建状态自由响应轨迹 */
    double* X_free = (double*)calloc(nx * (Np+1), sizeof(double));
    double* x_k = (double*)calloc(nx, sizeof(double));
    memcpy(x_k, mpc->x0, nx * sizeof(double));
    
    for (int k = 0; k <= Np; k++) {
        memcpy(X_free + k*nx, x_k, nx * sizeof(double));
        double* x_next = (double*)calloc(nx, sizeof(double));
        for (int i = 0; i < nx; i++) {
            for (int j = 0; j < nx; j++) {
                x_next[i] += mpc->A[i][j] * x_k[j];
            }
        }
        memcpy(x_k, x_next, nx * sizeof(double));
        free(x_next);
    }
    
    /* 构建不等式约束: X_free + Phi * u 必须在边界内 */
    for (int k = 0; k < Np; k++) {
        /* 状态约束: x_min ≤ x_k ≤ x_max */
        double* row_low = mpc->l_ineq + 2*k*nx;
        double* row_up = mpc->u_ineq + 2*k*nx;
        for (int i = 0; i < nx; i++) {
            row_low[i] = -(mpc->x1_max);  /* 简化:只约束第一维(位置) */
            row_low[nx + i] = -1e20; 
            row_up[i] = -mpc->x1_min;
            row_up[nx + i] = 1e20;
        }
        
        /* 不等式约束的系数矩阵:C_ineq * u = -X_free + bound */
        for (int i = 0; i < nx; i++) {
            for (int j = 0; j < n_vars; j++) {
                mpc->A_ineq[2*k*nx + i][j] = Phi[k*nx*n_vars + i*n_vars + j];
                mpc->A_ineq[2*k*nx + nx + i][j] = -Phi[k*nx*n_vars + i*n_vars + j];
            }
            mpc->l_ineq[2*k*nx + i] += (mpc->x1_max - X_free[k*nx + i]);
            mpc->u_ineq[2*k*nx + i] += (mpc->x1_min - X_free[k*nx + i]);
            mpc->l_ineq[2*k*nx + nx + i] += -(mpc->x1_max - X_free[k*nx + i]);
            mpc->u_ineq[2*k*nx + nx + i] += -(mpc->x1_min - X_free[k*nx + i]);
        }
        
        /* 控制输入约束: u_min ≤ u_k ≤ u_max */
        for (int i = 0; i < nu; i++) {
            mpc->l_ineq[2*Np*nx + 2*k*nu + i] = mpc->u_min;
            mpc->u_ineq[2*Np*nx + 2*k*nu + i] = mpc->u_max;
            mpc->l_ineq[2*Np*nx + 2*k*nu + nu + i] = -mpc->u_max;
            mpc->u_ineq[2*Np*nx + 2*k*nu + nu + i] = -mpc->u_min;
            
            for (int j = 0; j < n_vars; j++) {
                mpc->A_ineq[2*Np*nx + 2*k*nu + i][j] = (j == k*nu + i) ? 1.0 : 0.0;
                mpc->A_ineq[2*Np*nx + 2*k*nu + nu + i][j] = (j == k*nu + i) ? -1.0 : 0.0;
            }
        }
    }
    
    free(Phi);
    free(Apow);
    free(temp);
    free(X_free);
    free(x_k);
}

/* 初始化MPC工作区 */
MPCWorkspace* mpc_init(double dt, double Q_diag[2], double R_diag[1], double Qf_diag[2]) {
    MPCWorkspace* mpc = (MPCWorkspace*)malloc(sizeof(MPCWorkspace));
    memset(mpc, 0, sizeof(MPCWorkspace));
    
    mpc->horizon = N;
    
    /* 初始化系统矩阵 (双积分器模型) */
    mpc->A[0][0] = 1.0; mpc->A[0][1] = dt;
    mpc->A[1][0] = 0.0; mpc->A[1][1] = 1.0;
    
    mpc->B[0][0] = 0.5 * dt * dt;
    mpc->B[1][0] = dt;
    
    /* 初始化代价矩阵 */
    mpc->Q[0][0] = Q_diag[0]; mpc->Q[0][1] = 0.0;
    mpc->Q[1][0] = 0.0; mpc->Q[1][1] = Q_diag[1];
    
    mpc->R[0][0] = R_diag[0];
    
    mpc->Qf[0][0] = Qf_diag[0]; mpc->Qf[0][1] = 0.0;
    mpc->Qf[1][0] = 0.0; mpc->Qf[1][1] = Qf_diag[1];
    
    /* 默认动态约束边界 */
    mpc->u_min = -1.0; mpc->u_max = 1.0;
    mpc->x1_min = -10.0; mpc->x1_max = 10.0;
    mpc->x2_min = -5.0; mpc->x2_max = 5.0;
    
    /* OSQP求解器设置 */
    osqp_set_default_settings(&mpc->settings);
    mpc->settings.verbose = 0;
    mpc->settings.polish = 1;
    mpc->settings.scaling = 10;
    mpc->settings.max_iter = 200;
    mpc->settings.eps_abs = 1e-4;
    mpc->settings.eps_rel = 1e-4;
    
    return mpc;
}

/* 更新动态约束边界 */
void mpc_set_constraints(MPCWorkspace* mpc, double u_min, double u_max, 
                         double x1_min, double x1_max) {
    mpc->u_min = u_min;
    mpc->u_max = u_max;
    mpc->x1_min = x1_min;
    mpc->x1_max = x1_max;
}

/* 执行MPC计算,返回当前控制量 */
double mpc_compute(MPCWorkspace* mpc, double* state, double* ref) {
    /* 更新当前状态和参考值 */
    memcpy(mpc->x0, state, NX * sizeof(double));
    memcpy(mpc->x_ref, ref, NX * sizeof(double));
    
    /* 构建QP问题 */
    build_qp(mpc);
    build_constraints(mpc);
    
    int n_vars = NU * mpc->horizon;
    
    /* 将Hessian矩阵转换为稀疏格式 */
    int nnz_P = 0;
    for (int i = 0; i < n_vars; i++) {
        for (int j = 0; j < n_vars; j++) {
            if (fabs(mpc->H[i][j]) > 1e-10) nnz_P++;
        }
    }
    double* P_x = (double*)malloc(nnz_P * sizeof(double));
    OSQPInt* P_i = (OSQPInt*)malloc(nnz_P * sizeof(OSQPInt));
    OSQPInt* P_p = (OSQPInt*)malloc((n_vars+1) * sizeof(OSQPInt));
    int idx = 0;
    P_p[0] = 0;
    for (int j = 0; j < n_vars; j++) {
        for (int i = 0; i < n_vars; i++) {
            if (fabs(mpc->H[i][j]) > 1e-10) {
                P_x[idx] = mpc->H[i][j];
                P_i[idx] = i;
                idx++;
            }
        }
        P_p[j+1] = idx;
    }
    
    /* 将约束矩阵转换为稀疏格式 */
    int n_ineq = mpc->n_ineq;
    double* A_x = (double*)malloc(n_vars * n_ineq * sizeof(double));
    OSQPInt* A_i = (OSQPInt*)malloc(n_vars * n_ineq * sizeof(OSQPInt));
    OSQPInt* A_p = (OSQPInt*)malloc((n_vars+1) * sizeof(OSQPInt));
    idx = 0;
    A_p[0] = 0;
    for (int j = 0; j < n_vars; j++) {
        for (int i = 0; i < n_ineq; i++) {
            if (fabs(mpc->A_ineq[i][j]) > 1e-10) {
                A_x[idx] = mpc->A_ineq[i][j];
                A_i[idx] = i;
                idx++;
            }
        }
        A_p[j+1] = idx;
    }
    
    /* 设置OSQP数据 */
    mpc->data.n = n_vars;
    mpc->data.m = n_ineq;
    mpc->data.P = osqp_csc_matrix(n_vars, n_vars, nnz_P, P_x, P_i, P_p);
    mpc->data.q = mpc->f;
    mpc->data.A = osqp_csc_matrix(n_ineq, n_vars, idx, A_x, A_i, A_p);
    mpc->data.l = mpc->l_ineq;
    mpc->data.u = mpc->u_ineq;
    
    /* 求解QP问题 */
    if (mpc->solver) osqp_cleanup(mpc->solver);
    osqp_setup(&mpc->solver, &mpc->data, &mpc->settings);
    osqp_solve(mpc->solver);
    
    /* 获取最优控制量 */
    double u_opt = mpc->solver->solution->x[0];
    
    /* 清理动态分配的数组 */
    free(P_x); free(P_i); free(P_p);
    free(A_x); free(A_i); free(A_p);
    
    return u_opt;
}

/* 清理MPC工作区 */
void mpc_cleanup(MPCWorkspace* mpc) {
    if (mpc->solver) osqp_cleanup(mpc->solver);
    free(mpc);
}

/* 主函数示例:仿真闭环控制过程 */
int main() {
    /* 初始化系统状态和参考值 */
    double state[NX] = {0.0, 0.0};   /* 初始位置和速度 */
    double ref[NX] = {5.0, 0.0};     /* 目标位置和速度 */
    double dt = 0.05;                 /* 采样时间 */
    
    /* 代价矩阵权重 */
    double Q_diag[2] = {10.0, 1.0};    /* 位置误差权重10,速度误差权重1 */
    double R_diag[1] = {0.1};          /* 控制量权重0.1 */
    double Qf_diag[2] = {100.0, 10.0}; /* 终端代价权重更高,保证收敛 */
    
    /* 初始化MPC控制器 */
    MPCWorkspace* mpc = mpc_init(dt, Q_diag, R_diag, Qf_diag);
    
    /* 初始约束边界 */
    mpc_set_constraints(mpc, -1.0, 1.0, -8.0, 8.0);
    
    /* 仿真循环 */
    for (int step = 0; step < 200; step++) {
        /* 根据仿真进程动态调整约束边界 */
        if (step == 50) {
            /* 第50步后收紧控制约束 */
            mpc_set_constraints(mpc, -0.8, 0.8, -6.0, 6.0);
            printf("--- 约束收紧: u in [-0.8, 0.8], pos in [-6.0, 6.0] ---\n");
        } else if (step == 120) {
            /* 第120步后放松约束以更快收敛 */
            mpc_set_constraints(mpc, -1.5, 1.5, -10.0, 10.0);
            printf("--- 约束放松: u in [-1.5, 1.5], pos in [-10.0, 10.0] ---\n");
        }
        
        /* 计算最优控制量 */
        double u = mpc_compute(mpc, state, ref);
        
        /* 应用控制量,更新系统状态(离散化双积分器模型) */
        double x1_next = state[0] + dt * state[1] + 0.5 * dt * dt * u;
        double x2_next = state[1] + dt * u;
        state[0] = x1_next;
        state[1] = x2_next;
        
        /* 每10步打印一次信息 */
        if (step % 10 == 0) {
            printf("step %3d: pos=%.3f, vel=%.3f, u=%.3f\n", 
                   step, state[0], state[1], u);
        }
        
        /* 收敛检查 */
        if (fabs(state[0] - ref[0]) < 0.01 && fabs(state[1] - ref[1]) < 0.01) {
            printf("Converged at step %d\n", step);
            break;
        }
    }
    
    /* 清理资源 */
    mpc_cleanup(mpc);
    return 0;
}

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐