VHDL의 FIR / IIR 필터에 대한 코드 예?


11

스파르탄 -3 보드에서 DSP를 시작하려고합니다. 오래된 마더 보드의 칩으로 AC97 보드를 만들었고 지금까지 ADC를 수행하여 샘플 수를 1보다 작게 (볼륨 감소) DAC했습니다.

이제 저역 통과 필터, 고역 통과와 같은 기본적인 DSP 작업을하고 싶습니다.하지만 숫자 표현 (정수? 고정 소수점? Q0.15? 오버플로 또는 채도)에 대해 정말로 혼란 스럽습니다.

시작하기 위해 실제 간단한 필터 의 예제 코드를 원합니다 . 고효율, 빠름 또는 이와 유사한 것은 없습니다. VHDL에서 구현 된 이론적 필터입니다.

나는 검색했지만 이론적 인 공식을 찾았습니다. 이해할 수없는 것은 ADC에서 가져 오는 부호있는 16 비트, 48KHz 오디오 샘플을 처리하는 방법입니다. http://www.vhdl.org/fphdl/ 라이브러리를 사용하고 있습니다. 샘플에 0.5, 0.25 등을 곱하면 차이를들을 수 있습니다. 그러나 더 큰 필터는 소음을 줄뿐입니다.

감사.


2
내가 배우는 것을 위해 손에 든 것을 모두 사용하고 있지만 FPGA에서 오디오 필터를 수행하는 것이 그렇게 효율적이거나 비용 효율적인 방법이 아니라는 점을 지적하고 싶습니다. 따라서 실제 프로젝트를 수행하는 경우 저비용 DSP를 대신 사용하는 것이 좋습니다. 예외 : 불경건 한 수의 오디오 채널을 동시에 수행하거나 탭 수가 불합리한 FIR을 수행하는 경우.

답변:


8

DSP 측면을 먼저 파악한 다음 FPGA로 구현해야하는 것처럼 들린다.

  • C, Matlab, Excel 또는 다른 곳에서 DSP 정렬
  • 배운 것을 FPGA 랜드로 어떻게 이전 할 것인지 생각해보십시오.
  • 제대로 작동하지 않는 구현에 대한 가정을 세웠습니다 (예 : 부동 소수점 사용).
  • 다시 돌아가서 오프라인 DSP를 업데이트하여이를 고려하십시오.
  • n 번 반복 :)

데이터 유형과 관련하여 정수를 잘 사용할 수 있습니다.

다음은 샘플 코드입니다. 실제 문제 (예 : 재설정, 오버플로 관리)가 많이 누락되어 있지만 유익한 정보가 있기를 바랍니다.

library ieee;
use ieee.std_logic_1164.all;
entity simple_fir is
    generic (taps : integer_vector); 
    port (
        clk      : in  std_logic;
        sample   : in  integer;
        filtered : out integer := 0);
end entity simple_fir;
----------------------------------------------------------------------------------------------------------------------------------
architecture a1 of simple_fir is
begin  -- architecture a1
    process (clk) is
        variable delay_line : integer_vector(0 to taps'length-1) := (others => 0);
        variable sum : integer;
    begin  -- process
        if rising_edge(clk) then  -- rising clock edge
            delay_line := sample & delay_line(0 to taps'length-2);
            sum := 0;
            for i in 0 to taps'length-1 loop
                sum := sum + delay_line(i)*taps(taps'high-i);
            end loop;
            filtered <= sum;
        end if;
    end process;
end architecture a1;
----------------------------------------------------------------------------------------------------------------------------------
-- testbench
----------------------------------------------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity tb_simple_fir is
end entity tb_simple_fir;
architecture test of tb_simple_fir is
    -- component generics
    constant lp_taps : integer_vector := ( 1, 1, 1, 1, 1);
    constant hp_taps : integer_vector := (-1, 0, 1);

    constant samples : integer_vector := (0,0,0,0,1,1,1,1,1);

    signal sample   : integer;
    signal filtered : integer;
    signal Clk : std_logic := '1';
    signal finished : std_logic;
begin  -- architecture test
    DUT: entity work.simple_fir
        generic map (taps => lp_taps)  -- try other taps in here
        port map (
            clk      => clk,
            sample   => sample,
            filtered => filtered);

    -- waveform generation
    WaveGen_Proc: process
    begin
        finished <= '0';
        for i in samples'range loop
            sample <= samples(i);
            wait until rising_edge(clk);
        end loop;
        -- allow pipeline to empty - input will stay constant
        for i in 0 to 5 loop
            wait until rising_edge(clk);
        end loop;
        finished <= '1';
        report (time'image(now) & " Finished");
        wait;
    end process WaveGen_Proc;

    -- clock generation
    Clk <= not Clk after 10 ns when finished /= '1' else '0';
end architecture test;

답변 주셔서 감사합니다. 그것은 내가 한 일이 다소 많지만 숫자 표현에 문제가 있습니다. 내 ADC는 -32k ~ + 32k (16 비트 부호)의 값을 제공합니다. 또한 필터 상수 문제가 있습니다. 어떻게 표현합니까? 그리고 표본과 상수를 곱한 결과는? 그것이 가장 혼란스러운 부분입니다.
hjf 2016 년

@ hjf-모두 정수입니다. 모든 것이 32 비트 내에 머무르면 괜찮습니다. 너비보다 더 넓은 너비가 필요한 경우 원하는만큼 넓은 너비의 부호없는 벡터 나 부호있는 벡터를 사용할 수 있습니다. 또는 VHDL2008의 fixed_point 유형을 사용하십시오 (여기 : vhdl.org/fphdl 참조 )
Martin Thompson

5

시도 할 수있는 가장 간단한 저역 통과 FIR 필터는 y (n) = x (n) + x (n-1)입니다. VHDL에서이를 쉽게 구현할 수 있습니다. 아래는 구현하려는 하드웨어의 매우 간단한 블록 다이어그램입니다.

간단한 저역 통과 필터의 블록 다이어그램

공식에 따르면 적절한 출력을 얻으려면 전류 및 이전 ADC 샘플이 필요합니다. 해야 할 일은 들어오는 ADC 샘플을 클럭의 하강 에지에서 래치하고 적절한 출력을 얻기 위해 상승 에지에서 적절한 계산을 수행하는 것입니다. 두 개의 16 비트 값을 함께 추가하므로 17 비트 응답으로 끝날 수 있습니다. 입력을 17 비트 레지스터에 저장하고 17 비트 가산기를 사용해야합니다. 그러나 출력은 답의 하위 16 비트가됩니다. 코드는 다음과 같이 보일 수 있지만 테스트하지 않았으므로 코드가 합성되지 않았으므로 코드가 완전히 작동한다고 보장 할 수 없습니다.

IEEE.numeric_std.all;
...
    signal x_prev, x_curr, y_n: signed(16 downto 0);
    signal filter_out: std_logic_vector(15 downto 0);
...
process (clk) is
begin
    if falling_edge(clk) then
        --Latch Data
        x_prev <= x_curr;
        x_curr <= signed('0' & ADC_output); --since ADC is 16 bits
    end if;
end process;

process (clk) is
begin
    if rising_edge(clk) then
        --Calculate y(n)
        y_n <= x_curr + x_prev;
    end if;
end process;

filter_out <= std_logic_vector(y_n(15 downto 0));  --only use the lower 16 bits of answer

보시다시피이 일반적인 아이디어를 사용하여 계수가있는 수식과 같이 더 복잡한 수식을 추가 할 수 있습니다. IIR 필터와 같은보다 복잡한 공식은 알고리즘 논리를 올바르게 얻기 위해 변수를 사용해야 할 수 있습니다. 마지막으로, 계수로 실수가있는 필터를 쉽게 해결할 수있는 방법은 모든 계수가 가능한 한 정수에 가까워 지도록 배율을 찾는 것입니다. 올바른 결과를 얻으려면 최종 결과를 동일한 요소로 축소해야합니다.

나는 이것이 당신에게 유용 할 수 있기를 바랍니다.

* 데이터 래칭과 출력 래칭이 별도의 프로세스에 있도록 편집되었습니다. 또한 std_logic_vector 대신 부호있는 유형을 사용합니다. ADC 입력이 std_logic_vector 신호가 될 것이라고 가정합니다.


2
두 가장자리를 모두 촉발시키는 프로세스는 설명하기 어렵습니다.
Martin Thompson

@Martin 나는 당신이 나보다 FPGA에 대해 더 많이 알고 있다고 가정하지만 클래스 할당을 위해 들어오는 데이터를 하강 에지에 래치하고 상승 에지에 래치 출력을 래치하여 이것이 효과가 있다고 생각했습니다. 그러한 프로세스가 작동하지 않는 이유를 설명 할 수 있습니까?
dhsieh2 2016 년

3
시뮬레이터에서 잘 작동합니다. 장치의 플립 플롭은 쪽 가장자리 에서만 클럭 할 수 있기 때문에 신디사이저는 (내 경험상) 그것을 질식시킬 것이다 .
Martin Thompson

@ dhsieh2 감사합니다. 이것은 제가 찾던 답변입니다. 또 다른 질문은 부호있는 숫자를 사용하는 경우 어떻게해야합니까 (내 ADC는 -32k ~ + 32k의 값을 제공합니다).
hjf 2016 년

4
@Martin 자일링스 FPGA에서 항상 두 클럭 에지를 모두 클럭킹한다. 양쪽 가장자리에서 동일한 FF를 클록 할 수는 없습니다. 타이밍 분석기 출력을 살펴보면 실제로 반대쪽 가장자리를하고 있음을 분명히하고 타이밍 예산을 적절하게 조정합니다.

5

또 다른 간단한 코드 스 니펫 (직장). 참고 VHDL을 직접 쓰지 않았고 MyHDL을 사용하여 VHDL을 생성했습니다.

-- VHDL code snip
architecture MyHDL of sflt is

type t_array_taps is array(0 to 6-1) of signed (15 downto 0);
signal taps: t_array_taps;

begin

SFLT_RTL_FILTER: process (clk) is
    variable sum: integer;
begin
    if rising_edge(clk) then
        sum := to_integer(x * 5580);
        sum := to_integer(sum + (taps(0) * 5750));
        sum := to_integer(sum + (taps(1) * 6936));
        sum := to_integer(sum + (taps(2) * 6936));
        sum := to_integer(sum + (taps(3) * 5750));
        sum := to_integer(sum + (taps(4) * 5580));
        taps(0) <= x;
        for ii in 1 to 5-1 loop
            taps(ii) <= taps((ii - 1));
        end loop;
        y <= to_signed(sum, 16);
    end if;
end process SFLT_RTL_FILTER;

end architecture MyHDL;

합성 회로

이것은 직접 구현입니다. 승수가 필요합니다. Altera Cyclone III을 대상으로하는이 회로의 합성에는 명시적인 승수를 사용하지 않았지만 350 개의 논리 요소가 필요했습니다.

이것은 작은 FIR 필터이며 다음과 같은 응답을 갖지만 예를 들어 유용합니다.

필터 응답

또한 여기여기 에 유용한 몇 가지 예가 있습니다.

또한 귀하의 질문은 "적절한 고정 소수점 표현은 무엇입니까?" DSP 기능을 구현할 때 필터 분석을 단순화하기 때문에 고정 소수점 표현이 자주 사용됩니다. 언급했듯이 고정 소수점은 정수 arthimetic입니다. 실제 구현은 단순히 정수를 사용하는 것이지만 우리가 생각한 표현은 소수입니다.
일반적으로 구현 정수 (고정 소수점)를 부동 소수점 디자인으로 변환 할 때 문제가 발생합니다.

VHDL 고정 소수점 및 부동 소수점 유형이 얼마나 잘 지원되는지 모르겠습니다. 그것들은 시뮬레이션에서 잘 작동하지만 대부분의 합성 도구로 합성할지 모르겠습니다. 이에 대한 별도의 질문 을 만들었습니다 .


3

OpenCores 에는 BiQuad를 포함하여 많은 DSP 예제, IIR 및 FIR이 있습니다. 파일을 다운로드하려면 등록해야합니다.

편집
나는 죽은 링크에 대한 Kortuk의 의견을 이해하고 실제로 OpenCores에 대한 링크가 죽으면 대답이 쓸모 없게 될 것입니다. 나는 이것이 일어나지 않을 것이라고 확신한다. 내 링크는 일반적인 링크이며 전체 OpenCores 도메인이 사라질 경우에만 죽습니다.
이 답변에 사용할 수있는 몇 가지 예를 찾으려고했지만 여기에 표시하기에는 너무 깁니다. 그래서 나는 직접 사이트를 등록하라는 조언을 고수 할 것입니다 (고향이 받아 들여지지 않았기 때문에 뉴욕으로 이사해야했습니다). 그리고 거기에 제시된 코드를 살펴보십시오.


모든 것과 마찬가지로 링크가 끊어집니다. 우리는 그 자체로 링크가 응답하지 않는다고 전에 논의했습니다. 거기에있는 것들 중 일부를 가져 와서 더 많은 것을 배우기위한 참고 자료로 그 연관성이있는 강력한 답변을 할 수 있습니까?
Kortuk

@ Kotuk-어제 이것을하고 싶었습니다. 나는 어제 오픈 코어에 등록하여 세부 사항을 얻었지만, 그들이 있을지 생각하려면 며칠이 필요하다
stevenvh

듣고 기뻐, 나는 당신의 방식으로 무언가를 얻었는지 솔직히 궁금했습니다. 그것에 대해 더 많은 소식을 기다리겠습니다.
Kortuk

1

나는 디자인이 가능한 한 빠른지 (각 곱셈은 전용 곱셈기로 수행되는지) 가능한 한 작게 (각 곱셈기가 재사용되도록) 정의 할 수있는 IIR 필터의 정식 구현을위한 스크립트를 구현하려고했습니다.

소스는 alt.sources에 "VHDL에서 IIR 필터의 동작 적이지만 합성 가능한 구현"으로 게시되었습니다 (Google 아카이브 ( https://groups.google.com/group/alt.sources/msg/c8cf038b9b8ceeec)). ? dmode = source )

alt.sources에 대한 게시물은 "공유"형식이므로 메시지를 텍스트로 저장하고 소스를 가져 오려면 공유를 해제해야합니다 ( "unshar"유틸리티 사용).


0

이것은 어떤가요? https://github.com/MauererM/VIIRF

고정 소수점 구현을 처리하는 바이 쿼드 (SOS, 2 차 섹션) 기반 IIR 필터를 구현합니다. 또한 필터 디자인 및 검증을위한 Python 스크립트가 있습니다. 벤더 고유의 FPGA 구성을 사용하지 않으며 고속 및 저 영역 사용간에 트레이드 오프를 선택할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.