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

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

Этот пример генерирует код С из конструкции a Sinusoidal Signal Using High Energy FFT Coefficients и создает исполняемый файл из сгенерированного кода.

Вот код 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.

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

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

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

Управляемый codegen на 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-функцию с Simulation

Заметьте, что обвязка запускается намного быстрее с 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

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

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 является создание coder.config объект для исполняемого файла и предоставить 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. Например, пример, иллюстрирующий оба рабочих процессов, см. в Package Code for Other Development Environments (MATLAB Coder). Для получения дополнительной информации о packNGo опция, см. packNGo в методах RTW.BuildInfo (MATLAB Coder). Перемещение и распаковка сжатого zip- файла можно выполнить с помощью стандартного zip- утилиты. Пример упаковки исполняемого файла, сгенерированного в этом примере, см. в разделе Перемещение кода, сгенерированного из кода MATLAB, в другую среду разработки.

См. также

Функции

Похожие темы

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

Для просмотра документации необходимо авторизоваться на сайте