單級CIC濾波器理論與設計
項目簡述
工慾善其事必先利其器,信號處理有強大的理論支撐。若是沒有掌握這些理論,只是隨便找一些符合要求的代碼,那麼自己很難更近一步。而且算法本身就是FPGA工程師的難點,而不是硬件邏輯。所以,本篇文章我們將進行CIC抗混疊濾波器的設計,這在信號處理中具有及其重要的地位。接下來,我們將從理論與FPGA設計的兩個角度來講解CIC的設計
多速率信號處理
這個概念是相對於單速率(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,狀態方程爲:
上述的積分器也可以看做是累加器。根據Z變換,積分器的傳輸函數爲:
梳妝器是一份FIR濾波器,其狀態方程爲:
式中,D是設計參數,稱爲微分延遲,其傳輸函數爲:
那麼:單級CIC濾波器的傳遞函數爲:
令,帶入上式,可以得到傳遞函數的幅頻響應爲:
CIC濾波器的幅頻響應特性如圖所示,其中[0,2π/DM]爲主瓣,其他的區間稱爲旁瓣。
從幅頻響應特性可以看到,主瓣的最大值爲DM(在w=0時),旁瓣的最大值在處 取得
它與主瓣電平的比值爲:
根據在θ在0~45°時,,可得:
可見單級CIC濾波器的旁瓣電平較大,阻帶衰減較差。爲降低旁瓣電平,可以採用多級CIC濾波器級聯辦法來實現。
多級CICI濾波器
根據前面可知,單級CIC濾波器的第一旁瓣電平衰減固定爲13.46dB,且與濾波器的階數無關。這個值不滿足通常的阻帶衰減要求,解決方法就是通過級聯CIC濾波器來達到更大的阻帶衰減。事實上實際應用中採用的都是多級CIC濾波器。
一個N級CIC抽取濾波器系統傳遞函數爲:
在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 : [email protected]
// Website :
// Module Name : cic.v
// Create Time : 2020-04-24 15:08:16
// 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恆等式。***I
在抽取的過程中,一般是信號先經過抗混疊低通濾波器進行濾波,來避免頻譜混疊現象的發生,然後再進行抽取處理,但是我們可以利用Noble恆等式,先對信號進行抽取,再對其進行濾波。這些知識再多級CIC濾波器應用中尤其明顯,我們將在下一篇文章中進行進一步的講解
CIC抽取濾波器測試代碼
關於CIC抽取濾波器的代碼,我們使用了DDS來產生採樣率50MHz、頻率0.25MHz的正弦波。代碼如下:
tb模塊:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : [email protected]
// Website :
// Module Name : tb.v
// Create Time : 2020-04-24 16:00:12
// 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 : [email protected]
// Website :
// Module Name : CIC_inter.v
// Create Time : 2020-04-24 20:20:56
// 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 : [email protected]
// Website :
// Module Name : cic.v
// Create Time : 2020-04-24 15:08:16
// 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 : [email protected]
// Website :
// Module Name : tb.v
// Create Time : 2020-04-24 16:00:12
// 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濾波器進行濾波,詳細的情況將在我們接下來的博客中進行論述。
參考文獻
[1]、FPGADesigner——CSDN博主
[2]、長弓的堅持——CSDN博主
[3]、行州人——CSDN博主
總結
在查找一些資料的時候,發現一些博主只給出部分代碼,其實這樣別人根本看不懂,只有給出整個工程代碼才易於知識的傳播。創作不易,認爲文章有幫助的同學們可以關注、點贊、轉發支持。爲行業貢獻及其微小的一部分。或者對文章有什麼看法或者需要更近一步交流的同學,可以加入下面的羣: