Генерация модульного HDL-кода для функций

В этом примере показано, как сгенерировать модульный HDL-код из кода MATLAB ®, который содержит функции.

По умолчанию HDL Coder™ встроенное тело всех функций MATLAB, которые вызываются внутри тела проекта верхнего уровня. Это встраивание приводит к генерации одного файла, который содержит HDL-код для функций. Чтобы сгенерировать модульный HDL-код, используйте код Generate instantiable для настройки функций. Когда вы включаете эту настройку, HDL Coder генерирует одну сущность VHDL ® или модуль Verilog ® для каждой функции.

MATLAB фильтра LMS Проекта

Проект MATLAB, используемый в примере, является реализацией фильтра LMS (методом наименьших средних квадратов). Фильтр LMS является классом адаптивного фильтра, который идентифицирует сигнал конечной импульсной характеристики, который встроен в шум. Реализация создания фильтра LMS в MATLAB состоит из функции верхнего уровня mlhdlc_lms_fcn который вычисляет оптимальные коэффициенты фильтра, чтобы уменьшить различие между сигналом выхода и желаемым сигналом.

design_name = 'mlhdlc_lms_fcn';
testbench_name = 'mlhdlc_lms_fir_id_tb';

Проверьте проект MATLAB:

open(design_name);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% MATLAB Design: Adaptive Noise Canceler algorithm using Least Mean Square 
% (LMS) filter implemented in MATLAB
%
% Key Design pattern covered in this example: 
% (1) Use of function calls
% (2) Function inlining vs instantiation knobs available in the coder
% (3) Use of system objects in the testbench to stream test vectors into the design
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%#codegen
function [filtered_signal, y, fc] = mlhdlc_lms_fcn(input, ...
                                        desired, step_size, reset_weights)
% 'input'  : The signal from Exterior Mic which records the ambient noise.
% 'desired': The signal from Pilot's Mic which includes 
%            original music signal and the noise signal
% 'err_sig': The difference between the 'desired' and the filtered 'input'
%           It represents the estimated music signal (output of this block)
% 
% The LMS filter is trying to retrieve the original music signal('err_sig') 
% from Pilot's Mic by filtering the Exterior Mic's signal and using it to 
% cancel the noise in Pilot's Mic. The coefficients/weights of the filter 
% are updated(adapted) in real-time based on 'input' and 'err_sig'.

% register filter coefficients
persistent filter_coeff;
if isempty(filter_coeff)
    filter_coeff = zeros(1, 40);
end

% Variable Filter: Call 'tapped_delay_fcn' function on path to create 
% 40-step tapped delay
delayed_signal = mtapped_delay_fcn(input);

% Apply filter coefficients 
weight_applied = delayed_signal .* filter_coeff;

% Call treesum function on matlab path to sum up the results
filtered_signal = mtreesum_fcn(weight_applied);

% Output estimated Original Signal
td = desired;
tf = filtered_signal;
esig = td - tf;
y = esig;

% Update Weights: Call 'update_weight_fcn' function on MATLAB path to 
% calculate the new weights
updated_weight = update_weight_fcn(step_size, esig, delayed_signal, ...
                                   filter_coeff, reset_weights);

% update filter coefficients register
filter_coeff = updated_weight;
fc = filter_coeff;

function y = mtreesum_fcn(u)
%Implement the 'sum' function without a for-loop
%  y = sum(u);

%  The loop based implementation of 'sum' function is not ideal for 
%  HDL generation and results in a longer critical path. 
%  A tree is more efficient as it results in
%  delay of log2(N) instead of a delay of N delay

%  This implementation shows how to explicitly implement the vector sum in 
%  a tree shape to enable hardware optimizations.

%  The ideal way to code this generically for any length of 'u' is to use 
%  recursion but it is not currently supported by MATLAB Coder


% NOTE: To instruct MATLAB Coder to compile an external function, 
% add the following compilation directive or pragma to the function code
%#codegen

% This implementation is hardwired for a 40tap filter.

level1 = vsum(u);
level2 = vsum(level1);
level3 = vsum(level2);
level4 = vsum(level3);
level5 = vsum(level4);
level6 = vsum(level5);
y = level6;

function output = vsum(input)

coder.inline('always');

vt = input(1:2:end);
    
for i = int32(1:numel(input)/2)
    k = int32(i*2);
    vt(i) = vt(i) + input(k);
end

output = vt;

function tap_delay = mtapped_delay_fcn(input)
% The Tapped Delay function delays its input by the specified number 
% of sample periods, and outputs all the delayed versions in a vector
% form. The output includes current input

% NOTE: To instruct MATLAB Coder to compile an external function, 
% add the following compilation directive or pragma to the function code
%#codegen

persistent u_d;
if isempty(u_d)
    u_d = zeros(1,40);
end


u_d = [u_d(2:40), input];

tap_delay = u_d;

function weights = update_weight_fcn(step_size, err_sig, ... 
            delayed_signal, filter_coeff, reset_weights)
% This function updates the adaptive filter weights based on LMS algorithm

%   Copyright 2007-2015 The MathWorks, Inc.

% NOTE: To instruct MATLAB Coder to compile an external function, 
% add the following compilation directive or pragma to the function code
%#codegen

step_sig = step_size .* err_sig;
correction_factor = delayed_signal .* step_sig;
updated_weight = correction_factor + filter_coeff;

if reset_weights
    weights = zeros(1,40);
else    
    weights = updated_weight;
end

Функция MATLAB является модульной и использует функции:

  • mtapped_delay_fcn вычисление задержанных версий входного сигнала в векторной форме.

  • mtreesum_fcn для вычисления суммы приложенных весов в древовидной структуре. Индивидуальная сумма вычисляется с помощью vsum функция.

  • update_weight_fcn вычисление обновленных весов фильтра на основе наименьшего среднего квадратного алгоритма.

MATLAB фильтра LMS Испытательного стенда

Проверьте испытательный стенд MATLAB:

open(testbench_name);
clear ('mlhdlc_lms_fcn');
% returns an adaptive FIR filter System object, HLMS, that computes the 
% filtered output, filter error, and the filter weights for a given input 
% and desired signal using the Least MeanSquares (LMS) algorithm.

% Copyright 2011-2019 The MathWorks, Inc.

stepSize = 0.01;
reset_weights =false;

hfilt = dsp.FIRFilter;                     % System to be identified
hfilt.Numerator = fir1(10, .25);

rng('default');                            % always default to known state  
x = randn(1000,1);                         % input signal
d = step(hfilt, x) + 0.01*randn(1000,1);   % desired signal

hSrc = dsp.SignalSource(x);
hDesiredSrc = dsp.SignalSource(d);

hOut = dsp.SignalSink;
hErr = dsp.SignalSink;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Call to the design
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
while (~isDone(hSrc))
    [y, e, w] = mlhdlc_lms_fcn(step(hSrc), step(hDesiredSrc), ... 
                stepSize, reset_weights);
    step(hOut, y);
    step(hErr, e);
end

figure('Name', [mfilename, '_plot']);
subplot(2,1,1), plot(1:1000, [d,hOut.Buffer,hErr.Buffer]);
title('System Identification of an FIR filter');
legend('Desired', 'Output', 'Error');
xlabel('time index'); ylabel('signal value');
subplot(2,1,2); stem([hfilt.Numerator.', w(end-10:end).']);
legend('Actual','Estimated');
xlabel('coefficient #'); ylabel('coefficient value');

Протестируйте алгоритм MATLAB

Чтобы избежать ошибок времени выполнения, моделируйте проект с помощью испытательного стенда.

mlhdlc_lms_fir_id_tb

Создайте папку и скопируйте соответствующие файлы

Прежде чем вы сгенерируете HDL-код для проекта MATLAB, скопируйте файлы дизайна и испытательного стенда в папку с возможностью записи. Эти команды копируют файлы во временную папку.

mlhdlc_demo_dir = fullfile(matlabroot, 'toolbox', 'hdlcoder', 'hdlcoderdemos', 'matlabhdlcoderdemos');
mlhdlc_temp_dir = [tempdir 'mlhdlc_fcn_partition'];

Создайте временную папку и скопируйте файлы MATLAB.

cd(tempdir);
[~, ~, ~] = rmdir(mlhdlc_temp_dir, 's');
mkdir(mlhdlc_temp_dir);
cd(mlhdlc_temp_dir);
copyfile(fullfile(mlhdlc_demo_dir, [design_name,'.m*']), mlhdlc_temp_dir);
copyfile(fullfile(mlhdlc_demo_dir, [testbench_name,'.m*']), mlhdlc_temp_dir);

Создайте HDL Coder проект

Чтобы сгенерировать HDL-код из проекта MATLAB:

1. Создайте проект HDL Coder:

coder -hdlcoder -new mlhdlc_fcn_partition

2. Добавьте файл mlhdlc_lms_fcn.m к проекту в качестве функции MATLAB и mlhdlc_lms_fir_id_tb.m в качестве испытательного стенда MATLAB.

3. Щелкните Типы Autodefine, чтобы использовать рекомендуемые типы для входных и выходных входов функции MATLAB mlhdlc_lms_fcn.

Более полное руководство по созданию и заполнению проектов MATLAB HDL Coder см. в разделе «Начало работы с MATLAB в HDL».

Запуск преобразования с фиксированной точкой и генерации HDL-кода

  1. Нажмите кнопку Советник по рабочему процессу, чтобы запустить Советник по рабочему процессу.

  2. Щелкните правой кнопкой мыши Генерации HDL-кода задачу и выберите Запуск для выбранной задачи.

Один файл HDL mlhdlc_lms_fcn_FixPt.vhd генерируется для проекта MATLAB. Код VHDL для всех функций в проекте MATLAB вставлен в этот файл.

Сгенерируйте инстанцируемый HDL-код

  1. На вкладке Advanced установите флажок Generate instantiable code for functions.

  2. Нажмите кнопку Run, чтобы перезапустить Генерацию HDL-кода задачу.

Вы видите несколько HDL- файлов, которые содержат сгенерированный код для функции верхнего уровня и функций, которые вызываются внутри функции верхнего уровня. Смотрите также Сгенерируйте Instantiable Code для функций.

Управление инкрустацией для каждой функции

В некоторых случаях можно хотеть встроить HDL-код для вспомогательных функций и утилит и затем создать их экземпляры. Чтобы локально контролировать встраивание таких функций, используйте coder.inline прагма в коде MATLAB.

Чтобы вписать функцию в сгенерированный код, поместите эту директиву внутрь этой функции:

coder.inline('always')

Чтобы предотвратить встраивание функции в сгенерированный код, поместите эту директиву внутрь этой функции:

coder.inline('never')

Чтобы позволить генератору кода определить, вводить ли функцию в сгенерированный код, поместите эту директиву внутрь этой функции:

coder.inline('default')

Чтобы узнать, как использовать coder.inline pragma, введите:

help coder.inline

Ограничения для создания экземпляров HDL-кода из функций

  • Вызовы функций внутри условных выражений и циклов inlined и не являются экземплярами.

  • Функции с состояниями встроены.

Очистка сгенерированных файлов

Чтобы очистить временную папку проекта, запустите следующие команды:

mlhdlc_demo_dir = fullfile(matlabroot, 'toolbox', 'hdlcoder', 'hdlcoderdemos', 'matlabhdlcoderdemos');
mlhdlc_temp_dir = [tempdir 'mlhdlc_fcn_partition'];
clear mex;
cd (mlhdlc_demo_dir);
rmdir(mlhdlc_temp_dir, 's');