You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C调用MATLAB编译的复数矩阵DLL报错排查及复数读取方法

问题排查与修复方案

1. 稀疏矩阵索引报错核心原因

报错Error using sparse: Index into matrix must be positive本质是创建稀疏矩阵时传入的行/列索引存在0或负数,你的代码存在4个直接触发该问题的硬伤:

  • 矩阵创建维度和实际数据不匹配:MATPOWER case9的bus矩阵为9行13列、gen矩阵为3行21列,但你创建Bus时指定为9行17列、Gen为3行25列,多分配的内存未初始化,为随机垃圾值;虽然你拷贝了对应长度的有效数据,但一旦MATLAB读取到未初始化的列,就会得到错误数值。
  • 存储顺序不匹配:C语言原生二维数组是行优先存储(同一行元素连续存放),MATLAB的mxArray是列优先存储(同一列元素连续存放),直接用memcpy把C二维数组拷贝到mxArray内存,会导致整个矩阵元素完全错位,读取gen(:,1)(机组所在母线号)、gen(:,8)(机组投运状态)时拿到的根本不是对应列的正确值,很容易出现0或负数的索引。
  • baseMVA参数赋值错误:你创建的var是double类型1x1矩阵,但memcpy时写入了int类型的100,int和double二进制存储格式完全不同,MATLAB读取该参数时得到的是一个接近0的乱码浮点数,即使稀疏矩阵创建成功,最终计算结果也会完全错误。
  • 提前创建输出矩阵无意义:mlfMakeSbus会自动为输出参数sbus分配内存,你提前创建的9x1复数矩阵会被覆盖,反而会造成内存泄漏。

2. 报错排查步骤

  • 第一步对齐矩阵维度:创建mxArray时维度严格和实际读入的矩阵一致,Bus创建为9行13列,Gen创建为3行21列,不要多开冗余空间。
  • 第二步修正数据写入逻辑:不要直接用memcpy拷贝C的二维数组,要么读csv时按列优先顺序写入mxArray内存,要么循环逐元素赋值,确保mxGetPr(Bus)[row + col*9]对应的是bus矩阵第row+1行、第col+1列的数值(MATLAB为1基索引)。
  • 第三步修正baseMVA赋值:不要用int类型拷贝,直接赋值为double类型即可:*mxGetPr(var) = 100.0;
  • 第四步入参校验:调用mlfMakeSbus前,打印关键位置的数值验证正确性:比如gen矩阵第8列(投运状态,对应C端列索引7,列优先下偏移量为7*3)的3个值都应为1,gen矩阵第1列(母线号,对应C端列索引0)的3个值应为1、2、3,如果打印结果不对,说明数据写入顺序或读csv的逻辑有问题。
  • 第五步移除提前创建sbus的代码,将sbus初始化为NULL即可,交给编译后的函数自行分配输出内存。

3. C端读取MATLAB复数矩阵的正确方法

MATLAB的复数类型mxArray分两块存储:实部数据存在mxGetPr()返回的指针指向的内存,虚部数据存在mxGetPi()返回的指针指向的内存,你之前只读取了实部指针,完全丢失了虚部数据。
正确读取逻辑示例:

double *real_ptr = mxGetPr(sbus);
double *imag_ptr = mxGetPi(sbus);
size_t elem_num = mxGetM(sbus) * mxGetN(sbus);
// 9行1列的列优先矩阵直接按顺序遍历即可
for (int idx = 0; idx < elem_num; idx++) {
    printf("%.4f %+.4fi\n", real_ptr[idx], imag_ptr[idx]);
}

读取前建议增加格式校验:判断返回值是否为复数类型、维度是否符合预期,避免访问非法内存。

4. 修正后的完整调用逻辑参考

mxArray *Bus = NULL, *Gen = NULL, *var = NULL, *sbus = NULL;
double B[9][13], G[3][21];
// 从csv读取B、G矩阵的逻辑,确保数值和MATPOWER case9完全一致,列顺序对齐

// 创建维度匹配的mxArray
Bus = mxCreateDoubleMatrix(9, 13, mxREAL);
Gen = mxCreateDoubleMatrix(3, 21, mxREAL);
var = mxCreateDoubleMatrix(1, 1, mxREAL);

// 逐元素按列优先顺序写入,避免行优先/列优先错位
double *bus_pr = mxGetPr(Bus);
for (int col = 0; col < 13; col++) {
    for (int row = 0; row < 9; row++) {
        bus_pr[row + col*9] = B[row][col];
    }
}
double *gen_pr = mxGetPr(Gen);
for (int col = 0; col < 21; col++) {
    for (int row = 0; row < 3; row++) {
        gen_pr[row + col*3] = G[row][col];
    }
}
// 正确赋值baseMVA
*mxGetPr(var) = 100.0;

if (!makeSbusInitialize()) {
    fprintf(stderr, "库初始化失败\n");
    goto EXIT; // 统一走资源释放逻辑
}

// 调用函数
mlfMakeSbus(1, &sbus, var, Bus, Gen);

// 读取并打印结果
if (sbus != NULL && mxIsComplex(sbus) && mxGetM(sbus) ==9 && mxGetN(sbus) ==1) {
    double *real_ptr = mxGetPr(sbus);
    double *imag_ptr = mxGetPi(sbus);
    for (int idx = 0; idx <9; idx++) {
        printf("Sbus[%d] = %.4f %+.4fi\n", idx+1, real_ptr[idx], imag_ptr[idx]);
    }
}

makeSbusTerminate();

EXIT:
// 统一释放所有mxArray内存,避免泄漏
if (Bus) mxDestroyArray(Bus);
if (Gen) mxDestroyArray(Gen);
if (var) mxDestroyArray(var);
if (sbus) mxDestroyArray(sbus);

注意:所有mxArray创建后必须显式调用mxDestroyArray释放,否则会出现内存泄漏;不要手动释放mxGetPr/mxGetPi返回的指针,这部分内存由mxArray自行管理。

内容的提问来源于stack exchange,提问作者S2022

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 07:15:54