The Zephyr Scientific Library (zscilib) is an attempt to provide a set of functions useful for scientific computing, data analysis and data manipulation in the context of resource constrained embedded hardware devices.
It is written entirely in C, and while the main development target for the library is the Zephyr Project, it tries to be as portable as possible, and a standalone reference project is included to use this library in non-Zephyr-based projects.
This version of zscilib has been developed and tested against Zephyr 2.2.
For project that have been setup using west
, you can add a local copy of
zscilib by adding the following sections to zephyr/west.yml
:
- In the
manifest/remotes
section add:
remotes:
- name: zscilib
url-base: https://github.com/zscilib
- In the
manifest/projects
section add:
- name: zscilib
remote: zscilib
path: modules/lib/zscilib
revision: master
- Save the file, and run
west update
from the project root to retrieve the latest version of zscilib from Github, or whateverrevision
was specified above.
To run the benchmark sample using qemu, run the following commands:
Be sure to run
source zephyr/zephyr-env.sh
(OS X or Linux) or.\zephyr\zephyr-env.cmd
(Windows) before the commands below!
$ west build -p -b qemu_cortex_m3 modules/lib/zscilib/samples/benchmarking -t run
Press CTRL+A
then x
to quit qemu.
To run the unit tests for this library, run the following command:
$ sanitycheck -p qemu_cortex_m3 -T modules/lib/zscilib/tests
See the tests
folder for further details.
The sample code in this library typically has the CONFIG_FLOAT
option set,
meaning that floating-point support is configured for
Unshared FP registers mode. This mode is used when the application
has a single thread that uses floating point registers.
If your application makes use of multiple threads, and more than one of
these threads uses floating-point operations, you should also enable the
CONFIG_FP_SHARING
config flag, which configures the kernel for
Shared FP registers mode. In this mode, the floating point registers are
saved and restored during each context switch, even when the associated threads
are not using them. This feature comes at the expense of an extra 72 bytes of
stack memory per stack frame (s0..s15
+ FPCSR
, plus an alignment word
to ensure that the stack pointer is double-word aligned).
A few makefile-based projects are included in samples/standalone
showing
how zscilib can be used independent of Zephyr.
If you already have an appropriate GNU toolchain and build tools (make
, etc.)
installed, you can simply execute the following commands:
$ cd samples/standalone/svd_pinv
$ make
$ bin/zscilib
Hello, zscilib!
...
The feature tables below indicate whether implemented functions support:
- f32: Single-precision floating-point operations
- f64: Double-precision floating-point operations
- ARM: Optimised ARM Thumb-2 ASM implementation
Feature | Func | f32 | f64 | ARM | Notes |
---|---|---|---|---|---|
Array to vector | zsl_vec_from_arr |
x | x | ||
Copy | zsl_vec_copy |
x | x | ||
Get subset | zsl_vec_get_subset |
x | x | ||
Add | zsl_vec_add |
x | x | ||
Subtract | zsl_vec_sub |
x | x | ||
Negate | zsl_vec_neg |
x | x | ||
Sum | zsl_vec_sum |
x | x | 2 or more vects | |
Scalar add | zsl_vec_scalar_add |
x | x | ||
Scalar multiply | zsl_vec_scalar_mult |
x | x | ||
Scalar divide | zsl_vec_scalar_div |
x | x | ||
Distance | zsl_vec_dist |
x | x | Between 2 vects | |
Dot product | zsl_vec_dot |
x | x | ||
Norm/abs value | zsl_vec_norm |
x | x | ||
Project | zsl_vec_project |
x | x | ||
To unit vector | zsl_vec_to_unit |
x | x | ||
Cross product | zsl_vec_cross |
x | x | ||
Sum of squares | zsl_vec_sum_of_sqrs |
x | x | ||
Comp-wise mean | zsl_vec_mean |
x | x | ||
Arithmetic mean | zsl_vec_ar_mean |
x | x | ||
Reverse | zsl_vec_rev |
x | x | ||
Zero to end | zsl_vec_zte |
x | x | 0 vals to end | |
Equality check | zsl_vec_is_equal |
x | x | ||
Non-neg check | zsl_vec_is_nonneg |
x | x | All values >= 0 | |
Contains | zsl_vec_contains |
x | x | ||
zsl_vec_print |
x | x |
Feature | Func | f32 | f64 | ARM | Notes |
---|---|---|---|---|---|
Array to matrix | zsl_mtx_from_arr |
x | x | ||
Copy | zsl_mtx_copy |
x | x | ||
Get value | zsl_mtx_get |
x | x | ||
Set value | zsl_mtx_set |
x | x | ||
Get row | zsl_mtx_get_row |
x | x | ||
Set row | zsl_mtx_set_row |
x | x | ||
Get col | zsl_mtx_get_col |
x | x | ||
Set col | zsl_mtx_set_col |
x | x | ||
Add | zsl_mtx_add |
x | x | ||
Add (d) | zsl_mtx_add_d |
x | x | Destructive | |
Sum rows | zsl_mtx_sum_rows_d |
x | x | Destructive | |
Sum rows scaled | zsl_mtx_sum_rows_scaled_d |
x | x | Destructive | |
Subtract | zsl_mtx_sub |
x | x | ||
Subtract (d) | zsl_mtx_sub_d |
x | x | Destructive | |
Multiply | zsl_mtx_mult |
x | x | ||
Multiply (d) | zsl_mtx_mult_d |
x | x | Destructive | |
Multiply row (d) | zsl_mtx_mult_row_d |
x | x | Destructive | |
Transpose | zsl_mtx_trans |
x | x | ||
Adjoint | zsl_mtx_adjoint |
x | x | ||
Reduce | zsl_mtx_reduce |
x | x | Row+col removal | |
Reduce (iter) | zsl_mtx_reduce_iter |
x | x | Iterative ver. | |
Augment | zsl_mtx_augm_diag |
x | x | Adds row+col(s) | |
Determinant | zsl_mtx_deter |
x | x | ||
Gaussian El. | zsl_mtx_gauss_elim |
x | x | ||
Gaussian El. (d) | zsl_mtx_gauss_elim_d |
x | x | Destructive | |
Gaussian Rd. | zsl_mtx_gauss_reduc |
x | x | ||
Column norm. | zsl_mtx_cols_norm |
x | x | Unitary col vals | |
Elem. norm. | zsl_mtx_norm_elem |
x | x | Norm vals to i,j | |
Elem. norm. (d) | zsl_mtx_norm_elem_d |
x | x | Destructive | |
Gram-Schmidt | zsl_mtx_gram_schmidt |
x | x | ||
Invert | zsl_mtx_inv |
x | x | ||
Balance | zsl_mtx_balance |
x | x | ||
Householder Ref. | zsl_mtx_householder |
x | x | ||
QR decomposition | zsl_mtx_qrd |
x | x | ||
QR decomp. iter. | zsl_mtx_qrd_iter |
x | |||
Eigenvalues | zsl_mtx_eigenvalues |
x | |||
Eigenvectors | zsl_mtx_eigenvectors |
x | |||
SVD | zsl_mtx_svd |
x | |||
Pseudoinverse | zsl_mtx_pinv |
x | |||
Min value | zsl_mtx_min |
x | x | ||
Max value | zsl_mtx_max |
x | x | ||
Min index | zsl_mtx_min_idx |
x | x | ||
Max index | zsl_mtx_max_idx |
x | x | ||
Equality check | zsl_mtx_is_equal |
x | x | ||
Non-neg check | zsl_mtx_is_notneg |
x | x | All values >= 0 | |
Symmetr. check | zsl_mtx_is_sym |
x | x | ||
zsl_mtx_print |
x | x |
The following component-wise unary operations can be executed on a matrix
using the zsl_mtx_unary_op
function:
- Increment (
++
) - Decrement (
--
) - Negative (
-
) - Logical negation (
!
) - Round
- Abs
- Floor
- Ceiling
- Exponent
- Natural log
- Log10
- Square root
- Sin, cos, tan
- Asin, acos, atan
- Sinh, cosh, tanh
The following component-wise binary operations can be executed on a pair
of symmetric matrices using the zsl_mtx_binary_op
function:
- Add (
a + b
) - Subtract (
a - b
) - Multiply (
a * b
) - Divide (
a / b
) - Mean (
mean(a, b
) - Exponent (
a^b
) - Min (
min(a, b)
) - Max (
max(a, b)
) - Equal (
a == b
) - Not equal (
a != b
) - Less than (
a < b
) - Greater than (
a > b
) - Less than or equal to (
a <= b
) - Greater than or equal to (
a >= b
)
NOTE: Component-wise unary and binary matrix operations can also make use of user-defined functions at the application level if the existing operand list is not sufficient. See
zsl_mtx_unary_func
andzsl_mtx_binary_func
for details.
- Nearest neighbour (AKA 'piecewise constant')
- Linear (AKA 'piecewise linear')
- Natural cubic spline
- Change in distance (initial velocity, time, acceleration)
- Change in time (initial and final velocity, acceleration)
- Instantaneous velocity (initial velocity, time, acceleration)
- Velocity (initial velocity, distance, acceleration)
- Average velocity (distance, time)
- Acceleration (initial and final velocity, time)
- Centripetal acceleration (radius, period, via radius/speed or radius/period)
- Horizontal and vertical velocity components (initial velocity, theta)
- Total time of flight
- Formula 1: gravity, y2, y1, Vy
- Formula 2: initial and final vertical velocity and gravity
- Vertical motion: position at time (Vy, gravity, time, initial height)
- Horizontal motion: horizontal change of distance at time
- Velocity (overall velocity from vertical and horizontal components)
- Theta (and between vertical and horizontal velocity)
- Range (distance travelled from ground using initial velocity, gravity, angle)
- Newton's second law
- Mass-acceleration relationship
- Friction (Fn, uK/s)
- Normal force on an incline (in newtons based on mass, gravity, angle)
- Work done over an interval of distance and constant applied force
- Work done cosine (as above but with x-component or on an incline)
- Work done sine (as above but with y-component or on an incline)
- Work-KE theorem
- Kinetic energy
- Elastic potential energy
- Gravitational potential energy
- Power (work/energy over time)
- Energy lost to friction
- Energy of a photon
- Mechanical energy of a system
- Total energy of a system
- Calculate momentum (mass, velocity)
- Impulse (force, time)
- Change in momentum/force (mass, initial and final velocity)
- Elastic collision (when two objects collide and bounce)
- Inelastic collision (when two objects collide and stick)
- Orbital period
- Escape velocity
- Gravitational acceleration
- Orbital velocity
- Gravitational force
- Gravitational potential energy
- Change in theta (analog to distance in kinematics)
- Change in time (analog to time in kinematics)
- Instantaneous angular velocity
- Angular velocity
- Average angular velocity
- Angular acceleration
- Rotational kinetic energy
- Power (torque multiplied by angular velocity)
TBD
- Pressure amplitude
- Decibels (sound level between two intensities of the same frequency)
- Intensity (pressure amplitude, bulk modulus, density)
- Shock wave angle (speed of sound and velocity through medium)
- Doppler effect
- Beats (frequency resulting from overlap of two similar frequencies)
- Kinetic theory of gases
- Ideal gas law
- Combined gas law (relationship of pressure, volume, temperature)
- Boyle's law (relationship of pressure, volume)
- Charles/Gay-Lussac law (relationship of pressure, volume)
- Density (of substance in Kg/m^2)
- Simple pressure (force, area)
- Pressure in a fluid (at a certain height/depth, gravity, density, surf. pres.)
- Fluid flow rate proportion
- Fluid force rate proportion
- Bernoulli's equation
- To known pressure
- Calculate pressure and equate
- Volume flow rate
- Temperature conversion (fahrenheit, celsius, kelvin)
- Latent heat of fusion/vaporisation
- Heat (in joules of a material based on mass, specific heat and delta temp)
- Linear expansion of metal (length, alpha constant, change in temperature)
- Average velocity of molecules (RMS velocity of molecules in a gas)
- Mean free path
- Efficiency of a heat engine (based on energy of hot and cold chambers)
- Carnot engine proportion
- Calculate the CoM of a group of objects based on their mass and distance from an arbitrary point
- Coulomb's law
- Charge density
- Potential energy
- Electric field
- Coulombs potential
- Electric flux
- Force from a charge
- Current (charge per second)
- Resistors in series/parallel
- Capacitors in series/parallel
- Resistivity of wire
- Include constants like aluminium, copper, steel, silicon, etc.
- Ohm's law
- Power
- Current, voltage
- Voltage, resistance
- Current, resistance
- Capacitance
- Charge, voltage
- Area, distance
- Energy stored in capacitor
- Energy stored in inductor
- Transformer turns to voltage
- Resistor/inductor/capacitor voltage relationship
- Resistor/capacitor charge/discharge
- Current during charge
- Current during discharge
- Charge (in coulombs) during charge
- Charge (in coulombs) during discharge
- Inductor/capacitor energising/de-energising
- Energising
- De-energising
- Magnetic force
- Force on current carrying wire
- Torque on current loop
- Potential energy from a dipole
- Orbital radius in magnetic field
- Magnetic flux
- Magnetic moment
- TBD
- Time dilatation
- Lorentz contraction
- Relativistic momentum
- Kinetic energy
- Mass to energy
- Lorenz velocity transformation
- Relativistic doppler affect
- Nuclear radius
- Radioactive decay
- Bohr orbital radius
- Bohr orbital velocity
- Bohr orbital energy
- Bragg's law
- Periodic table data including:
- Full name
- Abbreviation
- Atomic number
- Standard atomic weight
Help is welcome on the following planned or desirable features.
- Fast trigonometry approximations
- Mean
- Median
- Quantile
- Quartile
- Mode
- Data range
- De-mean
- Variance
- Standard deviation
- Interquartile range
- Covariance
- Covariance Matrix
- Correlation
- Error
- Uniform probability density function (PDF)
- Uniform cumulative distribution function (CDF)
- Normal probability density function
- Normal cumulative distribution function
- Inverse normal cumulative distribution function
- Information entropy
- Simple moving average filter
- Windowed moving average filter
- Weighted moving average filter
- Other basic IIR and FIR-type filters and helper functions.
- Basic neural network processing
- Simplistic training of models
- Feeding data through a trained network
- Acceleration/magnetic field -> orientation
- Sensor fusion (accel/mag/gyro -> quaternion)
- Euler/Quaternion conversion
- Functions for acceleration, time/distance, etc. (see
Physics
above) - Frame of reference conversion (Aerospace, Android, etc.)
- Conversion between radiometric and photometric units
- Radiometric data to lux
- Radiometric data to CCT/Duv
- Spectral analysis
- Percent error (statistics?)
- Efficiency
- Quadratic formula
As the processing power of small, embedded MCUs increases and costs fall, more computation can be done on the endnode itself. This allows for more of the 'complex' data analysis that used to take place at the PC or server level (data aggregation, statistical analysis, etc.) to be done in less time, using less data storage, and at a lower overall processing cost.
A key goal of zscilib is to allow more data processing to happen on the endnode.
By generating immediately actionable and scientifically-relevant data points
(standard SI units, pre-filtered data, etc.) directly on the endnode, zscilib
aims to be a bridge between raw data and more numerically complex toolkits like
gsl
, numpy
or R
.
Numerous high quality, mature, open source scientific libraries already exist:
Despite the wealth of mature functions in these existing libraries, though, they tend to have the following two problems in an embedded context:
- They are overly broad and resource intensive (GSL, etc.), and thus aren't appropriate for small, resource constrained devices like the ARM Cortex M family.
- They are missing many of the domain-specific features required to convert raw sensor data into actionable information (CMSIS-DAP, Lis).
The second item is of particular importance, since the goal of embedded systems is often 'sensing' via raw data, correlating that data, and acting on the final data points or passing them on for further analysis.
CMSIS-DAP contains a number of highly efficient algorithms for filtering raw sensor data, but it doesn't offer any domain-specific assistance converting filtered accelerometer vectors into orientation data, for example, or reading a set of photodiodes and converting that data into a useful photometric value like lux. It is excellent at 'conditioning' data, but not at 'understanding' it.
zscilib aims to find a middle ground between these two, allowing for richer processing of raw data, but within the confines and limitations of the class of microcontrollers commonly used on low-cost sensor endnodes.
Basic tooling has been added to allow for optimised architecture-specific implementations of key functions in assembly.
At present, this feature isn't being actively used or developed, but an aim of zscilib is to add optimised versions of key functions to try to get the best possible performance out of limited resources.
Initial optimisation will target the ARM Cortex-M family of devices and the Thumb and Thumb-2 instruction sets, though other architectures can be accommodated if necessary or useful.
Since the primary target of this codebase is running as a module in Zephyr OS, it follows the same coding style, which is itself based on the Linux kernel coding style.
You can format the source code to match this style automatically using the uncrustify command line tool, which has plugins available for many common text editors (Atom Beautify, for example).
If you wish to contribute to this library, you can raise a PR as follows:
- Fork the repository: https://github.com/zscilib/zscilib/fork
git clone
your forked repository.- Update your local repo and commit any changes.
- Push the changes out to your fork on Github.
- Navigate to https://github.com/zscilib/zscilib and to the right of the Branch menu click New pull request.
- Fill out the form that is presented.
- Click the Create Pull Request button to submit the PR.
Also have a look at the Issues page to see if there is any outstanding work or issues that you might be able to help with!
Apache 2.0.