SciDart
Signal processing
FIR filter design, filtering, peaks, window functions and convolution.
Like scipy.signal
FIR filters
firwin designs a linear phase FIR filter with the window method, like scipy.signal.firwin, and lfilter applies it. pass_zero accepts true, false, 'lowpass', 'highpass', 'bandpass' and 'bandstop'.
import 'dart:math' as math;
import 'package:scidart/numdart.dart';
import 'package:scidart/scidart.dart';
void main() {
var fs = 100.0;
var t = linspace(0, 1, num: 100, endpoint: false);
var slow = arraySin(arrayMultiplyToScalar(t, 2 * math.pi * 2));
var fast = arraySin(arrayMultiplyToScalar(t, 2 * math.pi * 30));
var x = slow + fast;
// 31 taps, cutoff at 10 Hz
Array b = firwin(31, Array([10]), fs: fs);
var y = lfilter(b, Array([1]), x);
// after the filter delay (15 samples), y follows the slow wave
var error = 0.0;
for (var i = 30; i < 100; i++) {
error = math.max(error, (y[i] - slow[i - 15]).abs());
}
print('taps: ${b.length}, sum of taps: ${arraySum(b).toStringAsFixed(6)}');
print('max difference to the 2 Hz wave: ${error.toStringAsFixed(4)}');
}
Output
taps: 31, sum of taps: 1.000000 max difference to the 2 Hz wave: 0.0017
Loading the interactive demo…
Peaks
import 'package:scidart/numdart.dart';
import 'package:scidart/scidart.dart';
void main() {
var a = Array([0, 2, 1, 3, 0, 1, 5, 2, 0]);
var all = findPeaks(a);
print(
'indexes: ${(all[0] as Array).toList()}, values: ${(all[1] as Array).toList()}');
var tall = findPeaks(a, threshold: 3);
print(
'above 3: indexes ${(tall[0] as Array).toList()}, values ${(tall[1] as Array).toList()}');
}
Output
indexes: [1.0, 3.0, 6.0], values: [2.0, 3.0, 5.0] above 3: indexes [3.0, 6.0], values [3.0, 5.0]
Window functions
hann, hamming, blackman, blackmanharris, nuttall, flattop and kaiser, plus getWindow to pick one by name. With sym: false they return the periodic version used for spectral analysis.
import 'package:scidart/numdart.dart';
import 'package:scidart/scidart.dart';
void main() {
String show(Array w) => w.map((v) => v.toStringAsFixed(4)).join(', ');
print('hann(5): ${show(hann(5))}');
print('hamming(5): ${show(hamming(5))}');
print('blackman(5): ${show(blackman(5))}');
print('kaiser(5, 8): ${show(kaiser(5, 8))}');
}
Output
hann(5): 0.0000, 0.5000, 1.0000, 0.5000, 0.0000 hamming(5): 0.0800, 0.5400, 1.0000, 0.5400, 0.0800 blackman(5): -0.0000, 0.3400, 1.0000, 0.3400, -0.0000 kaiser(5, 8): 0.0023, 0.3690, 1.0000, 0.3690, 0.0023
Loading the interactive demo…
Convolution
import 'package:scidart/numdart.dart';
import 'package:scidart/scidart.dart';
void main() {
var x = Array([1, 2, 3, 4, 5]);
print(convolution(x, Array([1, 1, 1])).toList());
print(arrayDivisionToScalar(convolution(x, Array([1, 1, 1])), 3).toList());
print(correlate(x, Array([0, 1, 0.5])).toList());
}
Output
[1.0, 3.0, 6.0, 9.0, 12.0, 9.0, 5.0] [0.3333333333333333, 1.0, 2.0, 3.0, 4.0, 3.0, 1.6666666666666667] [0.5, 2.0, 3.5, 5.0, 6.5, 5.0, 0.0]
convolution and correlate return the full result, like numpy.convolve(..., mode='full'). Pass fast: true to compute them through the FFT.