VHDL में FIR / IIR फ़िल्टर के लिए कोड उदाहरण?


11

मैं अपने स्पार्टन -3 बोर्ड में डीएसपी के साथ शुरुआत करने की कोशिश कर रहा हूं। मैंने एक पुराने मदरबोर्ड से चिप के साथ एक AC97 बोर्ड बनाया, और अब तक मुझे यह ADC करने के लिए मिला, एक नंबर <1 के लिए नमूने गुणा करें (वॉल्यूम कम करें) और फिर डीएसी।

अब मैं कुछ बुनियादी डीएसपी सामान करना चाहूंगा, जैसे एक कम-पास फ़िल्टर, उच्च-पास आदि। लेकिन मैं वास्तव में संख्यात्मक (पूर्णांक? निश्चित बिंदु? Q0.15? अतिप्रवाह या संतृप्ति?) के बारे में भ्रमित हूं।

मैं बस मुझे आरंभ करने के लिए एक वास्तविक सरल फिल्टर का कुछ उदाहरण कोड चाहता हूं । कोई उच्च दक्षता, तेज, या ऐसा कुछ भी नहीं। बस वीएचडीएल में लागू सैद्धांतिक फिल्टर।

मैं खोज रहा हूं, लेकिन मैं सिर्फ सैद्धांतिक सूत्र खोजता हूं - मुझे वह मिलता है, जो मुझे समझ में नहीं आता है कि मैं हस्ताक्षर किए गए 16-बिट, 48KHz ऑडियो नमूनों को कैसे संसाधित कर सकता हूं, जो मैं एडीसी से प्राप्त कर रहा हूं। मैं इन पुस्तकालयों का उपयोग कर रहा हूं: http://www.vhdl.org/fphdl/ । अगर मैं अपने नमूनों को 0.5, 0.25 आदि से गुणा करता हूं, तो मैं अंतर सुन सकता हूं। लेकिन एक बड़ा फिल्टर मुझे सिर्फ शोर देता है।

धन्यवाद।


2
जब मैं सीखने के सामान के लिए आपके पास जो कुछ भी हाथ में है, उसका उपयोग करने के लिए, मैं यह बताना चाहता हूं कि FPGA में ऑडियो फिल्टर करना एक बहुत ही कुशल या लागत प्रभावी तरीका नहीं है। इसलिए, यदि आप एक वास्तविक परियोजना करते हैं तो मैं इसके बजाय कम लागत वाले डीएसपी का उपयोग करने की सलाह दूंगा। अपवाद: जब आप एक ही समय पर एक से अधिक संख्या में ऑडियो चैनल कर रहे हों, या आप एक बेहूदी संख्या में टैप के साथ FIR कर रहे हों।

जवाबों:


8

ऐसा लगता है कि आपको पहले डीएसपी पहलुओं का पता लगाने की आवश्यकता है, फिर एफपीजीए में कार्यान्वयन करें।

  • C, Matlab, Excel, या कहीं भी DSP को क्रमबद्ध करें
  • कोशिश करें और सोचें कि आपने FPGA- भूमि में जो कुछ भी सीखा है, उसे कैसे स्थानांतरित करेंगे
  • डिस्कवर करें कि आपने कार्यान्वयन के बारे में कुछ धारणा बनाई है जो अच्छी तरह से काम नहीं करती है (उदाहरण के लिए फ्लोटिंग पॉइंट का उपयोग)
  • इस पर ध्यान देने के लिए अपने ऑफ़लाइन डीएसपी सामान को वापस जाएं और अपडेट करें।
  • Iterate 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;

आपके उत्तर के लिए धन्यवाद। यह कमोबेश मैंने क्या किया है, लेकिन मैं संख्या प्रतिनिधित्व के साथ कुछ मुद्दे रख रहा हूं। मेरा एडीसी मुझे -32k से + 32k (16-बिट पर हस्ताक्षर किए) में मान देता है। मुझे फ़िल्टर स्थिर की समस्या भी है - मैं इसका प्रतिनिधित्व कैसे करूं? और नमूना और स्थिर के बीच गुणा का परिणाम है? यही मुझे सबसे ज्यादा भ्रमित कर रहा है।
hjf

@hjf - यह सब सिर्फ पूर्णांक है। जब तक सब कुछ 32 बिट्स के भीतर रहता है तब तक आप ठीक हैं। यदि आपको उससे अधिक चौड़ाई की आवश्यकता है, तो आप अपनी इच्छानुसार UNSIGNED या SIGNED वैक्टर का उपयोग कर सकते हैं। या VHDL2008 से फिक्स्ड_पॉइंट प्रकार का उपयोग करें (यहां देखें: vhdl.org/fphdl )
मार्टिन थॉम्पसन

5

सबसे सरल कम पास एफआईआर फ़िल्टर जो आप कोशिश कर सकते हैं y (n) = x (n) + x (n-1) है। आप इसे VHDL में आसानी से लागू कर सकते हैं। नीचे हार्डवेयर का एक बहुत ही सरल ब्लॉक आरेख है जिसे आप लागू करना चाहते हैं।

एक साधारण कम पास फिल्टर के लिए आरेख ब्लॉक करें

सूत्र के अनुसार, उपयुक्त आउटपुट प्राप्त करने के लिए आपको वर्तमान और पिछले एडीसी नमूनों की आवश्यकता है। आपको क्या करना चाहिए कि घड़ी के गिरने वाले किनारे पर आने वाले एडीसी के नमूनों को कुंडी करना है, और उचित आउटपुट प्राप्त करने के लिए बढ़ते किनारे पर उचित गणना करना है। चूंकि आप दो 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

जैसा कि आप देख सकते हैं, आप इस सामान्य विचार का उपयोग अधिक जटिल सूत्रों में जोड़ने के लिए कर सकते हैं, जैसे कि गुणांक वाले। अधिक जटिल सूत्र, जैसे आईआईआर फिल्टर, एल्गोरिथ्म तर्क को सही पाने के लिए चर के उपयोग की आवश्यकता हो सकती है। अंत में, फिल्टर के आसपास पाने के लिए एक आसान तरीका है कि गुणांक के रूप में वास्तविक संख्याएं हैं, एक स्केल फैक्टर ढूंढना है ताकि सभी संख्याएं यथासंभव पूर्ण संख्याओं के करीब हों। आपका अंतिम परिणाम सही परिणाम प्राप्त करने के लिए एक ही कारक द्वारा वापस नीचे स्केल किया जाना होगा।

मुझे उम्मीद है कि यह आपके काम आ सकता है और आपको गेंद को लुढ़काने में मदद करेगा।

* इसे संपादित किया गया है ताकि डेटा लैचिंग और आउटपुट लैचिंग अलग-अलग प्रक्रियाओं में हो। इसके अलावा std_logic_vector के बजाय हस्ताक्षरित प्रकारों का उपयोग करना। मैं मान रहा हूं कि आपका ADC इनपुट std_logic_vector सिग्नल होने जा रहा है।


2
प्रक्रियाएं जो दोनों किनारों को ट्रिगर करती हैं (जैसा कि आपने वर्णित किया है) संश्लेषण करने की बहुत संभावना नहीं है
मार्टिन थॉम्पसन

@ मैं आपको मान रहा हूं कि मैं FPGA की तुलना में बहुत अधिक जानता हूं, लेकिन मैंने गिरने वाले किनारे पर आने वाले डेटा को हटा दिया है और एक वर्ग असाइनमेंट के लिए बढ़ते किनारे पर आउटपुट को हटा दिया है, इसलिए मुझे लगा कि यह काम करेगा। क्या आप बता सकते हैं कि ऐसी प्रक्रियाएँ काम क्यों नहीं करती हैं?
dhsieh2

3
यह एक सिम्युलेटर में ठीक काम करेगा। सिंथेसिसर्स इसे चोक कर देंगे हालांकि (मेरे अनुभव में) क्योंकि डिवाइस में फ्लिपफ्लॉप केवल एक किनारे पर घड़ी कर सकते हैं ।
मार्टिन थॉम्पसन

@ dhsieh2 धन्यवाद, यह उसी तरह का उत्तर है जिसकी मुझे तलाश थी। एक और सवाल, अगर मैं हस्ताक्षरित संख्याओं का उपयोग कर रहा था तो मैं इसे कैसे करूंगा (मेरा एडीसी मुझे -32k से +32 k में मान देता है)।
hjf

4
@ मर्टिन मैं दोनों घड़ी के किनारों को हर समय बंद कर देता हूं Xilinx FPGA की, कोई समस्या नहीं। आप बस दोनों किनारों से एक ही एफएफ को बंद नहीं कर सकते। जब आप टाइमिंग एनालाइज़र आउटपुट को देखते हैं, तो यह वास्तव में यह बहुत स्पष्ट करता है कि आप विपरीत किनारों को कर रहे हैं और समय के अनुसार बजट को समायोजित करता है।

5

एक और सरल कोड स्निपेट (सिर्फ हिम्मत)। नोट मैंने सीधे VHDL नहीं लिखा था, मैंने VHDL उत्पन्न करने के लिए MyHDL का उपयोग किया।

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

संश्लेषित सर्किट

यह प्रत्यक्ष कार्यान्वयन है। इसके लिए मल्टीप्लायरों की आवश्यकता होगी। एल्टर साइक्लोन III के लिए लक्षित इस सर्किट का संश्लेषण किसी भी स्पष्ट गुणक का उपयोग नहीं करता है, लेकिन इसके लिए 350 तर्क तत्वों की आवश्यकता होती है।

यह एक छोटा सा एफआईआर फ़िल्टर है और इसमें निम्नलिखित प्रतिक्रिया होगी (इतनी बड़ी नहीं) लेकिन एक उदाहरण के रूप में उपयोगी होनी चाहिए।

फ़िल्टर प्रतिक्रिया

इसके अलावा, मेरे पास कुछ उदाहरण हैं, यहां और यहां , यह उपयोगी हो सकता है।

इसके अलावा, आपका प्रश्न यह प्रतीत होता है: "उचित निश्चित-बिंदु प्रतिनिधित्व क्या है?" डीएसपी कार्यों को लागू करते समय, निश्चित-बिंदु प्रतिनिधित्व का उपयोग किया जाता है, क्योंकि यह फिल्टर का विश्लेषण सरल करता है। जैसा कि उल्लेख किया गया है, फिक्स्ड-पॉइंट सिर्फ पूर्णांक अर्थमेटिक है। वास्तविक कार्यान्वयन केवल पूर्णांकों के साथ काम कर रहा है, लेकिन हमारा पूर्वनिर्धारित प्रतिनिधित्व आंशिक है।
कार्यान्वयन पूर्णांक (फिक्स्ड-पॉइंट) से / फ़्रॉग डिज़ाइन फ़्लोटिंग-पॉइंट में कनवर्ट करते समय समस्याएँ आमतौर पर उत्पन्न होती हैं।

मुझे नहीं पता कि वीएचडीएल फिक्स्ड-पॉइंट और फ्लोटिंग-पॉइंट प्रकार कितनी अच्छी तरह से समर्थित हैं। वे अनुकरण में ठीक काम करेंगे, लेकिन मुझे नहीं पता कि वे सबसे अधिक संश्लेषण उपकरण के साथ संश्लेषण करेंगे या नहीं। मैंने इसके लिए एक अलग प्रश्न बनाया ।


3

OpenCores में कई डीएसपी उदाहरण हैं, IIR और FIR, जिसमें BiQuad भी शामिल है। आपको फ़ाइलों को डाउनलोड करने के लिए पंजीकरण करना होगा।

संपादित करें
मैं मृत लिंक पर कोरटुक की टिप्पणी को समझता हूं, और वास्तव में, अगर ओपनकोरस के लिंक की मृत्यु हो जाती है, तो उत्तर बेकार हो जाएगा। मुझे पूरा विश्वास है कि ऐसा नहीं होगा; मेरा लिंक एक सामान्य है, और यह तभी पूरा होगा जब पूरा OpenCores डोमेन गायब हो जाएगा।
मैंने कुछ उदाहरणों की तलाश करने की कोशिश की, जिनका मैं इस उत्तर के लिए उपयोग कर सकता हूं, लेकिन वे सभी यहां प्रस्तुत किए जाने के लिए बहुत लंबे हैं। इसलिए मैं अपनी सलाह के लिए साइट पर खुद को पंजीकृत करने के लिए चिपके रहूंगा (मुझे न्यूयॉर्क जाना था, क्योंकि मेरा होम टाउन स्वीकार नहीं किया गया था) और वहां प्रस्तुत कोड पर एक नज़र है।


सभी चीजों की तरह, लिंक टूट जाते हैं। हमने पहले भी चर्चा की है कि अपने आप में एक लिंक उत्तर नहीं देता है। क्या आप इसमें से कुछ को ला सकते हैं और अधिक जवाब देने के लिए एक संदर्भ के रूप में उस मांसयुक्त उत्तर को बना सकते हैं?
कोर्तुक

@ कोरटुक - मैं कल ऐसा करना चाहता था। मैंने कुछ विवरण प्राप्त करने के लिए कल opencores के साथ पंजीकरण किया था, लेकिन उन्हें यह सोचने के लिए कुछ दिनों की आवश्यकता है कि क्या वे मेरे पास होंगे
स्टीवनव सिप

यह सुनकर खुशी हुई, मैं ईमानदारी से सोच रहा था कि क्या आपके रास्ते में कुछ हुआ है। इसके बारे में अधिक सुनने के लिए तत्पर हैं।
कोर्तुक

1

मैंने IIR फ़िल्टरों के योजनाबद्ध कार्यान्वयन के लिए स्क्रिप्ट को लागू करने की कोशिश की है, जहाँ आप यह परिभाषित कर सकते हैं कि क्या डिज़ाइन जितना संभव हो उतना तेज़ होना चाहिए (इसलिए प्रत्येक गुणक को समर्पित गुणक के साथ प्रदर्शन किया जाता है) या जितना संभव हो उतना छोटा (ताकि प्रत्येक गुणक का पुन: उपयोग किया जाता है)।

स्रोतों को "VhaLL में व्यवहार और IIR फ़िल्टर के संश्लेषण योग्य कार्यान्वयन" के रूप में alt.sources पर प्रकाशित किया गया है (आप इसे Google संग्रह में भी देख सकते हैं: https://groups.google.com/group/alt.sources/msg/b8cf038b9b8ceeec ? dmode = स्रोत )

Alt.source पर पोस्ट "तीव्र" प्रारूप में हैं, इसलिए आपको संदेश को पाठ के रूप में सहेजने की आवश्यकता है, और सूत्रों को प्राप्त करने के लिए इसे ("अनिश्चित" उपयोगिता के साथ) अनचाहे।


0

इस बारे में कैसा है? https://github.com/MauererM/VIIRF

यह एक बिराद (एसओएस, द्वितीय-क्रम अनुभाग) आधारित आईआईआर फिल्टर को लागू करता है जो निश्चित-बिंदु कार्यान्वयन का ध्यान रखता है। इसमें फ़िल्टर के डिज़ाइन और सत्यापन के लिए पायथन स्क्रिप्ट भी हैं। यह विक्रेता-विशिष्ट FPGA निर्माणों का उपयोग नहीं करता है और आप उच्च गति और निम्न क्षेत्र उपयोग के बीच व्यापार बंद का चयन कर सकते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.