Note: This library is not currently being maintained.
The ability to create 2-dimensional, canvas based plots of signal waveforms is available through the simplot library.
The graph-centric algorithms (ie, scc, 2-sat, Prim's MST, Kruskal's MST, all pairs shortest path and the knapsack algorithm) have been moved to the graphlab library.
The library is currently moving its 1-dimensional data structure from List
to Sequence
, which extends the ListBase
class and adds a number of methods and capabilities.
Some features of the library include:
- Flexible data structures:
Sequences: generate and easily manipulate impulse, step, position or arbitrary sequences
Complex numbers: create complex numbers and handle complex calculations - Hyperbolic and logarithmic functions:
sinh()
,cosh()
,log2()
,log10()
etc. - Simple waveform generator: square, pulse, triangular, etc.
- Polynomial string construction in text, HTML or latex format
- Common signal processing algorithms including (more are in development):
fft()
: fast and discrete Fourier transform
ifft()
: fast and discrete inverse Fourier transform
fsps()
: partial sums of Fourier series
conv()
: convolution
deconv()
: deconvolution
corr()
: cross and auto correlation
filter()
: a 1D transposed direct form II digital filter structure
Most library access is through top level function calls.
Add the following to your pubspec.yaml:
convolab:
git: git://github.com/scribeGriff/ConvoLab.git
Then import the library to your app:
import 'package:convolab/convolab.dart';
The library is currently moving to using Sequences as the main data structure. A sequence extends from the ListBase
class and therefore shares many of the same methods of the List data type. Some examples of using a Sequence data structure:
// Creates a List object.
var list = [1, 2, 3, 4];
// Converts the List into a Sequence.
var seq1 = sequence(list);
// Check if seq1 is a Sequence.
print(seq1 is Sequence);
// Print the sequence.
print(seq1);
// Prints:
// true
// [1, 2, 3, 4]
// Any Iterable, including another sequence, can be passed to the
// sequence function.
var seq2 = sequence(list.map((element) => element * 2));
// Sequences can be added, subtracted, multiplied, and divided element
// by element:
var seq3 = seq1 + seq2;
print(seq3);
// Prints:
// [3, 6, 9, 12]
// and element by number:
var seq4 = seq3 * 2;
print(seq4);
// Prints:
// [6, 12, 18, 24]
// Sequences can be made periodic:
print(sequence(seq1, 4));
// Prints:
// [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
Sequences allow us to perform a variety of tasks on sampled data. For example, suppose we had a sample sequence, x(n), and we wanted to know what x1(n) = 2x(n - 5) - 3x(n + 4) was.
// x(n)
Sequence x = sequence([1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1]);
// n, zeroth position at element 2.
Sequence n = x.position(2);
// n - 5
Sequence nm5 = shiftseq(n, 5);
// n + 4
Sequence np4 = shiftseq(n, -4);
// x1(n) = 2x(n - 5) - 3x(n + 4)
var x1 = addseqs(x * 2, x * -3, nm5, np4);
print(x1.x);
print(x1.n);
// Prints:
// [-3, -6, -9, -12, -15, -18, -21, -18, -15, -10, -5, 0, 5, 10, 12, 14, 12, 10, 8, 6, 4, 2]
// [-6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
The function, addseqs()
, allows us to add sequences that have position information. In this example, the n = 0 sample point was the 3rd element in the sequence x(n). The function shiftseq()
(as well as foldseq()
), are also methods of the Sequence class. Therefore, we could do the following:
var x2 = position(11, 5);
print(x2);
print(x2.shiftseq(2).foldseq(negate:true));
// Prints:
// [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]
// [-7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3]
The position()
function creates a sample position sequence 11 samples long and places the 0 position at the 6th position in the sequence (sequences, like all Iterables
in the Dart programming language, are based on the first element being element 0).
To convert a sequence to a list, simply use the toList()
method of the ListBase
class.
+
operator - adds a sequence to another sequence of the same length or to a number-
operator - subtracts a sequence from another sequence of the same length or from a number*
operator - multiplies a sequence by another sequence of the same length or by a number/
operator - divides a sequence by another sequence of the same length or by a numberposition()
- creates a position sequenceshiftseq()
- shifts a sequencefoldseq()
- folds(ie, reverses) a sequencetoReal()
- converts a complex sequence to a real valued sequencetoComplex()
- converts a real sequence to a complex valued sequenceequals()
- returns a boolean indicating element by element equivalence between two sequencesabs()
- returns a sequence with the absolute value of each elementmin()
- returns the minimum of a sequencemax()
- returns the maximum of a sequencesum()
- returns the sum of a sequenceprod()
- returns the product of a sequenceenergy()
- returns the energy of a sequencepower()
- returns the power of a sequenceiterator
- returns an iterator to the sequence (allowsfor
in
andforEach
)middle
- returns the index of the middle element of the sequence (truncates)
sequence()
- create a new sequence from an Iterableposition()
- creates a position sequencezeros()
- creates a sequence of zerosones()
- creates a sequence of onesimpseq()
- creates an impulse sequencestepseq()
- creates a step sequenceshiftseq()
- shifts a sequencefoldseq()
- folds (ie, reverses) a sequenceaddseqs()
- adds sequences that are of differing lengths and/or have position informationmultseqs()
- multiplies sequences that are of differing lengths and/or have position informationevenodd()
- decompose a sequence into its even and odd components.
The library contains support for complex numbers. A complex number can be defined as follows:
var c = complex(1, 2);
print(c.string);
// Prints:
// 1.00 + 2.00j
The complex class implements the following methods:
string
- returns the complex number as a stringmagnitude
- returns the magnitude of a complex numberphase
- returns the phase of a complex numbercroud2
- rounds fractional part of complex number to two significant digitsconj
- returns the complex conjugate of the complex numberrecip
- returns the reciprocal of the complex numbercexp
- returns the complex exponential of the complex numbercsin
- returns the complex sine of the complex numberccos
- returns the complex cosine of the complex numberctan
- returns the complex tangent of the complex numberscale()
- scales the complex number by a number of type int or double+
operator adds a complex number to another complex number-
operator subtracts a complex number from another complex number*
operator multiplies a complex number by another complex number/
operator divides a complex number by another complex number==
operator checks if two complex numbers are equal (hashCode
is implemented)
To convert a sequence to a readable polynomial string, the library contains a function called pstring()
. The function can generate strings in text, HTML, or Latex format. In its simplest form, pstring()
requires only a sequence of polynomial coefficients:
// Simple case - defaults
Sequence coefficients = sequence([2, 5, -3, 7]);
String polyString = pstring(coefficients);
print(polyString);
// prints:
// $$f(x) = 2 + 5x^{-1} - 3x^{-2} + 7x^{-3}$$
The Latex format, for use with MathJax in a browser, is the default. The pstring()
function also accepts several named optional parameters:
index
: for causal signals, this is the n = 0 position index (default = 0)type
: String representing desired format text, html, latex (default = 'latex')variable
: String representing the variable name (default = 'x')name
: String representing the function name (default = 'f')
Some additional examples:
// Setting options - html format.
polyString = pstring(coefficients, type: 'html', name: 'y', variable: 'n');
print(polyString);
// prints:
// y(n) = 2 + 5n<sup>-1</sup> - 3n<sup>-2</sup> + 7n<sup>-3</sup>
// Send the output to element on a webpage
query("#myDiv").appendHtml(pstring(test, type:'html'));
// Working with causal signals.
zeroIndex = 2;
polyString = pstring(coefficients, index: zeroIndex, type: 'html', name: 'y', variable: 'n');
print(polyString);
// prints:
// y(n) = 2n<sup>2</sup> + 5n - 3 + 7n<sup>-1</sup>
// Another example working with causal signals.
coefficients = sequence([1, 1, 1, 1, 1, 1]);
polyString = pstring(coefficients, index: zeroIndex, type: 'text');
print(polyString);
// prints:
// f(x) = x^2 + x + 1 + x^-1 + x^-2 + x^-3
The library functions conv()
and deconv()
both implement the PolyString
class as a format()
method to the function results. In the case of deconv()
, the format()
method handles remainders.