javaweb(四)——过滤器与监听器(中)

本文涉及的产品
函数计算FC,每月15万CU 3个月
简介: javaweb(四)——过滤器与监听器

6. 相位响应(Phase Response)


相位响应指的是滤波器对信号引起的相位变化。不同类型的滤波器对相位的影响也不同,一般来说,保持相位不变或者产生线性相移的滤波器更为常见。


Java代码实现:


相位响应可以在滤波器内部计算得到。

public class HighPassFilter {
    private double alpha;
    private double cutoffFrequency;
    private double[] output;
    public HighPassFilter(double alpha, double cutoffFrequency) {
        this.alpha = alpha;
        this.cutoffFrequency = cutoffFrequency;
        output = new double[1];
    }
    // 计算相位响应
    public double getPhaseResponse(double frequency) {
        double omega = 2 * Math.PI * frequency;
        return -Math.atan(alpha * Math.sin(omega) / (1 - alpha * Math.cos(omega)));
    }
    // ... 其他代码
}


以上是滤波器相关的参数,它们能够帮助我们评估滤波器的性能和适用场景,并根据需要进行参数调整。


滤波器设计


掌握各种滤波器设计方法,包括窗函数法、频率采样法、最小二乘法和极点优化法等。

滤波器是数字信号处理中十分重要的一部分,可以用来去除信号中的噪声、选择特定频率范围内的信号等。以下是各种滤波器设计方法的详细概念和Java代码实现。


1. 窗函数法


窗函数法是一种常见的理想滤波器设计方法,其基本思想是在频域上使用一个矩形窗函数作为滤波器的频率响应,然后将其变换到时域上得到实际的滤波器系数。这种方法的主要优点是简单易懂,但缺点是会产生较大的纹波和截止带宽过渡区域较宽的问题。


下面是一个简单的Java代码示例:

public class WindowFilter {
    public static double[] lowPass(int M, double fc) {
        double[] h = new double[M + 1];
        for (int n = 0; n <= M; n++) {
            if (n == M / 2) h[n] = 2 * fc;
            else h[n] = Math.sin(2 * Math.PI * fc * (n - M / 2)) / (Math.PI * (n - M / 2));
            h[n] *= 0.54 - 0.46 * Math.cos(2 * Math.PI * n / M);
        }
        return h;
    }
    public static double[] highPass(int M, double fc) {
        double[] h = new double[M + 1];
        for (int n = 0; n <= M; n++) {
            if (n == M / 2) h[n] = 1 - 2 * fc;
            else h[n] = -Math.sin(2 * Math.PI * fc * (n - M / 2)) / (Math.PI * (n - M / 2));
            h[n] *= 0.54 - 0.46 * Math.cos(2 * Math.PI * n / M);
        }
        return h;
    }
    public static void main(String[] args) {
        int M = 31;
        double[] hlp = lowPass(M, 0.4);
        double[] hhp = highPass(M, 0.4);
        System.out.println("Low pass filter coefficients:");
        for (int i = 0; i < hlp.length; i++) {
            System.out.printf("%.3f ", hlp[i]);
        }
        System.out.println("\nHigh pass filter coefficients:");
        for (int i = 0; i < hhp.length; i++) {
            System.out.printf("%.3f ", hhp[i]);
        }
    }
}

2. 频率采样法


频率采样法是一种比较常用的滤波器设计方法,其基本思想是通过对目标滤波器的理想频率响应进行采样,得到离散的频率响应后再进行离散余弦变换(DCT)或者离散傅里叶变换(DFT),最终得到实际的滤波器系数。这种方法的优点是可以比较精确地设计滤波器,但缺点是需要进行频率采样,会产生一些采样误差。


下面是一个简单的Java代码示例:

public class FrequencySamplingFilter {
    public static double[] lowPass(int M, double[] f, double[] a) {
        int L = f.length;
        double[] h = new double[M + 1];
        for (int n = 0; n <= M; n++) {
            double hn = 0;
            for (int k = 0; k < L; k++) {
                hn += a[k] * Math.cos(2 * Math.PI * f[k] * (n - M / 2));
            }
            h[n] = hn / L;
        }
        return h;
    }
    public static double[] highPass(int M, double[] f, double[] a) {
        int L = f.length;
        double[] h = new double[M + 1];
        for (int n = 0; n <= M; n++) {
            double hn = 0;
            for (int k = 0; k < L; k++) {
                hn += a[k] * Math.cos(2 * Math.PI * f[k] * (n - M / 2));
            }
            h[n] = (k % 2 == 0 ? 1 : -1) * hn / L;
        }
        return h;
    }
    public static void main(String[] args) {
        int M = 31;
        double[] f = {0, 0.2, 0.3, 0.5};
        double[] a = {1, 1, 0, 0};
        double[] hlp = lowPass(M, f, a);
        double[] hhp = highPass(M, f, a);
        System.out.println("Low pass filter coefficients:");
        for (int i = 0; i < hlp.length; i++) {
            System.out.printf("%.3f ", hlp[i]);
        }
        System.out.println("\nHigh pass filter coefficients:");
        for (int i = 0; i < hhp.length; i++) {
            System.out.printf("%.3f ", hhp[i]);
        }
    }
}


3. 最小二乘法


最小二乘法是一种通过线性拟合的方式来设计滤波器的方法,其基本思想是寻找一个滤波器系数向量,使得该向量与目标响应之间的误差平方和最小。这种方法的优点是可以比较精确地设计滤波器,但缺点是计算量较大。


下面是一个简单的Java代码示例:

public class LeastSquaresFilter {
    public static double[] lowPass(int M, double fc) {
        int N = M + 1;
        double[] t = new double[N];
        double[] b = new double[N];
        for (int n = 0; n < N; n++) {
            t[n] = 2 * Math.PI * fc * (n - M / 2);
            b[n] = (n == M / 2 ? 2 * fc : Math.sin(t[n]) / t[n]);
        }
        Matrix A = new Matrix(N, N);
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                A.set(i, j, b[Math.abs(i - j)]);
            }
        }
        Matrix B = new Matrix(N, 1);
        B.set(M / 2, 0, 2 * fc);
        Matrix X = A.solve(B);
        double[] h = new double[M + 1];
        for (int n = 0; n <= M / 2; n++) {
            h[n] = X.get(M / 2 - n, 0);
        }
        for (int n = M / 2 + 1; n <= M; n++) {
            h[n] = X.get(n - M / 2, 0);
        }
        return h;
    }
    public static double[] highPass(int M, double fc) {
        int N = M + 1;
        double[] t = new double[N];
        double[] b = new double[N];
        for (int n = 0; n < N; n++) {
            t[n] = 2 * Math.PI * fc * (n - M / 2);
            b[n] = (n == M / 2 ? 1 - 2 * fc : -Math.sin(t[n]) / t[n]);
        }
        Matrix A = new Matrix(N, N);
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                A.set(i, j, b[Math.abs(i - j)]);
            }
        }
        Matrix B = new Matrix(N, 1);
        B.set(M / 2, 0, 1 - 2 * fc);
        Matrix X = A.solve(B);
        double[] h = new double[M + 1];
        for (int n = 0; n <= M / 2; n++) {
            h[n] = X.get(M / 2 - n, 0) * (n % 2 == 0 ? 1 : -1);
        }
        for (int n = M / 2 + 1; n <= M; n++) {
            h[n] = X.get(n - M / 2, 0) * (n % 2 == 0 ? 1 : -1);
        }
        return h;
    }
    public static void main(String[] args) {
        int M = 31;
        double[] hlp = lowPass(M, 0.4);
        double[] hhp = highPass(M, 0.4);
        System.out.println("Low pass filter coefficients:");
        for (int i = 0; i < hlp.length; i++) {
            System.out.printf("%.3f ", hlp[i]);
        }
        System.out.println("\nHigh pass filter coefficients:");
        for (int i = 0; i < hhp.length; i++) {
            System.out.printf("%.3f ", hhp[i]);
        }
    }
}


4. 极点优化法


极点优化法是一种将滤波器设计问题转化为寻找最佳极点位置的方法,其基本思想是在预设截止频率范围内选择若干个复平面上的点作为极点,然后计算出对应的幅度响应和相位响应,以此得到实际的滤波器系数。这种方法的优点是可以比较精确地设计滤波器,但缺点是计算量较大。


下面是一个简单的Java代码示例:

public class PoleZeroFilter {
    public static double[] lowPass(int M, double fc) {
        double[] p = new double[M / 2];
        for (int k = 0; k < M / 2; k++) {
            double theta = Math.PI * (2 * k + 1) / (2 * M);
            p[k] = -Math.sin(theta) / Math.cos(theta);
        }
        ComplexDouble[] zeros = new ComplexDouble[0];
        ComplexDouble[] poles = new ComplexDouble[M / 2];
        for (int k = 0; k < M / 2; k++) {
            poles[k] = new ComplexDouble(p[k], 0);
        }
        FilterCoefficients coeffs = new FilterCoefficients(zeros, poles, 1.0);
        double[] h = coeffs.getImpulseResponse(M + 1);
        return h;
    }
    public static double[] highPass(int M, double fc) {
        double[] p = new double[M / 2];
        for (int k = 0; k < M / 2; k++) {
            double theta = Math.PI * (2 * k + 1) / (2 * M);
            p[k] = -Math.sin(theta) / Math.cos(theta);
        }
        ComplexDouble[] zeros = new ComplexDouble[1];
        zeros[0] = new ComplexDouble(0, 0);
        ComplexDouble[] poles = new ComplexDouble[M / 2];
        for (int k = 0; k < M / 2; k++) {
            poles[k] = new ComplexDouble(p[k], 0);
        }
        FilterCoefficients coeffs = new FilterCoefficients(zeros, poles, -1.0);
        double[] h = coeffs.getImpulseResponse(M + 1);
        return h;
    }
    public static void main(String[] args) {
        int M = 31;
        double[] hlp = lowPass(M, 0.4);
        double[] hhp = highPass(M, 0.4);
        System.out.println("Low pass filter coefficients:");
        for (int i = 0; i < hlp.length; i++) {
            System.out.printf("%.3f ", hlp[i]);
        }
        System.out.println("\nHigh pass filter coefficients:");
        for (int i = 0; i < hhp.length; i++) {
            System.out.printf("%.3f ", hhp[i]);
        }
    }
}


滤波器实现


了解滤波器的实现方法,包括有限脉冲响应(FIR)和无限脉冲响应(IIR)结构等。

滤波器是一种信号处理工具,它可以将输入信号通过某些特定的算法转换为特定频率范围内的输出信号。在实际应用中,有两种常见的滤波器实现方法:有限脉冲响应(FIR)和无限脉冲响应(IIR)结构。


1. 有限脉冲响应(FIR)滤波器


有限脉冲响应(FIR)滤波器是一种基于线性时不变系统的滤波器,其特点是具有有限长度的单位冲激响应。FIR滤波器可以通过卷积运算来实现,因此也称为卷积滤波器。FIR滤波器的优点是稳定、易于设计,但缺点是需要较大的存储空间和处理时间,且对于高阶滤波器,其相位响应可能会引入延迟。


下面是一个简单的Java代码示例,实现了一个10阶低通FIR滤波器:

public class FIRFilter {
    private double[] b; // FIR filter coefficients
    private double[] x; // input buffer
    private int pos; // current position in input buffer
    public FIRFilter(double[] b) {
        this.b = b;
        this.x = new double[b.length];
        this.pos = 0;
    }
    public double filter(double input) {
        x[pos] = input;
        double output = 0;
        for (int i = 0; i < b.length; i++) {
            output += b[i] * x[(pos + b.length - i) % b.length];
        }
        pos = (pos + 1) % b.length;
        return output;
    }
    public static void main(String[] args) {
        double[] b = {0.1, 0.2, 0.3, 0.4};
        FIRFilter filter = new FIRFilter(b);
        double[] input = {0.5, 0.6, 0.7, 0.8, 0.9};
        for (double x : input) {
            System.out.printf("%.3f ", filter.filter(x));
        }
    }
}


2. 无限脉冲响应(IIR)滤波器


无限脉冲响应(IIR)滤波器是一种基于反馈系统的滤波器,其特点是具有无限长度的单位冲激响应。IIR滤波器可以通过递归运算来实现,因此也称为递归滤波器。IIR滤波器的优点是存储空间和处理时间更低,且对于高阶滤波器,其相位响应可能会更加平稳,但缺点是可能不稳定,需要进行稳定性分析和设计。


下面是一个简单的Java代码示例,实现了一个一阶低通IIR滤波器:

public class IIRFilter {
    private double a; // IIR filter coefficient
    private double b; // IIR filter coefficient
    private double yPrev; // previous output value
    public IIRFilter(double a, double b) {
        this.a = a;
        this.b = b;
        this.yPrev = 0;
    }
    public double filter(double input) {
        double output = b * input + a * yPrev;
        yPrev = output;
        return output;
    }
    public static void main(String[] args) {
        double a = 0.5;
        double b = 0.5;
        IIRFilter filter = new IIRFilter(a, b);
        double[] input = {0.5, 0.6, 0.7, 0.8, 0.9};
        for (double x : input) {
            System.out.printf("%.3f ", filter.filter(x));
        }
    }
}


以上是有限脉冲响应(FIR)和无限脉冲响应(IIR)滤波器的概念和Java代码实现。接下来,我们将介绍如何对这两种滤波器进行优化。


3. 有限脉冲响应(FIR)滤波器的优化


FIR滤波器的性能取决于其滤波器系数的数量,因此可以通过优化滤波器系数来提高其性能。常见的优化方法包括:


窗函数法:选择一个特定的窗函数,并使用该窗函数来设计滤波器系数。

Parks-McClellan算法:使用最小最大误差准则来设计滤波器系数。

Remez交错最小二乘法:使用迭代方法来设计滤波器系数。

下面是一个简单的Java代码示例,展示了如何使用Parks-McClellan算法来设计20阶低通FIR滤波器:

public class FIRFilter {
    private double[] b; // FIR filter coefficients
    private double[] x; // input buffer
    private int pos; // current position in input buffer
    public FIRFilter(double[] b) {
        this.b = b;
        this.x = new double[b.length];
        this.pos = 0;
    }
    public double filter(double input) {
        x[pos] = input;
        double output = 0;
        for (int i = 0; i < b.length; i++) {
            output += b[i] * x[(pos + b.length - i) % b.length];
        }
        pos = (pos + 1) % b.length;
        return output;
    }
    public static double[] designLowPassFilter(int M, double fc) {
        int N = 2 * M + 1;
        double[] bands = {0, fc, fc + 0.1, 0.5};
        double[] desired = {1, 0};
        FIRFilterDesign design = new FIRFilterDesign();
        design.setFilterType(FIRFilterDesign.FilterType.BANDPASS);
        design.setWindowType(FIRFilterDesign.WindowType.KAISER);
        design.setNumTaps(N);
        design.setBandEdges(bands);
        design.setDesiredResponse(desired);
        double[] b = design.design();
        return b;
    }
    public static void main(String[] args) {
        int M = 10;
        double fc = 0.4;
        double[] b = designLowPassFilter(M, fc);
        FIRFilter filter = new FIRFilter(b);
        double[] input = {0.5, 0.6, 0.7, 0.8, 0.9};
        for (double x : input) {
            System.out.printf("%.3f ", filter.filter(x));
        }
    }
}


4. 无限脉冲响应(IIR)滤波器的优化


IIR滤波器的性能取决于其极点和零点的位置,因此可以通过优化极点和零点的位置来提高其性能。常见的优化方法包括:


极点优化法:通过最小化最大误差来确定极点的位置。

零极点双线性变换法:将连续时间滤波器转换为离散时间滤波器,并使零点和极点保持不变,以提高滤波器性能。

下面是一个简单的Java代码示例,展示了如何使用极点优化法来设计一阶低通IIR滤波器:

public class IIRFilter {
    private double a; // IIR filter coefficient
    private double b; // IIR filter coefficient
    private double yPrev; // previous output value
    public IIRFilter(double a, double b) {
        this.a = a;
        this.b = b;
        this.yPrev = 0;
    }
    public double filter(double input) {
        double output = b * input + a * yPrev;
        yPrev = output;
        return output;
    }
    public static double[] optimizePole(double fc) {
        double omegaC = 2 * Math.PI * fc;
        double T = 1;
        double thetaP = 0.5 * (-Math.cos(omegaC * T / 2) + Math.sqrt(Math.pow(Math.cos(omegaC * T / 2), 2) - 1));
        double real = -Math.log(0.01) / (T * thetaP);
        double imag = Math.sqrt(1 - Math.pow(real, 2));
        double[] pole = {-real, imag};
        return pole;
    }
    public static void main(String[] args) {
        double fc = 0.4;
        double[] pole = optimizePole(fc);
        double a = -pole[0];
        double b = (1 - Math.exp(-pole[0])) / (1 + Math.exp(-pole[0]));
        IIRFilter filter = new IIRFilter(a, b);
        double[] input = {0.5, 0.6, 0.7, 0.8, 0.9};
        for (double x : input) {
            System.out.printf("%.3f ", filter.filter(x));
        }
    }
}


以上是有限脉冲响应(FIR)和无限脉冲响应(IIR)滤波器的概念、Java代码实现以及优化方法。需要注意的是,在实际应用中,滤波器的设计和优化通常需要考虑多个因素,并进行综合分析和评估。


数字滤波器的稳定性


掌握数字滤波器的稳定性判断方法。

数字滤波器的稳定性是指输入信号有限时,输出信号是否有界。如果输出信号有界,则滤波器是稳定的;否则,滤波器是不稳定的。数字滤波器的稳定性判断方法包括两种:极点分布法和频率响应法。


1. 极点分布法


根据数字滤波器的传递函数,可以求出其所有极点及其在复平面内的位置。如果所有极点都位于单位圆内或左半个复平面,则滤波器是稳定的;否则,滤波器是不稳定的。下面是一个简单的Java代码示例,演示如何利用极点分布法判断数字滤波器的稳定性:

public class FilterStability {
    public static boolean isStable(double[] a) {
        Complex[] poles = PolynomialUtils.findRoots(a);
        for (Complex pole : poles) {
            if (pole.abs() >= 1) {
                return false;
            }
        }
        return true;
    }
    public static void main(String[] args) {
        double[] a = {1, -1.5, 0.7};
        boolean stable = isStable(a);
        System.out.println(stable ? "Stable" : "Unstable");
    }
}


2. 频率响应法


对于任意数字滤波器,其稳定性可以通过检查其频率响应是否满足BIBO(Bounded-Input, Bounded-Output)条件来判断。如果数字滤波器的频率响应有限,则它是一个稳定的滤波器;否则,它是不稳定的。下面是一个简单的Java代码示例,演示如何利用频率响应法判断数字滤波器的稳定性:

public class FilterStability {
    public static boolean isStable(double[] b, double[] a) {
        int N = 100;
        double[] H = new double[N];
        for (int i = 0; i < N; i++) {
            double w = Math.PI * i / N;
            Complex z = new Complex(Math.cos(w), Math.sin(w));
            Complex Hz = PolynomialUtils.evaluate(b, z).divide(PolynomialUtils.evaluate(a, z));
            H[i] = Hz.abs();
        }
        double maxH = DoubleStream.of(H).max().getAsDouble();
        return maxH < Double.POSITIVE_INFINITY;
    }
    public static void main(String[] args) {
        double[] b = {0.1, 0.2, 0.3, 0.4};
        double[] a = {1, -0.5, 0.25};
        boolean stable = isStable(b, a);
        System.out.println(stable ? "Stable" : "Unstable");
    }
}


以上是数字滤波器的稳定性判断方法及其在Java中的实现。需要注意的是,这两种方法仅适用于线性时不变系统,对于其他类型的数字滤波器如非线性系统、时变系统等,还需要使用其他方法来判断其稳定性。

相关实践学习
【文生图】一键部署Stable Diffusion基于函数计算
本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
相关文章
|
9天前
|
监控 Java 数据管理
java会话跟踪和拦截器过滤器
本文介绍了Web开发中的会话跟踪技术——Cookie与Session,以及过滤器(Filter)和监听器(Listener)的概念和应用。Cookie通过在客户端记录信息来识别用户,而Session则在服务器端保存用户状态。过滤器用于拦截和处理请求及响应,监听器则监控域对象的状态变化。文章详细解释了这些技术的实现方式、应用场景和主要方法,帮助开发者更好地理解和使用这些工具。
21 1
|
2月前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
392 37
|
1月前
|
前端开发 Java 应用服务中间件
Javaweb学习
【10月更文挑战第1天】Javaweb学习
31 2
|
1月前
|
安全 Java Android开发
JavaWeb解压缩漏洞之ZipSlip与Zip炸弹
JavaWeb解压缩漏洞之ZipSlip与Zip炸弹
45 5
|
1月前
|
分布式计算 Java Hadoop
Hadoop-30 ZooKeeper集群 JavaAPI 客户端 POM Java操作ZK 监听节点 监听数据变化 创建节点 删除节点
Hadoop-30 ZooKeeper集群 JavaAPI 客户端 POM Java操作ZK 监听节点 监听数据变化 创建节点 删除节点
61 1
|
2月前
|
缓存 前端开发 Java
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
|
2月前
|
安全 Java Android开发
JavaWeb解压缩漏洞之ZipSlip与Zip炸弹
JavaWeb解压缩漏洞之ZipSlip与Zip炸弹
97 2
|
1月前
|
Java C#
Java的监听处理事件--小球移动案例
Java的监听处理事件--小球移动案例
13 0
|
2月前
|
SQL JSON JavaScript
JavaWeb基础9——VUE,Element&整合Javaweb的商品管理系统
Vue 指令、生命周期、this和$、vue脚手架进行模块化开发/ElementUI框架、综合案例,element商品列表展示增删改查
JavaWeb基础9——VUE,Element&整合Javaweb的商品管理系统
|
2月前
|
监控 前端开发 Java
Java里的过滤器和拦截器是什么原理,如何选择?
Java里的过滤器和拦截器是什么原理,如何选择?
29 0