matlab调用python,解释器没有第三方模块,如numpy等——解决simulink保存历史数据问题

matlab、simulink与python交互

  • 一.matlab调用python程序
    • 1.准备部分
      • 1.找到python解释器路径的Library文件夹
        • 注意:找到你需要使用的解释器的library,我一开始把自带的解释器与自己安装的解释器位置弄错了
      • 2.在电脑-属性-高级系统设置-环境变量-系统变量path
      • 3.验证
    • 2.遇到的问题
      • (1)python处理matlab导入数据
    • (2)Python 函数 "pred_matlab" 无法接受位置 1 处的至少一个输入参数。
    • (3)python程序修改后需要重启matlab才能更新py程序
    • (4)simulink仿真运行时无法获取工作空间变量,现在有两种方法:1.实时获取数据,加入数组;2.暂停获取工作空间变量
      • 1.实时获取数据,加入数组——转永久变量
      • 2.暂停获取工作空间变量——无法实现,仿真结束后才会将数据送到工作变量,结束前工作空间没有变量,除非代码赋值
    • (5)numpy的索引-1是倒数第二个
    • (6)python可以运行,但是matlab不行
      • 解决办法,matlab跟python实验程序用两个程序处理,matlab接收作为普通列表使用
    • (7)import matplotlib.pyplot as plt 这个导入可能会报错,报错注释掉就行,不需要重启matlab
    • (8)继续报错,快不想做了——输出a是mxArray数组
      • 解决办法:对a进行声明
    • (9) 更改python程序后不用matlab重启
    • (10)无法解析名称 out.input1.data——转永久变量
    • (11) matlab无法将多维数组输入到python中,会提示程序无法接收超过一个参数
      • 解决:变成多个一维数组,pyhton接收多个数组,在用np.hstack()函数合并——注意维度问题
    • 听说sfunction函数,尝试一下
    • matlab和s函数共有的问题,无法实时读取工作空间变量——转永久变量
    • 局部永久变量persistent很好用
    • a是可变大小矩阵。。。
    • 代数环问题
  • 二.python调用matlab
    • 注意事项:
    • 1.模型名称与py程序在同一个文件夹,绝对路径没用(导入参数相同)
    • 2.eng.set_param必须加参数最后(nargout=0),否则报错
    • 3.eng.set_param其他参数都必须是字符,数字转成字符格式
    • 4.获取工作空间变量需要提取数据列表,无法直接输出timemetadata格式数据
    • 5.matlab时间戳会有几位很长的小数,需要取前几位有些时间戳不是采样时间整倍数,要筛选出来
    • 6.垃圾python,0.3%0.1 不等于0,需要处理
    • 数据处理,将数组筛选,合并,返回4*n的数组
    • 合并三个相同维度数组
  • 目前问题
    • 1.循环内改暂停时间不成功,没有后续断点情况(可能是没运行?)重点!!!
      • 方法:调用m文件作为循环,
    • 2.m文件不能运行,想直接得到数组不成功
    • 目前问题仍没有解决,但是模型运行成功了
  • 最终:还是用matlab function函数做的,用永久变量保存之前的数据,数据处理,输入到python中
  • 果然需要系统学习才能使用的极其方便,针对保存数据这一部分卡了我很久,最终在某人介绍s函数的时候我才知道这个名称

一.matlab调用python程序

问题如图所示,根据指令,我已经改了解释器,但是还是只能用pyhton原本模块,第三方模块都无法使用,显示

pyenv('D:\soft\anaconda\envs\offten\python.exe')

报错内容:

>> py.importlib.import_module('pred1')
错误使用 __init__> (第 48 行)
Python 错误 ImportError:

IMPORTANT: PLEASE READ THIS FOR ADVICE ON HOW TO SOLVE THIS ISSUE!

Importing the numpy C-extensions failed. This error can happen for
many reasons, often due to issues with your setup or how NumPy was
installed.

We have compiled some common reasons and troubleshooting tips at:

    https://numpy.org/devdocs/user/troubleshooting-importerror.html

Please note and check the following:

  * The Python version is: Python3.8 from "D:\soft\matlab2020\bin\win64\MATLAB.exe"
  * The NumPy version is: "1.21.2"

and make sure that they are the versions you expect.
Please carefully study the documentation linked above for further help.

Original error was: DLL load failed while importing _multiarray_umath: 找不到指定的模块。


出错 __init__> (第 150 行)

出错 pred1> (第 4 行)

出错 _call_with_frames_removed (第 219 行)

出错 exec_module (第 783 行)

出错 _load_unlocked (第 671 行)

出错 _find_and_load_unlocked (第 975 行)

出错 _find_and_load (第 991 行)

出错 _gcd_import (第 1014 行)

出错 __init__>import_module (第 127 行)

补充一点:python环境应该是能用的,掉用print、os函数可以,numpy,pandas,torch不行

  PythonEnvironment - 属性:

          Version: "3.8"
       Executable: "D:\soft\anaconda\envs\offten\python.exe"
          Library: "D:\soft\anaconda\envs\offten\python38.dll"
             Home: "D:\soft\anaconda\envs\offten"
           Status: Loaded
    ExecutionMode: InProcess
        ProcessID: "19124"
      ProcessName: "MATLAB"

排查方式:
我的matlab2020b, python3.8
numpy1.21.2,都没有问题
现在怀疑dll缺失可能是其他原因?

根据此网址Original error was: DLL load failed while importing _multiarray_umath: 找不到指定的模块,解决方案的方式,anacoda更新numpy试一下,

不行,依旧报错,显示numpy更新到1.21.5

3.11更新,matlab可以使用python第三方库了,mmp,我已经用python做了好久了。。。(虽然至今不能用python运行m文件)

根据报错提示:

Original error was: DLL load failed while importing _multiarray_umath: 找不到指定的模块。

终于在一篇讲述vscode中无法使用python第三方模块的文章中指出,需要手动将环境的library路径放入系统变量path中。文章链接

1.准备部分

1.找到python解释器路径的Library文件夹

我是anacoda安装的库,所以路径为

D:\soft\anaconda\envs\offten\Library\bin

注意:找到你需要使用的解释器的library,我一开始把自带的解释器与自己安装的解释器位置弄错了

2.在电脑-属性-高级系统设置-环境变量-系统变量path

点击编辑,添加你的路径,然后重启电脑

3.验证

如果你安装了numpy库,可以像我一样

py.numpy.array([1, 2, 3, 4, 5])

显示如下,即为成功

ans = 

  Python ndarray:

     1     2     3     4     5

    使用 details 函数查看 Python 对象的属性。

    使用 double 函数转换为 MATLAB 数组。

2.遇到的问题

(1)python处理matlab导入数据

我希望运行模型的时候直接获得数据,就不再保存mat文件或excel文件了

    x = np.array(x._data).reshape(x.size, order='F')  # 将matlab数据转换成np格式

经过对比,顺序实际完全一致的

[[0.8147236863931789,0.09754040499940952,0.15761308167754828,0.14188633862721534,0.6557406991565868,0.7577401305783334,0.7060460880196088,0.8234578283272926,0.43874435965639824,0.48976439578823106],[0.9057919370756192,0.2784982188670484,0.9705927817606157,0.421761282626275,0.035711678574189554,0.7431324681249162,0.031832846377420676,0.694828622975817,0.3815584570930084,0.4455862007108995],[0.12698681629350606,0.5468815192049838,0.9571669482429456,0.9157355251890671,0.8491293058687771,0.39222701953416816,0.27692298496088996,0.31709948006086053,0.7655167881490024,0.6463130101112646],[0.9133758561390194,0.9575068354342976,0.4853756487228412,0.7922073295595544,0.9339932477575505,0.6554778901775566,0.04617139063115394,0.9502220488383549,0.7951999011370632,0.7093648308580726],[0.6323592462254095,0.9648885351992765,0.8002804688888001,0.959492426392903,0.6787351548577735,0.17118668781156177,0.09713178123584754,0.03444608050290876,0.1868726045543786,0.7546866819823609]]
[[0.81472369 0.0975404  0.15761308 0.14188634 0.6557407  0.75774013
  0.70604609 0.82345783 0.43874436 0.4897644 ]
 [0.90579194 0.27849822 0.97059278 0.42176128 0.03571168 0.74313247
  0.03183285 0.69482862 0.38155846 0.4455862 ]
 [0.12698682 0.54688152 0.95716695 0.91573553 0.84912931 0.39222702
  0.27692298 0.31709948 0.76551679 0.64631301]
 [0.91337586 0.95750684 0.48537565 0.79220733 0.93399325 0.65547789
  0.04617139 0.95022205 0.7951999  0.70936483]
 [0.63235925 0.96488854 0.80028047 0.95949243 0.67873515 0.17118669
  0.09713178 0.03444608 0.1868726  0.75468668]]

(2)Python 函数 “pred_matlab” 无法接受位置 1 处的至少一个输入参数。

错误使用 py.pred1.pred_matlab
Python 函数 “pred_matlab” 无法接受位置 1 处的至少一个输入参数。该函数可能需要您可以从 MATLAB 数组构造的特定数据类型。有关详细信息,请参阅关于 Python 函数 “pred_matlab”
和使用 Python 数组的文档。

(3)python程序修改后需要重启matlab才能更新py程序

(4)simulink仿真运行时无法获取工作空间变量,现在有两种方法:1.实时获取数据,加入数组;2.暂停获取工作空间变量

1.实时获取数据,加入数组——转永久变量

function u = fcn(input1, input2, opera, target_now, target)

    input1_list = [];
    input2_list = [];
    opera_list = [];
    target_now_list = [];
    target_list = [];
    input1_list = [input1_list, input1];
    input2_list = [input2_list, input2];
    opera_list = [opera_list, opera];
    target_now_list = [target_now_list, target_now];
    target_list = [target_list, target];
    
    disp(length(input1_list))
    if (length(input1_list) < 10)
        u = input1_list(end)
    else
        u = 2;
    end
end

问题:每次输入都是当前值,历史值存不下来

2.暂停获取工作空间变量——无法实现,仿真结束后才会将数据送到工作变量,结束前工作空间没有变量,除非代码赋值

assign('base', 'var', var)

(5)numpy的索引-1是倒数第二个

(6)python可以运行,但是matlab不行

[[0.0],[0.00010047545726038319],[0.000602852743562299],[0.0031147391750718785],[0.015674171332619776],[0.05567417133261977],[0.09567417133261977],[0.1],[0.1216291433369012],[0.1616291433369012],[0.2],[0.24000000000000002],[0.28],[0.30000000000000004],[0.34],[0.38],[0.4],[0.44],[0.48],[0.5],[0.54],[0.5800000000000001],[0.6000000000000001],[0.6400000000000001],]
matlab:
     0
    0.0001
    0.0006
    0.0031
    0.0157
    0.0757
    0.1000
    0.1600
    0.2000
    0.2600
    0.3000
    0.3600
    0.4000
    0.4600
    0.5000
    0.5600
    0.6000
    0.6600
    0.7000
    0.7600
    0.8000
    0.8600
    0.9000
    0.9600
    1.0000
    1.0000
    1.0000
    1.0400
    1.0800
    1.1000
    1.1600
    1.2000
    1.2600
    1.3000
    1.3600
    1.4000
    1.4600
    1.5000
    1.5600
    1.6000
    1.6600
    1.7000
    1.7600
    1.8000
    1.8600
    1.9000
    1.9600
    2.0000
    2.0600
    2.1000
    2.1600
    2.2000
    2.2600
    2.3000
    2.3600
    2.4000
    2.4600
    2.5000
    2.5600
    2.6000
    2.6600
    2.7000
    2.7600
    2.8000
    2.8600
    2.9000
    2.9600
    3.0000

解决办法,matlab跟python实验程序用两个程序处理,matlab接收作为普通列表使用

这样的数组,matlab说不可迭代,python数据是嵌套列表,因此后续作为普通列表使用

(7)import matplotlib.pyplot as plt 这个导入可能会报错,报错注释掉就行,不需要重启matlab

(8)继续报错,快不想做了——输出a是mxArray数组

Function output 'a' cannot be an mxArray in this context. Consider preinitializing the output variable with a known type.

Function 'MATLAB Function1' (#24.9.10), line 1, column 10:
"a"
Launch diagnostic report.
Component:MATLAB Function | Category:Coder error
Errors occurred during parsing of MATLAB function 'xunhuan_pred/MATLAB Function1'
Component:MATLAB Function | Category:Coder error
Simulink cannot determine sizes and/or types of the outputs for block 'xunhuan_pred/MATLAB Function1' due to errors in the block body, or limitations of the underlying analysis. The errors might be inaccurate. Fix the indicated errors, or explicitly specify sizes and/or types for all block outputs.
Component:MATLAB Function | Category:Coder error
Simulink cannot determine sizes and/or types of the outputs for block 'xunhuan_pred/MATLAB Function1' due to errors in the block body, or limitations of the underlying analysis. The errors might be inaccurate. Fix the indicated errors, or explicitly specify sizes and/or types for all block outputs.

问题:输出a是mxArray数组,不能输出,切不能应用于表达式

解决办法:对a进行声明

matlab官方给出的答案是,对U提前声明,代码如下:

a=zeros(n); % n是a的维数,之后再进行:

(9) 更改python程序后不用matlab重启

clear classes
mod = py.importlib.import_module('pred1');
py.importlib.reload(mod);

(10)无法解析名称 out.input1.data——转永久变量

Error in 'xunhuan_pred/MATLAB Function1' (line 22)
input1 = evalin('base','out.input1.data');
 matlab和s函数共有的问题,无法实时读取工作空间变量

(11) matlab无法将多维数组输入到python中,会提示程序无法接收超过一个参数

解决:变成多个一维数组,pyhton接收多个数组,在用np.hstack()函数合并——注意维度问题

听说sfunction函数,尝试一下

本质上跟matlab fcn差不多,但是有采样时间设置,比fcn灵活一些

matlab和s函数共有的问题,无法实时读取工作空间变量——转永久变量

根据查阅资料,等仿真结束后才会将变量赋值to workspace, 但是我需要实时获取变量信息,在运行过程中获得工作空间变量会报错
暂时解决方法:matlabfcn函数添加输入,将输入元素添加至从工作空间获取的变量——只能读取前十秒和此刻数据
不行就sim方针一次,获取一次值,循环30次

局部永久变量persistent很好用

甚至不需要考虑时间问题,simulink仿真采样时间就是模块数字输入时间

function a   = return_list(input1_t, input2_t, opera_t, target_now_t, target_t)
    a=zeros(1);  % 对a进行声明
    len=zeros(1);
    
    coder.extrinsic('py.importlib.import_module') 
    coder.extrinsic('py.pred1.data_deal_var')
    coder.extrinsic('py.pred1.pred_matlab_2')
    py.importlib.import_module('pred1');
%     input1, input2, opera, target_now, target
%     env_name = 'xunhuan_pred';
%     sim('xunhuan_pred','ReturnWorkspaceOutputs','on');
%     out = ans;
%     env_name = 'xunhuan_pred';
%     load_system(env_name)
%     set_param(env_name, 'StopTime', '3');
%     pause(0.1)
%     set_param(env_name, 'SimulationCommand', 'stop')
%     eng.set_param(env_name, 'SimulationCommand', 'start');
    
    coder.extrinsic('evalin');
    coder.extrinsic('length');
    coder.extrinsic('persistent');
    
    persistent input1_len
    persistent input2_len
    persistent opera_len
    persistent target_now_len
    persistent target_len
%     input1 = evalin('base','out.input1.data');
% %     disp(input1)
%     input2 = evalin('base','out.input2.data');
%     opera = evalin('base','out.opera.data');
%     target = evalin('base','out.target.data');
%     target_now = evalin('base','out.target_now.data');
%     time = evalin('base','out.input2.time');
    if isempty(input1_len)
        input1_len = [];
        input1_len = [input1_len; input1_t];
    else
        input1_len = [input1_len; input1_t];
    end
    if isempty(input2_len)
        input2_len = [];
        input2_len = [input2_len; input2_t];
    else
        input2_len = [input2_len; input2_t];
    end
    if isempty(opera_len)
        opera_len = [];
        opera_len = [opera_len; opera_t];
    else
        opera_len = [opera_len; opera_t];
    end
    if isempty(target_now_len)
        target_now_len = [];
        target_now_len = [target_now_len; target_now_t];
    else
        target_now_len = [target_now_len; target_now_t];
    end
    if isempty(target_len)
        target_len = [];
        target_len = [target_len; target_t];
    else
        target_len = [target_len; target_t];
    end
%     
    len = length(input1_len);
%     disp(len)
%     input1 = [input1;input1_t];
%     input2 = [input2;input2_t];
%     opera = [opera;opera_t];
%     target = [target;target_t];
%     target_now = [target_now; target_now_t];
    
    disp(len)
    if (len < 11)
        a = 0.3;
    else
        a = [input1_len, input2_len, opera_len, target_now_len, target_len]
%         b = a(end-9:end,:)
%         c = reshape(b, 5, 10);
        a = py.pred1.pred_matlab_2(input1_len, input2_len, opera_len, target_now_len, target_len);
%         a = py.pred1.data_deal_var(input1, input2, opera, target_now, target, time)
    end

end

a是可变大小矩阵。。。

在edit data中设置变量,勾选可变矩阵,设置最大维度就可以了。

代数环问题

or the model referenced by it contains a block that updates persistent or state variables while computing outputs and is not supported in an algebraic loop. It is in an algebraic loop with the following blocks.
加memory模块,虽然线还是红得,但是至少他能用了

二.python调用matlab

换个方向,python调用matlab:
暂时可行

注意事项:

1.模型名称与py程序在同一个文件夹,绝对路径没用(导入参数相同)

2.eng.set_param必须加参数最后(nargout=0),否则报错

报错原因:返回参数过多


例子:
用法:eng.set_param(env_name, 'StopTime', '3')
改变后: eng.set_param(env_name, 'StopTime', '3', nargout=0)

3.eng.set_param其他参数都必须是字符,数字转成字符格式

如果想用sst_param输入变量,貌似不行,需要转成字符型数据就可以了

 eng.set_param('exp_sub/pause_time', 'value', str(i / 10), nargout=0)  # 修改下一个pause_time

以上方法无法输入格式

4.获取工作空间变量需要提取数据列表,无法直接输出timemetadata格式数据

直接输出timemetadata格式数据会输出地址


获得变量值:

一般是  变量.data

可以在工作空间中查看格式,有些需要筛选后使用
推荐用m文件筛选数据,python需要一个一个导入,有些麻烦(也可以用循环)

5.matlab时间戳会有几位很长的小数,需要取前几位有些时间戳不是采样时间整倍数,要筛选出来

out.input1.time=[[0.0],[0.1],[0.2],[0.30000000000000004],[0.4],[0.5],[0.6000000000000001],[0.7000000000000001],[0.8],[0.9],[1.0],[1.1]]
a=('%.2f' % out.input1.time)

a = decimal.Decimal(str(a)).quantize(decimal.Decimal('0.00'))  # 取前两位小数

6.垃圾python,0.3%0.1 不等于0,需要处理

低情商:(无法实现功能)
def is_norm(a):
    a = decimal.Decimal(str(a)).quantize(decimal.Decimal('0.00'))  # 取前两位小数
    return a % decimal.Decimal('0.1') == 0  #
    
list_a = list(filter(is_norm, m))  # 若符合条件则返回,不符合过滤掉


高情商:
time_zero = []
for num, a in enumerate(m):
    a = decimal.Decimal(str(a)).quantize(decimal.Decimal('0.00000000000000'))
    # 这么多0我也很难受,这个0的数量是根据time数据一次次调整出来的,
    if a % decimal.Decimal('0.1') != 0:
        time_zero.append(num)
# TODO 删掉time_zero的元素位置
np_input2 = np.delete(np_input2, time_zero)

数据处理,将数组筛选,合并,返回4*n的数组

将多个数组合并,好多坑啊

不行的:
m = np.array(zip(np_a, np_b, np_c)).flatten()

np.concatenate() # 只能合并两个数组
a = [np_a, np_b, np_c] 
这是1s到1.1s的数据,只能留两个,不这么多零分不开
  [[1.00000000e+00 1.00000000e+00 1.00000000e+00 1.04000000e+00
  1.08000000e+00 1.10000000e+00 1.10000000e+00]]

合并三个相同维度数组

a = [np_a, np_b, np_c]
m = tuple(a)                                                         # 将list类型转换成元组类型  m = (array([1, 2, 3]), array([4, 5, 6]))
n = np.hstack(m)

print(n.shape)
print(n)

目前问题

1.循环内改暂停时间不成功,没有后续断点情况(可能是没运行?)重点!!!

a=(‘%.2f’ % out.input1.time) 成功,但是无法取到数据???
猜想:
eng.pause(0.1) 终止matlab运行时python程序,仍在运行

4.26补充:
在仿真程序没有完成前,to workshape函数貌似是不工作的,暂停时matlab工作空间没有所需变量,因此取不到数据

方法:调用m文件作为循环,

2.m文件不能运行,想直接得到数组不成功

目前问题仍没有解决,但是模型运行成功了

最终:还是用matlab function函数做的,用永久变量保存之前的数据,数据处理,输入到python中

果然需要系统学习才能使用的极其方便,针对保存数据这一部分卡了我很久,最终在某人介绍s函数的时候我才知道这个名称

在查找这个问题的时候见到很多人提出如何保存变量,几乎没有说出有效方法的,很多都是sim函数仿真后获取工作空间变量。
maltba中文论坛中我见到很多,我不想注册账号了,准备攻坚下一步难题,多部预测,希望看到我文章的人以后看见这个问题,能回复一下他们,给后来的新手少点弯路!

你可能感兴趣的:(matlab,python,matlab,开发语言)