Этот пример иллюстрирует, как сгенерировать HDL-код для симметричного конечная импульсная характеристика с полностью параллельной, полностью последовательной, частично последовательной и каскадно-последовательной архитектурами для lowpass для приложения фильтрации аудио.
Используйте частоту дискретизации аудио 44,1 кГц и частоту ребра полосы пропускания 8,0 кГц. Установите допустимый пик-к-пику неравномерности в полосе пропускания равным 1 дБ, а затуханием в полосе задерживания равным -90 дБ. Затем разработайте фильтр с помощью fdesign.lowpass и создайте конечную импульсную характеристику Системного объекта фильтра с помощью метода 'equiripple' с симметричной структурой 'Direct form'.
Fs = 44.1e3; % Sampling Frequency in Hz Fpass = 8e3; % Passband Frequency in Hz Fstop = 8.8e3; % Stopband Frequency in Hz Apass = 1; % Passband Ripple in dB Astop = 90; % Stopband Attenuation in dB fdes = fdesign.lowpass('Fp,Fst,Ap,Ast',... Fpass, Fstop, Apass, Astop, Fs); lpFilter = design(fdes,'equiripple', 'FilterStructure', 'dfsymfir', ... 'SystemObject', true);
Предположим, что вход для аудиофильтра происходит от 12 бит АЦП, а выход является 12-битным ДАЦ.
nt_in = numerictype(1,12,11); nt_out = nt_in; lpFilter.FullPrecisionOverride = false; lpFilter.CoefficientsDataType = 'Custom'; lpFilter.CustomCoefficientsDataType = numerictype(1,16,16); lpFilter.OutputDataType = 'Custom'; lpFilter.CustomOutputDataType = nt_out; % Check the response with fvtool. fvtool(lpFilter,'Fs',Fs, 'Arithmetic', 'fixed');
Начиная с правильно квантованного фильтра, сгенерируйте код VHDL или Verilog. Создайте временную рабочую директорию. После генерации HDL-кода (выбор VHDL в данном случае) откройте сгенерированный VHDL- файла в редакторе нажав на гиперссылку, отображаемую в командной строке отображения сообщениями.
Это случай по умолчанию и генерирует полностью параллельную архитектуру. Существует выделенный множитель для каждого отвода фильтра в прямой форме конечной импульсной характеристики структуры фильтра и один для двух симметричных отводов в симметричной конечной импульсной характеристике структуре. Это приводит к большой площади микросхемы (78 умножителей, в этом примере). Можно реализовать фильтр в различных последовательных архитектурах, чтобы получить желаемый компромисс скорость/площадь. Они проиллюстрированы в последующих разделах этого примера.
workingdir = tempname; % fully parallel (default) generatehdl(lpFilter, 'Name', 'fullyparallel', ... 'TargetLanguage', 'VHDL', ... 'TargetDirectory', workingdir, ... 'InputDataType', nt_in);
### Starting VHDL code generation process for filter: fullyparallel ### Generating: /tmp/BR2021ad_1655202_180016/mlx_to_docbook2/tp82318ff2_aa22_4795_8726_127d9a22996f/fullyparallel.vhd ### Starting generation of fullyparallel VHDL entity ### Starting generation of fullyparallel VHDL architecture ### Successful completion of VHDL code generation process for filter: fullyparallel ### HDL latency is 2 samples
Сгенерируйте испытательный стенд VHDL, чтобы убедиться, что результат точно соответствует ответу, который вы видите в MATLAB ®. Сгенерированные VHDL- кода и VHDL-тестбенч можно скомпилировать и моделировать с помощью симулятора .
Сгенерируйте тональные сигналы DTMF, которые будут использоваться в качестве тестового стимула для фильтра. Сигнал DTMF состоит из суммы двух синусоидов - или тонов - с частотами, взятыми из двух взаимоисключающих групп. Каждая пара тонов содержит одну частоту низкой группы (697 Гц, 770 Гц, 852 Гц, 941 Гц) и одну частоту высокой группы (1209 Гц, 1336 Гц, 1477Hz) и представляет собой уникальный символ. Вы сгенерируете все сигналы DTMF, но используйте один из них (цифра 1 здесь) для тестирования стимула. Это обеспечит разумный предел длительности тестовых стимулов.
symbol = {'1','2','3','4','5','6','7','8','9','*','0','#'}; lfg = [697 770 852 941]; % Low frequency group hfg = [1209 1336 1477]; % High frequency group % Generate a matrix containing all possible combinations of high and low % frequencies, where each column represents one combination. f = zeros(2,12); for c=1:4 for r=1:3 f(:,3*(c-1)+r) = [lfg(c); hfg(r)]; end end
Далее давайте сгенерируем тональные сигналы DTMF
Fs = 8000; % Sampling frequency 8 kHz N = 800; % Tones of 100 ms t = (0:N-1)/Fs; % 800 samples at Fs pit = 2*pi*t; tones = zeros(N,size(f,2)); for toneChoice=1:12 % Generate tone tones(:,toneChoice) = sum(sin(f(:,toneChoice)*pit))'; end % Taking the tone for digit '1' for test stimulus. userstim = tones(:,1); generatehdl(lpFilter, 'Name', 'fullyparallel',... 'GenerateHDLTestbench','on', ... 'TestBenchUserStimulus', userstim,... 'TargetLanguage', 'VHDL',... 'TargetDirectory', workingdir, ... 'InputDataType', nt_in);
### Starting VHDL code generation process for filter: fullyparallel ### Generating: /tmp/BR2021ad_1655202_180016/mlx_to_docbook2/tp82318ff2_aa22_4795_8726_127d9a22996f/fullyparallel.vhd ### Starting generation of fullyparallel VHDL entity ### Starting generation of fullyparallel VHDL architecture ### Successful completion of VHDL code generation process for filter: fullyparallel ### HDL latency is 2 samples ### Starting generation of VHDL Test Bench. ### Generating input stimulus ### Done generating input stimulus; length 800 samples.
Warning: Wrap on overflow detected. This originated from 'DiscreteFir' Suggested Actions: • Suppress future instances of this diagnostic from this source. - Suppress
### Generating Test bench: /tmp/BR2021ad_1655202_180016/mlx_to_docbook2/tp82318ff2_aa22_4795_8726_127d9a22996f/fullyparallel_tb.vhd ### Creating stimulus vectors ... ### Done generating VHDL Test Bench.
Последовательные архитектуры представляют множество способов совместного использования аппаратных ресурсов за счет увеличения тактовой частоты относительно частоты дискретизации. В конечная импульсная характеристика мы будем делить множители между входами каждого последовательного раздела. Это будет иметь эффект увеличения тактовой частоты на множитель, известный как коэффициент складывания.
Можно использовать функцию hdlfilterserialinfo, чтобы получить информацию относительно различных длин фильтра на основе значения коэффициентов. Эта функция также отображает исчерпывающую таблицу возможных опций для задания свойства SerialPartition с соответствующими значениями коэффициента складывания и количества умножителей.
hdlfilterserialinfo(lpFilter, 'InputDataType', nt_in);
| Total Coefficients | Zeros | A/Symm | Effective | --------------------------------------------------- | 156 | 0 | 78 | 78 | Effective filter length for SerialPartition value is 78. Table of 'SerialPartition' values with corresponding values of folding factor and number of multipliers for the given filter. | Folding Factor | Multipliers | SerialPartition | ------------------------------------------------------ | 1 | 78 |ones(1,78) | | 2 | 39 |ones(1,39)*2 | | 3 | 26 |ones(1,26)*3 | | 4 | 20 |[ones(1,19)*4, 2] | | 5 | 16 |[ones(1,15)*5, 3] | | 6 | 13 |ones(1,13)*6 | | 7 | 12 |[ones(1,11)*7, 1] | | 8 | 10 |[ones(1,9)*8, 6] | | 9 | 9 |[9 9 9 9 9 9 9 9 6] | | 10 | 8 |[ones(1,7)*10, 8] | | 11 | 8 |[ones(1,7)*11, 1] | | 12 | 7 |[ones(1,6)*12, 6] | | 13 | 6 |[13 13 13 13 13 13] | | 14 | 6 |[14 14 14 14 14 8] | | 15 | 6 |[15 15 15 15 15 3] | | 16 | 5 |[16 16 16 16 14] | | 17 | 5 |[17 17 17 17 10] | | 18 | 5 |[18 18 18 18 6] | | 19 | 5 |[19 19 19 19 2] | | 20 | 4 |[20 20 20 18] | | 21 | 4 |[21 21 21 15] | | 22 | 4 |[22 22 22 12] | | 23 | 4 |[23 23 23 9] | | 24 | 4 |[24 24 24 6] | | 25 | 4 |[25 25 25 3] | | 26 | 3 |[26 26 26] | | 27 | 3 |[27 27 24] | | 28 | 3 |[28 28 22] | | 29 | 3 |[29 29 20] | | 30 | 3 |[30 30 18] | | 31 | 3 |[31 31 16] | | 32 | 3 |[32 32 14] | | 33 | 3 |[33 33 12] | | 34 | 3 |[34 34 10] | | 35 | 3 |[35 35 8] | | 36 | 3 |[36 36 6] | | 37 | 3 |[37 37 4] | | 38 | 3 |[38 38 2] | | 39 | 2 |[39 39] | | 40 | 2 |[40 38] | | 41 | 2 |[41 37] | | 42 | 2 |[42 36] | | 43 | 2 |[43 35] | | 44 | 2 |[44 34] | | 45 | 2 |[45 33] | | 46 | 2 |[46 32] | | 47 | 2 |[47 31] | | 48 | 2 |[48 30] | | 49 | 2 |[49 29] | | 50 | 2 |[50 28] | | 51 | 2 |[51 27] | | 52 | 2 |[52 26] | | 53 | 2 |[53 25] | | 54 | 2 |[54 24] | | 55 | 2 |[55 23] | | 56 | 2 |[56 22] | | 57 | 2 |[57 21] | | 58 | 2 |[58 20] | | 59 | 2 |[59 19] | | 60 | 2 |[60 18] | | 61 | 2 |[61 17] | | 62 | 2 |[62 16] | | 63 | 2 |[63 15] | | 64 | 2 |[64 14] | | 65 | 2 |[65 13] | | 66 | 2 |[66 12] | | 67 | 2 |[67 11] | | 68 | 2 |[68 10] | | 69 | 2 |[69 9] | | 70 | 2 |[70 8] | | 71 | 2 |[71 7] | | 72 | 2 |[72 6] | | 73 | 2 |[73 5] | | 74 | 2 |[74 4] | | 75 | 2 |[75 3] | | 76 | 2 |[76 2] | | 77 | 2 |[77 1] | | 78 | 1 |[78] |
Можно использовать дополнительные свойства 'Multipliers' и 'FoldingFactor', чтобы отобразить конкретную информацию.
hdlfilterserialinfo(lpFilter, 'Multipliers', 4, ... 'InputDataType', nt_in);
Serial Partition: [20 20 20 18], Folding Factor: 20, Multipliers: 4
hdlfilterserialinfo(lpFilter, 'Foldingfactor', 6, ... 'InputDataType', nt_in);
Serial Partition: ones(1,13)*6, Folding Factor: 6, Multipliers: 13
В полностью последовательной архитектуре вместо того, чтобы иметь выделенный умножитель для каждого отвода, входная выборка для каждого отвода выбирается последовательно и умножается на соответствующий коэффициент. Для симметричных (и антисимметричных) структур входные выборки, соответствующие каждому набору симметричных отводов, предварительно складываются (для симметричных) или предварительно вычитаются (для антисимметричных) перед умножением соответствующими коэффициентами. Продукт накапливается последовательно с использованием регистра, и конечный результат сохраняется в регистре до прибытия следующего набора входа отсчетов. Этой реализации нужна тактовая частота, которая в столько раз быстрее, чем входная частота выборки, сколько количество вычисляемых продуктов. Это приводит к уменьшению необходимой площади микросхемы, поскольку реализация включает только один умножитель с несколькими дополнительными логическими элементами, такими как мультиплексоры и регистры. Тактовая частота будет в 78 раз выше входной частоты выборки (foldingfactor из 78), равной 3,4398 МГц для этого примера.
Чтобы реализовать полностью последовательную архитектуру, используйте функцию hdlfilterserialinfo и установите ее свойство 'Multipliers' равным 1. Можно также задать свойство 'SerialPartition' с его значением, равным эффективной длине фильтра, которая в этом случае равна 78. Функция также возвращает коэффициент складывания и количество умножителей, используемых для этой настройки последовательного раздела.
[spart, foldingfact, nMults] = hdlfilterserialinfo(lpFilter, 'Multipliers', 1, ... 'InputDataType', nt_in); %#ok<ASGLU> generatehdl(lpFilter,'Name', 'fullyserial', ... 'SerialPartition', spart, ... 'TargetLanguage', 'VHDL', ... 'TargetDirectory', workingdir, ... 'InputDataType', nt_in);
### Starting VHDL code generation process for filter: fullyserial ### Generating: /tmp/BR2021ad_1655202_180016/mlx_to_docbook2/tp82318ff2_aa22_4795_8726_127d9a22996f/fullyserial.vhd ### Starting generation of fullyserial VHDL entity ### Starting generation of fullyserial VHDL architecture ### Clock rate is 78 times the input sample rate for this architecture. ### Successful completion of VHDL code generation process for filter: fullyserial ### HDL latency is 3 samples
Сгенерируйте тестбенч так же, как и в полностью параллельном случае. Важно снова сгенерировать testbench для каждой реализации архитектуры.
Полностью параллельные и полностью последовательные представляют две крайности реализаций. Несмотря на то, что Fully serial очень низкая площадь, для работы по своей сути требуется более высокая тактовая частота. Полностью параллельная занимает много площади чипа, но имеет очень хорошую эффективность. Частично последовательная архитектура охватывает все случаи, которые находятся между этими двумя крайностями.
Входные отводы разделены на наборы. Каждый набор обрабатывается параллельно последовательным разбиением, состоящим из умноженного накопления и мультиплексора. Здесь набор последовательных разделов обрабатывает данный набор ответвлений. Эти последовательные перегородки работают параллельно друг другу, но обрабатывают каждый отгиб последовательно, чтобы накопить результат, соответствующий обслуживаемым отводам. Наконец, результат каждого последовательного раздела складывается вместе с помощью сумматоров.
Предположим, что вы хотите реализовать этот фильтр на FPGA, который имеет только 4 умножителя, доступных для фильтра. Можно реализовать фильтр с помощью 4 последовательных разделов, каждый с помощью одной схемы умножения накопления.
hdlfilterserialinfo(lpFilter, 'Multipliers', 4, ... 'InputDataType', nt_in);
Serial Partition: [20 20 20 18], Folding Factor: 20, Multipliers: 4
Входные отводы, которые обрабатываются этими последовательными разделами, будут [20 20 20 18]. Вы задаете SerialPartition с этим вектором, указывающим на разложение отводов для последовательных разделов. Тактовая частота определяется самым большим элементом этого вектора. В этом случае тактовая частота будет в 20 раз выше входной частоты выборки, 0,882 МГц.
[spart, foldingfact, nMults] = hdlfilterserialinfo(lpFilter, 'Multipliers', 4, ... 'InputDataType', nt_in); generatehdl(lpFilter,'Name', 'partlyserial1',... 'SerialPartition', spart,... 'TargetLanguage', 'VHDL', ... 'TargetDirectory', workingdir, ... 'InputDataType', nt_in);
### Starting VHDL code generation process for filter: partlyserial1 ### Generating: /tmp/BR2021ad_1655202_180016/mlx_to_docbook2/tp82318ff2_aa22_4795_8726_127d9a22996f/partlyserial1.vhd ### Starting generation of partlyserial1 VHDL entity ### Starting generation of partlyserial1 VHDL architecture ### Clock rate is 20 times the input sample rate for this architecture. ### Successful completion of VHDL code generation process for filter: partlyserial1 ### HDL latency is 3 samples
Предположим, что у вас есть ограничение на тактовую частоту для реализации фильтра, и максимальная тактовая частота составляет 2 МГц. Это означает, что тактовая частота не может быть более чем в 45 раз больше входной частоты выборки. Для такого ограничения проекта значение 'SerialPartition' должно быть задано как [45 33]. Обратите внимание, что это приводит к дополнительному аппаратному оборудованию последовательного разбиения, подразумевающему дополнительную схему для умножения-накопления 33 отводов. Можно задать SerialPartition с помощью hdlfilterserialinfo и его свойства 'Foldingfactor' следующим образом.
spart = hdlfilterserialinfo(lpFilter, 'Foldingfactor', 45, ... 'InputDataType', nt_in); generatehdl(lpFilter,'Name', 'partlyserial2', ... 'SerialPartition', spart,... 'TargetLanguage', 'VHDL',... 'TargetDirectory', workingdir, ... 'InputDataType', nt_in);
### Starting VHDL code generation process for filter: partlyserial2 ### Generating: /tmp/BR2021ad_1655202_180016/mlx_to_docbook2/tp82318ff2_aa22_4795_8726_127d9a22996f/partlyserial2.vhd ### Starting generation of partlyserial2 VHDL entity ### Starting generation of partlyserial2 VHDL architecture ### Clock rate is 45 times the input sample rate for this architecture. ### Successful completion of VHDL code generation process for filter: partlyserial2 ### HDL latency is 3 samples
В целом можно задать любое произвольное разложение отводов для последовательных разбиений в зависимости от других ограничений. Единственным требованием является то, что сумма элементов вектора должна быть равной эффективной длине фильтра.
Аккумуляторы в последовательных перегородках могут быть повторно использованы, чтобы добавить результат следующего последовательного разбиения. Это возможно, если количество отводов, обрабатываемых одним последовательным разделом, должно быть больше, чем число отводов, обрабатываемых рядом с ним, по меньшей мере, на 1. Преимущество этого метода заключается в том, что набор сумматоров, необходимых для добавления результата всех последовательных разделов, удаляется. Однако это увеличивает тактовую частоту на 1, так как для завершения дополнительного шага накопления требуется дополнительный тактовый цикл.
Архитектура Cascade-Serial может быть задана с помощью свойства 'ReuseAccum'. Это можно сделать двумя способами.
Добавьте 'ReuseAccum' в метод generatehdl и укажите его как 'on'. Обратите внимание, что значение, заданное для свойства 'SerialPartition', должно быть таким, чтобы повторное использование аккумулятора было допустимым. Элементы вектора должны быть в порядке убывания, кроме последних двух, которые могут быть одинаковыми.
Если свойство 'SerialPartition' не задано и 'ReuseAccum' задано как 'on', разложение отводов для последовательных разделов определяется внутренне. Это делается, чтобы минимизировать тактовую частоту и повторно использовать аккумулятор. Для этого аудиофильтра это [12 11 10 9 8 7 6 5 4 3 3]. Обратите внимание, что он использует 11 последовательных разбиений, что подразумевает 11 умножение схем накопления. Тактовая частота будет в 13 раз выше входной выборки, 573,3 кГц .
generatehdl(lpFilter,'Name', 'cascadeserial1',... 'SerialPartition', [45 33],... 'ReuseAccum', 'on', ... 'TargetLanguage', 'VHDL', ... 'TargetDirectory', workingdir, ... 'InputDataType', nt_in);
### Starting VHDL code generation process for filter: cascadeserial1 ### Generating: /tmp/BR2021ad_1655202_180016/mlx_to_docbook2/tp82318ff2_aa22_4795_8726_127d9a22996f/cascadeserial1.vhd ### Starting generation of cascadeserial1 VHDL entity ### Starting generation of cascadeserial1 VHDL architecture ### Clock rate is 46 times the input sample rate for this architecture. ### Successful completion of VHDL code generation process for filter: cascadeserial1 ### HDL latency is 3 samples
Оптимальное разложение на столько последовательных разделов, сколько требуется для минимальной тактовой частоты, возможной для повторного использования аккумулятора.
generatehdl(lpFilter,'Name', 'cascadeserial2', ... 'ReuseAccum', 'on',... 'TargetLanguage', 'VHDL',... 'TargetDirectory', workingdir, ... 'InputDataType', nt_in);
### Starting VHDL code generation process for filter: cascadeserial2 ### Generating: /tmp/BR2021ad_1655202_180016/mlx_to_docbook2/tp82318ff2_aa22_4795_8726_127d9a22996f/cascadeserial2.vhd ### Starting generation of cascadeserial2 VHDL entity ### Starting generation of cascadeserial2 VHDL architecture ### Clock rate is 13 times the input sample rate for this architecture. ### Serial partition # 1 has 12 inputs. ### Serial partition # 2 has 11 inputs. ### Serial partition # 3 has 10 inputs. ### Serial partition # 4 has 9 inputs. ### Serial partition # 5 has 8 inputs. ### Serial partition # 6 has 7 inputs. ### Serial partition # 7 has 6 inputs. ### Serial partition # 8 has 5 inputs. ### Serial partition # 9 has 4 inputs. ### Serial partition # 10 has 3 inputs. ### Serial partition # 11 has 3 inputs. ### Successful completion of VHDL code generation process for filter: cascadeserial2 ### HDL latency is 3 samples
Вы разработали lowpass прямую форму симметричной конечной импульсной характеристики, чтобы соответствовать заданной спецификации. Затем вы квантовали и проверили свой проект. Вы сгенерировали код VHDL для полностью параллельной, полностью последовательной, частично последовательной и каскадно-последовательной архитектур. Вы сгенерировали испытательный стенд VHDL, используя тональный сигнал DTMF для одной из архитектур.
Можно использовать Симулятор HDL, чтобы проверить сгенерированный HDL-код для различных последовательных архитектур. Можно использовать инструмент синтеза, чтобы сравнить площадь и скорость этих архитектур. Вы также можете экспериментировать и генерировать код Verilog и испытательные стенды.