Fast implementations of FastICA and DUET for blind source separation
Author baggepinnen
5 Stars
Updated Last
1 Year Ago
Started In
July 2020


Build Status Coverage


This package modifies the implementation of the FastICA algorithm from MultivariateStats.jl to make it more than 5x faster. This comes at the expense of taking an additional dependency, on LoopVectorization.jl and some additional compilation time.

This package also modifies the interface to the algorithm slightly, use it like this:

using IndependentComponentAnalysis
X = randn(4,100)
k = 2 # Number of components to extract
ica = fit(ICA, X, k,  alg = FastICA();
                fun       = Tanh(),
                do_whiten = true,
                maxiter   = 100,
                tol       = 1e-6,
                mean      = nothing,
                winit     = nothing

Xt = transform(ica, X)
  • The options for fun are Tanh(a::Real) and Gaus()
  • If you have also loaded MultivariateStats, a conflict will arise, cauing you to have to qualify fun like this: IndependentComponentAnalysis.Tanh etc. If this PR is merged, this package will work better together with MultivariateStats.


DUET (Degenerate Unmixing Estimation Technique) is an algorithm for blind source separation. It works on stereo mixtures and can separate any number of sources as long as they do not overlap in the time-frequency domain. The interface looks like this:

est, H = duet( x1, x2, n_sources, n = 1024;
                    p            = 1, # amplitude power used to weight histogram
                    q            = 0, # delay power used to weight histogram
                    amax         = 0.7,
                    dmax         = 3.6,
                    abins        = 35,
                    dbins        = 50,
                    kernel_size  = 1, # Controls the smoothing of the histogram.
                    bigdelay     = false,
                    kernel_sizeδ = 1,
                    window       = hanning,
                    kwargs..., # These are sent to the stft function

The returned values are est::Matrix(time, n_sources) and H::DUET. H can be plotted plot(H), which shows the delay/amplitude histogram and the identified peaks. This can be used to tweak the input parameters.

  • bigdelay indicates whether or not the two microphones are far apart. If true, the delay δ is estimated using the differential method (see the paper sec 8.4.1) and the delay map is smoothed using kernel_sizeδ.


t  = 0:0.1:2000
x1 = sin.(t)
x2 = @. 1.3 * sign(sin(2t + 0.2) ) + 0.001 * randn()
W  = [0.3 0.7; 0.6 0.4] # Mixing matrix
R  = W * [x1 x2]'
r1, r2 = R[1, :], R[2, :]

est, H = duet( r1, r2, 2, 1024,
    dmax        = 3.5,
    amax        = 2.8,
    kernel_size = 1,

plotinds = 10000:10200
plot(plotinds, est[plotinds,:], lab = "Estimated components", c = :blue)
plot!(plotinds, [x1 x2][plotinds,:], lab = "True signal", c = :black)
plot!(plotinds, [r1 r2][plotinds,:], lab = "Received signal", c = :orange) |> display

plot(H) |> display

signals hist

Creating mixture signals

mix   = mixture(signals, amps, [delays::Vector{Int}])
mixes = mixture(signals, amps::Vector{Vector}, [delays::Vector{Vector{Int}}])

Mixes together signals using amplitudes amps and delays (delays is specified in samples). If amps and the optional delays are vectors of vectors, then a vector of mixtures is returned. A vector of vectors is converted to a matrix using M = reduce(hcat, mixes).