在JAVA开发中调用matlab程序

0.需求

做了一个优化算法可视化系统,但优化的过程需要使用matlab来计算,因此需要在项目里引入matlab封装好的jar包,并在java开发中调用matlab方法,指定输入参数,转换输出类型。

1.matlab封装jar包

这篇文章讲的很详细:Matlab代码打包成jar包供java调用_marleb算法 打成jar与java交互怎么使用-CSDN博客

打包后在for_redistribution_files_only文件中获取jar包。

【报错与解决】打包过程有出现过一个小报错,根据错误日志发现是编码问题,最简单粗暴的解决方法就是删掉代码中的中文注释。

2.项目引入jar包

这里讲的很详细,推荐通过Maven来引入:
IDEA、Maven引入外部jar包-CSDN博客

3.调用方法与类型转换

3.1 调用方法

可以在matlab导出的文件夹里找到接口文档

我封装时定义的包名是optbymatlab,类名是OptWork,顺着点进去,就能找到类方法。

方法名和导入的matlab程序是一样的,主要关注原matlab函数对应的入口函数的参数与返回值。以下示例为我封装的matlab函数原程序和接口文档里的类方法介绍。原程序有4个输入参数和2个输出,接口方法的详情部分里也写了需要4个输入参数,和原程序是对应的,且输出的java类型为Object[]。
需要另外注意的是形参列表里第一个参数【int类型的nargout】,这里的意思是设定输出的数量,也就是要得到几个输出。因此整体的输入是【一个int类型 + 4个输入参数】,输出为Object[],且这个数组的大小就是输入的int。

3.1 输入

那么就可以开始写程序了。因为我这里matlab设置的输入类型是整数和字符串,int型数据和String类型的数据可以直接带入,所以就没有进行输入类型的转换。
如果是其他类型,可以查一下官方文档:处理从 Java 方法返回的数据 - MATLAB & Simulink - MathWorks 中国
注意,输入的参数一定是【int类型的输出数量设置 + matlab程序设置的输入参数】。即,如果只想要第一个输出,就可以设置为1。

import optbymatlab.OptWork;

OptWork optWork = new OptWork();
//希望获取2个输出,输入四个参数
Object[] outputs = optWork.demo_(2,30,30,"model1","alg1");
System.out.println("完成计算");

 3.2 输出

获取到一个Object数组之后,通过debug查看数组内元素的运行类型。我的matlab程序输出的分别是一个值(或者说,一个矩阵),和一个元胞数组。对应的类型就是矩阵类型-MWNumericArray、元胞数组类型-MWCellArray。需要对这些类型进行转换,然后提取里面的数值

【如果找不到类】这些MW开头类型就在导入matlab封装的jar包时要一块儿导入的那个javabuilder包里,所以如果找不到类可能是因为没导入javabuilder。

3.2.1 MWNumericArray类型【矩阵】

一般用的比较多的都是矩阵,即MWNumericArray类型。整理常用的方法:
①getDouble():如果矩阵只有一个数,用该方法提出来;
②getDoubleData():如果是一个多维数组,提出一个一维数组【按列提取】

更多方法可以参考官方文档:在 MATLAB 中管理数值数组的 Java 类 - MATLAB - MathWorks 中国

只有一个数的示例:

import com.mathworks.toolbox.javabuilder.*;

double acc = ((MWNumericArray) outputs[0]).getDouble();

3.2.2 MWCellArray类型【元胞数组】

元胞数组也是matlab的一个常用类型,我在matlab的程序中,所输出元胞数组内的元素是个结构体,结构体内包含三个字段,每个字段是一个矩阵,大家可以做个参考。

首先转换成MWNumericArray类型,然后找方法。整理比较有用的方法是这些:
① numberOfElements() :返回元胞数组的长度,即元素数量
② get(int i):返回第i个元素(索引从1开始)

官方文档:用于管理 MATLAB 元胞数组的 Java 类 - MATLAB - MathWorks 中国

设置循环,对每个结构体进行提取。这里的提取过程不太美观,甚至有点粗暴,我本意是打算再使用结构体的类型MWStructArray再次提取,但是debug时发现粗暴一点好像更直接,还不用转来转去了。能解决问题的都是好方法!
大概的提取过程是这样的:通过get(int i)方法得到这个结构体的Object类型,debug时发现运行类型为一个三维数组,且第一维对应结构体的三个字段,第三维对应字段里的数据且类型是double[][],于是转成三维Object[][][]然后提取第三维的数据,并将第三维的数据转换成double[][],就得到数据了。

 因为我只需要第二个字段的数据,所以以下示例为只获取元胞数组中结构体的第二个字段【代码的可参考性不强,但是上面的获取思路可以借鉴】

import optbymatlab.OptWork;
import com.mathworks.toolbox.javabuilder.*;

OptWork optWork = new OptWork();
Object[] outputs = optWork.demo_(2,N,G,sModel,alg);

//矩阵类型
acc = ((MWNumericArray) outputs[0]).getDouble();
//元胞数组
MWCellArray cellArray = (MWCellArray)outputs[1];
int K = cellArray.numberOfElements();
for (int k = 1; k <= K; k++) {
    //每个元素是一个结构体
    Object o = cellArray.get(k);
    Object[][][] cellData = (Object[][][])o;
    double[][] R = (double[][]) cellData[1][0][0];
    int n = R.length;
    List<DataPoint3> xyz = new ArrayList<>();
    for (int i = 0; i < n; i++) {
        double x =  R[i][0];
        double y =  R[i][1];
        double z =  R[i][2];
        xyz.add(new DataPoint3(x, y, z));
    }
   xyzBatches.add(xyz);
}

3.2.2 MWStructArray类型【结构体】

虽然我没用到结构体,但如果有结构体类型的需要,可以查看官方文档:
用于管理 MATLAB 结构体数组的 Java 类 - MATLAB - MathWorks 中国

  • 19
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值