Attempt to extract field 'Value' from 'mxArray'.

In Simulink, Im trying to get the value from a cell in an Excel Spreadsheet, but everytime I try to run the model, I get this error...
Attempt to extract field 'Value' from 'mxArray'.
Why? and how do I fix it.
PS: The error comes from disp(iiTHEVALUE.Value); (right now I'm just displaying the value in the matlab command window, once I get it working, I will start to do things with it)
This is my code in a Matlab function box in Simulink...
function count_oute = Excel(counte)
%#codegen
%%Lets Simulink know to read commands as Matlab commands
%Keep at top
coder.extrinsic('pwd');
coder.extrinsic('strcat');
coder.extrinsic('actxserver');
coder.extrinsic('invoke');
coder.extrinsic('get');
coder.extrinsic('set');
coder.extrinsic('delete');
%%Global Variables?
%%Editable Variables
Excel_File = 'If_actxserver.xlsx';
%%Defining Variables
Current_Directory = pwd;
excel_filename = strcat(Current_Directory,'\',Excel_File);
%%Keeping COM.handles active through iterations in this specific function block
%Excel handle Variables
persistent h_Excel;
if isempty(h_Excel)
%if handle is empty, define (which it is at the start of a model)
h_Excel = actxserver('Excel.Application');
end
persistent Excel_Workbook;
if isempty(Excel_Workbook)
%if handle is empty, define (which it is at the start of a model)
Excel_Workbook = invoke(get(h_Excel, 'Workbook'), 'Open',excel_filename);
end
%%If first iteration
if (counte==1)
set(h_Excel, 'Visible', 1);
disp('Started Mathcad application');
end
%%Iterate on Excel
disp('Excel Iterate #');
disp(counte);
%%Save, Close, and Quit actxservers on last iteration
if (counte==11)
iTHEVALUE = invoke(get(Excel_Workbook, 'Worksheets'),'Item','InitialVars');
iiTHEVALUE = invoke(iTHEVALUE, 'Range','A1:B4');
disp(iiTHEVALUE.Value);
invoke(Excel_Workbook,'Close');
invoke(h_Excel,'Quit');
invoke(h_Excel,'delete');
disp('Excel Closed');
end
%Out value is the same as the in value, just displaying again
count_oute=counte;
end

댓글 수: 3

Found a way to display the answer, but using the mxArray is still a different story...
Replaced
disp(iiTHEVALUE.Value);
with
disp(get(iiTHEVALUE,'Value'));
Will let me view the Value, but using it farther in simulink still gives me a mxArray Error :(
Hi Brian,
I have the same error too.
Currently, in my case, I am sending values from an integrator to a Data Store Block.
This Data store block is output of a PV Farm -> Signal converted from DC to AC.
However in the Master Code, it displays the 'mxArray' error.
Is it because I need to store the signal as an array ? Or make it global so the Array in Master code can directly access it instead of reading the whole PV Farm file ?
Thank you
Shray
Shray 2023년 6월 18일
Can you able to find answer to this question????

댓글을 달려면 로그인하십시오.

 채택된 답변

Ryan Livingston
Ryan Livingston 2014년 3월 26일
편집: Ryan Livingston 2014년 3월 26일

4 개 추천

When using the output of an extrinsic function, it may often be necessary to preinitialize the variable to which it is assigned. Doing so is what tells the code generation software about the type, size and complexity of the value returned. If foo is extrinsic, then you could use:
x = zeros(3,4);
x = foo(y);
to call foo extrinsically and assign the output as a 3-by-4 array. See:
for more details.
However, in your case, the output of invoke is likely not going to be a type supported for code generation as it is likely an ActiveX or COM object. When that is the case I find it easier to put all of the unsupported functionality into a single function and then just call that function extrinsically.
So in your case, you could write a separate MATLAB function that takes counte and the file name as arguments and returns the data as a numeric array. Then you can use the preinitialization technique above when calling your new function to let Simulink know what type it is.

댓글 수: 4

Yes, and no. Your answer does in fact remove the error "Function output 'x' cannot be an mxArray in this context. Consider preinitializing the output variable with a known type." and did answer my question after I commented again. So thank you! But I do have a question farther down!
Over the last few days of fiddling with this, I have found (although have no idea if I am anywhere close to being correct) a way to use the data without errors!
function [count_outer,Excel_EXIT] = ExcelRead(counter)
%#codegen
%%Show Iteration Number
disp('Iterate #');
disp(counter);
%%Lets Simulink know to read commands as Matlab commands
%Keep at top
coder.extrinsic('pwd');
coder.extrinsic('strcat');
coder.extrinsic('actxserver');
coder.extrinsic('assignin');
coder.extrinsic('evalin');
coder.extrinsic('invoke');
coder.extrinsic('get');
coder.extrinsic('cell2mat');
%%Predefining sizing with variables
E_rows = 5; % Number of rows in Excel
E_cols = 2; % Number of cols in Excel
%%%%%%%%%%%%%%%%% CHANGE RANGE BELOW!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
%%Global Variables
%%Editable Variables
Excel_File = 'Persistent_actx_testx2.xlsx';
%%Defining Variables
Current_Directory = pwd;
excel_filename = strcat(Current_Directory,'\',Excel_File);
Excel_EXIT = zeros(E_rows,E_cols); %(row,col)
%%Start Excel COM.handles
%saves COM.handles to the base workspace (MATLAB) to be called in other function blocks
persistent StartExcel; %variable for this function only
if isempty(StartExcel) %if first iteration
assignin('base','h_Excel',actxserver('Excel.Application'));
ExcelONE = evalin('base', 'h_Excel');
Excel_WorkbookONE = invoke(get(ExcelONE, 'Workbook'), 'Open',excel_filename);
assignin('base','Excel_Workbook',Excel_WorkbookONE);
%set(ExcelONE, 'Visible', 1); %show Excel
disp('showonce h_Excel');
StartExcel = false; %makes it false after first run.
end
%h_Excelrl = evalin('base', 'h_Excelr');
Excel_Workbooklr = evalin('base', 'Excel_Workbook');
%%Iterate on Excel (ALL ITERATIONS)
if (counter==1) %if first iteration
%Read Initial Values From Excel
Init_ExcelSheet = invoke(get(Excel_Workbooklr, 'Worksheets'),'Item','InitialVars');
Excel_Init_Range = invoke(Init_ExcelSheet, 'Range','A1:B5');
Excel_Matrix_Values = cell2mat(get(Excel_Init_Range,'Value'));
Excel_EXIT = Excel_Matrix_Values;
disp('Initial Excel Values');
disp(Excel_Matrix_Values);
else
%Read New Values From Excel
New_ExcelSheet = invoke(get(Excel_Workbooklr, 'Worksheets'),'Item','MathCadVar');
Excel_New_Range = invoke(New_ExcelSheet, 'Range','A1:B5');
Excel_New_Matrix_Values = cell2mat(get(Excel_New_Range,'Value'));
Excel_EXIT = Excel_New_Matrix_Values;
disp('Newly Read In Values');
disp(Excel_New_Matrix_Values);
end
%%Continue Counter
count_outer=counter;
end
(PS:the COM.handle is now closed and deleted elsewhere.)
(MY ASSUMPTION) to answer the error shown in this posts title, is for some reason Simulink does not like dot notation? (meaning Excel_Init_Range.Value) but does work when using this notation get(Excel_Init_Range,'Value'), which will get you the same thing. THAT, fixed my first problem. Then, as you pointed out, Simulink didn't support that "cell" data type, so I needed to convert.
Excel_Matrix_Values = cell2mat(get(Excel_Init_Range,'Value'));
This will now allow me to use the matrix called from Excel.
But, as you answered, I need to preinitialize my matrix to finally let the function block run without errors! But I do get a warning! which is my question I said I will have! I get the warning, "The variable 'Excel_Exit' appears to be preallocated, but preallocation is not recommended here."
I understand the use of
x = zeros(3,4);
x = foo(y);
But, I don't understand how I can fix that, if possible. The help link you gave me, "Call MATLAB Functions", sorta shows what I did was correct, But then why does it give me a warning...?
(Also, as I think of it, how do I call a function extrinsically in Simulink? Its not the same as just a .m file or matlab script, is it?)
Thanks so much for the help you already gave!
When you say it gives a warning do you mean that it shows up underlined in yellow? If so, sometimes the warning mechanism can't tell that preinitialization is needed for codegen. You can right-click on the warning and choose to suppress it on that line.
The MATLAB Function Block doesn't have issue with dot notation in most cases like structures and even MATLAB Classes. However, in this case, the value returned from calling a function declared as extrinsic (i.e. coder.extrinsic(...)) doesn't support dot notation without being assigned first.
I like to think of extrinsic functions like this: they are a way of telling the MATLAB Function Block "don't worry about what code is in this function. When I call it take the inputs and just go ask MATLAB for the outputs". Because we'll be asking MATLAB for the results during runtime, we need to tell Simulink something about what type to expect so it can do its work.
Because Simulink and the MATLAB Function Block are not considering the contents of the extrinsic function, one can use many MATLAB constructs which are unsupported for code generation in code which is called extrinsically.
Calling functions extrinsically is something you are already doing with coder.extrinsic('pwd') and the like. My suggestion was to take all of this code and move it to a .m file, say getValueFromXLS.m. Then say coder.extrinsic('getValueFromXLS') in your function block code and call getValueFromXLS to retrieve the proper value. You would then only need to pre-assign one value when making the call to your function and you can use non-codegen supported constructs in that .m file.
Brian
Brian 2014년 3월 27일
"When you say it gives a warning do you mean that it shows up underlined in yellow?"
Yes I do. My plan was to ignore it because it was still working with it, but if there was a fix for it, then I would have wanted to know it for this and future references.
And okay! That makes alot of sense. would you say its quicker to call the .m file rather than throw the code in the MATLAB Function Block? It probably would be easier for me to just create the .m file and call it, as you said, without worrying about alot of coder.extrinsic. etc.. But in terms of 100000 of iterations, would it make a difference?
Also, what about the S-Block? As long as I make the correct 'wrapper' functions for calling the .m file, would this be even faster? (or more code supported friendly?)
If you don't know, that's okay, they were just thoughts while reading your response. Thank you for all your help! I'll accept your answer as it did, with these comments, help answer my overall question!
Thanks again!
Sure thing. Generally, it may or may not improve performance by calling extrinsically. This depends upon how the function block code compares to what MATLAB is doing. If you have MATLAB code which is supported for code generation and that MATLAB code relies mostly on other MATLAB files, then the performance may be better to use the code in the function block.
However, if your code uses constructs which are unsupported for code generation, then calling it extrinsically is about the only recourse. I'm not too familiar with the S-Block workings, so I'll let others comment there.

댓글을 달려면 로그인하십시오.

추가 답변 (0개)

카테고리

도움말 센터File Exchange에서 Data Import from MATLAB에 대해 자세히 알아보기

질문:

2014년 3월 20일

댓글:

2023년 6월 18일

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by