非線性數(shù)字濾波器:用例和示例代碼
出處:維庫電子市場網(wǎng) 發(fā)布于:2024-03-14 16:34:20
在某些情況下,F(xiàn)IR 和 IIR 可能會遇到脈沖噪聲和突發(fā)噪聲等問題,這些噪聲可能導(dǎo)致輸出以不可接受的方式做出反應(yīng)。非線性濾波器可以為數(shù)據(jù)流提供保護(hù)。根據(jù)您的應(yīng)用,它們可以用作獨(dú)立濾波器或用作 FIR、IIR 或 Boxcar 濾波器之前的預(yù)濾波器。
本文中的示例假設(shè)是一維流式、有符號或無符號整數(shù)(包括 long 和 long long)。一些示例可能適用于浮動,但其他示例則不然。提到流式傳輸是因?yàn)榧僭O(shè)數(shù)據(jù)將連續(xù)來自源,并且這些過濾器將處理數(shù)據(jù)并將其實(shí)時一對一地發(fā)送出去。換句話說,我們不能只是扔掉壞數(shù)據(jù),我們需要發(fā)送一些值來替換輸入。不過,某些示例可能允許過采樣,在這種情況下,它可能會抽取數(shù)據(jù)。例如,傳感器可以以比所需速度快 10 倍的速率發(fā)送數(shù)據(jù),然后在將 1 個樣本發(fā)送到下一階段之前處理 10 個樣本。
本討論的另一個假設(shè)是,我們正在設(shè)計需要實(shí)時處理傳入樣本的小型嵌入式系統(tǒng)。小是指我們不會有大量內(nèi)存或高 MIPS 等級。因此,我們將避免使用浮動。
那么,讓我們看一下一些非線性濾波器,看看它們在哪里有用。
邊界檢查過濾器
您以前可能使用過此過濾器,但可能不認(rèn)為它是過濾器。這些過濾器通常也稱為邊界檢查、裁剪、范圍檢查、限制,甚至健全性檢查。我們指的不是指針檢查,而是對傳入數(shù)據(jù)或已被先前代碼修改的數(shù)據(jù)的數(shù)據(jù)檢查。
這是一段簡單的示例代碼:
#define Upper_Limit 1000
#define Lower_Limit -1000
int limit_check(int n)
{
if (n < Lower_Limit) n = Lower_Limit;
else if (n > Upper_Limit) n = Upper_Limit;
return n;
}
清單 1
您可以看到,如果整數(shù) n 大于 1000,則返回 1000。如果小于 -1000,則返回 -1000。如果介于 1000 和 -1000(含)之間,則返回 n 的原始值。這將限制大的脈沖噪聲值通過您的系統(tǒng),即它會過濾數(shù)據(jù)。
當(dāng)與 FIR、IIR 或時間濾波器(如下所述)等其他濾波器結(jié)合使用時,可以根據(jù)運(yùn)行的濾波器值縮放限制值。如果檢測到超出范圍的樣本,則基于此移動限制,邊界檢查器可以返回的過濾器輸出,而不是固定限制或可疑樣本。
某些系統(tǒng)可能會提供邊界檢查的某些變體作為預(yù)定義的函數(shù)調(diào)用或宏。
軟削波濾波器
這與邊界檢查有關(guān),但它不僅僅是在達(dá)到一定水平后限制值,而是隨著輸入接近值或值而慢慢開始回退輸出值。這種類型的軟削波通常用于音頻信號處理應(yīng)用中。
軟裁剪可以通過 sigmoid 函數(shù)或雙曲正切函數(shù)等函數(shù)來完成。這里的問題是這些方法需要強(qiáng)大的處理能力并且需要快速逼近方法。
軟削波通常會扭曲輸入與輸出關(guān)系的很大一部分,因此它不適合用于大多數(shù)測量溫度、電路電壓、電流、光照水平或其他計量輸入等的傳感器輸入。因此,我們不會進(jìn)一步討論它,只是說如果你搜索“軟剪輯”,網(wǎng)上有很多信息。
截斷均值濾波器
截斷平均值或截尾平均值是一種方法,您獲取一組(至少 3 個)讀數(shù),丟棄和讀數(shù),然后對其余讀數(shù)進(jìn)行平均。這與您在某些奧運(yùn)會評審中看到的方法類似。對于嵌入式項目,它擅長消除脈沖噪聲。實(shí)現(xiàn)此過濾器的一種方法是排序,但在小型處理器的大多數(shù)應(yīng)用中,這可能在計算上很昂貴,因此對于大于 5 個樣本的任何樣本,我建議掃描列表以查找值和值。運(yùn)行掃描時,還計算所有條目的總數(shù)。,從總數(shù)中減去值和值,然后將該值除以條目數(shù)減 2。下面是在輸入值數(shù)組上執(zhí)行此類函數(shù)的示例。在代碼末尾有一個可選行,可以根據(jù)需要進(jìn)行舍入。
#include
int TruncatedMean(int inputArray[], unsigned int arraySize) {
int i = 0;
int min = INT_MAX;
int max = 0;
int total = 0;
int mean = 0;
for (i = 0; I < arraySize; i++) {
if (inputArray[i] < min) min = inputArray[i];
if (inputArray[i] > max) max = inputArray[i];
total = total + inputArray[i];
}
//mean = (total - min - max) / (arraySize - 2);
// The previous truncates down. To assist in rounding use the following line
mean = (total - min - max + ((arraySize - 2)/2)) / (arraySize - 2);
return mean ;
}
清單 2
如果只有 3 個值,則在計算時間上重寫 C 代碼以消除循環(huán)可能會更有利,如本代碼示例中針對 3 個值的情況所示。
int TruncatedMean_3(int a, int b, int c) {
int mean = 0;
if ((a<=b) && (a>=c) || ((a<=c) && (a>=b)) ) mean = a;
else if ((b<=c) && (b>=a) || ((b<=a) && (b>=c)) ) mean = b;
else mean = c;
return mean;
}
清單 3
請注意,如果需要,還可以使用至少 5 個樣本來實(shí)現(xiàn)截斷平均值,以去除多個值和一個值,這對于突發(fā)噪聲很有好處。另請注意,您可以將其實(shí)現(xiàn)為滑動函數(shù)或過采樣函數(shù)?;瑒雍瘮?shù)(如移動平均值)會滑出舊的輸入并插入新的輸入,然后再次執(zhí)行該函數(shù)。因此,每個輸入都會得到一個輸出?;蛘撸^采樣函數(shù)接受一個值數(shù)組,找到平均值,然后獲取一個新的新值數(shù)組來處理。因此,每個輸入樣本數(shù)組僅生成一個輸出,然后您需要在計算新平均值之前獲取一組新的輸入值。
中值過濾
中值濾波器查找一組樣本中的中間值。這對于各種類型的噪聲源可能有用。在大量樣本中,將對樣本數(shù)組進(jìn)行排序,然后讀取中間索引變量。例如,假設(shè)我們有一個包含 7 個樣本的數(shù)組(樣本[0 到 6]),我們對它們進(jìn)行排序,然后中位數(shù)是樣本[3]。請注意,由于執(zhí)行速度的原因,在小型嵌入式系統(tǒng)中排序可能會出現(xiàn)問題,因此應(yīng)明智地使用中值過濾。對于 3 個樣本,代碼與上面的代碼示例函數(shù)“TruncatedMean_3”(清單 3)相同。對于較大的組,清單 4 顯示了一段用于查找中位數(shù)的 C 代碼示例。在代碼底部,您將看到基于樣本數(shù)量奇數(shù)或偶數(shù)的中位數(shù)設(shè)置。這是必需的,因?yàn)榕紨?shù)個樣本的中位數(shù)被定義為中間兩個值的平均值。根據(jù)您的需要,您可能需要對此平均值進(jìn)行四舍五入。
#define numSamples 6
int sample[numSamples] = {5,4,3,3,1,0};
int Median( int sample[], int n) {
int i = 0;
int j = 0;
int temp = 0;
int median = 0;
// First sort the array of samples
for (i = 0; i < n; ++i){
for (j = i + 1; j < n; ++j){
if (sample[i] > sample[j]){
temp = sample[i];
sample[i] = sample[j];
sample[j] = temp;
}
}
}
// If numSamples is odd, take the middle number
// If numSamples is even, average the middle two
if ( (n & 1) == 0) {
median = (sample[(n / 2) - 1] + sample[n / 2]) / 2; // Even
}
else median = sample[n / 2]; // Odd
return(median);
}
清單 4
正如截斷均值濾波器一樣,您可以將其實(shí)現(xiàn)為滑動函數(shù)或過采樣函數(shù)。
多數(shù)過濾
多數(shù)過濾器,也稱為模式過濾器,從一組出現(xiàn)次數(shù)多的樣本中提取值——多數(shù)投票。(這不應(yīng)與“多數(shù)元素”混淆,“多數(shù)元素”是出現(xiàn)次數(shù)超過樣本數(shù)/2 的值。)清單 5 顯示了 5 個樣本的多數(shù)過濾器。
#define numSamples 5
int Majority( int sample[], int n) {
unsigned int count = 0;
unsigned int oldcount = 0;
int majoritysample = sample[0];
int i = 0;
int j = 0;
for (i = 0; i < numSamples; i++) {
count = 0;
for (j = i; j < numSamples; j++) {
if (sample[i] == sample[j]) count++;
}
if (count > oldcount) {
majoritysample = sample[i];
oldcount = count;
}
}
return majoritysample;
}
清單 5
該代碼使用兩個循環(huán),個循環(huán)抓取一個元素,第二個循環(huán)然后單步遍歷列表并計算有多少樣本與個循環(huán)索引的值匹配。第二個循環(huán)保留沿途找到的匹配計數(shù)及其樣本值,直到個循環(huán)遍歷整個數(shù)組。如果有多于一組具有相同計數(shù)的樣本值(即,{1, 2, 2, 0, 1},兩個 2 和兩個 1),則個找到的樣本值將作為多數(shù)返回。
請注意,多數(shù)過濾器可能不適用于典型的嵌入數(shù)據(jù),因?yàn)閿?shù)字的動態(tài)范圍(來自傳感器)通常為 8、10、12 位或更大。如果接收到的樣本使用動態(tài)范圍的大部分,則來自一小組的樣本匹配的機(jī)會很小,除非所測量的信號非常穩(wěn)定。由于這種動態(tài)范圍問題,對多數(shù)濾波器進(jìn)行修改可能會有用。通過對二進(jìn)制符號進(jìn)行右移,過濾器可以匹配彼此接近的符號。例如,假設(shè)我們有數(shù)字(二進(jìn)制??)00100000、00100011、01000011、00100001。這些數(shù)字都不匹配,它們都是不同的。但是,如果我們將它們?nèi)坑乙?2 位,我們會得到 00001000、00100011、00010000、00001000。現(xiàn)在其中三個匹配。
同樣,與截斷均值濾波器一樣,您可以將其實(shí)現(xiàn)為滑動函數(shù)或過采樣函數(shù)。
時間過濾
這是一組濾波器,它們對信號的反應(yīng)更多地基于時間而不是幅度。一分鐘后這一點(diǎn)就會變得更清楚。我們將這些不同的時間濾波器稱為模式 1 到模式 4,我們從模式 1 開始:
模式 1的工作原理是將輸入樣本與起始過濾值(“filterout”)進(jìn)行比較,然后,如果樣本大于當(dāng)前過濾值,則當(dāng)前過濾值增加 1。同樣,如果樣本小于當(dāng)前過濾值,則當(dāng)前過濾值增加 1。過濾后的值,當(dāng)前過濾后的值減1。(增減數(shù)也可以是任意合理的固定值(如2、5、10……)。該過濾器的輸出為“filterout”??梢钥吹捷敵鰧⒙蛐盘栯娖揭苿?,因此變化與時間(樣本數(shù)量)比與樣本值更相關(guān)。
現(xiàn)在,如果我們得到不需要的脈沖,無論樣本的幅度是多少,它都只能將輸出移動 1。這意味著突發(fā)噪聲和脈沖噪聲大大減輕。這種類型的濾波器非常適合相對于采樣率緩慢移動的信號。它可以很好地過濾 ADC 的溫度讀數(shù)等數(shù)據(jù),尤其是在電噪聲環(huán)境中。它在我從事的一個項目中表現(xiàn)非常好,該項目提取了在電力線上發(fā)送的非常緩慢的移動信號(非常嘈雜的環(huán)境,信號比線路電壓低約 -120 dB)。此外,它非常適合創(chuàng)建動態(tài)數(shù)字參考電平,例如交流信號的直流偏置電平或控制 PLL 的信號。清單 6 說明了使用模式 1 時間濾波器來平滑值“filterout”。
#define IncDecValue 1
int sample = 0;
int filterout = 512; // Starting value
call your “getsample” function here…
if (sample > filterout) filterout = filterout + IncDecValue;
else if (sample < filterout) filterout = filterout - IncDecValue;
清單 6
如果您要過濾的樣本是 int,您可能需要進(jìn)行檢查以確保過濾后的值不會上溢/下溢和回繞。如果您的樣本來自 10 或 12 位的傳感器或 ADC,則這不是問題,無需檢查。
模式2與模式1相同,但是增加/減少數(shù)不是使用單個值,而是使用兩個或更多個值。一個示例是根據(jù)樣本與當(dāng)前過濾值(“過濾”)之間的差異使用不同的增加/減少值。如果它們很接近,我們使用±1,如果它們相距較遠(yuǎn),我們使用±10。這已成功用于加速 VCO 的時間濾波控制的啟動,該 VCO 用于匹配 GPS 信號的頻率。
#define IncDecValueSmall 1
#define IncDecValueBig 10
#define BigDiff 100
int sample = 0;
int filterout = 100; // Starting value
call your “getsample” function here…
if (sample > filterout) {
if ((sample - filterout) > BigDiff) filterout = filterout + IncDecValueBig;
else filterout = filterout + IncDecValueSmall;
}
else if (sample < filterout) {
if ((filterout - sample) > BigDiff) filterout = filterout - IncDecValueBig;
else filterout = filterout - IncDecValueSmall;
}
清單 7
增量/減量值還可以是由固件根據(jù)各種內(nèi)部因素或直接由用戶調(diào)整的變量。
模式 3也與模式 1 非常相似,但如果樣本大于當(dāng)前濾波信號,則當(dāng)前濾波信號將增加當(dāng)前濾波信號與樣本之間差異的固定百分比,而不是增加 ±1。如果樣本小于當(dāng)前濾波信號,則當(dāng)前濾波信號減少一定百分比。讓我們看一個例子。假設(shè)我們從當(dāng)前過濾值(“filterout”)1000 開始,并使用 10% 的變化值。然后我們得到一個新的樣本 1500。這將導(dǎo)致 1500-100 或 50 增加 10%。所以當(dāng)前的過濾值現(xiàn)在是 1050。如果下一個樣本是 500,并且我們使用 -10%,我們會得到過濾后的新電流為 995(1050 減去 1050-500 的 10%)。
#define IncPercent 10 // 10%
#define DecPercent 10 // 10%
int sample = 0;
int filterout = 1000; // Starting value
call your “getsample” function here…
if (sample > filterout) {
filterout = filterout + (((sample - filterout) * IncPercent) / 100);
}
else if (sample < filterout) {
filterout = filterout - (((filterout - sample) * DecPercent) / 100);
}
清單 8
需要注意的一件事是乘法中的溢出。進(jìn)行這些計算時您可能需要使用長整型。另請注意,將“IncPercent”和“DecPercent”設(shè)置為可通過內(nèi)??部算法或用戶干預(yù)進(jìn)行調(diào)整的變量可能很有用。
要在缺乏 1 或 2 個周期劃分的系統(tǒng)上加速此代碼:不要將 IncPercent 和 DecPercent 縮放 100,而是將其縮放 128(10 % 約為 13)然后代碼中的“/100”將是“/128” ” 編譯器會將其優(yōu)化為移位操作。
模式 4與模式 3 類似,只不過與模式 2 一樣,根據(jù)樣本和當(dāng)前輸出值(“過濾器”)之間的差異,可以發(fā)揮兩個或多個級別的作用。在清單 9 的代碼中,有兩個級別。
#define IncPctBig 25 // 25%
#define DecPctBig 25 // 25%
#define IncPctSmall 10 // 10%
#define DecPctSmall 10 // 10%
int sample = 0;
int filterout = 1000; // Stating value
call your “getsample” function here…
if (sample > filterout) {
if ((sample - filterout) > BigDiff) {
filterout = filterout + (((sample - filterout) * IncPctBig) / 100);
}
else filterout = filterout + (((sample - filterout) * IncPctSmall) / 100);
}
else if (sample < filterout) {
if ((filterout - sample) > BigDiff){
filterout = filterout - (((filterout - sample) * DecPctBig) / 100);
}
else filterout = filterout - (((filterout - sample) * DecPctSmall) / 100);
}
清單 9
一個有趣的想法是,時間濾波器也可用于生成脈沖噪聲和突發(fā)噪聲等統(tǒng)計數(shù)據(jù)。他們可以計算一段時間內(nèi)發(fā)生的次數(shù)并計算脈沖/秒等統(tǒng)計數(shù)據(jù)。這可以通過添加另一個比“過濾”值大得多或小得多的樣本進(jìn)行比較來完成。
版權(quán)與免責(zé)聲明
凡本網(wǎng)注明“出處:維庫電子市場網(wǎng)”的所有作品,版權(quán)均屬于維庫電子市場網(wǎng),轉(zhuǎn)載請必須注明維庫電子市場網(wǎng),http://udpf.com.cn,違反者本網(wǎng)將追究相關(guān)法律責(zé)任。
本網(wǎng)轉(zhuǎn)載并注明自其它出處的作品,目的在于傳遞更多信息,并不代表本網(wǎng)贊同其觀點(diǎn)或證實(shí)其內(nèi)容的真實(shí)性,不承擔(dān)此類作品侵權(quán)行為的直接責(zé)任及連帶責(zé)任。其他媒體、網(wǎng)站或個人從本網(wǎng)轉(zhuǎn)載時,必須保留本網(wǎng)注明的作品出處,并自負(fù)版權(quán)等法律責(zé)任。
如涉及作品內(nèi)容、版權(quán)等問題,請在作品發(fā)表之日起一周內(nèi)與本網(wǎng)聯(lián)系,否則視為放棄相關(guān)權(quán)利。
- ADI - 深度探討RF信號鏈中的濾波器應(yīng)用2024/7/15 11:22:01
- 帶通濾波器有哪幾種?帶通濾波器的設(shè)計2024/6/3 17:51:52
- 什么是fir濾波器?2024/2/27 17:14:02
- 使用示波器濾波器實(shí)現(xiàn)更好的測量2023/12/7 15:18:59
- 參數(shù)提取法設(shè)計帶通濾波器詳細(xì)教程2018/5/28 11:21:50