Hello! I’ve updated my VecLab DSP package to follow more Swift-like conventions. The package uses Accelerate to provide real and complex vector operations. Here’s a quick summary of its features:
- Mixed scalar, vector, real and complex operators:
+
,-
,*
,\
- Power operator
**
- Vectorized operations and functions using Accelerate
- DSP functions like
fft
,ifft
,ifftshift
Originally, VecLab was designed to quickly to port MATLAB code into Swift. It used tuples to represent complex numbers and arrays . Good enough for porting, but it became awkward for writing new Swift-native code. As the package developed into a more standalone DSP toolkit, I decided it was time to update the design.
VecLab 2.0
The biggest change is to complex scalars and arrays. Complex arrays are stored as split complex real and imaginary arrays for compatibility with VDSP, but now conform to the Collection
protocol.
ComplexDouble
struct conforms toSignedNumeric
protocol.ComplexDoubleArray
struct conforms toCollection
protocol.- Get and set Index ranges:
a[2...4] = b[10...12]
- Ranges can have an optional
step
parameter :a[2...4, 2] = b[10...12, 2]
GitHub
Documentation
You can find the DocC documention hosted on the Swift Package Index site:
VecLab Online Documentation
VecLab SwiftPackage Index Page
Example: Chirp Z-Transform (CZT)
Here’s an example of computing the Chirp Z-Transform using VecLab. The CZT allows you to perform FFT-like transforms of arbitrary length (non-power-of-2), useful for spectral zooming and frequency analysis with higher resolution in selected regions.
This implementation is based on the Chirp Z-Transform Spectral Zoom Optimization with MATLAB document.
func czt(_ x: ComplexArray, k: Int? = nil, w: Complex? = nil, a: Complex? = nil) -> ComplexArray {
// Handle input parameters
let m = x.count
let k = k ?? m
let w = w ?? expi(-2.0 * .pi / Double(k)) // expi is shortcut for Euler cos(x) + sin(x)*i
let a = a ?? Complex(1.0, 0.0)
// Length for power-of-two FFT
let nfft = Int(2 ** nextpow2(m+k-1))
// Premultiply data
let kk = vector((-m+1) ... max(k-1, m-1))
let kk2 = (kk ** 2.0) / 2.0
let ww = w ** kk2 // Chirp filter is 1./ww
// Apply initial twiddle factor
let nn = vector(0 ... (m-1))
var aa = a ** nn
aa = aa * ww[m-1 ..< m+m-1]
let y = x * aa
let inv_ww = 1.0 / ww[0 ..< (m+k-1)] // <----- Chirp filter.
// Fast convolution via FFT zero padded to length
var fy = fft(y, length: nfft)
let fv = fft(inv_ww, length: nfft)
fy = fy * fv
var g = ifft(fy)
// Final multiply
g = g[m-1 ..< (m+k-1)] * ww[m-1 ..< (m+k-1)]
return g
}
Expanded Functions
VecLab now includes a wide range of functions inspired by MATLAB and NumPy. Most operations support real or complex inputs, with scalar or vector types.
Group | Functions |
---|---|
Arrays | arange, cat, circshift, dot, flip, length, ones, paddata, repelem, resize, slice, trimdata, zeros |
Basic | abs, cumprod, cumsum, disp, iterate, norm, prod, sign, sum |
Complex | abs, angle, conj, cplxpair, imag, real, unwrap, wrapTo2Pi, wrapToPi |
Conversion | cart2pol, cart2sph, d2f, db2mag, db2pow, deg2rad, f2d, mag2db, pol2cart, pow2db, rad2deg, sph2cart |
Discrete | factor, factorial, gcd, isprime, lcm, nextprime, nchoosek, perms, prevprime, primes |
Exponents | exp, expi, log, log2, log10, nextpow2, sqrt |
FFT | dft, dftr, fft, fftr, fftshift, fftsymmetric, idft, idftr, ifft, ifftr, ifftshift |
Filter | biquad, freqz, filter |
Integration | diff, gradient, trapz |
Interpolation | interp1, interpft, sincresample |
Modulo | ceil, fix, floor, mod, rem, round, trunc |
Optimization | fminbnd, fminsearch |
Power | pow |
Random | awgn, rand, randn, rng |
Smoothing | hampel, medfilt1 |
Space | freqspace, linspace, logspace |
Special | besseli0, sinc |
Statistics | histcounts, max, maxindex, mean, median, min, minindex, mode, rms, stddev, variance |
Timing | tic, toc, timeit |
Trigonometry | acos, asin, atan, atan2, cos, sin, tan |
Window | blackman, blackmanharris, flattopwin, gausswin, hamming, hann, kaiser, tukeywin, rectwin |