- Ensure the .fmu file path is correctly specified.
- The Options parameter allows you to specify whether to delete the cache folder generated during the process. By default, this is set to true.
- This function creates a temporary Simulink model to import the FMU block, from which it then extracts the required information.
How to analyze FMU Files in MATLAB: Extracting Input and Output Information in R2024a?
29 views (last 30 days)
Show older comments
MathWorks Support Team
on 21 Mar 2024
Edited: MathWorks Support Team
on 21 Mar 2024
Is there a way to analyze .fmu files in MATLAB? Specifically, I'm looking to gather information such as the number of inputs and outputs without running a simulation, but also port- and parameter names.
Accepted Answer
MathWorks Support Team
on 19 Apr 2024
Edited: MathWorks Support Team
on 21 Mar 2024
Currently, MATLAB does not provide a direct function to analyze .fmu (Functional Mock-up Unit) files solely for the purpose of extracting information like the number of inputs and outputs. However, this functionality can be achieved by utilizing the Simulink API along with a custom MATLAB function. Below is a step-by-step guide on how to implement this solution.
Custom Function to Extract FMU Information:
The function getFmuInformation allows you to extract detailed information from an FMU file by leveraging Simulink's capabilities to handle FMU files. This function returns a structure containing the number of input and output ports along with their names.
function fmuInfoStruct = getFmuInformation(fmuFilePath,Options)
%GETFMUINFORMATION Extract information from an FMU file in Simulink.
% fmuInfoStruct = GETFMUINFORMATION(fmuFilePath, Options) returns a
% structure containing information about the FMU file with additional
% options specified.
%
% Inputs:
% fmuFilePath - A text scalar that specifies the path to the FMU file.
% This must be a valid file path ending with the .fmu
% extension.
%
% Name-Value Pair Arguments:
% 'deleteCacheFolder' - A logical value indicating whether to delete
% the cache folder generated during the import
% process. Default is true.
%
% Outputs:
% fmuInfoStruct - A structure with the following fields:
% Inports - A structure containing:
% numInput - The number of input ports.
% names - A string array of names for each input port.
% Outports - A structure containing:
% numOutput - The number of output ports.
% names - A string array of names for each output port.
% Parameters - A structure containing:
% names - A string array of parameter names, if available
%
% Example:
% % Specify the path to the FMU file
% fmuFilePath = 'path/to/model.fmu';
%
% % Get information about the FMU
% info = getFmuInformation(fmuFilePath);
%
% % Display the number of inputs and outputs
% disp(info.Inports.numInput);
% disp(info.Outports.numOutput);
arguments
fmuFilePath {mustBeTextScalar, mustBeFile}
Options.deleteCacheFolder (1,1) logical = true
end
[pathToFmu,fmuName,ext] = fileparts(fmuFilePath);
if ext ~= ".fmu"
error("Input file is not an FMU file.")
end
state = warning('query','Simulink:Engine:MdlFileShadowing').state;
if state == "on"
cleanUpObjWarn = onCleanup(@()warning('on','Simulink:Engine:MdlFileShadowing'));
warning('off','Simulink:Engine:MdlFileShadowing')
end
tempMdlHdl = new_system;
cleanupObjMdl = onCleanup(@()bdclose(tempMdlHdl));
tempMdlName = get_param(tempMdlHdl,'Name');
fmuBlkPath = [tempMdlName,'/FMU'];
add_block('simulink_extras/FMU Import/FMU',fmuBlkPath);
if ~isempty(pathToFmu)
pathCheck = isempty(which([fmuName ext]));
if pathCheck
addpath(pathToFmu)
fmuPathCleanupObj = onCleanup(@()rmpath(pathToFmu));
end
end
set_param(fmuBlkPath,'FMUName',fmuName)
portHandles = get_param(fmuBlkPath,'PortHandles');
numInput = length(portHandles.Inport);
numOutput = length(portHandles.Outport);
fmuInfoStruct.Inports.numInput = numInput;
fmuInfoStruct.Outports.numOutput = numOutput;
maskDisplayInfo = get_param(fmuBlkPath,'MaskDisplay');
maskDisplayInfo = splitlines(string(maskDisplayInfo));
[namesInput, namesOut] = getInOutInfoFromMaskDisplayInfo(maskDisplayInfo);
assert(length(namesInput) == numInput,"Number of inputs unequal to number of Inport names.")
assert(length(namesOut) == numOutput,"Number of outputs unequal to number of Outport names.")
fmuInfoStruct.Inports.names = namesInput;
fmuInfoStruct.Outports.names = namesOut;
paramData = get_param(fmuBlkPath,'DialogParameters');
if isempty(paramData)
fmuInfoStruct.Parameters.names = string.empty(0,0);
else
fmuInfoStruct.Parameters.names = string(fieldnames(paramData));
end
if Options.deleteCacheFolder
clearFmuCache(fmuName)
end
function [namesInput, namesOut] = getInOutInfoFromMaskDisplayInfo(maskDisplayInfo)
allInputLines = maskDisplayInfo(contains(maskDisplayInfo,"port_label('input',"));
allOutputLines = maskDisplayInfo(contains(maskDisplayInfo,"port_label('output',"));
namesInput = extractBetween(allInputLines,"," + digitsPattern + ",'","');");
namesOut = extractBetween(allOutputLines,"," + digitsPattern + ",'","');");
end
function clearFmuCache(fmuName)
foundFmuFolder = false;
pathToSlprjFmuFolder = fullfile(Simulink.fileGenControl('get','CacheFolder'),"slprj","_fmu");
folderContentOfFmuCacheFolder = dir(pathToSlprjFmuFolder);
allFolderNames = string({folderContentOfFmuCacheFolder.name});
allFolderNames = allFolderNames([folderContentOfFmuCacheFolder.isdir]);
allFolderNames = allFolderNames(and(allFolderNames ~= ".",allFolderNames ~= ".."));
for numFolder = 1:length(allFolderNames)
pathToFMUCacheFolderFromFMU = fullfile(pathToSlprjFmuFolder,allFolderNames(numFolder));
allSubFmuCacheFolders = string({dir(pathToFMUCacheFolderFromFMU).name});
if any(contains(allSubFmuCacheFolders,fmuName))
foundFmuFolder = true;
break
end
end
if ~foundFmuFolder
return
end
clear cleanupObjMdl
rmdir(pathToFMUCacheFolderFromFMU,"s")
if length(allFolderNames) > 1
return
end
rmdir(pathToSlprjFmuFolder,"s")
pathToSlprjFolder = fileparts(pathToSlprjFmuFolder);
if length({dir(pathToSlprjFolder).name}) > 2
return
end
rmdir(pathToSlprjFolder,"s")
end
end
Important Notes:
Usage Example:
To use the getFmuInformation function, simply call it with the path to your FMU file as shown in the example within the function comment. The function will return a structure with the information about the inputs and outputs of the FMU.
% Specify the FMU file path
fmuFilePath = 'path/to/yourModel.fmu';
% Extract FMU information
fmuInfo = getFmuInformation(fmuFilePath);
% Display the extracted information
disp(['Number of Inputs: ', num2str(fmuInfo.Inports.numInput)]);
disp(['Number of Outputs: ', num2str(fmuInfo.Outports.numOutput)]);
Conclusion:
While MATLAB does not natively support the analysis of .fmu files for the purpose of extracting input and output information, the custom function getFmuInformation provides a workaround by utilizing Simulink's FMU import capabilities. Additionally, for those not using Simulink, parsing the modelDescription.xml file directly from the FMU package could be an alternative method to obtain this information. This approach allows users to programmatically access detailed information about their FMU files within the MATLAB environment. Please be aware that the function could break in any future release. It was tested with R2023b and R2024a.
0 Comments
More Answers (0)
See Also
Categories
Find more on Create Standalone FMU in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!