Using Julia to model DSP signals and systems efficiently with reusable and composable system blocks.
Julia iterators provide a convenient means for describing sampled-data signals used in digital signal processors. This work builds on this and describes a simple means of composing signal processing operations to describe a signal processing system independent of the applied input signal.
DSP term | more general term | Julia etc |
---|---|---|
Signal | sequence | iterator |
System | processor | transducer |
Julia already provides some functions that operate on iterators. For example Base.Iterators.map and Base.Iterators.take, but it is not possible to use these without also specifying the input iterator to act on. For example this is not supported:
system = Base.Iterators.map( x->x^2 ) |> Base.Iterators.take(5) # this does not work
To make this work, it would need to be written as:
system = sig -> Base.Iterators.map( x->x^2, sig ) |> sig -> Base.Iterators.take(sig,5)
which returns an anonymous function with a meaningless symbol name during debugging.
However, using this very simple framework, this is supported:
system = Processors.Map( x->x^2 ) |> Processors.Take(5)
y = 1:10 |> system |> collect
giving:
5-element Vector{Int64}:
1
4
9
16
25
This could also be achieved using Transducers.jl but transducers are more general and harder to comprehend. The heart of this functionality is the few lines of code in src/Processors/processor.jl. The rest of repository contains example processors and also some signal generators.
upsample, downsample, take, map, flatten, SlidingWindow etc
A version of this was presented at OrConf 2024 - Slides - YouTube.