项目作者: baggepinnen

项目描述 :
Classical adaptive linear filters in Julia
高级语言: Julia
项目地址: git://github.com/baggepinnen/AdaptiveFilters.jl.git
创建时间: 2019-12-24T02:05:13Z
项目社区:https://github.com/baggepinnen/AdaptiveFilters.jl

开源协议:MIT License

下载


AdaptiveFilters

CI
Coverage

Simple adaptive AR filters. We export two functions:

  1. yh = adaptive_filter(y, alg=MSPI; order=4, lr=0.1)

This filters y with an adaptive AR (only poles) filter with specified order and returns yh which is the predicted output from an adaptive line enhancer (ALE). If your noise is wideband and signal narrowband, yh is your desired filtered signal. If the noise is narrowband and the signal is wideband, then y-yh is your desired filtered signal.

Arguments:

  • alg: Stochastic approximation algorithm or weight function. Examples: OMAP, MSPI, OMAS, ADAM, ExponentialWeight, EqualWeight. ExponentialWeight corresponds to the recursive least-squares algorithm (RLS). ADAM corresponds roughly to the normalized least-mean squares (NLMS) algorithm. More options exist if OnlineStats is loaded.
  • y: Input signal
  • order: Filter order
  • lr: Learning rate or weight depending on alg

The function

  1. focused_adaptive_filter(y, band, fs, args...; kwargs...)

allows you to specify a frequency band (tuple) in which to focus the attention of the adaptive filter. fs here denotes the sample rate, e.g., 44100Hz.

Installation

  1. using Pkg; Pkg.add("AdaptiveFilters")

Demo app

  1. using AdaptiveFilters, Plots, Interact
  2. inspectdr() # Preferred plotting backend for waveforms
  3. y = [sin.(1:100); sin.(0.2 .*(1:100))] # A sinusoid with changing frequency
  4. yn = y .+ 0.1*randn(length(y)) # A sinusoid with noise
  5. function app(req=nothing)
  6. @manipulate for order = 2:2:10,
  7. lr = LinRange(0.01, 0.99, 100),
  8. alg = [ExponentialWeight, MSPI, OMAP, OMAS, ADAM]
  9. yh = adaptive_filter(yn, alg, order=order, lr=lr)
  10. e = yn.-yh
  11. plot([yn yh], lab=["Measured signal" "Prediction"], layout=(2,1), show=false, sp=1)
  12. plot!(e, lab="Error", sp=2, title="RMS: $(√mean(abs2, e))")
  13. end
  14. end
  15. app()
  16. # Save filtered sound to disk
  17. using WAV
  18. yh = adaptive_filter(yn, OMAP, order=4, lr=0.25)
  19. e = yn.-yh
  20. wavwrite(e, "filtered.wav", Fs=fs)

window

NLMS

A normalized least-mean squares (NLMS) filter can be created like

  1. using AdaptiveFilters, Random
  2. N = 60 # Number of filter taps
  3. μ = 0.01 # Learning rate
  4. f = NLMS(N, μ)

This filter can then be called like

  1. ŷ, e = f(x, d)

where x is the input signal, d is the desired signal and is the filtered signal. The error e is also returned. This call modifies the internal state of f.

Adaptive line enhancer

The NLMS filter can be used to build an adaptive line enhancer (ALE) by letting the input signal be the desired signal delayed by a number of samples Δ:

  1. using Random
  2. Random.seed!(0)
  3. y = sin.(0:0.1:100)
  4. yn = y + 0.1*randn(length(y)) # A sinusoid with noise
  5. T = length(y)
  6. YH = zeros(T)
  7. E = zeros(T)
  8. Δ = 1 # Delay in samples
  9. for i = eachindex(y)
  10. YH[i], E[i] = f(yn[max(i-Δ, 1)], yn[i])
  11. end
  12. using Plots, Test
  13. @test mean(abs2, y[end-100:end] - YH[end-100:end]) < 1e-3
  14. plot([y yn YH E y-YH], lab=["y" "yn" "yh" "e" "y-yh"])

Internals

This is a lightweight wrapper around functionality in OnlineStats.jl which does all the heavy lifting.

Usage from python

  1. First install Julia and install this package in Julia.
  2. Install pyjulia using their instructions.
  3. Now the following should work
  1. $ python3
  2. >>> import julia
  3. >>> from julia import AdaptiveFilters as af
  4. >>> yh = af.adaptive_filter(y)

if that fails, try replacing the first line with

  1. >>> from julia.api import Julia
  2. >>> jl = Julia(compiled_modules=False)

Keyword args etc. work as normal

  1. af.adaptive_filter(y, af.ADAM, order=2)

Example: Adaptive cicada filtering

The following function does a reasonable job at filtering out the sound of cicadas from an audio recording

  1. cicada_filter(y,fs,args...; kwargs...) = y-focused_adaptive_filter(data,(4200,11000),fs,args...; kwargs...)