Сгенерируйте код С из кода MATLAB

MATLAB® Coder™ генерирует высоко оптимизированный ANSI C и Код С++ от функций и Системных объектов в Communications Toolbox™. Можно развернуть этот код в большом разнообразии приложений. Рабочий процесс, описанный в этой теме, использует функции DSP System Toolbox™, но тот же рабочий процесс запрашивает Communications Toolbox.

Этот пример генерирует код С от Построения Синусоидальный Сигнал Используя Высокий энергетический Содействующий пример БПФ и создает исполняемый файл из сгенерированного кода.

Вот код MATLAB для этого примера:

L = 1020;
Sineobject = dsp.SineWave('SamplesPerFrame',L,...  
'PhaseOffset',10,'SampleRate',44100,'Frequency',1000);
ft = dsp.FFT('FFTImplementation','FFTW');
ift = dsp.IFFT('FFTImplementation','FFTW','ConjugateSymmetricInput',true);
rng(1);
numIter = 1000;
for Iter = 1:numIter
    Sinewave1 = Sineobject();
    Input = Sinewave1 + 0.01*randn(size(Sinewave1));
    FFTCoeff = ft(Input);
    FFTCoeffMagSq = abs(FFTCoeff).^2;
    
    EnergyFreqDomain = (1/L)*sum(FFTCoeffMagSq);
    [FFTCoeffSorted, ind] = sort(((1/L)*FFTCoeffMagSq),1,'descend');
    
    CumFFTCoeffs = cumsum(FFTCoeffSorted);
    EnergyPercent = (CumFFTCoeffs/EnergyFreqDomain)*100;
    Vec = find(EnergyPercent > 99.99);
    FFTCoeffsModified = zeros(L,1);
    FFTCoeffsModified(ind(1:Vec(1))) = FFTCoeff(ind(1:Vec(1)));
    ReconstrSignal = ift(FFTCoeffsModified);
end
max(abs(Input-ReconstrSignal))
plot(Input,'*');
hold on;
plot(ReconstrSignal,'o');
hold off;

Можно запустить сгенерированный исполняемый файл в среде MATLAB. Кроме того, можно группировать и переместить код к другой среде разработки, которой не установили MATLAB. Можно сгенерировать код с помощью приложения MATLAB Coder или codegen (MATLAB Coder) функция. Этот пример показывает вам рабочий процесс с помощью codegen функция. Для получения дополнительной информации о рабочем процессе приложения смотрите, Генерируют код С при помощи Приложения MATLAB Coder (MATLAB Coder).

Настройте компилятор

Первый шаг должен настроить поддерживаемый компилятор C. MATLAB Coder автоматически определяет местоположение и использует поддерживаемый установленный компилятор. Можно изменить использование компилятора по умолчанию mex -setup. Для получения дополнительной информации см. Компилятор Значения по умолчанию Изменения. Для текущего списка поддерживаемых компиляторов см. Поддерживаемые и Совместимые Компиляторы.

Вспыхните вычислительная часть алгоритма в функцию MATLAB

Чтобы сгенерировать код С, точка входа должна быть функцией. Вы не должны генерировать код для целого приложения MATLAB. Если у вас есть определенные фрагменты, которые в вычислительном отношении интенсивны, генерируют код от этих фрагментов для того, чтобы ускорить ваш алгоритм. Обвязка или драйвер, который вызывает эту функцию MATLAB, не должны генерировать код. Запуски обвязки в MATLAB и могут содержать визуализацию и другие инструменты верификации, которые не являются на самом деле частью системы под тестом. Например, в Построении Синусоидальный Сигнал Используя Высокий энергетический Содействующий пример БПФ, plot функции строят входной сигнал и восстановленный сигнал. plot не поддерживается для генерации кода и должен остаться в обвязке. Чтобы сгенерировать код от обвязки, которая содержит инструменты визуализации, перепишите обвязку как функцию и объявите функции визуализации как внешнее использование функций coder.extrinsic (MATLAB Coder). Чтобы запустить сгенерированный код, который содержит внешние функции, необходимо было установить MATLAB на машине.

Код MATLAB в for цикл, который восстанавливает исходный сигнал с помощью высокоэнергетических коэффициентов БПФ, является в вычислительном отношении интенсивным фрагментом этого алгоритма. Убыстритесь for цикл путем перемещения этой вычислительной части в собственную функцию, GenerateSignalWithHighEnergyFFTCoeffs.m.

L = 1020;
Sineobject = dsp.SineWave('SamplesPerFrame',L,...
    'SampleRate',44100,'Frequency',1000);
rng(1);
numIter = 1000;
for Iter = 1:numIter
    Sinewave1 = Sineobject();
    Input = Sinewave1 + 0.01*randn(size(Sinewave1));
    [ReconstrSignal,numCoeff] = GenerateSignalWithHighEnergyFFTCoeffs(Input);
end
max(abs(Input-ReconstrSignal))
figure(1);
plot(Input)
hold on;
plot(ReconstrSignal,'*')
hold off
function [ReconstrSignal,numCoeff] = GenerateSignalWithHighEnergyFFTCoeffs(Input)

ft = dsp.FFT('FFTImplementation','FFTW');
ift = dsp.IFFT('FFTImplementation','FFTW','ConjugateSymmetricInput',true);

FFTCoeff = ft(Input);
FFTCoeffMagSq = abs(FFTCoeff).^2;
L = size(Input,1);
EnergyF = (1/L)*sum(FFTCoeffMagSq);
[FFTCoeffSorted, ind] = sort(((1/L)*FFTCoeffMagSq),1,'descend');

CumFFTCoeffs = cumsum(FFTCoeffSorted);
EnergyPercent = (CumFFTCoeffs/EnergyF)*100;
Vec = find(EnergyPercent > 99.99);
FFTCoeffsModified = zeros(L,1);
FFTCoeffsModified(ind(1:Vec(1))) = FFTCoeff(ind(1:Vec(1)));
numCoeff = Vec(1);
ReconstrSignal = ift(FFTCoeffsModified);
end

Сделайте код подходящим для генерации кода

Прежде чем вы сгенерируете код, необходимо подготовить код MATLAB к генерации кода.

Проверяйте проблемы во время проектирования

Первый шаг должен устранить неподдерживаемые построения и проверку на любые проблемы генерации кода. Для списка функций Communications Toolbox, поддерживавших MATLAB Coder, смотрите Функции и Системные объекты, Поддержанные для генерации кода C. Для списка поддерживаемых построений языка смотрите Функции языка MATLAB, Поддерживавшие для Генерации кода C/C++ (MATLAB Coder).

Анализатор кода обнаруживает проблемы кодирования во время проектирования, когда вы вводите код. Чтобы включить анализатор кода, необходимо добавить %#codegen прагма к вашему файлу MATLAB.

Snapshot of the GeneratSignalWithHighEnergyFFTCoeffs.m file. The snapshot shows the placement of %#codegen pragma at the end of the first line of the function. The first line of the function is function [ReconstrSignal,numCoeff] = GenerateSignalWithHighEnergyFFTCoeffs(Input) %#codegen

Инструмент готовности генерации кода экранирует код MATLAB на функции, которые не поддерживаются для генерации кода. Один из способов получить доступ к этому инструменту путем щелчка правой кнопкой по файлу MATLAB в его текущей папке. Работа инструмента генерации кода GenerateSignalWithHighEnergyFFTCoeffs.m не находит проблем.

Snapshot of code gen readiness tool. The code generation readiness score shows 5 green bars, indicating that the code is now suitable for code generation. This is a preliminary check and it found no issues. Some minor problems might be found if code generation is attempted, but if so, they should be easy to fix.

Проверяйте проблемы во время генерации кода

Прежде чем вы сгенерируете код С, гарантируете, что код MATLAB успешно генерирует MEX-функцию. codegen (MATLAB Coder) команда раньше генерировала MEX-функцию, обнаруживает любые ошибки, которые предотвращают код для того, чтобы подойти для генерации кода.

Запущенный codegen on GenerateSignalWithHighEnergyFFTCoeffs.m функция.

codegen -args {Input} GenerateSignalWithHighEnergyFFTCoeffs 

Следующее сообщение появляется в командной строке MATLAB:

??? The left-hand side has been constrained to be non-complex, but the right-hand side 
is complex. To correct this problem, make the right-hand side real using the function 
REAL, or change the initial assignment to the left-hand side variable to be a complex 
value using the COMPLEX function.

Error in ==> GenerateSignalWithHighEnergy Line: 24 Column: 1
Code generation failed: View Error Report
Error using codegen
 
 

Это сообщение относится к переменной FFTCoeffsModified. Кодер ожидает, что эта переменная будет инициализирована как комплексная переменная. Чтобы решить этот вопрос, инициализируйте FFTCoeffsModified переменная как комплекс.

FFTCoeffsModified = zeros(L,1)+0i;

Повторно выполнитесь codegen функционируйте и вы видите, что файл MEX сгенерирован успешно в текущей папке с .mex расширение.

codegen -args {Input} GenerateSignalWithHighEnergyFFTCoeffs 

Проверяйте проблемы во время выполнения

Запустите сгенерированную MEX-функцию, чтобы видеть, существуют ли какие-либо проблемы во время выполнения, о которых сообщают. Для этого замена

[ReconstrSignal,numCoeff] = GenerateSignalWithHighEnergyFFTCoeffs(Input);
с
[ReconstrSignalMex,numCoeffMex] = GenerateSignalWithHighEnergyFFTCoeffs_mex(Input);
в обвязке.

Обвязка теперь похожа:

L = 1020;
Sineobject = dsp.SineWave('SamplesPerFrame',L,...
    'SampleRate',44100,'Frequency',1000);
rng(1);
numIter = 1000;
for Iter = 1:numIter
    Sinewave1 = Sineobject();
    Input = Sinewave1 + 0.01*randn(size(Sinewave1));
    [ReconstrSignalMex,numCoeffMex] = GenerateSignalWithHighEnergyFFTCoeffs_mex(Input,L);
end
max(abs(Input-ReconstrSignalMex))
figure(1);
plot(Input)
hold on;
plot(ReconstrSignalMex,'*')
hold off

Код запускается успешно, указывая, что нет никаких ошибок времени выполнения.

Сравните MEX-функцию с симуляцией

Заметьте, что обвязка запускается намного быстрее с MEX-функцией по сравнению с регулярной функцией. Причина генерации MEX-функции не только, чтобы обнаружить генерацию кода и проблемы во время выполнения, но также и ускорить определенные части вашего алгоритма. Для примера смотрите Ускорение алгоритма Обработки сигналов в MATLAB.

Необходимо также проверять, что числовой выход следует из MEX и соответствия регулярной функции. Сравните восстановленный сигнал, сгенерированный GenerateSignalWithHighEnergyFFTCoeffs.m функционируйте и его дубликат MEX GenerateSignalWithHighEnergyFFTCoeffs_mex.

max(abs(ReconstrSignal-ReconstrSignalMex))

ans =

     2.2204e-16

Результаты соответствуют очень тесно, подтверждая, что генерация кода успешна.

Сгенерируйте независимый исполняемый файл

Если ваша цель состоит в том, чтобы запустить сгенерированный код в среде MATLAB, вашей целью сборки может только быть MEX-функция. Если развертывание кода к другому приложению является целью, то сгенерируйте независимый исполняемый файл из целого приложения. Для этого обвязка должна быть функцией, которая вызывает подфункцию GenerateSignalWithHighEnergyFFTCoeffs. Перепишите обвязку как функцию.

function reconstructSignalTestbench()
L = 1020;
Sineobject = dsp.SineWave('SamplesPerFrame',L,...
    'SampleRate',44100,'Frequency',1000);
rng(1);
numIter = 1000;
for Iter = 1:numIter
    Sinewave1 = Sineobject();
    Input = Sinewave1 + 0.01*randn(size(Sinewave1));
    [ReconstrSignal,numCoeff] = GenerateSignalWithHighEnergyFFTCoeffs(Input,L);
end

Регистрируйте все 1 000 систем координат входа и восстановленного сигнала, и количество коэффициентов БПФ раньше восстанавливало каждую систему координат сигнала. Запишите все эти данные в двоичный файл под названием data.bin использование dsp.BinaryFileWriter Система object™. Этот пример регистрирует количество коэффициентов, которые являются скалярными значениями как первый элемент каждой системы координат входного сигнала и восстановленного сигнала. Данные, которые будут записаны, имеют формат кадра M = L + 1 и имеют формат, который выглядит так фигура.

Two matrices on both sides of an equal sign. On the left of the equal sign, the first frame is N followed by input signal. The second frame is N followed by reconstructed signal. On the right of the equal sign, the first frame is 'InputAll' signal and the second frame is 'ReSignalAll'.

N является количеством коэффициентов БПФ, которые представляют 99,99% энергии сигнала текущего входного кадра. Метаданные двоичного файла указывают эту информацию. Выпустите средство записи двоичного файла и закройте двоичный файл в конце.

Обновленная функция обвязки, reconstructSignalTestbench, показан здесь:

function reconstructSignalTestbench()
L = 1020;
Sineobject = dsp.SineWave('SamplesPerFrame',L,...
    'SampleRate',44100,'Frequency',1000);
header = struct('FirstElemInBothCols','Number of Coefficients',...
    'FirstColumn','Input','SecondColumn','ReconstructedSignal');
bfw = dsp.BinaryFileWriter('data.bin','HeaderStructure',header);
numIter = 1000;

M = L+1;
ReSignalAll = zeros(M*numIter,1);
InputAll = zeros(M*numIter,1);
rng(1);

for Iter = 1 : numIter
    Sinewave1 = Sineobject();
    Input = Sinewave1 + 0.01*randn(size(Sinewave1));
    [ReconstrSignal,numCoeffs] = GenerateSignalWithHighEnergyFFTCoeffs(Input);
    InputAll(((Iter-1)*M)+1:Iter*M) = [numCoeffs;Input];
    ReSignalAll(((Iter-1)*M)+1:Iter*M) = [numCoeffs;ReconstrSignal];
end

bfw([InputAll ReSignalAll]);   
release(bfw);

Следующий шаг в генерации исполняемого файла C должен создать a coder.config объект для исполняемого файла и обеспечивает a main.c функционируйте к этому объекту.

cfg =  coder.config('exe');
cfg.CustomSource = 'reconstructSignalTestbench_Main.c';

Вот то, как reconstructSignalTestbench_Main.c функция ищет этот пример.

/*
** reconstructSignalTestbench_main.c
*
* Copyright 2017 The MathWorks, Inc.
*/
#include <stdio.h>
#include <stdlib.h>

#include "reconstructSignalTestbench_initialize.h"
#include "reconstructSignalTestbench.h"
#include "reconstructSignalTestbench_terminate.h"

int main()
{
    reconstructSignalTestbench_initialize();
    reconstructSignalTestbench();    
    reconstructSignalTestbench_terminate();
    
    return 0;
}

Для дополнительных деталей о создании основной функции смотрите Генерирующие Автономные Исполняемые файлы C/C++ из кода MATLAB (MATLAB Coder).

Установите CustomInclude свойство настройки возражает, чтобы задать местоположение основного файла. В этом примере местоположение является текущей папкой.

cfg.CustomInclude = ['"',pwd,'"'];

Сгенерируйте исполняемый файл C путем выполнения следующей команды в командной строке MATLAB:

codegen -config cfg -report reconstructSignalTestbench

MATLAB Coder компилирует и соединяет основную функцию с кодом С, который это генерирует от reconstructSignalTestbench.m.

Если вы используете Windows, вы видите это reconstructSignalTestbench.exe сгенерирован в текущей папке. Если вы используете Linux, сгенерированный исполняемый файл не имеет .exe расширение.

Считайте и проверьте данные о двоичном файле

Выполнение исполняемого файла создает двоичный файл, data.bin, в текущем каталоге и записях вход, восстановленный сигнал и количество коэффициентов БПФ раньше восстанавливали сигнал.

!reconstructSignalTestbench

Можно считать эти данные из двоичного файла с помощью dsp.BinaryFileReader объект. Проверять, что данные записаны правильно, считанные данные из двоичного файла в MATLAB и сравнивают выход с переменными InputAll и ReSignalAll.

Прототип заголовка должен иметь структуру, похожую на структуру заголовка, записанную в файл. Считайте данные как два канала.

M = 1021;
numIter = 1000;
headerPro = struct('FirstElemInBothCols','Number of Coefficients',...
    'FirstColumn','Input','SecondColumn','ReconstructedSignal');
bfr = dsp.BinaryFileReader('data.bin','HeaderStructure',...
headerPro,'SamplesPerFrame',M*numIter,'NumChannels',2);
Data = bfr();

Сравните первый канал с InputAll и второй канал с ReSignalAll.

isequal(InputAll,Data(:,1))
ans =

  logical

   1
isequal(ReSignalAll,Data(:,2))
ans =

  logical

   1

Результаты соответствуют точно, показывая на успешную операцию записи.

Переместите код к другой среде разработки

Если вы генерируете код из своего алгоритма MATLAB, можно переместить код к другой среде разработки, такой как система или интегрированная среда разработки (IDE), которая не включает MATLAB. Можно группировать файлы в сжатый файл с помощью packNGo функция в командной строке или опции Package в приложении MATLAB Coder. Для примера, который иллюстрирует обоих рабочие процессы, см. Код Пакета для Других Сред разработки (MATLAB Coder). Для получения дополнительной информации о packNGo опция, смотрите packNGo в Методах RTW.BuildInfo (MATLAB Coder). Можно переместить и распаковать сжатый zip-файл с помощью стандартной утилиты zip. Для примера о том, как группировать исполняемый файл, сгенерированный в этом примере, смотрите, Перемещают Код, Сгенерированный от кода MATLAB до Другой Среды разработки.

Смотрите также

Функции

Похожие темы

Внешние веб-сайты