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