smart_signal_processing 2.0.2 smart_signal_processing: ^2.0.2 copied to clipboard
Provides useful functions for signal processing such as Fast Fourier Transform, windowing (apodization), variance/standard deviation and others.
// Copyright (c) 2019, Dr. Bruno Guigas. All rights reserved. Use of this source
// code is governed by a BSD-style license that can be found in the LICENSE file.
import 'package:smart_signal_processing/smart_signal_processing.dart';
import 'dart:typed_data';
import 'dart:math' as math;
/// Signal processing example:
/// - Computes 8 periods of a cosine shape filling an array of 256 points.
/// - Applies an exponential function, resulting in a decaying oscillation
/// - Applies a real Fourier transform, resulting in a complex-valued line shape
/// whose real part is an absorption mode Lorentzian, and whose imaginary
/// part is a dispersion mode Lorentzian. The real part's maximum is at
/// index 8, corresponding to the number of periods.
/// Paste the printed output into MS Excel, OpenOffice calc, Google tables or
/// similar to view result as a curve.
main() {
// Generate sine wave consisting of [npoints] with [amplitude] and [phase],
// and [nperiods] periods within [npoints]. Make the sine "noisy" by adding
// [noise] a fraction of [amplitude].
Float64List genSine(
int npoints, double amplitude, double phase, int nperiods, double noise) {
math.Random rand = math.Random();
double xmax = 2 * math.pi * nperiods, x, y;
Float64List sine = new Float64List(npoints);
for (int i = 0; i < npoints; i++) {
x = (i * xmax) / npoints;
y = amplitude * math.sin(x + phase);
// add noise between -1 and 1
sine[i] = y + noise * amplitude * (2 * rand.nextDouble() - 1.0).sign;
}
return sine;
}
// Generate cosine
final int NPOINTS = 256, NPERIODS = 8;
Float64List reals = genSine(NPOINTS, 100.0, math.pi / 2, NPERIODS, 0.0);
Float64List imags = Float64List(reals.length);
// Make cosine exponentially decaying
double decayFactor = -3.0 / (reals.length - 1);
WinFunc.expMult(reals, decayFactor, false, "0");
// In-place transform: initally [imags] has only zeroes. After transform,
// [reals] contains absorption mode and [imags] dispersion mode Lorentzian shape.
FFT.transform(reals, imags);
// Print result: Due to the symmetry properties of the FFT only the first
// halfs play a role. The second halfs contain identical information
// (corresonding to "negative frequencies")
for (int i = 0; i < reals.length ~/ 2; i++) {
print("$i\t ${reals[i].toStringAsFixed(2)}");
}
for (int i = 0; i < imags.length ~/ 2; i++) {
print("$i\t ${imags[i].toStringAsFixed(2)}");
}
}