Background
- python调用matlab脚本需要注意前置条件,具体参考官方文档:从 Python 中调用 MATLAB,大致就是两点:一是需要python和matlab版本对应,二是需要matlab运行环境mcr。具体安装配置可以参考:java和python调用matlab程序详细记录
- 调用方式分两种吧:一是使用matlab engine,二是把matlab程序打成python包。第二种在传递参数上效率高点,所以这里只介绍第二种。
- 测试用例:一个基于bp神经网络开发的损伤预测matlab程序,输入一组数据,输出一个损伤值,输入多组就会输出多个。我们首先把程序改写,输入是读mat输入文件,输出也是一个mat文件。在python中,接收到参数写入到mat输入文件中,然后调用matlab程序,最后从mat输出文件中获取结果就行了。
1、mat文件
- mat数据格式是Matlab的数据存储的标准格式。在Matlab中主要使用load()函数导入一个mat文件,使用save()函数保存一个mat文件。
- load,save函数具体用法请参考官方文档:load函数用法,save函数用法
2、scipy
- Scipy 是基于 Numpy 的科学计算库,提供了许多的操作numpy的数组的函数。
- scipy.io包提供了多种功能来解决不同格式的文件的输入和输出。
- 在python中可以使用scipy.io中的函数loadmat()读取mat文件,函数savemat保存文件。
3、测试用例matlab源码
- 下载地址:https://pan.baidu.com/s/13VX1nm6Qj9TdWowLnnj_lw,提取码:king
- 注意:输入文件必须写全路径,打包的时候这个文件是不存在的,后面python调用前会先生成这个文件放到指定位置。
function predict_damage()
%{
params:截面高度,截面宽度,腹板厚度,翼缘厚度,钢材屈服强度,柱高,轴压比,温度,柱中竖向位移
res:返回损伤值
注意:输入参数按顺序逗号分隔;输出一个数据
%}
clear;
% 关闭告警
warning('off')
%% 输入数据-转置归一化
% 输入文件
load C:\Users\ssyc\sim_input.mat sim_input;
input_params=sim_input';
lines=size(sim_input, 1);
load predict.mat predict;
predict_p=zeros(9, 2398);
fmt_sim_input=zeros(9, lines);
for i=1:9
predict_p(i,:)=predict(:,i)';
end
for i=1:9
fmt_sim_input(i,:)=(input_params(i,:)-min(predict_p(i,:)))/(max(predict_p(i,:))-min(predict_p(i,:)));
end
%% BP神经网络
% 创建网络
threshold=[0 1;0 1;0 1;0 1;0 1;0 1;0 1;0 1;0 1];
net=newff(threshold,[9,1],{'logsig','logsig'},'trainlm');
% 设置训练参数
net.IW{1,1}=struct2array(load('IW.mat'));
net.LW{2,1}=struct2array(load('LW.mat'));
net.b=struct2array(load('b.mat'));
% 损伤预测
sim_output=sim(net,fmt_sim_input);
%% 保存预测结果到mat文件中
save('sim_output', 'sim_output')
end
4、matlab源码打python包
- 在当前目录进入shell后执行安装命令
python3 setup.py install
- 然后就可以在python代码中引用这个方法了
5、python中调用方式
from scipy.io import savemat, loadmat
from numpy import array
from com.wlf import predict_damage
def ssyc():
"""损伤预测"""
matlab_func = predict_damage.initialize()
matlab_func.predict_damage(nargout=0)
matlab_func.terminate()
def main():
"""主函数"""
# 这里测试给了三组数据,每组数据9个
sp = [
[0.1500, 0.1500, 0.0070, 0.0100, 235.0000, 3.0000, 0.5000, 225.0000, 2.9403],
[0.175, 0.175, 0.0075, 0.011, 235, 3.3, 0.2, 400, 7.9905],
[0.3, 0.3, 0.01, 0.015, 390, 3, 0.1, 100, 1.1919]
]
file_input, file_output = 'sim_input.mat', 'sim_output.mat'
data_input = {'sim_input': array(sp)}
savemat(file_input, data_input)
ssyc()
data_output = loadmat(file_output)
sim_output = data_output['sim_output'][0]
print(list(sim_output))
if __name__ == '__main__':
main()
附赠:matlab一键打包压缩脚本
package.m
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 自动打包脚本【通用脚本,固定步骤,请勿修改】
% 在该脚本的当前路径下直接运行即可打包生成新的zip算法包
% 前提条件:压缩文件目录和算法源码主函数文件名相同
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clear;clc
% 获取被打包的函数文件名
currentDir = pwd;
[filepath,~,~] = fileparts(currentDir);
[~,filename,~] = fileparts(filepath);
% 打包步骤
cd ../..;
packageOutput='packageOutput/';
file=[currentDir, '/', filename, '.m'];
theoutputdir=[packageOutput, filename];
theoutputfile=[packageOutput, 'setup.py'];
zipfilename=[filename, '.zip'];
compiler.build.pythonPackage(file, ...
'PackageName',filename, ...
'OutputDir',packageOutput, ...
'Verbose', 'off');
movefile(theoutputdir, filename,'f');
movefile(theoutputfile, filename,'f');
rmdir(packageOutput, 's');
if exist(zipfilename, 'file')~=0
delete(zipfilename)
end
zip(zipfilename, filename);
disp('Success!');
fprintf("Here it is '%s'!\n", zipfilename);
- matlab算法源码
electric_damage_state_ct.m
matlab读写json文件可以参考这篇文章:【matlab读写json文件】
function electric_damage_state_ct()
% electric_damage_state_ct-某某算法
% 输入:
% mcs-输入参数1
% seismics-输入参数2
% 输出:
% nodeds-输出参数1
% lineds-输出参数2
%% 输入数据
pcs=3;
input=loadjson('input.json');
mcs=input.mcs;
seismics=input.seismics;
if isfield(input,pcs)
pcs=input.pcs;
end
%% 数据处理
pcs=cast(pcs, 'double');
pcs=-pcs;
%% 算法逻辑
disp('很复杂的算法逻辑!');
%% 输出数据
output = struct('nodeds', nodeds, 'lineds', lineds);
savejson('', output, 'output.json');
end
- 通用交互主函数
main.py
import electric_damage_state_ct
import warnings
from wlfutil.all import UniUtil
# 忽略告警
warnings.filterwarnings("ignore")
def call_matlab_func():
"""调用matlab函数"""
mf = electric_damage_state_ct.initialize()
mf.electric_damage_state_ct(nargout=0)
mf.terminate()
@UniUtil.time_cost
def main():
"""主函数
cost 8.22s
"""
# 调用算法计算
call_matlab_func()
if __name__ == '__main__':
"""函数入口"""
main()