1. 程式人生 > >使用java實現數字濾波器

使用java實現數字濾波器

藉助 dsp-collection 庫實現 java 數字濾波器。

在網上搜索“使用 java 實現數字濾波器”,搜尋結果大多是利用 MATLAB 生成濾波器係數 a 、 b,然後在 java 中進行濾波,但是我的需求是整個過程完全在 java 中完成。之後搜尋“ java 實現 DSP Filter ”則在stackoverflow中找到了解決辦法。

dsp-collection 庫 支援多種 IIR 濾波器,包括巴特沃斯,切比雪夫和貝塞爾濾波器。筆者在這裡使用的是巴特沃斯濾波器。其他的請參考 API 文件

模擬訊號:
f(t)=sin(10πt)+sin(30πt) f(t)=sin(10 \pi t)+sin(30 \pi t)


其中包含 5Hz 和 15Hz 兩個頻率分量,訊號的取樣率為 50Hz :

double[] time = new double[150];
double[] valueA = new double[150];
for (int i = 0; i < 50 * 3; i++) {
    time[i] = i / 50.0;
    valueA[i] = Math.sin(2 * Math.PI * 5 * time[i])+Math.sin(2 * Math.PI * 15 * time[i]);
}

生成濾波器:

IirFilterCoefficients iirFilterCoefficients;
iirFilterCoefficients = IirFilterDesignExstrom.design(FilterPassType.lowpass, 10, 10.0 / 50, 10.0 / 50);

檢視係數的值:

public class Filter {
    public static void main(String[] args) {
        IirFilterCoefficients iirFilterCoefficients;
        iirFilterCoefficients = IirFilterDesignExstrom.design(FilterPassType.
lowpass, 10, 10.0 / 50, 10.0 / 50); for (int i=0;i<iirFilterCoefficients.a.length;i++) { System.out.println("A["+i+"]:"+iirFilterCoefficients.a[i]); } for (int i=0;i<iirFilterCoefficients.b.length;i++) { System.out.println("B["+i+"]:"+iirFilterCoefficients.b[i]); } } }

輸出為:

A[0]:1.0
A[1]:-1.9924014816014122
A[2]:3.0194828633553836
A[3]:-2.8185224264945132
A[4]:2.038720637062525
A[5]:-1.0545446210956793
A[6]:0.41444626875039875
A[7]:-0.1157186252368282
A[8]:0.022498509272218276
A[9]:-0.0026689123535761005
A[10]:1.4876445217776215E-4
B[0]:4.994540782331007E-4
B[1]:0.004994540782331008
B[2]:0.022475433520489533
B[3]:0.05993448938797209
B[4]:0.10488535642895115
B[5]:0.12586242771474138
B[6]:0.10488535642895115
B[7]:0.05993448938797209
B[8]:0.022475433520489533
B[9]:0.004994540782331008
B[10]:4.994540782331007E-4

使用巴特沃斯濾波器,濾波器設定為低通,濾波器階數為 10 ,下截止頻率為 10Hz 。則 iirFilterCoefficients.a 為濾波器係數 a,iirFilterCoefficients.b 為濾波器係數 b 。
使用濾波器處理訊號:

valueA = IIRFilter(valueA, iirFilterCoefficients.a, iirFilterCoefficients.b);

IIR 系統的表示式:
y(n)+1Na(k)y(nk)=0Mb(r)x(nr) y(n)+\sum _1^N a(k)y(n-k)=\sum _0^M b(r)x(n-r)
封裝的濾波器函式,裡面的資料型別可以改為 float :

public synchronized double[] IIRFilter(double[] signal, double[] a, double[] b) {

        double[] in = new double[b.length];
        double[] out = new double[a.length-1];

        double[] outData = new double[signal.length];

        for (int i = 0; i < signal.length; i++) {

            System.arraycopy(in, 0, in, 1, in.length - 1);
            in[0] = signal[i];

            //calculate y based on a and b coefficients
            //and in and out.
            float y = 0;
            for(int j = 0 ; j < b.length ; j++){
                y += b[j] * in[j];

            }

            for(int j = 0;j < a.length-1;j++){
                y -= a[j+1] * out[j];
            }

            //shift the out array
            System.arraycopy(out, 0, out, 1, out.length - 1);
            out[0] = y;

            outData[i] = y;


        }
        return outData;
    }

濾波前後的幅頻影象(左圖為濾波前的幅頻圖,右圖為濾波後的幅頻圖):

濾波前的幅頻影象 濾波後的幅頻影象
濾波之後的幅頻影象:

如何對訊號進行頻譜分析以及將頻譜圖在 Android 中顯示請參見:
java 實現離散時間傅立葉變換

注意:

  1. 濾波器係數:
iirFilterCoefficients = IirFilterDesignExstrom.design(FilterPassType.lowpass, 10,
        10.0 / 50, 10.0 / 50);

··design()`` 方法的四個引數,第一個表示選擇濾波器型別(低通,高通,帶通,帶阻),第二個引數表示濾波器的階數,第三個引數表示下截止頻率,第四個引數表示上截止頻率,在低通和高通濾波器中只需要一個截止頻率,所以在低通和高通中上截止頻率是沒有作用的。只有在帶通或者帶阻濾波器中才需要兩個截止頻率。
例如當設定為:

iirFilterCoefficients = IirFilterDesignExstrom.design(FilterPassType.lowpass, 10,
        10.0 / 50, 13.0 / 50);

結果:

A[0]:1.0
A[1]:-1.9924014816014122
A[2]:3.0194828633553836
A[3]:-2.8185224264945132
A[4]:2.038720637062525
A[5]:-1.0545446210956793
A[6]:0.41444626875039875
A[7]:-0.1157186252368282
A[8]:0.022498509272218276
A[9]:-0.0026689123535761005
A[10]:1.4876445217776215E-4
B[0]:4.994540782331007E-4
B[1]:0.004994540782331008
B[2]:0.022475433520489533
B[3]:0.05993448938797209
B[4]:0.10488535642895115
B[5]:0.12586242771474138
B[6]:0.10488535642895115
B[7]:0.05993448938797209
B[8]:0.022475433520489533
B[9]:0.004994540782331008
B[10]:4.994540782331007E-4

可以看到,濾波器係數和之前是一樣的。
當使用python的時候:

from scipy import signal
import numpy as np
import matplotlib.pyplot as plt
b, a = signal.butter(10, 0.4, 'low')
print "A:"
print a
print "B:"
print b

輸出為:

A:
[  1.00000000e+00  -1.99240148e+00   3.01948286e+00  -2.81852243e+00
   2.03872064e+00  -1.05454462e+00   4.14446269e-01  -1.15718625e-01
   2.24985093e-02  -2.66891235e-03   1.48764452e-04]
B:
[ 0.00049945  0.00499454  0.02247543  0.05993449  0.10488536  0.12586243
  0.10488536  0.05993449  0.02247543  0.00499454  0.00049945]

可以看到,與 java 生成濾波器係數的是一致的。

參考資料:

相關推薦

使用java實現數字濾波器

藉助 dsp-collection 庫實現 java 數字濾波器。 在網上搜索“使用 java 實現數字濾波器”,搜尋結果大多是利用 MATLAB 生成濾波器係數 a 、 b,然後在 java 中進行濾波,但是我的需求是整個過程完全在 java 中完成。之後搜尋

java實現數字反轉(逆序輸出)

要求:輸入一個整數,將這個數字逆序輸出(數字反轉) 例如:輸入3251,需輸出1523 package com.number.test; import java.util.Scanner; /**

Java實現數字大寫

轉自:http://blog.csdn.net/u011943172/article/details/51554457 /** * @author QSJ * @describe 金額大寫 * @date 2018-02-25 */ public class AmountOfmoney {

java實現數字金額轉換中文大寫金額

直接貼程式碼吧! public class CnNumberUtils { private final static Logger logger = LoggerFactory.getLogger(CnNumberUtils.class);

java實現數字金錢轉化為英文字母顯示

public class MoneyUtil { String[] smallNumbers = new String[]{"ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE",

JAVA實現數字反轉

import java.util.Scanner; public class Reverse{ //輸入一個整數然後反轉 public static void main(String[] ar

java 實現數字簽名自動補零

方法一: for 迴圈判斷位數; 補零個數是,進行總長度減去數字長度。 方法二: 善用String.format 方法 如: public static void main(String[

java實現數字轉換人民幣中文大寫工具

業務場景: 1.在人事業務系統開發的報表列印文書時經常需要將人民幣數值轉換為大寫, 所以用java寫了一個通用的大寫轉換函式。 為了更加方便呼叫函式的引數使用字串型別。例如:825.45 轉換後:捌佰貳拾伍元肆角伍分 2.在人事業務系統中經常把日期

Java 實現數字在排序陣列中出現的次數

統計一個數字在排序陣列中出現的次數程式碼解法一 /** * 暴力求解,直接遍歷 * @param array * @param k * @return */ public static int findAppea

java實現從命令行接收多個數字,求和之後輸出結果

system 程序流程圖 sta num 思想 pri for循環 含義 自動 1.設計思想 首先要了解從命令行輸入數字的含義,不需要在程序中自己定義。需要定義int類的num和sum。之後利用num=Integer.parseInt(arg);將String型轉化為int

java 實現數字遊戲 隨機給定一個數字,猜大小直到正確

個數字 blog spa 猜數字 style ring imp code ont package com.swift; import java.util.Random; import java.util.Scanner; public class GuessBigSm

RSA加密解密及數字簽名Java實現

cto 包括 sign object misc 數據 factory 了解 對稱密鑰 RSA公鑰加密算法是1977年由羅納德·李維斯特(Ron Rivest)、阿迪·薩莫爾(Adi Shamir)和倫納德·阿德曼(Leonard Adleman)一起提出的。當時他們三人都在

人名幣金額阿拉伯數字轉化為中國傳統形式JAVA實現

[1] 中國 [] data args pen ins string AS 1. 在金融項目中,常常需要對金額進行轉換,阿拉伯數字轉換成中國傳統形式。人民幣保留到分。 如輸入:16700 返回:壹萬陸仟柒佰元 如輸入:167.5785 返回:壹佰陸拾柒元伍角捌分 (

數組中只出現一次的數字java實現

num 整型 根據 長度 問題 程序 oid [] 情況 問題描述 一個整型數組裏除了兩個數字之外,其他的數字都出現了偶數次。請寫程序找出這兩個只出現一次的數字。 解題思路 如果數組中只有一個數字出現奇數次,則將數組中所有的數字做異或可得該數字。 數組中有兩個數

java實現迴圈列印堆型數字

目標和效果 輸入一個數,得到一個堆型的輸出 如 輸入7 程式碼 private static void funtion(int a) { int a1 = a; for (int i = 1; i <= a; i++) { for (int j = a1 -

Java】 劍指offer(39) 陣列中出現次數超過一半的數字 《劍指Offer》Java實現合集 《劍指Offer》Java實現合集

本文參考自《劍指offer》一書,程式碼採用Java語言。 更多:《劍指Offer》Java實現合集   題目    陣列中有一個數字出現的次數超過陣列長度的一半,請找出這個數字。例如輸入一個長度為9的陣列{1, 2, 3, 2, 2, 2, 5, 4, 2}。由於數字2在陣列中出現

Java】 劍指offer(40) 最小的k個數 《劍指Offer》Java實現合集 劍指offer(39) 陣列中出現次數超過一半的數字 《劍指Offer》Java實現合集

本文參考自《劍指offer》一書,程式碼採用Java語言。 更多:《劍指Offer》Java實現合集   題目    輸入n個整數,找出其中最小的k個數。例如輸入4、5、1、6、2、7、3、8這8個數字,則最小的4個數字是1、2、3、4。 思路   思路一:同劍指offer(39

Java】 劍指offer(46) 把數字翻譯成字串 《劍指Offer》Java實現合集 《劍指Offer》Java實現合集

本文參考自《劍指offer》一書,程式碼採用Java語言。 更多:《劍指Offer》Java實現合集   題目    給定一個數字,我們按照如下規則把它翻譯為字串:0翻譯成"a",1翻譯成"b",……,11翻譯成"l",……,25翻譯成"z"。一個數字可能有多個翻譯。例如12258有

Java】 劍指offer(53-2) 0到n-1中缺失的數字 《劍指Offer》Java實現合集 《劍指Offer》Java實現合集

  本文參考自《劍指offer》一書,程式碼採用Java語言。 更多:《劍指Offer》Java實現合集   題目   一個長度為n-1的遞增排序陣列中的所有數字都是唯一的,並且每個數字都在範圍0到n-1之內。在範圍0到n-1的n個數字中有且只有一個數字不在該陣列中,請找

Java】 劍指offer(56-2) 陣列中唯一隻出現一次的數字 《劍指Offer》Java實現合集 56-1) 陣列中只出現一次的兩個數字 《劍指Offer》Java實現合集

  本文參考自《劍指offer》一書,程式碼採用Java語言。 更多:《劍指Offer》Java實現合集   題目   在一個數組中除了一個數字只出現一次之外,其他數字都出現了三次。請找出那個只出現一次的數字。 思路   這道題中數字出現了三次,無法像56-1) 陣列