Rufen Sie gemeinsam genutzte Bibliotheken von Similink aus auf

Hallo Habr!
Ich präsentiere Ihnen die Übersetzung eines Artikels meines Kollegen Mikhail über Methoden zum Aufrufen von gemeinsam genutzten Bibliotheken in Simulink. Warum wurde es überhaupt geschaffen? Tatsache ist, dass viele Unternehmen bereits viele Legacy-Modelle haben, die wir gerne wiederverwenden möchten, und uns häufig Fragen gestellt werden: „Wie kann ich Legacy-Modelle in Simulink integrieren? Und wenn mein Vermächtnis in Form einer DLL vorliegt? “ Daher wurde der Originalartikel geschrieben.
Unter der Katze werden verschiedene Möglichkeiten zum Aufrufen gemeinsam genutzter Bibliotheken in Simulink erläutert.

Alle Änderungen am Code wurden mit Genehmigung von Mikhail vorgenommen, um den Artikel nicht zu überladen.


Dieser Artikel zeigt, wie Funktionen aus gemeinsam genutzten Bibliotheken in Simulink-Modellen verwendet werden.
Angenommen, wir müssen die Exlib-Bibliothek in Simulink einbetten. Sein Code ist in den Quellen von exlib.c und exlib.h enthalten . Dies ist eine sehr einfache Bibliothek mit drei Funktionen:
void exlib_init (void) - öffnet eine Datei zum Schreiben.
void exlib_print (float data) - schreibt Daten in eine Datei.
void exlib_term (void) - schließt die Datei.

Bibliotheksmontage


Kompilieren Sie zunächst die Bibliothek.
Dieser Schritt ist nicht erforderlich, wenn die Bibliothek vorkompiliert und als Binärdatei geliefert wird. In diesem Fall können Sie sofort mit Schritt 3 fortfahren. Beachten Sie jedoch, dass Sie für die Arbeit mit der Bibliothek die DLL-Datei (oder .so für Linux) und die entsprechende Header-Datei (.h) vom Bibliotheksanbieter erhalten müssen. Für Windows benötigen Sie außerdem eine LIB-Datei, bei der es sich nicht um eine statische Bibliothek handelt, sondern um die sogenannte Importbibliothek. Diese Importbibliothek wird für die implizite Verknüpfung benötigt.
Zuerst verwenden wir den Befehl MATLAB mex, der den aktuell aktiven Host-Compiler aufruft, um die gemeinsam genutzte Bibliothek zu kompilieren (exlib.dll unter Windows und exlib.so unter Linux). Es ist wichtig sicherzustellen, dass der Befehl zuerst ausgeführt wurde.
mex -setup


um einen unterstützten Compiler auszuwählen .
Verwenden Sie jetzt mex, um die Bibliothek zu kompilieren:

Code zum Erstellen einer Bibliothek
mingw = strfind(mex.getCompilerConfigurations('C','Selected').Name,'MinGW64 Compiler');
if isunix
    % GCC
    mex('LDEXT=.so','LINKEXPORT=','LINKEXPORTVER=','LINKLIBS=','exlib.c');
elseif mingw
    % MinGW builds static shared library, so dll and lib files are the same
    % loadlibrary uses the dll file, while legacy code tool looks for the lib file
    mex('LDEXT=.lib','LINKEXPORT=','LINKEXPORTVER=','LINKLIBS=','exlib.c');
    mex('LDEXT=.dll','LINKEXPORT=','LINKEXPORTVER=','LINKLIBS=','exlib.c');
else
    % Visual
    mex('LDEXT=.dll','LINKEXPORT=','LINKEXPORTVER=','CMDLINE300="del exlib.exp exlib.dll.manifest"','exlib.c');
end
Building with 'gcc'.
MEX completed successfully.



Überprüfen der kompilierten Bibliothek


Nach dem Kompilieren müssen Sie sicherstellen, dass die resultierende Bibliothek geladen und in MATLAB verwendet werden kann:

Code zum Überprüfen der Bibliothek
% Load the library
[~,~] = loadlibrary(['exlib',system_dependent('GetSharedLibExt')],'exlib.h');
% Display functions available in the library
libfunctionsview('exlib');
% Initialize
calllib('exlib','exlib_init');
% Step
for i = 1:10
    calllib('exlib','exlib_print',single(i));
end
% Terminate
calllib('exlib','exlib_term');
% Unload the library
unloadlibrary('exlib');
% Show contents of generated file
type('exlib.txt');
0.000000
1.000000
2.000000
3.000000
4.000000
5.000000
6.000000
7.000000
8.000000
9.000000
10.000000


Nachdem wir sichergestellt haben, dass alles funktioniert, können wir mit Simulink beginnen!

Aufrufen einer gemeinsam genutzten Bibliothek mit S-Funktionen


Mit S-Funktionen können Sie C-Code in Simulink verwenden. Dieser Ansatz ermöglicht es dem Benutzer, jeden C-Code zu entwickeln, der zum Laden der Bibliothek und zum Aufrufen ihrer Funktionen erforderlich ist. Anschließend wird dieser Code in eine Binärdatei kompiliert, die von Simulink erkannt und mit einer gemeinsam genutzten Bibliothek verknüpft wird. Diese Binärdatei wird als S-Funktion bezeichnet. Simulink hat einen Block zum Aufrufen dieser S-Funktion. Es gibt verschiedene Ansätze zum Erstellen von S-Funktionen in Simulink.

Verwenden des Legacy-Code-Tools


Der erste Ansatz ist die Verwendung des Legacy-Code- Tools, mit dem Sie automatisch S-Funktionen gemäß den mit MATLAB erstellten Spezifikationen erstellen können. In diesem Beispiel ist die S-Funktion mit der Importbibliothek verknüpft (unter Windows benötigen wir die entsprechende * .lib-Datei) und die Bibliotheksfunktionen werden aufgerufen. Dieser Ansatz wird als implizite Verknüpfung bezeichnet.
Zunächst müssen Sie die Struktur für das Legacy Code Tool initialisieren
Code zum Initialisieren der Legacy Code Tool-Struktur
specs = legacy_code('initialize');
% Prototype for the initialization function
specs.StartFcnSpec = 'exlib_init()';
% Prototype for the step function
specs.OutputFcnSpec = 'exlib_print(single u1)';
% Prototype for the terminate function
specs.TerminateFcnSpec = 'exlib_term()';
% Shared library to link with (.so on Linux and .dll on Windows)
specs.HostLibFiles = {['exlib',strrep(system_dependent('GetSharedLibExt'),'.dll','.lib')]};
% We must supply header file when linking with shared library, otherwise
% compiler might make wrong assumptions about function's prototype.
specs.HeaderFiles = {'exlib.h'};
specs.SFunctionName = 'sfun_exlib';



Erstellen Sie eine S-Funktion, kompilieren und verknüpfen Sie sie:
legacy_code('generate_for_sim',specs);
### Start Compiling sfun_exlib
    mex('sfun_exlib.c', '-I/tmp/simulink_shrlib_fex', '/tmp/simulink_shrlib_fex/exlib.so')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling sfun_exlib
### Exit


Erstellen Sie abschließend den Simulink-Block:
legacy_code('slblock_generate',specs);


Führen Sie die Simulation aus:
open_system('simlib_test');
snapnow;
sim('simlib_test');
% Observe the results:
type('exlib.txt');
0.000000
1.000000
2.000000
3.000000
4.000000
5.000000
6.000000
7.000000
8.000000
9.000000
10.000000


Manuelles Schreiben von S-Funktionen


Der zweite Ansatz besteht darin, eigene S-Funktionen zum Laden einer gemeinsam genutzten Bibliothek und zum Aufrufen von Funktionen aus dieser Bibliothek zu schreiben. Bei diesem Ansatz wird eine explizite Verknüpfung verwendet, die auch als Laufzeitverknüpfung bezeichnet wird. Die einfachste Lösung besteht darin, die S-Funktion anzupassen, die zuvor vom Legacy Code Tool automatisch generiert wurde. In diesem Beispiel werden die Funktionen mdlStart , mdlOutputs und mdlTerminate geändert .
So sehen diese Funktionen nach Änderungen aus:
Code anzeigen
void mdlStart(SimStruct *S)
{
  /*
   * Load the dynamic library
   */

  #if defined(__GNUC__) && !defined(__MINGW32__)
    void (*exlib_init_ptr)(void);
    dllHandle = dlopen("./exlib.so",RTLD_LAZY);
    exlib_init_ptr = dlsym(dllHandle, "exlib_init");
  #else
    exlib_init_type exlib_init_ptr = NULL;
    dllHandle = LoadLibrary("exlib.dll");
    exlib_init_ptr = (exlib_init_type)GetProcAddress(dllHandle,"exlib_init");
  #endif

  exlib_init_ptr();
}


void mdlOutputs(SimStruct *S, int_T tid)
{
  real32_T *u1 = 0;

  #if defined(__GNUC__) && !defined(__MINGW32__)
    void (*exlib_print_ptr)(float);
    exlib_print_ptr = dlsym(dllHandle,"exlib_print");
  #else
    exlib_print_type exlib_print_ptr = NULL;
    exlib_print_ptr = (exlib_print_type)GetProcAddress(dllHandle,"exlib_print");
  #endif

  /*
   * Get access to Parameter/Input/Output/DWork/size information
   */
  u1 = (real32_T *) ssGetInputPortSignal(S, 0);

  /*
   * Call the function from library
   */
  exlib_print_ptr( *u1);
}


void mdlTerminate(SimStruct *S)
{
  /*
   * Unload the dynamic library
   */

  #if defined(__GNUC__) && !defined(__MINGW32__)
    void (*exlib_term_ptr)(void);
    exlib_term_ptr = dlsym(dllHandle,"exlib_term");
    exlib_term_ptr();
    dlclose(dllHandle);
  #else
    exlib_term_type exlib_term_ptr = NULL;
    exlib_term_ptr = (exlib_term_type)GetProcAddress(dllHandle,"exlib_term");
    exlib_term_ptr();
    FreeLibrary(dllHandle);
  #endif
}



Kompilieren Sie die resultierende S-Funktion:
if isunix
    mex('sfun_exlib_dyn.c','-ldl');
else
    mex('sfun_exlib_dyn.c');
end
Building with 'gcc'.
MEX completed successfully.


Und führen Sie die Simulation aus:
open_system('simlib_test_dyn');
sim('simlib_test_dyn');
% Observe the results:
type('exlib.txt');
0.000000
1.000000
2.000000
3.000000
4.000000
5.000000
6.000000
7.000000
8.000000
9.000000
10.000000


Verwenden des S-Function Builder


Ein anderer Ansatz ist die Verwendung des S-Function Builder- Blocks . Dies ist eine spezielle Einheit, die hinsichtlich der Komplexität als Kreuzung zwischen dem Legacy Code Tool und handgeschriebenen S-Funktionen angesehen werden kann. S-Function Builder bietet eine grafische Oberfläche, die die Eigenschaften Ihrer S-Funktion beschreibt, und die S-Funktion wird automatisch erstellt.
Es gibt einige Leistungseinschränkungen und Probleme bei der Verwendung von S-Function Builder. Derzeit wird dies als veralteter Ansatz zur Erstellung von S-Funktionen angesehen. Es wird empfohlen, den C-Funktionsblock zu verwenden, der in der Version von R2020a enthalten ist und später erläutert wird.

Aufrufen einer gemeinsam genutzten Bibliothek mit der MATLAB-Funktion


Mit dem MATLAB-Funktionsblock können Sie die MATLAB-Sprache verwenden, um einen benutzerdefinierten Algorithmus in Simulink zu beschreiben.
Verwenden Sie die Funktion coder.ceval , die nur im Hauptteil der MATLAB-Funktion (und nicht in MATLAB) verwendet werden kann , um die gemeinsam genutzte Bibliothek über die MATLAB-Funktion aufzurufen . Für Coder.ceval ist MATLAB Coder nicht erforderlich.
Code für den MATLAB-Funktionsblock, der die gemeinsam genutzte Bibliothek aufruft:
Code anzeigen
function fcn(u)
%#codegen

% Keep track of initialization and runtime count
persistent runTimeCnt

% Generate library path on the fly (current directory in this case)
coder.extrinsic('pwd','system_dependent');
libpath = coder.const(pwd);
% Shared library to link with
libname = coder.const(['exlib',strrep(system_dependent('GetSharedLibExt'),'.dll','.lib')]);
% Add the external library. Mark it as precompiled, so it won't appear as
% makefile target during code generation.
coder.updateBuildInfo('addLinkObjects',libname,libpath,1000,true,true);
coder.updateBuildInfo('addIncludePaths',libpath);
coder.cinclude('exlib.h');

if isempty(runTimeCnt)
    % Initialize
    coder.ceval('exlib_init');
    runTimeCnt = 0;
end
% Step
coder.ceval('exlib_print',single(u));
runTimeCnt = runTimeCnt+1;
% Terminate on the 10th step
if (runTimeCnt == 11)
    coder.ceval('exlib_term');
end



Dieser Ansatz hat einen Nachteil - das Fehlen einer guten Möglichkeit, die Abschlussfunktion am Ende der Simulation aufzurufen (im Vergleich zum MATLAB-Systemblock).
Sie können die Abschlussfunktion für das Modell definieren, indem Sie exlib_term () festlegen. in den Modelleinstellungen in der Kategorie Simulationsziel -> Benutzerdefinierter Code -> Funktion beenden .

HINWEIS . Wenn der Parameter "Benutzerdefinierten Code importieren " in den Modelleinstellungen festgelegt ist, müssen Sie alle Codeabhängigkeiten im Bereich "Simulationsziel" angeben (anstatt coder.cinclude und coder.updateBuildInfo zu verwenden ). Wenn dieser Parameter nicht festgelegt ist, können Sie die Einstellungen aus Simulationsziel, coder.cinclude und coder.updateBuildInfo kombinieren.


Eine andere Möglichkeit besteht darin, Abhängigkeiten mit zu pflegencoder.cinclude und coder.updateBuildInfo und rufen Sie exlib_term () gemäß Konvention auf, wie im obigen Beispiel gezeigt.
Führen Sie die Simulation aus:
open_system('simlib_test_mlf');
sim('simlib_test_mlf');
% Observe the results:
type('exlib.txt');
0.000000
1.000000
2.000000
3.000000
4.000000
5.000000
6.000000
7.000000
8.000000
9.000000
10.000000


Aufrufen einer gemeinsam genutzten Bibliothek aus Stateflow


Wenn Sie die Funktionen der gemeinsam genutzten Bibliothek in Stateflow- Diagrammen verwenden möchten , sollten diese Funktionen direkt von Stateflow aufgerufen werden. Die Stateflow-Dokumentation enthält Beispiele, die zeigen, wie dies getan wird.
Das Aufrufen einer externen Funktion in Stateflow ist sehr einfach. Sie müssen den Funktionsnamen im Stateflow-Diagramm angeben:


Außerdem müssen Sie die Modellparameter so konfigurieren, dass Stateflow weiß, wo nach diesen externen Funktionen gesucht werden muss. In den Einstellungen der Simulation Target -> Custom Code -> Bibliotheken, Sie eingeben müssen exlib.lib (oder exlib.so in Linux) . In Simulation Target -> Custom Code -> Header - Datei Sie eingeben müssen #include "exlib.h" . Es ist auch wichtig, nicht zu vergessen, die Abschlussfunktion anzugeben. BEIMSimulationsziel -> Benutzerdefinierter Code -> Abschlussfunktion muss exlib_term () angeben ; .
Führen Sie die Simulation aus:
if isunix
    set_param('simlib_test_sf','SimUserLibraries','exlib.so');
end
sim('simlib_test_sf');
% Observe the results:
type('exlib.txt');
0.000000
1.000000
2.000000
3.000000
4.000000
5.000000
6.000000
7.000000
8.000000
9.000000
10.000000


Beachten Sie, dass die Informationen in diesem Abschnitt für Stateflow-Diagramme gelten, die die Aktionssprache C verwenden . Wenn das Stateflow-Diagramm die Aktionssprache MATLAB verwendet , ist coder.ceval erforderlich , wie dies bei der MATLAB-Funktion der Fall ist.

Aufrufen einer gemeinsam genutzten Bibliothek mit dem MATLAB-Systemblock


Mit dem MATLAB-Systemblock können Sie Systemobjekte in Simulink verwenden. Weitere Informationen zu diesem Block finden Sie in der Dokumentation.
Die Unterstützung für Systemobjekte wurde in Simulink in der Version von R2013b veröffentlicht. Viele Benutzer verwenden Systemobjekte, weil sie die Definition der Initialisierungs-, Simulations- und Abschlussfunktionen vereinfachen. Außerdem können Systemobjekte den zusätzlichen MATLAB-Code für diese Funktionen verwenden, z. B. für die Vor- und Nachbearbeitung von Daten einer Schrittfunktion, ohne C-Code schreiben zu müssen.
So sieht das im MATLAB-Systemblock verwendete Systemobjekt aus:
Systemobjektcode
classdef exlib < matlab.System
    % Call exlib shared library
    %
    % This example shows how to call shared library from Simulink using
    % MATLAB System block.
    properties (Nontunable,Access=private)
        libName = exlib.getLibName;
        libPath = pwd;
        libHeader = 'exlib.h';
    end
    
    methods (Static)
        function libName = getLibName
            if isunix
                libName = 'exlib.so';
            else
                libName = 'exlib.lib';
            end
        end
    end
    
    methods (Access=protected)
        function setupImpl(obj, ~)
            % Initialize.
            coder.updateBuildInfo('addLinkObjects',obj.libName,obj.libPath,1000,true,true);
            coder.updateBuildInfo('addIncludePaths',obj.libPath);
            coder.cinclude(obj.libHeader);
            coder.ceval('exlib_init');
        end
        
        function stepImpl(~, u)
            % Step.
            coder.ceval('exlib_print',u);
        end
        
        function releaseImpl(~)
            % Terminate.
            coder.ceval('exlib_term');
        end
    end
end



Führen Sie die Simulation aus:
open_system('simlib_test_mls');
sim('simlib_test_mls');
% Observe the results:
type('exlib.txt');
0.000000
1.000000
2.000000
3.000000
4.000000
5.000000
6.000000
7.000000
8.000000
9.000000
10.000000


Rufen Sie gemeinsam genutzte Bibliotheken mit dem C Caller-Block auf


Mit dem C Caller- Block können Sie C-Funktionen direkt von Simulink aus aufrufen. Weitere Informationen zu diesem Block finden Sie in der Dokumentation.
Dies ist ein relativ neuer Ansatz, der erstmals in MATLAB R2018b vorgestellt wurde. Hauptziel ist es, Funktionsaufrufe und C-Bibliotheken in Simulink extrem einfach zu gestalten. Es gibt jedoch Einschränkungen, über die Sie in der Dokumentation zu diesem Block lesen können.
Nachdem exlib.so/exlib.lib zu Simulationsziel -> Bibliotheken und #include "exlib.h" in Simulationsziel -> Header in den Modelleinstellungen hinzugefügt wurde , klicken Sie einfach auf die Schaltfläche "Benutzerdefinierten Code aktualisieren" im C-Anruferblock. um alle in der Bibliothek enthaltenen Funktionen zu sehen.
Nach Auswahl der Funktion exlib_print wird das Dialogfeld

für die Portspezifikation automatisch ausgefüllt: Außerdem müssen Sie die Funktionsaufrufe exlib_init und exlib_term zum Simulationsziel hinzufügen . Sie können auch einige andere C Caller-Blöcke hinzufügen, um die Initialisierungs- und Beendigungsfunktionen direkt aufzurufen. Diese C-Aufruferblöcke müssen in den Subsystemen Funktion initialisieren und Funktion beenden platziert werden. Sie können auch das folgende Beispiel aus Stateflow betrachten: Planen der Ausführung von Subsystemen zu bestimmten Zeiten
Führen Sie die Simulation aus:
open_system('simlib_test_ccaller');
if isunix
    set_param('simlib_test_ccaller','SimUserLibraries','exlib.so');
end
sim('simlib_test_ccaller');
% Observe the results:
type('exlib.txt');
0.000000
1.000000
2.000000
3.000000
4.000000
5.000000
6.000000
7.000000
8.000000
9.000000
10.000000


Gemeinsame Bibliotheken mit dem C-Funktionsblock aufrufen


Die neueste Ergänzung zur Integration von externem Code in Simulink ist der C-Funktionsblock . Er erschien in der R2020a.
Es ähnelt in seiner Benutzerfreundlichkeit dem C-Caller-Block, ermöglicht jedoch das Erstellen eines C-Wrappers um importierte Funktionen (daher ähnelt dieser Block dem S-Function Builder). Höchstwahrscheinlich besteht das Hauptszenario für die Verwendung des C-Funktionsblocks jedoch nicht darin, vorhandene C-Funktionen aufzurufen, sondern kleine Teile des C-Codes zu schreiben, wenn dieser Code in der Anwendung benötigt wird. Beispielsweise benötigen Sie möglicherweise Zugriff auf Hardwareregister oder die integrierten Funktionen des Compilers.
Vergessen Sie nicht, exlib.so/exlib.lib zu den Einstellungen "Simulationsziel -> Bibliotheken" und #include "exlib.h" hinzuzufügen.in den Einstellungen "Simulationsziel -> Header-Datei" in den Modelleinstellungen.
Danach müssen Sie in den Einstellungen des C-Funktionsblocks ein Zeichen für die Eingabedaten mit dem Datentyp single hinzufügen und den Ausgabe-, Start- und Endcode angeben:


open_system('simlib_test_cfunction');
if isunix
    set_param('simlib_test_cfunction','SimUserLibraries','exlib.so');
end
sim('simlib_test_cfunction');
% Observe the results:
type('exlib.txt');
0.000000
1.000000
2.000000
3.000000
4.000000
5.000000
6.000000
7.000000
8.000000
9.000000
10.000000


Aufrufen von gemeinsam genutzten Bibliotheken, die mit Embedded Coder erstellt wurden


Eines der Szenarien für die Verwendung von Embedded Coder ist die automatische Generierung von C-Code aus dem Simulink-Modell und das Packen dieses Codes in eine gemeinsam genutzte Bibliothek. Die Dokumentation enthält auch ein Beispiel, das zeigt, wie eine gemeinsam genutzte Bibliothek automatisch generiert und von einer in C geschriebenen externen Anwendung aufgerufen wird.
Beachten Sie, dass es besser ist, den Algorithmus oder einen Teil des Algorithmus als C-Code im selben Simulink-Modell auszuführen S-Funktionen von Simulink Coder oder Software-in-the-Loop- Simulation. Wenn jedoch die vom Embedded Coder generierte gemeinsam genutzte Bibliothek für die naturnahe Modellierung verwendet wird, müssen Sie möglicherweise dieselbe Bibliothek in das größere Modell anderer Entwickler integrieren und so Ihr geistiges Eigentum schützen.
Die Arbeit mit einer von Embedded Coder generierten gemeinsam genutzten Bibliothek unterscheidet sich nicht von der Arbeit mit einer gemeinsam genutzten Bibliothek, die im Artikel verwendet wurde. Stellen Sie sich ein einfaches Modell mit zwei Eingängen und einem Ausgang vor:
open_system('simlib_test_ert');
snapnow;



Nach dem Zusammenstellen des Modells erhalten wir eine DLL-Datei (.so unter Linux), eine LIB-Datei (eine Importbibliothek für DLL) und eine EXP-Datei (eine Exportdatei für die Kommunikation mit DLL).
if isunix
    set_param('simlib_test_ert','CustomHeaderCode','#include <stddef.h>');
end
rtwbuild('simlib_test_ert');
### Starting build procedure for: simlib_test_ert
### Successful completion of build procedure for: simlib_test_ert


Die generierte gemeinsam genutzte Bibliothek exportiert die folgenden Zeichen:
ex_init
double ex_step(double, double)
simlib_test_ert_terminate


Standardmäßig werden Ein- und Ausgaben als globale Zeichen exportiert, und die Initialisierungs-, Schritt- und Abschlussfunktionen folgen der Modellbenennungskonvention. Bei Bedarf können Sie Funktionsprototypen, Symbolnamen und mehr konfigurieren (eine Erläuterung dieser Einstellungen würde den Rahmen dieses Artikels sprengen). In diesem Modell ist der Prototyp der Schrittfunktion des Modells als Out1 = ex_step (In1, In2) definiert .
Um diese Funktionen aufzurufen, müssen Sie eine der oben aufgeführten Methoden verwenden. Sie können beispielsweise die MATLAB-Funktion verwenden (der Einfachheit halber nennen wir nur die Schrittfunktion):
Code anzeigen
function y = fcn(u1, u2)
%#codegen

% Generate library path on the fly
coder.extrinsic('RTW.getBuildDir','fullfile');
buildDir = coder.const(RTW.getBuildDir('simlib_test_ert'));
libpath = coder.const(buildDir.CodeGenFolder);
incpath = coder.const(fullfile(buildDir.BuildDirectory,'simlib_test_ert.h'));
% Shared library to link with
if isunix
    ext = '.so';
    libname = ['simlib_test_ert',ext];
else
    ext = '.lib';
    libname = ['simlib_test_ert_',computer('arch'),ext];
end
% Add the external library. Mark it as precompiled, so it won't appear as
% makefile target during code generation.
coder.updateBuildInfo('addLinkObjects',libname,libpath,1000,true,true);
coder.updateBuildInfo('addIncludePaths',libpath);
coder.cinclude(incpath);

% Initialize output
y = 0;
% Step
y = coder.ceval('ex_step',u1,u2);



Führen Sie die Simulation aus und sehen Sie sich die Ergebnisse an:
open_system('simlib_test_callert');
sim('simlib_test_callert');
snapnow;



Ergebnisse


Dieser Artikel beschreibt verschiedene Ansätze zum Aufrufen gemeinsam genutzter Bibliotheken aus Simulink-Modellen. Es wurden sowohl implizite als auch explizite Links berücksichtigt. Alle Methoden haben ihre Vor- und Nachteile, und ihre Eignung hängt von den spezifischen Arbeitsabläufen, Anforderungen und Zielen ab.
Der Ansatz des Legacy Code Tools funktioniert am besten, wenn eine implizite Verknüpfung mit einer gemeinsam genutzten Bibliothek implementiert wird. In diesem Fall können wir Funktionen einfach direkt aus der Bibliothek aufrufen, und der Linker kümmert sich um den Rest.
Der MATLAB-Systemblock ist ein weiterer Ansatz, der die folgenden Vorteile bietet:
  • Hervorragende Übereinstimmung mit dem Paradigma der Initialisierungs-, Schritt- und Abschlussfunktionen, sodass Sie alle diese Funktionen innerhalb des Blocks selbst und nicht im Maßstab des Modells beibehalten können

  • MATLAB MATLAB
  • MATLAB System (, S-)

Der Nachteil der Verwendung des MATLAB-Funktionsblocks besteht darin, dass seine Verwendung zu einem zusätzlichen Overhead während der Codegenerierung führen kann. Daher werden die Funktionen Legacy Code Tool und S weiterhin zum Generieren von Produktionscode bevorzugt.
Eine handgeschriebene S-Funktion eignet sich am besten zum Implementieren einer expliziten Verknüpfung zu einer gemeinsam genutzten Bibliothek. In diesem Fall müssen Sie Funktionen wie LoadLibrary / dlopen , GetProcAddress / dlsym , FreeLibrary / dlclose verwenden, um Funktionen aufrufen zu können.
Der in R2018b eingeführte C-Caller-Block ist bei weitem der einfachste Weg, C-Funktionen aufzurufen, hat jedoch seine Grenzen. Gleiches gilt für den C-Funktionsbaustein .Das ist die neueste Ergänzung zum R2020a.

Download - Quellen und Modelle hier

All Articles