4.10 - DCF IIR исследования

В качестве временной и не только, замены аппаратного фильтра VCF разрабатывается модуль программной фильтрации. Принцип перестройки частоты выбран тот же, что и у фильтров, которые собрались применять в аппаратной части: перестройкой частоты дискретизации. Для расчета применяется программа Nullhertz Filter Solutions, которая может рассчитывать разные фильтры и цифровые в том числе.

Тип фильтра выбрал БИХ. Порядок для начала 2-й. Частота среза выбрана 100 Гц, а частота дискретизации выбрана больше частоты среза в 2^8 степени раз. Зависимость частоты дискретизации от частоты сигнала кратная степени двойки в будущем позволить экономить на вычислении значения приращения DDS. Потребуется взять приращение VCO и сдвинуть на 8 бит.

После рассчета программа выдает исходный код на C++ одекватно, к сожалению, только для floatpoint. Для fixed и signed есть пересчет только для формулы, которая выводится на экран. И еще для целочисленных вычислений есть вывод сообщения об ошибке, если бит недостаточно. Для устранения проблемы можно масштабировать коэффициенты, но как это применять - не понятно.

Получившийся код

float DigFil(invar)float invar;/******************************************************************************//* Filter Solutions Version 2011 Nuhertz Technologies, L.L.C. *//* www.nuhertz.com *//* +1 602-279-2448 *//* 2nd Order Low Pass Butterworth *//* Bilinear Transformation with Prewarping *//* Sample Frequency = 25.60 KHz *//* Standard Form *//* Arithmetic Precision = 10 Digits *//* *//* Pass Band Frequency = 100.0 Hz *//* *//******************************************************************************//* *//* Input Variable Definitions: *//* Inputs: *//* invar float The input to the filter *//* *//* Option Selections: *//* Standard C; Not Initializable; Internal States; Not Optimized; *//* *//* There is no requirement to ever initialize the filter. *//* The default initialization is zero when the filter is first called *//* *//******************************************************************************//* *//* This software is automatically generated by Filter Solutions *//* no restrictions from Nuhertz Technologies, L.L.C. regarding the use and *//* distributions of this software. *//* *//******************************************************************************/{ float sumnum=0.0, sumden=0.0; int i=0; static float states[2] = {0.0,0.0}; static float znum[3] = { 1.480219865e-04, 2.960439731e-04, 1.480219865e-04 }; static float zden[2] = { .9658854606, -1.965293373 }; sumnum = sumden = 0.0; for (i=0;i<2;i++){ sumden += states[i]*zden[i]; sumnum += states[i]*znum[i]; if (i<1) states[i] = states[i+1]; } states[1] = invar-sumden; sumnum += states[1]*znum[2]; return sumnum;}

Преобразовал в Verilog float

`timescale 1us / 100 ps`define HalfPeriod 1.0 // 1 ns half-period at 500 KHz//`define OneUS 1000.0 // 1 us или мкс//`define OneMS 1000000.0 // 1 ms или мс//1 MHz период такта 1usmodule testbench();reg tb_clk;// DDS - расчет значения регистра для заданной частоты//32 бита это 4294967296//частота дискретизации//делим 25500Hz / 500 000 Hz / 2 * 4294967296 => 109521666,048//частота сигнала//делим 100Hz / 500 000 Hz / 2 * 4294967296 => 429496,7296wire [31:0] clk_f; dds32 clk255(tb_clk, 32'd109521666, clk_f);wire [31:0] sig; dds32 clk100(tb_clk, 32'd429496, sig);wire clk25500;assign clk25500 = clk_f[31:31];wire signed [15:0] sign;assign sign = sig[31:31-7] - 128; real states0, states1, states2; real znum0, znum1, znum2, znum3; real zden0, zden1, zden2; real sumden, sumnum; real result;reg [15:0] val1;wire [15:0] val2;assign val2 = val1 << 8; initial begin $dumpfile("bench.vcd"); $dumpvars(0,testbench); $display("starting testbench!!!!"); tb_clk = 0; val1 = 100; repeat (500000) begin #`HalfPeriod; tb_clk = 1; #`HalfPeriod; tb_clk = 0; end $display("finished OK!"); //$finish;end initial begin states0=0; states1=0; states2=0; znum0=0; znum1=0.00017304321; znum2=0.00034608643; znum3=0.00017304321; zden0=0.15452064; zden1=0.65132883; zden2=-1.8051573; sumden=0; sumnum=0;endalways @(posedge clk25500) begin sumden = (states0*zden0)+(states1*zden1)+(states2*zden2); sumnum = (states0*znum0)+(states1*znum1)+(states2*znum1); states0 = states1; states1 = states2; states2 = sign - sumden; sumnum = sumnum + (states2*znum3); result = sumnum;endendmodul

Но Float нет в аппаратной реализации Altera quartus. Долго читал, искал. Сначала хотел найти библиотеку для преобразования в IEEE Float и умножения, сложения. Потом, всетаки попробовал fixed point, который изначально не заработал. Потом fixed point был побежден. Основная суть в следующем:

1) берется фильтр и ВСЕ данные у него умножаются на 2^Х. Чтобы уместились самые маленькие числа

2) если два числа масштабированы, допустим, на 2^32, то есть сдвинуты на 32 бита, то после их умножения, результат нужно сдвинуть обратно на 32 бита >> 32. А если числа со знаком, то >>> 32.

3) при перемножении двух чисел, результат нужно присваивать промежуточному регистру, разрядность которого больше этих двух чисел в два раза (?вот тут не совсем точно?).

И вот, наконец-то, после долгих неудачных попыток, удалось сделать фильтр на целых числах. Но компиляция его в проект Quartus заняла все свободные умножители и 2600 ячеек, при этом еще и 2 - 3 сотни варнингов.

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

Вернул обратно. Белый шум, пропущенный через ФНЧ выглядит похоже на дело. Однако, сигнал генератора, пропущенный через фильтр, тикает раз в 10 секунд. Сложно сказать, ошибка ли это округления, либо проблемы в синхронизации внутри ПЛИС