exponenta event banner

Создание модульного кода HDL для функций

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

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

Конструкция фильтра LMS MATLAB

Конструкция MATLAB, используемая в примере, является реализацией фильтра LMS (наименьшие средние квадраты). Фильтр LMS является классом адаптивного фильтра, который идентифицирует сигнал фильтра FIR, который встроен в шум. Реализация конструкции фильтра 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

Для создания кода HDL из конструкции MATLAB:

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

coder -hdlcoder -new mlhdlc_fcn_partition

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

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

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

Выполнение преобразования с фиксированной точкой и создание кода HDL

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

  2. Щелкните правой кнопкой мыши задачу Создание кода HDL и выберите Выполнить для выбранной задачи.

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

Создание кода HDL с возможностью создания экземпляров

  1. На вкладке Дополнительно установите флажок Генерировать код экземпляра для функций.

  2. Нажмите кнопку Run для повторного запуска задачи создания кода HDL.

Отображается несколько HDL-файлов, содержащих созданный код для функции верхнего уровня и функций, вызываемых внутри функции верхнего уровня. См. также раздел Создание кода экземпляра для функций.

Включение управления для каждой функции

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

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

coder.inline('always')

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

coder.inline('never')

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

coder.inline('default')

Как использовать coder.inline pragma, введите:

help coder.inline

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

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

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

Очистка созданных файлов

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

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');