9

Matlab コーダーによって生成された c コードを呼び出そうとしています。Matlab は emxArray と呼ばれる ac 構造体を使用して行列を表します (ここに文書化されています: http://www.mathworks.co.uk/help/fixedpoint/ug/c-code-interface-for-unbounded-arrays-and-structure-fields.html)。

struct emxArray_real_T
{
    double *data;
    int *size;
    int allocatedSize;
    int numDimensions;
    boolean_T canFreeData;
};

私は ctypes の経験がほとんどなく、 c .so で定義された関数にベクトルを前後に渡すために使用できる同等の構造体を作成するのに苦労しています。

これが私がPythonでこれまでに得た場所です...

class EmxArray(ctypes.Structure):
    """ creates a struct to match emxArray_real_T """

    _fields_ = [('data', ctypes.POINTER(ctypes.c_double)),
                ('size', ctypes.POINTER(ctypes.c_int)),
                ('allocatedSize', ctypes.c_int),
                ('numDimensions', ctypes.c_int),
                ('canFreeData', ctypes.c_bool)]    

ただし、これを定義すると:

data = (1.1, 1.2, 1.3, 1.4)
L = len(data)

x = EmxArray()
x.data = (ctypes.c_double * L)(*data)
x.data = (ctypes.c_int * 1)(L)    

これはその後動作します

print len(x.data[:L]) 

for v in x.data[:L]: print v

編集:ローランドの提案を片付けて採用し、次を使用してデータを抽出できます

data_out = x.data[:L]

この構造体を使用して C コードからデータを送受信できるかどうかをさらに調査する必要があります。

解決

Roland が提案したように ctypes 構造体を実装してもうまくいきませんでした - 返された値はガベージでした。その答えが最も近かったので、私はその答えを受け入れました...

他の誰かが私と同じくらい多くの時間を無駄にするのを防ぐことができるので、ここで私の解決策を文書化します。

まず、関数の各要素をそれ自体で乗算する単純な matlab 関数を生成し、コーダーを使用してこれを ac .so にコンパイルしました。これは、ctypes を使用して python にインポートされます。コードは次のとおりです...

import ctypes

LIBTEST = '..../dll/emx_test/'
EMX = ctypes.cdll.LoadLibrary(LIBTEST + 'emx_test.so')
init = EMX.emx_test_initialize()

# Create a data structure to hold the pointer generated by emxCreateWrapper...
class Opaque(ctypes.Structure):
    pass

# make some random data to pass in
data_in = [1., 2., 4., 8., 16.]
L = len(data_in)
# create an empty array of the same size for the output
data_ou = [0] * L

# put this in a ctypes array
ina = (ctypes.c_double * L)(*data_in)
oua = (ctypes.c_double * L)(*data_ou)
# create a pointer for these arrays & set the rows and columns of the matrix
inp = ctypes.pointer(ina)
oup = ctypes.pointer(oua)

nrows = ctypes.c_int(1)
ncols = ctypes.c_int(L)

# use EMX.emxCreateWrapper_real_T(double *data, int rows, int cols) to generate an emx wrapping the data 
# input arg types are a pointer to the data NOTE its not great to have to resize the ctypes.c_double but cant see another way
EMX.emxCreateWrapper_real_T.argtypes = [ctypes.POINTER(ctypes.c_double * L), ctypes.c_int, ctypes.c_int]
# a pointer to the emxArray is returned and stored in Opaque
EMX.emxCreateWrapper_real_T.restype = ctypes.POINTER(Opaque)
# use emxCreateWrapper
in_emx = EMX.emxCreateWrapper_real_T(inp, nrows, ncols)
ou_emx = EMX.emxCreateWrapper_real_T(oup, nrows, ncols)

# so now we have to emx's created and have pointers to them we can run the emx_test
# emx test looks like this in matlab
#
# function res = emx_test ( in )
#     res = in .* in;
# end
#
# so basically it multiplies each element of the matrix by itself
# 
# therefore [1., 2., 4., 8., 16.] should become [1., 4., 8., 64., 256.]

EMX.emx_test(in_emx, ou_emx)

# and voila...that's what we get
print 'In: ', ina[:L]
print 'Out:', oua[:L]

出力:

In: [1.0, 2.0, 4.0, 8.0, 16.0]
Out:[1.0, 4.0, 16.0, 64.0, 256.0]

お時間とご提案をいただき、ありがとうございました。

4

2 に答える 2

3

私は Python-C インターフェースに精通していないので、私が提案していることは理想的ではないかもしれません。私の推測では、がx->data初期化されておらず、それが指しているメモリが割り当てられていないため、クラッシュが発生する可能性があります。

引数が存在する場合に他の言語から MATLAB Coder によって生成されたコードにインターフェイスするときに私がとったアプローチemxArrayは、より単純な API を提供する C インターフェイス関数を手書きすることです。emxArrayこれにより、他の環境 (私の場合は Android Java) でを構築する必要があるという負担が軽減されます。生成された関数fooが 2 次元double配列を受け取って返す場合、次のようなものが機能します。

void foo(double *x, int *szx, double **y, int *szy);

この関数は、入力データとそのサイズへのポインターを取り、出力データとそのサイズへのポインターを提供します。実装は次のようになります。

void foo(double *x, int *szx, double **y, int *szy) 
{
  emxArray_real_T *pEmx;
  emxArray_real_T *pEmy;

  /* Create input emxArray assuming 2-dimensional input */
  pEmx = emxCreateWrapper_real_T(x, szx[0], szx[1]);

  /* Create output emxArray (assumes that the output is not */
  /* written before allocation occurs) assuming 2-D output  */
  pEmy = emxCreateWrapper_real_T(NULL, 0, 0);

  /* Call generated code (call foobar_initialize/terminate elsewhere) */
  foobar(pEmx, pEmy);

  /* Unpack result - You may want to MALLOC storage in *y and */
  /* MEMCPY there alternatively                               */
  *y = pEmy->data;
  szy[0] = pEmy->size[0];
  szy[1] = pEmy->size[1];

  /* Clean up any memory allocated in the emxArrays (e.g. the size vectors) */
  emxDestroyArray_real_T(pEmx);
  emxDestroyArray_real_T(pEmy);
}

Python からこの関数をより簡単に呼び出して、必要に応じて目的のデータを渡すことができるはずです。

私の他の答えemxArray_*には、 file にある関数の詳細がありますfoobar_emxAPI.h

于 2014-07-08T20:46:51.280 に答える