Поскольку MATLAB R2018a , комплекснозначные матрицы хранятся внутри как один блок данных, а действительный и мнимый компоненты каждого элемента матрицы хранятся рядом друг с другом - они называют этот «чередующийся комплекс»,(Раньше такие матрицы имели два блока данных, один для всех реальных компонентов, один для всех мнимых компонентов - «отдельный комплекс».)
Я полагаю, поскольку хранилище теперь позволяет это сделать, что это должно быть возможнопреобразовать массив с комплексным значением в массив с вещественным значением, содержащий в два раза больше элементов, без копирования данных.
В MATLAB есть функция typecast
, которая преобразует массив вдругой тип без копирования данных.Его можно использовать, например, для приведения массива с 16 8-битными значениями в массив с 2 двойными числами с плавающей запятой.Это происходит без копирования данных, битовая комбинация интерпретируется как новый тип.
К сожалению, эта функция вообще не работает с массивами со сложными значениями.
Янамереваясь повторить этот код:
A = fftn(randn(40,60,20)); % some random complex-valued array
assert(~isreal(A))
sz = size(A);
B = reshape(A,1,[]); % make into a vector
B = cat(1,real(B),imag(B)); % interleave real and imaginary values
B = reshape(B,[2,sz]); % reshape back to original shape, with a new first dimension
assert(isreal(B))
Матрицы A
и B
содержат (в R2018a и новее) точно такие же данные в абсолютно одинаковом порядке.Однако, чтобы добраться до B
, нам пришлось дважды скопировать данные.
Я попытался создать MEX-файл, который делает это, но я не вижу, как создать новый массив, который ссылается на данные ввходной массив.Этот MEX-файл работает, но вызывает сбой MATLAB при очистке переменных, потому что есть два массива, которые ссылаются на одни и те же данные, не осознавая, что они совместно используют данные (т. Е. Счетчик ссылок не увеличивается).
// Build with:
// mex -R2018a typecast_complextoreal.cpp
#include <mex.h>
#if MX_HAS_INTERLEAVED_COMPLEX==0
#error "This MEX-file must be compiled with the -R2018a flag"
#endif
#include <vector>
void mexFunction(int /*nlhs*/, mxArray* plhs[], int nrhs, const mxArray* prhs[]) {
// Validate input
if(nrhs != 1) {
mexErrMsgTxt("One input argument expected");
}
if(!mxIsDouble(prhs[0]) && !mxIsSingle(prhs[0])) {
mexErrMsgTxt("Only floating-point arrays are supported");
}
// Get input array sizes
mwSize nDims = mxGetNumberOfDimensions(prhs[0]);
mwSize const* inSizes = mxGetDimensions(prhs[0]);
// Create a 0x0 output matrix of the same type, but real-valued
std::vector<mwSize> outSizes(nDims + 1, 0);
plhs[0] = mxCreateNumericMatrix(0, 0, mxGetClassID(prhs[0]), mxREAL);
// Set the output array data pointer to the input array's
// NOTE! This is illegal, and causes MATLAB to crash when freeing both
// input and output arrays, because it tries to free the same data
// twice
mxSetData(plhs[0], mxGetData(prhs[0]));
// Set the output array sizes
outSizes[0] = mxIsComplex(prhs[0]) ? 2 : 1;
for(size_t ii = 0; ii < nDims; ++ii) {
outSizes[ii + 1] = inSizes[ii];
}
mxSetDimensions(plhs[0], outSizes.data(), outSizes.size());
}
Я хотел бы услышать о любых идеях о том, как действовать отсюда.Мне не обязательно исправлять MEX-файл, если решение - просто код MATLAB, тем лучше.