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

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

Этот пример генерирует код С от Построения Синусоидальный Сигнал Используя Высокие энергетические Коэффициенты БПФ (DSP System 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. Этот пример показывает вам рабочий процесс с помощью функции codegen. Для получения дополнительной информации о рабочем процессе приложения смотрите, Генерируют код С при помощи Приложения MATLAB Coder (MATLAB Coder).

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

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

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

Чтобы сгенерировать код С, точка входа должна быть функцией. Вы не должны генерировать код для целого приложения MATLAB. Если у вас есть определенные фрагменты, которые в вычислительном отношении интенсивны, генерируют код от этих фрагментов в порядке ускорить ваш алгоритм. Обвязка или драйвер, который вызывает эту функцию MATLAB, не должны генерировать код. Выполнения обвязки в MATLAB и могут содержать визуализацию и другие инструменты верификации, которые не являются на самом деле частью системы под тестом. Например, в Построении Синусоидальный Сигнал Используя Высокие энергетические Коэффициенты БПФ (DSP System Toolbox) пример, функции plot строят входной сигнал и восстановленный сигнал. plot не поддержан для генерации кода и должен остаться в обвязке. Чтобы сгенерировать код от обвязки, которая содержит инструменты визуализации, перепишите обвязку как функцию и объявите функции визуализации как внешние функции с помощью coder.extrinsic. Чтобы запустить сгенерированный код, который содержит внешние функции, необходимо было установить 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 к генерации кода.

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

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

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

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

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

Прежде чем вы сгенерируете код С, гарантируете, что код MATLAB успешно генерирует MEX-функцию. Команда codegen, используемая, чтобы сгенерировать 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-функцию с симуляцией

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

Необходимо также проверять, что числовой вывод следует из 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 и имеют формат, который выглядит так фигура.

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. Для примера, который иллюстрирует обоих рабочие процессы, см. Код Пакета для Других Сред разработки (MATLAB Coder). Для получения дополнительной информации об опции packNGo смотрите packNGo в Методах информации о Сборке (MATLAB Coder). Можно переместить и распаковать сжатый zip-файл с помощью стандартной утилиты zip. Для примера о том, как группировать исполняемый файл, сгенерированный в этом примере, смотрите, Перемещают Код, Сгенерированный от кода MATLAB до Другой Среды разработки (DSP System Toolbox).

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

Функции

Похожие темы

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