Octave/Matlab Vector Programming in Due

does this help a bit - Arduino Playground - MatrixMath -?
probably not tested on DUE yet?
And needs rework to overload the * operators etc. but it might be a start

There's no reason why the MatrixMath library should not work. It does need plenty of rework to overload the +, -, *, /, ~ operator for binary matrix math.

I'd rather use the following libraries because they are proven and my C programming skills are weak. I'd be nice if someone has done this already for the benefit of the community.

http://eigen.tuxfamily.org/index.php?title=Main_Page

http://www.robertnz.net/nm10.htm

Don't put too much hope in those two library especially Eigen. They are big packages not written for micro-controller.

I don't know much of the other but Eigen in is a very big library with complex inside dependency and even if you use only a very small subset of its functionality it will be very difficult to remove enough things to make it fit in the Due memory.
Better to look for math library specialized for micro controller where algorithm are chosen for their size.

@randomvibe

One or two people have experimented with Python on Arduinos, possibly easier now we have the Due. Might be worth looking at if someone could get it going with the 'numpy' library (now a serious contender to Matlab).

HTH
Jim

What have you tried so far? I tried Eigen 3 but got an internal compiler error. Eigen 2 seems to work OK though (but file sizes are rather large, ~170K)

I tried the Arduino matrix math library--> Arduino Playground - MatrixMath
and it works if these 2 steps are taken:

Firstly, the library should be copied to:
...\arduino-1.5.1r2\hardware\arduino\sam\libraries

Secondly, "MatrixMath.cpp" and "MatrixMath.h" fail to compile due to the following line:

#include "WProgram.h"

To correct the problem, replace the above line with the following:

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

I tested the matrix inversion on the Arduino-Due and the results match Octave and Matlab results.

Again, MatrixMath does not do overloaded operations for binary matrix math, as does "Eigen". I'm more of an Octave and Matlab power user, and not well versed with C++ overhead programming (classes, makefiles, links, etc.). I have not linked Eigen2 to Arduino.

stimmer:
Eigen 2 seems to work OK though (but file sizes are rather large, ~170K)

stimmer - Did you compile Eigen2 in the Arduino IDE? If you provide instructions in how to do that, I'd be happy to test it out and compare with Matlab.

@randomVibe
Thanks, I modified - Arduino Playground - MatrixMath - to point to your steps / this thread.
and I notified the original writer of the lib..

randomvibe:
stimmer - Did you compile Eigen2 in the Arduino IDE? If you provide instructions in how to do that, I'd be happy to test it out and compare with Matlab.

All I did was to follow the instructions supplied with Eigen 2, and all they said was to put a symlink to the Eigen subdirectory in an include directory (there are several, I chose g++_arm_none_eabi/arm-none-eabi/include). I didn't test thoroughly but overloaded operators and inversion worked on a 3x3 matrix.

That's very good news that it runs on the Due.

stimmer:
All I did was to follow the instructions supplied with Eigen 2, and all they said was to put a symlink to the Eigen subdirectory in an include directory (there are several, I chose g++_arm_none_eabi/arm-none-eabi/include).

What is a symlink?

Unix-speak!

stimmer:
I tried Eigen 3 but got an internal compiler error. Eigen 2 seems to work OK though (but file sizes are rather large, ~170K)

I tried Eigen3 and it does compile properly, and the file size is only 29K compared with Eigen2 at 170K. I'm using Windows7, so the installation was relatively straightforward - no esoteric linux stuff required.

Defining matrices in Eigen3 is cleaner, and more matrix decomp options are available compared to Eigen2.

Eigen is a C++ library enabling Matlab and Octave-like matrix programming. Eigen works very well with the Arduino Due. As a Matlab user that appreciates minimalism, the Eigen library is written as plain header files. So no makefiles, no binary files, nothing to compile upfront, no 20th century nonsense.

Important development regarding Eigen3. The Arduino/Eigen setup on Windows 7 seems to produce internal compiler errors when using matrices larger than 4x4. After struggling late at night with this, I found a solution. To add Eigen to the Arduino IDE (1.5.1r2) for Due, follow these instructions and try my example in step-6: (applies to Windows 7)

Step-1:
-> As of 1/25/2013, latest stable release is Eigen 3.1.2
-> Download ZIP from: http://eigen.tuxfamily.org

Step-2:
-> Unzip in temporary location
-> Unzip will create folder containing several files and subfolders.
-> The subfolder "Eigen" is all that is needed.

Step-3:
-> Copy "Eigen" subfolder to this precise location in the Arduino IDE directory tree:
...\arduino-1.5.1r2\hardware\arduino\sam\libraries

Step-4:
-> Eigen is written in C++, so header files do not include the *.h extension.
-> The Arduino IDE expects a *.h extension for it to appear in Sketch/Import Library pull-down menu.
-> So download "Eigen312.h" from this thread and copy to this precise location:
...\arduino-1.5.1r2\hardware\arduino\sam\libraries\Eigen
-> Notice "Eigen312.h" goes in the Eigen subdirectory
-> Normally, all that is needed in "Eigen312.h" is a call to the main Eigen Core header as follows: #include
However, the Arduino and AVR libraries interfere with Eigen for matrices larger than 4x4; this results in internal compiler errors. So @rpavlik came up with a bunch of #define statements that prevents this, and are conveniently included in "Eigen312.h".

Step-5:
-> Again, make sure you download "Eigen312.h" and copy to the Eigen subdirectory!

Step-6:
-> Run example code below demonstrating the Kalman gain equation using 6x6 matrices. Not as clean as Matlab or Octave, but not too shabby.
-> I wrote a function called print_mtxf that serially prints matrices; it's included in the example below.

Good luck.

// Example By: RandomVibe
// Eigen Doc: http://eigen.tuxfamily.org/dox/
// Quick Reference: http://eigen.tuxfamily.org/dox/QuickRefPage.html

#include <Eigen312.h>     // Calls main Eigen3.1.2 matrix class library
#include <LU>             // Calls inverse, determinant, LU decomp., etc.
using namespace Eigen;    // Eigen related statement; simplifies syntax for declaration of matrices

void print_mtxf(const Eigen::MatrixXf& K);


void setup() {

    Serial.begin(9600);
    
    // DECLARE MATRICES 
    //--------------------
    MatrixXf Pp(6,6);   // Produces 6x6 float matrix class
    MatrixXf H(6,6);    // Note: without "using namespace Eigen", declaration would be: Eigen::MatrixXf H(6,6);
    MatrixXf R(6,6);  
    MatrixXf X(6,6);  
    MatrixXf K(6,6);  
    MatrixXf Z(6,6);  

    // INPUT MATRICES (so-called comma-initialize syntax)
    //---------------------------------------------------------
    Pp << 0.3252,  0.3192,  1.0933, -0.0068, -1.0891, -1.4916,
         -0.7549,  0.3129,  1.1093,  1.5326,  0.0326, -0.7423,
          1.3703, -0.8649, -0.8637, -0.7697,  0.5525, -1.0616,
         -1.7115, -0.0301,  0.0774,  0.3714,  1.1006,  2.3505,
         -0.1022, -0.1649, -1.2141, -0.2256,  1.5442, -0.6156,
         -0.2414,  0.6277, -1.1135,  1.1174,  0.0859,  0.7481 ;

    H << 0.8147, 0.2785, 0.9572, 0.7922, 0.6787, 0.7060,
         0.9058, 0.5469, 0.4854, 0.9595, 0.7577, 0.0318,
         0.1270, 0.9575, 0.8003, 0.6557, 0.7431, 0.2769,
         0.9134, 0.9649, 0.1419, 0.0357, 0.3922, 0.0462,
         0.6324, 0.1576, 0.4218, 0.8491, 0.6555, 0.0971,
         0.0975, 0.9706, 0.9157, 0.9340, 0.1712, 0.8235;

    R << 0.3252,  0.3192,  1.0933, -0.0068, -1.0891, -1.4916,
        -0.7549,  0.3129,  1.1093,  1.5326,  0.0326, -0.7423,
         1.3703, -0.8649, -0.8637, -0.7697,  0.5525, -1.0616,
        -1.7115, -0.0301,  0.0774,  0.3714,  1.1006,  2.3505,
        -0.1022, -0.1649, -1.2141, -0.2256,  1.5442, -0.6156,
        -0.2414,  0.6277, -1.1135,  1.1174,  0.0859,  0.7481;


    // Kalman Gain Example; Matlab form:  K = Pp * H' * inv(H * Pp * H' + R)
    //-----------------------------------
    X  = H * Pp * H.transpose() + R;    
    K  = Pp * H.transpose() * X.inverse();   


    // Print Result
    //----------------------------
     print_mtxf(K);      // Print Matrix Result (passed by reference)
    
}




void loop() {
  // put your main code here, to run repeatedly: 
  
}




// PRINT MATRIX (float type)
//-----------------------------
void print_mtxf(const Eigen::MatrixXf& X)  
{
    int i, j, nrow, ncol;
    
    nrow = X.rows();
    ncol = X.cols();

    Serial.print("nrow: "); Serial.println(nrow);
    Serial.print("ncol: "); Serial.println(ncol);       
    Serial.println();
    
    for (i=0; i<nrow; i++)
    {
        for (j=0; j<ncol; j++)
        {
            Serial.print(X(i,j), 6);   // print 6 decimal places
            Serial.print(", ");
        }
        Serial.println();
    }
    Serial.println();
}

Eigen312.h (1.09 KB)

Matrices can eat away at SRAM very quickly. Float type variables are 4 bytes. So for example, a 12x12 matrix has 144 elements consumes 576 bytes. Including several matrices, this can add up quickly.

As programs become more complicated and more variables are added, it may be tricky computing RAM usage by hand.

Is there a way for the IDE to report RAM usage is it does for Flash?

This may help.

int freeRam() {
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

I tried the snippet below as suggested by Arctic_Eddie in Arduino-IDE-1.5.2 without luck. The compiler reports warnings about undefined references, and the function reports negative RAM sizes. Any other proved methods for reporting RAM usage? Thank you.

void setup() {
    
    int xxx;  
 
    Serial.begin(9600);    
    xxx = freeRam();
    Serial.println(xxx);
}

void loop() {
}

int freeRam() {
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

Compiler Message:

sketch_feb23b.cpp.o: In function `freeRam()':
C:\Programs\arduino-1.5.2/sketch_feb23b.ino:21: warning: undefined reference to `__brkval'
C:\Programs\arduino-1.5.2/sketch_feb23b.ino:21: warning: undefined reference to `__heap_start'

Program Output:

-28

Suggestion for future IDE release... include tally of RAM usage to supplement "sketch size" report. This added feature would be very useful for all users. Thank you.

Those are AVR specific labels, so the won't work on a DUE

Any other proved methods for reporting RAM usage?

It is rather impossible to make a RAM (peak) usage estimation compile time.
Only the global declared vars can be counted "relative" easily.

There was a thread here a short time ago about ram usage. I did post some code about an estimate of free RAM at runtime but it is not well tested. I'll try to find it.

update: here it is :slight_smile:
http://arduino.cc/forum/index.php/topic,146589.0.html

This is awsome and might work with the maple. I wonder if it would compile for fpga somehow like a xillinx.

I am interested in this and want to try to do linear discriminent analisis pattern matching.

The matrix inverse multiplication addition etc is needed for it.

I do not have a duo yet so i will try it in code blocks then on my leaflabs maple then the duo maby.

Has anyone tried this i like their documentation.

  1. XD :grin:

Pattern Matching in arduino c++
I don't have the Arduino Due yet but I did write this code in c++ code blocks on the release compile the size is Output size is 531.00 KB on my windows 8 computer and want to try it in a due. I wonder if the arduino due will be able to hold it and any suggestions to make it fit if not?

It inverts and multiplies and divides a constant from a matrix...

#include <iostream>
#include <Eigen/Dense>
#include <Eigen/LU>
using Eigen::MatrixXd;
using namespace std;
int main()
{
cout << "Hello Pattern matching Linear Discriminent Analisis!" << endl;
cout << "" << endl;
cout << "x data" << endl;

//data matrix x row col
MatrixXd x(4,2);
//cur
x(0,0) = 2.95;//g0
x(1,0) = 2.53;
x(2,0) = 3.57;
x(3,0) = 3.16;

//dia
x(0,1) = 6.63;//g0
x(1,1) = 7.79;
x(2,1) = 5.65;
x(3,1) = 5.47;

std::cout << x << std::endl;
cout << "End of x data" << endl;
cout << "" << endl;

cout << "x1 data" << endl;

MatrixXd x1(3,2);

x1(0,0) = 2.58;//g1
x1(1,0) = 2.16;
x1(2,0) = 3.27;

x1(0,1) = 4.46;//g1
x1(1,1) = 6.22;
x1(2,1) = 3.52;

std::cout << x1 << std::endl;
cout << "End of x1 data" << endl;
cout << "" << endl;

//group adv
cout << "x data adverage ui" << endl;

MatrixXd ui(1,2);//group/feature
ui(0,0)=(x(0,0) + x(1,0) + x(2,0) + x(3,0))/4;
ui(0,1)=(x(0,1) + x(1,1) + x(2,1) + x(3,1))/4;
std::cout << ui << std::endl;
cout << "" << endl;

cout << "x1 data adverage ui1" << endl;

MatrixXd ui1(1,2);//group/feature

ui1(0,0)=(x1(0,0) + x1(1,0) + x1(2,0))/3.0;
ui1(0,1)=(x1(0,1) + x1(1,1) + x1(2,1))/3.0;
std::cout << ui1 << std::endl;
cout << "" << endl;

cout << "x & x1 data adverage u" << endl;
MatrixXd u(1,2);//all group/feature
u(0,0)=(x(0,0) + x(1,0) + x(2,0) + x(3,0) + x1(0,0) + x1(1,0) + x1(2,0))/7.0;

u(0,1)=(x(0,1) + x(1,1) + x(2,1) + x(3,1) + x1(0,1) + x1(1,1) + x1(2,1))/7.0;

std::cout << u << std::endl;
cout << "" << endl;


cout << "mean corrected data xig - u" << endl;
MatrixXd ximinu(4,2);
//cur
ximinu(0,0) = x(0,0) - u(0,0);//f0
ximinu(1,0) = x(1,0) - u(0,0);
ximinu(2,0) = x(2,0) - u(0,0);
ximinu(3,0) = x(3,0) - u(0,0);
//dia
ximinu(0,1) = x(0,1) - u(0,1);//f1
ximinu(1,1) = x(1,1) - u(0,1);
ximinu(2,1) = x(2,1) - u(0,1);
ximinu(3,1) = x(3,1) - u(0,1);
std::cout << ximinu << std::endl;
cout << "" << endl;

cout << "mean corrected data xi1 - u" << endl;


MatrixXd ximinu1(3,2);
//cur
ximinu1(0,0) = x1(0,0) - u(0,0);
ximinu1(1,0) = x1(1,0) - u(0,0);
ximinu1(2,0) = x1(2,0) - u(0,0);
//dia
ximinu1(0,1) = x1(0,1) - u(0,1);//g1
ximinu1(1,1) = x1(1,1) - u(0,1);
ximinu1(2,1) = x1(2,1) - u(0,1);

std::cout << ximinu1 << std::endl;

cout << " " << endl;

cout << "Transpose matricies" << endl;
cout << "xi - u T" << endl;

MatrixXd ximinut(4,2);
ximinut= ximinu.transpose();
std::cout << ximinut<< std::endl;
cout << " " << endl;

cout << "xi1 - u T" << endl;
MatrixXd ximinu1t(3,2);
ximinu1t= ximinu1.transpose();
std::cout << ximinu1t << std::endl;
cout << " " << endl;

cout << "Covariance matrix of group ci" << endl;
MatrixXd ci(2,2);
ci = ( ximinut * ximinu ) /4.0;
std::cout << ci << std::endl;
cout << "" << endl;

cout << "Covariance matrix of group ci1" << endl;
MatrixXd ci1(2,2);
ci1 = ( ximinu1t * ximinu1 ) /3.0;
std::cout << ci1 << std::endl;
cout << "" << endl;

cout << "Pooled within group Covariance matrix c" << endl;
MatrixXd c(2,2);
c(0,0) = 4.0/7.0 * ci(0,0) + 3.0/7.0 * ci1(0,0);
c(1,0) = 4.0/7.0 * ci(1,0) + 3.0/7.0 * ci1(1,0);
c(0,1) = 4.0/7.0 * ci(0,1) + 3.0/7.0 * ci1(0,1);
c(1,1) = 4.0/7.0 * ci(1,1) + 3.0/7.0 * ci1(1,1);
std::cout << c << std::endl;
cout << "" << endl;

cout << "inverse of Pooled within group Covariance matrix cinverse" << endl;
MatrixXd cinverse(2,2);
 cinverse=c.inverse();
std::cout << cinverse << std::endl;
cout << "" << endl;

cout << "Probability of a group" << endl;
cout << "x = 4/7 x1 = 3/7" << endl;

//create a vector of a probability...
cout << "" << endl;

//formula for calculatin likelyhood of data in a group...
//fi = uig cinverse xkt - 1/2uig cinverse uitg + ln probability

cout << "End of program!" << endl;

    return 0;
}

main.cpp (3.72 KB)

Even without the Due you can download the IDE, follow the instructions to get Eigen working then try compiling your code and see what the code size is, that will give you an idea if it will work. The IDE will work without a board.

Although std::cout does work on the Due you might want to change those lines to use Serial.print as that uses a lot less flash.