MATLAB® Coder™ генерирует высоко оптимизированный ANSI C и Код С++ от функций и Системных объектов в 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 и могут содержать визуализацию и другие инструменты верификации, которые не являются на самом деле частью системы под тестом. Например, в Построении Синусоидальный Сигнал Используя Высокий энергетический Содействующий пример БПФ, функции 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. Для списка поддерживаемых построений языка смотрите Функции языка 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-функции не только, чтобы обнаружить генерацию кода и проблемы во время выполнения, но также и ускорить определенные части вашего алгоритма. Для примера смотрите Ускорение алгоритма Обработки сигналов в 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 и имеют формат, который выглядит так фигура.
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 до Другой Среды разработки.