从 C++ 调用 MATLAB 函数

目录

从 C++ 调用 MATLAB 函数

调用带单一返回参数的函数

使用名称/值参数调用函数

以异步方式调用函数

使用多个返回参数调用函数

用原生 C++ 类型调用函数

控制输出的数目


从 C++ 调用 MATLAB 函数

​        使用 matlab::engine::MATLABEngine 类的 feval 和 fevalAsync 成员函数从 C++ 调用 MATLAB® 函数。当要将函数参数从 C++ 传递给 MATLAB 和将函数执行的结果返回给 C++ 时,请使用这些函数。这些成员函数的工作方式类似于 MATLAB feval 函数。

​        要调用 MATLAB 函数,需要满足以下条件:

  • 将函数名称作为 matlab::engine::String 传递。

  • ​定义 MATLAB 函数所需的输入参数。可以使用原生 C++ 数据类型或 MATLAB 数据 API。有关详细信息,可以参考MATLAB 数据 API。​

  • ​指定 MATLAB 函数应提供的输出的数目。默认为一个输出。有关详细信息,可以参考使用多个返回参数调用函数和控制输出的数目。​

  • 为 MATLAB 函数的结果定义适当的返回类型。

  • 使用流缓冲区将标准输出和标准错误从 MATLAB 命令行窗口重定向到 C++。有关详细信息,可以参考Redirect MATLAB Command Window Output to C++​

调用带单一返回参数的函数

        此示例使用 MATLAB gcd函数求两个数值的最大公约数。MATLABEngine::feval 成员函数返回 gcd 函数调用的结果。使用 matlab::data::ArrayFactory 创建两个标量 int16_t 参数。将参数以 std::vector 形式传递给 MATLABEngine::feval。

#include "MatlabEngine.hpp"
#include "MatlabDataArray.hpp"
#include 
void callFevalgcd() {

    // Pass vector containing MATLAB data array scalar
    using namespace matlab::engine;

    // Start MATLAB engine synchronously
    std::unique_ptr matlabPtr = startMATLAB();

    // Create MATLAB data array factory
    matlab::data::ArrayFactory factory;

    // Pass vector containing 2 scalar args in vector    
    std::vector args({
        factory.createScalar(30),
        factory.createScalar(56) });

    // Call MATLAB function and return result
    matlab::data::TypedArray result = matlabPtr->feval(u"gcd", args);
    int16_t v = result[0];
    std::cout << "Result: " << v << std::endl;
}

        可以使用原生 C++ 类型调用 MATLABEngine::feval。为此,必须将调用 MATLABEngine::feval 的返回类型指定为:

feval(...)

        例如,此处返回类型是 int:

int cresult = matlabPtr->feval(u"gcd", 30, 56);

​        此示例定义一个 matlab::data::TypedArray,以将 double 类型的数组传递给 MATLAB sqrt 函数。由于数组中的数值之一是负数,因此 MATLAB 返回复数数组作为结果。因此,将返回类型定义为 matlab::data::TypedArray>。

#include "MatlabDataArray.hpp"
#include "MatlabEngine.hpp"
#include 
void callFevalsqrt() {
    // Call MATLAB sqrt function on array

    using namespace matlab::engine;

    // Start MATLAB engine synchronously
    std::unique_ptr matlabPtr = startMATLAB();

    // Create  MATLAB data array factory
    matlab::data::ArrayFactory factory;

    // Define a four-element array 
    matlab::data::TypedArray const argArray = 
        factory.createArray({ 1,4 }, { -2.0, 2.0, 6.0, 8.0 });

    // Call MATLAB function
    matlab::data::TypedArray> const results = 
        matlabPtr->feval(u"sqrt", argArray);

    // Display results
    int i = 0;
    for (auto r : results) {
        double a = argArray[i++];
        double realPart = r.real();
        double imgPart = r.imag();
        std::cout << "Square root of " << a << " is " << 
            realPart << " + " << imgPart << "i" << std::endl;
    }
}

        ​在调用 MATLAB 函数时,对返回类型使用 matlab::data::Array 是安全的。例如,可以对返回值使用 matlab::data::Array 来编写前面的示例。

void callFevalsqrt() {
    // Call MATLAB sqrt function on array

    using namespace matlab::engine;

    // Start MATLAB engine synchronously
    std::unique_ptr matlabPtr = startMATLAB();

    // Create MATLAB data array factory
    matlab::data::ArrayFactory factory;

    // Define a four-element array 
    matlab::data::Array const argArray = 
        factory.createArray({ 1,4 }, { -2.0, 2.0, 6.0, 8.0 });

    // Call MATLAB function    
    matlab::data::Array results = matlabPtr->feval(u"sqrt", argArray);

    // Display results 
    for (int i = 0; i < results.getNumberOfElements(); i++) {
        double a = argArray[i];
        std::complex v = results[i];
        double realPart = v.real();
        double imgPart = v.imag();
        std::cout << "Square root of " << a << " is " <<
            realPart << " + " << imgPart << std::endl;
    }
}

使用名称/值参数调用函数

        一些 MATLAB 函数接受可选的名称-值对组参数。名称是字符数组,值可以是任何类型的值。使用 std::vector 创建包含正确序列的名称和值的参数向量。此示例代码调用 MATLAB movsum 函数来计算行向量的三点中心移动和,而放弃端点计算。此函数调用需要以下参数:

  • 数值数组

  • 标量窗口长度

  • 名称-值对组由字符数组 Endpoint 和 discard 组成

        以下是等效的 MATLAB 代码:

A = [4 8 6 -1 -2 -3 -1 3 4 5];
M = movsum(A,3,'Endpoints','discard');

​        将这些要用于 MATLAB 函数的参数以 std::vector 形式传递给 MATLABEngine::feval。使用 matlab::data::ArrayFactory 创建每个参数。

void callFevalmovsum() {
    //Pass vector containing various types of arguments

    using namespace matlab::engine;

    // Start MATLAB engine synchronously
    std::unique_ptr matlabPtr = startMATLAB();

    // Create  MATLAB data array factory
    matlab::data::ArrayFactory factory;

   // Create a vector of input arguments
    std::vector args({
        factory.createArray({ 1, 10 }, { 4, 8, 6, -1, -2, -3, -1, 3, 4, 5 }),
        factory.createScalar(3),
        factory.createCharArray("Endpoints"),
        factory.createCharArray("discard")
    });

    // Call MATLAB function 
    matlab::data::TypedArray const result = matlabPtr->feval(u"movsum", args);

    // Display results    
    int i = 0;
    for (auto r : result) {
        std::cout << "results[" << i++ << "] = " << r << std::endl;
    }
}

以异步方式调用函数

        此示例调用 MATLAB conv函数来将两个多项式相乘。在调用 MATLABEngine::fevalAsync 后,使用 FutureResult::get 从 MATLAB 获得结果。

#include "MatlabDataArray.hpp"
#include "MatlabEngine.hpp"
#include 
static void callFevalAsync() {
    //Call MATLAB functions asynchronously

    using namespace matlab::engine;

    // Start MATLAB engine synchronously
    std::unique_ptr matlabPtr = startMATLAB();

    // Create MATLAB data array factory
    matlab::data::ArrayFactory factory;

     // Create input argument arrays
    std::vector args({
        factory.createArray({ 1, 3 },{ 1, 0, 1 }),
        factory.createArray({ 1, 2 },{ 2, 7 }) 
    });
    String func(u"conv");

    // Call function asnychronously
    FutureResult future = matlabPtr->fevalAsync(func, args);
    
    // Get results
    matlab::data::TypedArray results = future.get();

    // Display results
    std::cout << "Coefficients: " << std::endl;
    for (auto r : results) {
        std::cout << r << " " << std::endl;
    }
}

使用多个返回参数调用函数

        以下示例代码使用 MATLAB gcd函数对传递的两个数值输入求最大公约数和 Bézout 系数。gcd 函数可以返回一个或三个参数,具体取决于函数调用请求的输出的数目。在此示例中,对 MATLAB gcd函数的调用返回三个输出。

        默认情况下,MATLABEngine::feval 假设返回值的数目为1。因此,必须将返回值的实际数目指定为 MATLABEngine::feval 的第二个参数。在此示例中,MATLABEngine::feval 返回一个 std::vector,其中包含 gcd 函数调用的三个结果。返回值是整数标量。

#include "MatlabDataArray.hpp"
#include "MatlabEngine.hpp"
#include 
void multiOutput() {
    //Pass vector containing MATLAB data array array

    using namespace matlab::engine;

    // Start MATLAB engine synchronously
    std::unique_ptr matlabPtr = startMATLAB();
    std::cout << "Started MATLAB Engine" << std::endl;

    //Create MATLAB data array factory
    matlab::data::ArrayFactory factory;

    //Create vector of MATLAB data array arrays
    std::vector args({
        factory.createScalar(30),
        factory.createScalar(56)
    });

    //Call gcd function, get 3 outputs
    const size_t numReturned = 3;
    std::vector result = matlabPtr->feval(u"gcd", numReturned, args);

    //Display results
    for (auto r : result) {
        std::cout << "gcd output: " << int16_t(r[0]) << std::endl;
    }
}

用原生 C++ 类型调用函数

​        调用 MATLAB 函数时,可以使用原生 C++ 类型。MATLABEngine::feval 和 MATLABEngine::fevalAsync 接受作为 MATLAB 函数参数传递的某些标量 C++ 类型。要将数组和其他类型传递给 MATLAB 函数,可以使用MATLAB 数据 API。

​        此示例使用 int16_t 值作为输入,使用 std::tuple 从 MATLAB gcd 函数返回结果。以下是等效的 MATLAB 代码。

[G,U,V] = gcd(int16(30),int16(56));
#include "MatlabEngine.hpp"
#include 
#include 
void multiOutputTuple() {
    //Return tuple from MATLAB function call

    using namespace matlab::engine;

    // Start MATLAB engine synchronously
    std::unique_ptr matlabPtr = startMATLAB();

    //Call MATLAB gcd function    
    std::tuple nresults;
    nresults = matlabPtr->feval>
        (u"gcd", int16_t(30), int16_t(56));

    // Display results
    int16_t G;
    int16_t U;
    int16_t V;
    std::tie(G, U, V) = nresults;
    std::cout << "GCD : " << G << ", "
              << "Bezout U: " << U << ", "
              << "Bezout V: " << V << std::endl;
}

控制输出的数目

        根据请求的输出数量,MATLAB 函数的行为可能会有所不同。某些函数不返回任何输出或返回指定数量的输出。

        例如,MATLAB pause函数使执行暂停指定的秒数。但是,如果使用一个输出参数调用pause,它将立即返回状态值而不存在暂停。

pause(20) % Pause for 20 seconds
state = pause(20); % No pause, return pause state
此示例调用 pause 但不指定输出。指定 void 输出后,MATLAB 暂停执行 20 秒。

#include "MatlabEngine.hpp"
void voidOutput() {
    // No output from feval
    using namespace matlab::engine;

    // Start MATLAB engine synchronously    
    std::unique_ptr matlabPtr = startMATLAB();

    // Call pause function with no output    
    matlabPtr->feval(u"pause", 20); 
}

        对 MATLABEngine::feval 的以下调用使用将 MATLAB函数参数定义为 std::vector 的签名。在没有指定输出参数的情况下,MATLAB 将暂停执行 20 秒。

#include "MatlabDataArray.hpp"
#include "MatlabEngine.hpp"
void zeroOutput() {
    // No output from feval

    using namespace matlab::engine;

    // Start MATLAB engine synchronously    
    std::unique_ptr matlabPtr = startMATLAB();

    //Create MATLAB data array factory
    matlab::data::ArrayFactory factory;

    // Call pause function with no output    
    matlab::data::Array arg = factory.createScalar(20);
    const size_t numReturned = 0;
    matlabPtr->feval(u"pause", numReturned, { arg }); 
}

        MATLAB clock函数将当前日期和时间作为日期向量返回。如果指定两个输出,clock 会以布尔值形式返回第二个输出,指示它是否为系统时区的夏令时。

        此示例调用带一个输出或两个输出的 clock 函数,具体取决于输入参数的值。传递给 MATLABEngine::feval 调用的第二个参数决定从 clock 请求的输出的数目。

        使用这些参数调用 MATLABEngine::feval。

输入

MATLAB 函数名称 const matlab::engine::String
输出数量 const size_t
MATLAB 函数的输入参数(空) std::vector

输出

所有输出 std::vector
#include "MatlabDataArray.hpp"
#include "MatlabEngine.hpp"
#include 
void varOutputs(const bool tZone) {

    using namespace matlab::engine;

    // Start MATLAB engine synchronously
    std::unique_ptr matlabPtr = startMATLAB();
    std::cout << "Started MATLAB Engine" << std::endl;

    // Define number of outputs
    size_t numReturned(0);
    if (tZone) {
        numReturned = 2;
    } else {
        numReturned = 1;
    }
    std::vector dateTime = matlabPtr->feval(u"clock", numReturned, { });
    auto dateVector = dateTime[0];

    // Display results
    for (int i = 0; i < 6; i++) {
        std::cout << double(dateVector[i]) << " ";
    }

    if (tZone) {
        auto DTS = dateTime[1];
        if (bool(DTS[0])) {
            std::cout << "It is Daylight Saving Time" << std::endl;
        }
        else {
          std::cout << "It is Standard Time" << std::endl;
        }
    }
}

你可能感兴趣的:(MATLAB与C++,matlab,c++,开发语言)