Этот пример иллюстрирует, как сгенерировать HDL-код для симметричного КИХ-фильтра с полностью параллельной, полностью последовательной, частично последовательной и каскадно-последовательной архитектурой для фильтра lowpass для приложения фильтрации аудио.
Используйте уровень выборки аудио 44,1 кГц и частоту ребра полосы пропускания 8,0 кГц. Установите допустимую пульсацию полосы пропускания от пика к пику на 1 дБ и затухание полосы задерживания к-90 дБ. Затем разработайте фильтр с помощью fdesign.lowpass и создайте КИХ-Системный объект фильтра с помощью 'equiripple' метода с 'Прямой формой симметричная' структура.
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);
Примите, что вход для аудиофильтра прибывает из ADC на 12 битов, и вывод является DAC на 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/BR2019ad_1062519_57051/mlx_to_docbook1/tp78d09c7a_d025_454a_a5ae_e36cf85f7a48/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 Гц) и одну частоту высокой группы (1 209 Гц, 1 336 Гц, 1477 Гц) и представляет уникальный символ. Вы будете генерировать все сигналы 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/BR2019ad_1062519_57051/mlx_to_docbook1/tp78d09c7a_d025_454a_a5ae_e36cf85f7a48/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'<br>Suggested Actions:<br> • Suppress future instances of this diagnostic from this source. - Suppress<br>
### Generating Test bench: /tmp/BR2019ad_1062519_57051/mlx_to_docbook1/tp78d09c7a_d025_454a_a5ae_e36cf85f7a48/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/BR2019ad_1062519_57051/mlx_to_docbook1/tp78d09c7a_d025_454a_a5ae_e36cf85f7a48/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
Сгенерируйте испытательный стенд тот же путь, как в полностью аналогичном случае. Важно сгенерировать испытательный стенд снова для каждой реализации архитектуры.
Полностью параллельный и полностью последовательный представляют два экстремальных значения реализаций. В то время как Полностью последовательный очень низкая область, ей по сути нужна более быстрая тактовая частота, чтобы действовать. Полностью параллельный берет много области чипа, но имеет очень хорошую производительность. Частично последовательная архитектура покрывает все случаи, которые находятся между этими двумя экстремальными значениями.
Входные касания разделены на наборы. Каждый набор обрабатывается параллельно последовательным разделом, состоящим из, умножаются, накапливаются и мультиплексор. Здесь, набор последовательных разделов обрабатывает данный набор касаний. Эти последовательные разделы управляют параллельно друг относительно друга, но процесса каждым касанием последовательно, чтобы накопить результат, соответствующий подаваемым касаниям. Наконец, результат каждого последовательного раздела добавляется вместе с помощью сумматоров.
Давайте примем, что вы хотите реализовать этот фильтр на 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/BR2019ad_1062519_57051/mlx_to_docbook1/tp78d09c7a_d025_454a_a5ae_e36cf85f7a48/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/BR2019ad_1062519_57051/mlx_to_docbook1/tp78d09c7a_d025_454a_a5ae_e36cf85f7a48/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, когда дополнительный такт требуется, чтобы завершать дополнительный шаг накопления.
Каскадно-последовательная архитектура может быть задана с помощью свойства '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/BR2019ad_1062519_57051/mlx_to_docbook1/tp78d09c7a_d025_454a_a5ae_e36cf85f7a48/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/BR2019ad_1062519_57051/mlx_to_docbook1/tp78d09c7a_d025_454a_a5ae_e36cf85f7a48/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 и испытательные стенды.