以下文章來源于CSDN技術社區,作者開放原子開發者工作坊
多速率信號處理
這個概念是相對于單速率(Single Rate)信號處理而言的。單速率 是指整個信號處理流程中只有一種數據速率;多速率 是指系統中存在多個數據速率。使用多速率信號處理可以節省存儲空間、減少通信數據量、減少運算量、減輕設計難度。
很明顯從字面意思上可以理解,多采樣率嘛,就是有多個采樣率唄。前面所說的FIR,IIR濾波器都是只有一個采樣頻率,是固定不變的采樣率,然而有些情況下需要不同采樣頻率下的信號,具體例子我們將以數字下變頻(DDC)為例來進行講解。
按照傳統的速率轉換理論,我們要實現采樣速率的轉換,可以這樣做,假如有一個有用的正弦波模擬信號,AD采樣速率是f1,現在我需要用到的是采樣頻率是f2的信號,傳統做法是將這個經過f1采樣后的信號進行DA轉換,再將轉換后的模擬信號進行以f2采樣頻率的抽樣,得到采樣率為f2的數字信號,至此完成采樣頻率的轉換。所以我們引入了更好的抽取與內插方法。
比如在DDC(數字下變頻)系統中,前級需要很高的采樣率fs確保ADC采集到信號的信噪比;而在去載波并提取出低頻的基帶信號后,信號有效帶寬已經很小,此時可以滿足要求的采樣率也遠遠低于fs,如果不進行數據速率轉換的處理,會造成許多資源的浪費和設計上的困難:
多速率信號處理 主要包括 數據速率的轉換 和 LPF的設計 兩個過程。數據速率的轉換包括 抽取(Decimation,降低采樣率) 和 內插(interpolation,提高采樣率) 。抽取/內插時應保證信號的有效頻帶內沒有頻譜混疊,因此需要完成LPF的設計,常用的有 多速率FIR濾波器、CIC濾波器、HB濾波器。
從上面的文章中,我們可以看出多速率濾波器最重要的也就是抽取與內插兩個操作。
抽取
當需要降低采樣率時,輸入信號數據每隔D-1個取一個,取出的數據依次排序,這個過程稱作D倍抽取,采樣率變為原來的1/D。但是我們需要確保抽取之后的采樣率仍然可以滿足Nyquist采樣定理,否則會造成頻譜的混疊。當然由于ADC的轉換也會在整個頻段內引入白噪聲,因此在抽取前還是需要加入抗混疊濾波器。如下圖所示:
上面是抽取的主要操作,也是絕大多數FPGA工程師進行的操作,但是卻不明白其中的原理。接下來我們將從信號處理的角度解釋上面兩點:
1、為什么一定要保證抽取后滿足奈奎斯特抽樣定理。
2、為什么要先經過抗混疊濾波器。
先來總體來解釋一下抽取的含義:前面不是說,一個有用的正弦波模擬信號經采樣頻率為f1的抽樣信號抽樣后得到了數字信號,很明顯這個數字信號序列是在f1頻率下得到的,現在,假如我隔幾個點抽取一個信號,比如就是5吧,我隔5個點抽取一個信號,是不是就是相當于我采用了1/5倍f1的采樣頻率對模擬信號進行采樣了?所以,抽取的過程就是降低抽樣率的過程,但是我們知道,這是在時域的抽樣,時域的抽樣等于信號在頻域波形的周期延拓(信號系統中的公式),周期就是采樣頻率,所以,為了避免在頻域發生頻譜混疊,抽樣定理也是我們要考慮的因素
下面來具體來介紹:
如上圖所示,假如上面就是某一有用信號經采樣頻率f1抽樣得到的頻譜,假設這時候的采樣頻率為8Khz,可以通過數格子得到,從0到F1處有8個空格,每個空格代表1Khz,有些朋友可能會問,這不是在數字頻域嗎,單位不是π嗎,哪來的hz?是的,這里是數字頻域,采樣頻率F1處對應的是2π,這里只是為了好解釋,我們用模擬頻率來對應數字頻率(如果這里不懂的話需要惡補信號系統與數字信號處理的知識)。
下圖就是對信號進行了1/5倍的F1采樣頻率抽取,可見,由于發生了頻譜混疊現象,因為1/5倍的F1是1600hz,而信號的頻帶是1000hz,不滿足抽樣定理,導致發生了頻譜混疊,所以,為了避免發生這種情況,除了要滿足抽樣定理之外,即抽樣倍數不能太高,我們還需要把信號的頻帶設置在F1/2以下,才能確保信號不發生頻譜混疊,因此,我們需要在抽取之前加一個低通濾波器,書上叫做抗混疊低通濾波器,用來限制信號的頻帶,然后再進行抽取。
這樣的話我們來算一下,低通濾波器的截止頻率就是1/2倍的經抽取后的采樣速率,即fc = 1/2 * (F1/M) ,M是抽取倍數。而1/2*F1對應的數域頻率是π,因此我們得出,抗混疊低通濾波器的截止頻率是π/M。
內插
當需要提高采樣率時,在兩個相鄰的數據之間插入I-1個零值,再進行低通濾波,這個過程稱作 I倍內插 ,采樣率變為原來的I倍。只要LPF的通帶為信號的有效帶寬,即使插值時只插入零值點(沒有插入采樣值的點),也可以達到I倍內插的效果。經過插值后的信號由DAC輸出會引入更小的高頻噪聲。如下圖所示:
抽取的過程是降低采樣率的過程,那么插值的過程當然就是提高采樣率的過程。大體的思路可以這么理解,我們將經f1抽樣下得到的數字信號的每兩個點之間進行插值,插入的值是0,插值之后,信號在單位時間內的采樣點數增多,當然也就是采樣速率的提升,采樣速率提升后我們知道,那么信 號的頻譜的周期數就會增加:
信號系統學的好的同學可以試著推導一下上面的頻譜變化,相信不是太難。
需要注意的一點就是,插值前后,我們只是在時域信號中間插入了D-1個零值,僅僅是改變了采樣率,并沒有改變信號的信息,因此,在頻域,信號頻譜的形狀是不會改變的,改變的僅僅是模擬頻率與數字頻率的對應,如上圖,F1是插值之前信號的抽樣頻率,插值之后,信號頻譜的形狀不變,抽樣頻率成了F1D,D是插值倍數。如果我們直接用F1D倍的采樣率采信號,得到的頻譜會發現,就不會有中間兩個波形,因此,這兩個波形是多余的,書上叫做是鏡像頻譜*。既然是多余的,我們就可以將它用一個低通濾波器濾掉,這樣的低通濾波器,就叫做鏡像低通濾波器。這樣我們來計算一下鏡像低通濾波器的截止頻率
根據上面這張圖我們可以求出鏡像低通濾波器的截止頻率,可以看到,fc = 1/2 F1,這里我們假設,內插之后的采樣頻率為F2 =F1D,那么,fc =1/2*(F2/D),而1/2F2對應的是π,注意,這里是1/2F2對應π,不是1/2*F1了,因為這已經是插值之后采樣率增加之后的頻譜了,所以我們得出,鏡像低通濾波器的截止頻率為:π/D
分數倍抽取與內插
上面抽取和內插實現的都是整數倍數據速率的轉換。而實際設計中遇到的更多不會是整數倍關系。可以使用先內插、再抽取的方式完成采樣率為有理數比值的數據速率轉換,且可以共用一個LPF,截止頻率選取二者的最小帶寬即可。如下圖所示:
根據前面抽取與內插的介紹我們知道了,內插的過程是先進行內插處理,再通過鏡像低通濾波器,抽取的過程就是先進行抗混疊低通濾波,再進行抽取,我們可以看出來,假如我們想進行分數倍抽取,比如我要進行3/5倍抽取,就可以先進行3倍內插,再進行5倍抽取,這樣就可以實現分數倍抽取。
再來看一下,當進行分數倍抽取與內插的時候,鏡像低通濾波器和抗混疊低通濾波器是連在一起的,因此,我們可以將這兩個濾波器合二為一,截止頻率取兩個濾波器截止頻率的最小值就可以了。
上面關于數據的抽取與內插的知識已經介紹完畢,如果有哪里不懂,可以查閱書本知識。從這篇文章我們也可以看出來數字信號處理理論知識的重要性。如果上大學的同學看到這篇文章,這里勸誡一定學好基礎理論,否則只能做個調參俠。
CIC濾波器
CIC濾波器 是無線通信的常用模塊,一般用于 數字下變頻(DDC)和數字上變頻(DUC)系統。CIC濾波器結構簡單,沒有乘法器,只有加法器、積分器和寄存器,可以實現高速濾波,常用在輸入采樣率最高的第一級。從上面可以看出來CIC濾波器的優點:CIC(Cascaded Integrator Comb)積分梳狀與其他多速率FIR濾波器濾波器運算速度快、占用資源少C、工作頻率高(因為CIC只使用加法器、減法器和寄存器),在多速率信號處理系統中應用更廣泛。
CIC濾波器理論推導
單級CICI濾波器
CIC濾波器包括兩個基本組成部分:積分部分和梳妝部分,如圖所示:
積分部分的積分器是單極點的IIR濾波器,并且反饋系數為1,狀態方程為:
y(n)=y(n?1)+x(n)
上述的積分器也可以看做是累加器。根據Z變換,積分器的傳輸函數為:
H1(z)=1?z?11
梳妝器是一份FIR濾波器,其狀態方程為:
y(n)=x(n?1)?x(n?DM)
式中,D是設計參數,稱為微分延遲,其傳輸函數為:
Hc(z)=1?z?DM
那么:單級CIC濾波器的傳遞函數為:
H(z)=1?z?11(1?zDM)
令 z=ejw,帶入上式,可以得到傳遞函數的幅頻響應為:
CIC濾波器的幅頻響應特性如圖所示,其中[0,2π/DM]為主瓣,其他的區間稱為旁瓣。
從幅頻響應特性可以看到,主瓣的最大值為DM(在w=0時),旁瓣的最大值在 w=3π/DM處 取得
它與主瓣電平的比值為:
根據在θ在0~45°時,θ≈sinθ,可得:
α=20lg(23π)=13.36dB
可見單級CIC濾波器的旁瓣電平較大,阻帶衰減較差。為降低旁瓣電平,可以采用多級CIC濾波器級聯辦法來實現。
多級CICI濾波器
根據前面可知,單級CIC濾波器的第一旁瓣電平衰減固定為13.46dB,且與濾波器的階數無關。這個值不滿足通常的阻帶衰減要求,解決方法就是通過級聯CIC濾波器來達到更大的阻帶衰減。事實上實際應用中采用的都是多級CIC濾波器。
一個N級CIC抽取濾波器系統傳遞函數為:
H(z)=(1?z?11?z?DM)N
在N級級聯時,阻帶衰減為單級衰減的N倍,即13.46×N(dB)。
但是在阻帶衰減的情況下也帶來一系列的問題:
1、要同時滿足通帶容限跟阻帶容限的誤差的CIC濾波器實現起來比較困難,因為要想阻帶衰減大,就要增大濾波器級數,但是會導致通帶容限增大。
2、如果要實現這樣的濾波器,只有當有用信號的頻帶相對于采樣信號的速率很小時才能設計出符合要求的濾波器,這樣的話通帶衰減較大的情況下也對有用信號影響較小。
3、有用信號的頻帶相對于采樣信號的速率很小也就是意味著信號的采樣率很高,所以,CIC濾波器適合應用在多速率信號處理的前端,作為抗混疊濾波器來用,或者是作為后端的抗混疊插值濾波器。
CIC濾波器的FPGA實現
上面我們已經對CIC的主要原理進行了講述。其實CIC濾波器本質上就是一個簡單的低通濾波器,只是方便與抽取與內插聯系起來,下面我們將給出源代碼供大家學習:
CIC抽取濾波器代碼
使用50MHz采樣率對0.25MHz的信號進行采樣,由五階CIC濾波器進行5倍抽取,將采樣率降至10MHz。這里我們直接給出CIC抽取濾波器代碼,
cic模塊:
`timescale 1ns / 1ps // ********************************************************************************* // Project Name : OSXXXX // Author : zhangningning // Email : nnzhang1996@foxmail.com // Website : // Module Name : cic.v // Create Time : 2020-04-24 1516 // Editor : sublime text3, tab size (4) // CopyRight(c) : All Rights Reserved // // ********************************************************************************* // Modification History: // Date By Version Change Description // ----------------------------------------------------------------------- // XXXX zhangningning 1.0 Original // // ********************************************************************************* module cic( //System Interfaces input sclk , input rst_n , //Communication Interfaces input rvalid , input [ 9:0] din , output reg tvalid , output reg [12:0] dout ); //======================================================================================== //**************Define Parameter and Internal Signals********************************** //========================================================================================/ reg [ 2:0] cnt ; reg [12:0] sum ; wire [12:0] din_x ; //======================================================================================== //************** Main Code ********************************** //========================================================================================/ assign din_x = {{3{din[9]}},din}; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) cnt <= 3'd0; else if(rvalid == 1'b1 && cnt == 'd4) cnt <= 3'd0; else if(rvalid == 1'b1) cnt <= cnt + 1'b1; else cnt <= cnt; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) sum <= 13'd0; else if(rvalid == 1'b1 && cnt == 'd4) sum <= din_x; else if(rvalid == 1'b1) sum <= sum + din_x; else sum <= sum; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) dout <= 13'd0; else if(rvalid == 1'b1 && cnt == 'd4) dout <= sum; else dout <= dout; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) tvalid <= 1'b0; else if(rvalid == 1'b1 && cnt == 'd4) tvalid <= 1'b1; else tvalid <= 1'b0; endmodule
有不少同學會問嗎,這不就是對輸出的5個數據求了一次平均,咋么能說是CIC抽取濾波器呢。因為當梳狀濾波器的階數與抽取的的數目相同時,可以在積分器之后先抽取再經過梳狀濾波器。然后經過稍微化簡便可以成為上述形式。這也原理被稱為Noble恒等式。
在抽取的過程中,一般是信號先經過抗混疊低通濾波器進行濾波,來避免頻譜混疊現象的發生,然后再進行抽取處理,但是我們可以利用Noble恒等式,先對信號進行抽取,再對其進行濾波。這些知識再多級CIC濾波器應用中尤其明顯,我們將在下一篇文章中進行進一步的講解
CIC抽取濾波器測試代碼
關于CIC抽取濾波器的代碼,我們使用了DDS來產生采樣率50MHz、頻率0.25MHz的正弦波。代碼如下:
tb模塊:
`timescale 1ns / 1ps // ********************************************************************************* // Project Name : OSXXXX // Author : zhangningning // Email : nnzhang1996@foxmail.com // Website : // Module Name : tb.v // Create Time : 2020-04-24 1612 // Editor : sublime text3, tab size (4) // CopyRight(c) : All Rights Reserved // // ********************************************************************************* // Modification History: // Date By Version Change Description // ----------------------------------------------------------------------- // XXXX zhangningning 1.0 Original // // ********************************************************************************* module tb(); reg sclk ; reg rst_n ; wire rvalid ; wire [ 7:0] din ; wire tvalid ; wire [12:0] dout ; initial begin sclk = 1'b0; rst_n <= 1'b0; #(1000); rst_n <= 1'b1; end always #(10) sclk = ~sclk; dds_compiler_0 dds_compiler_0_inst ( .aclk (sclk ), // input wire aclk .m_axis_data_tvalid (rvalid ), // output wire m_axis_data_tvalid .m_axis_data_tdata (din ) // output wire [7 : 0] m_axis_data_tdata ); cic cic_inst( //System Interfaces .sclk (sclk ), .rst_n (rst_n ), //Communication Interfaces .rvalid (rvalid ), .din ({{2{din[7]}},din} ), .tvalid (tvalid ), .dout (dout ) ); endmodule
CIC抽取濾波器仿真結果
上述的仿真結果如下:
從上面我們很明顯看出我們成功實現了正弦波的抽取。從而驗證了我們實驗的正確性。
CIC內插濾波器代碼
關于CIC抽取濾波器的代碼,我們使用了DDS來產生采樣率50MHz、頻率0.25MHz的正弦波,然后經過10倍抽取使得采樣率降為5MHz;再經過10倍插值,最后經過100階的CIC濾波器檢驗其內插效果。代碼如下:
CIC_inter模塊:
`timescale 1ns / 1ps // ********************************************************************************* // Project Name : OSXXXX // Author : zhangningning // Email : nnzhang1996@foxmail.com // Website : // Module Name : CIC_inter.v // Create Time : 2020-04-24 2056 // Editor : sublime text3, tab size (4) // CopyRight(c) : All Rights Reserved // // ********************************************************************************* // Modification History: // Date By Version Change Description // ----------------------------------------------------------------------- // XXXX zhangningning 1.0 Original // // ********************************************************************************* module CIC_inter( //System Interfaces input sclk , input rst_n , //Communication Interfaces input rvalid , input [12:0] din , output reg tvalid , output wire [19:0] dout ); //======================================================================================== //**************Define Parameter and Internal Signals********************************** //========================================================================================/ reg [ 9:0] cnt ; wire [19:0] din_x ; wire [19:0] data ; reg data_valid ; reg [ 9:0] cnt_cic ; reg [19:0] sum ; //======================================================================================== //************** Main Code ********************************** //========================================================================================/ assign din_x = {{7{din[12]}},din}; assign data = din_x; assign dout = sum; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) cnt <= 10'd0; else if(cnt == 10'd0 && rvalid == 1'b1) cnt <= cnt + 1'b1; else if(cnt > 0 && cnt == 'd9) cnt <= 10'd0; else if(cnt > 0) cnt <= cnt + 1'b1; else cnt <= 10'd0; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) data_valid <= 1'b0; else if(cnt == 10'd0 && rvalid == 1'b1) data_valid <= 1'b1; else if(cnt > 0) data_valid <= 1'b1; else data_valid <= 1'b0; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) cnt_cic <= 10'd0; else if(data_valid == 1'b1 && cnt_cic == 'd99) cnt_cic <= 10'd0; else if(data_valid == 1'b1) cnt_cic <= cnt_cic + 1'b1; else cnt_cic <= cnt_cic; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) sum <= 16'd0; else if(data_valid == 1'b1 && cnt_cic == 'd99) sum <= data; else if(data_valid == 1'b1) sum <= sum + data; else sum <= sum; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) tvalid <= 1'b0; else if(data_valid == 1'b1) tvalid <= 1'b1; else tvalid <= 1'b0; endmodule
cic模塊:
`timescale 1ns / 1ps // ********************************************************************************* // Project Name : OSXXXX // Author : zhangningning // Email : nnzhang1996@foxmail.com // Website : // Module Name : cic.v // Create Time : 2020-04-24 1516 // Editor : sublime text3, tab size (4) // CopyRight(c) : All Rights Reserved // // ********************************************************************************* // Modification History: // Date By Version Change Description // ----------------------------------------------------------------------- // XXXX zhangningning 1.0 Original // // ********************************************************************************* module cic( //System Interfaces input sclk , input rst_n , //Communication Interfaces input rvalid , input [ 9:0] din , output reg tvalid , output reg [12:0] dout ); //======================================================================================== //**************Define Parameter and Internal Signals********************************** //========================================================================================/ reg [ 9:0] cnt ; reg [12:0] sum ; wire [12:0] din_x ; //======================================================================================== //************** Main Code ********************************** //========================================================================================/ assign din_x = {{3{din[9]}},din}; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) cnt <= 10'd0; else if(rvalid == 1'b1 && cnt == 'd9) cnt <= 10'd0; else if(rvalid == 1'b1) cnt <= cnt + 1'b1; else cnt <= cnt; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) sum <= 13'd0; else if(rvalid == 1'b1 && cnt == 'd9) sum <= din_x; else if(rvalid == 1'b1) sum <= sum + din_x; else sum <= sum; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) dout <= 13'd0; else if(rvalid == 1'b1 && cnt == 'd9) dout <= sum; else dout <= dout; always @(posedge sclk or negedge rst_n) if(rst_n == 1'b0) tvalid <= 1'b0; else if(rvalid == 1'b1 && cnt == 'd9) tvalid <= 1'b1; else tvalid <= 1'b0; endmodule
CIC內插濾波器測試代碼
tb模塊:
`timescale 1ns / 1ps // ********************************************************************************* // Project Name : OSXXXX // Author : zhangningning // Email : nnzhang1996@foxmail.com // Website : // Module Name : tb.v // Create Time : 2020-04-24 1612 // Editor : sublime text3, tab size (4) // CopyRight(c) : All Rights Reserved // // ********************************************************************************* // Modification History: // Date By Version Change Description // ----------------------------------------------------------------------- // XXXX zhangningning 1.0 Original // // ********************************************************************************* module tb(); reg sclk ; reg rst_n ; wire rvalid ; wire [ 7:0] din ; wire tvalid ; wire [12:0] dout ; wire [15:0] CIC_inter_data ; wire CIC_inter_tvalid; initial begin sclk = 1'b0; rst_n <= 1'b0; #(1000); rst_n <= 1'b1; end always #(10) sclk = ~sclk; dds_compiler_0 dds_compiler_0_inst ( .aclk (sclk ), // input wire aclk .m_axis_data_tvalid (rvalid ), // output wire m_axis_data_tvalid .m_axis_data_tdata (din ) // output wire [7 : 0] m_axis_data_tdata ); cic cic_inst( //System Interfaces .sclk (sclk ), .rst_n (rst_n ), //Communication Interfaces .rvalid (rvalid ), .din ({{2{din[7]}},din} ), .tvalid (tvalid ), .dout (dout ) ); CIC_inter CIC_inter_inst( //System Interfaces .sclk (sclk ), .rst_n (rst_n ), //Communication Interfaces .rvalid (tvalid ), .din (dout ), .tvalid (CIC_inter_tvalid ), .dout (CIC_inter_data ) ); endmodule
CIC內插濾波器仿真結果
將工程進行Modelsim仿真,結果如下:
從上面的結果可以看出內插結果正確,但是由于單級CIC濾波器的阻帶衰減太低,所以在實際工程中一般都是使用多級CIC濾波器進行濾波
原文鏈接:
https://openatomworkshop.csdn.net/674576e63a01316874d897d6.html
-
FPGA
+關注
關注
1629文章
21746瀏覽量
603748 -
濾波器
+關注
關注
161文章
7832瀏覽量
178225 -
adc
+關注
關注
98文章
6503瀏覽量
544815 -
CIC濾波器
+關注
關注
0文章
16瀏覽量
10541
原文標題:基于FPGA的CIC濾波器設計
文章出處:【微信號:gh_9d70b445f494,微信公眾號:FPGA設計論壇】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論