Printing 2D Arrays - Arduino UNO

Hello, This is my first post on the forum so I'm not quite sure how it works.

I am working on my project for my Uni course where I am using Arduino to build a neural network. I have been building up the size of the network and I am now trying to use arrays to streamline the process. Everything has bee fine so far and I have used a 2D array to hold the values for my weights.

bool finish = true;
void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
#include<math.h>
}

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

int n, c, count;  

// NODES //

float NODE[ ] = {0, 0 ,0};
float OUTPUTS[ ] = {0, 0};

// ERRORS //

float ERRORH[ ] = {0, 0, 0};
float ERRORO[ ] = {0, 0};
int INPUTS[4] = {1, 0, 1, 0};

float WEIGHTH[3][4] = 
{
{0.1, 0.9, 0.5, 0.25},
{-0.2, -0.1, 0.8, -0.45},
{0.7, -0.6, -0.3, 0.4}
};
float WEIGHTO[2][3] = 
{
{0.75, -0.4, -0.5},
{-0.9, 0.2, 0.3}
};

int TARGET[2] = {1, 0};


while (finish)
{
  // HIDDEN LAYER //
  for(n = 0; n <= 2; n ++)
  {
  for (c = 0; c <= 3; c++)
    {
    NODE[n] = NODE[n] + (INPUTS[c] * WEIGHTH[n][c]);
    }
  }
  // SIGMOID FUNCTION //
  for(count = 0; count <=2 ; count++)
  {
  NODE[count] = 1 / (1 + exp(-NODE[count]));
  }

  // OUTPUT LAYER //
  for(n = 0; n <= 1; n ++)
  {
  for (c = 0; c <= 2; c++)
    {
    OUTPUTS[n] = OUTPUTS[n] + (NODE[c] * WEIGHTO[n][c]);
    }
  }
  // SIGMOID FUNCTION //
  for(count = 0; count <=2 ; count++)
  {
  OUTPUTS[count] = 1 / (1 + exp(-OUTPUTS[count]));
  }


                                                        // Reverse Pass //
                                                        // ERRORS //

                                                        for(count = 0; count < 2; count++)
                                                        {
                                                          ERRORO[count] = OUTPUTS[count] * (1 - OUTPUTS[count]) * (TARGET[count] - OUTPUTS[count]); 
                                                        }

                                                        // NEW WEIGHTS //

                                                        for(n = 0; n <= 1; n ++)
                                                        {
                                                        for (c = 0; c <= 2; c++)
                                                        {
                                                          WEIGHTO[n][c] = WEIGHTO[n][c] + (ERRORO[n] * NODE[c]);
                                                        }
                                                        }
                                                        Serial.println();
                                                        Serial.println(WEIGHTO[0][0]);
                                                        Serial.println(WEIGHTO[0][1]);
                                                        Serial.println(WEIGHTO[0][2]);
                                                        Serial.println(WEIGHTO[1][0]);
                                                        Serial.println(WEIGHTO[1][1]);
                                                        Serial.println(WEIGHTO[1][2]);
  finish = false;
}
}

Everything was going fine and I was quite proud I was managing as well as I was, but when I went to print the values for my new weights as a test I was doing after each section, it wont print. I get a couple of squares and some question mark symbols. I would quite like to be checking my values after each step to make sure they match my own calculations, does this mean that the Arduino isn't calculating them or is it just a printing problem?
I have no idea what causes this so hopefully someone has some advice and I am probably missing a very obvious trick!

Welcome to the forum

Let's start with the simple stuff
What baud rate do you have the Serial monitor set to ?
What happens if you print the values immediately after declaring and defining the arrays ?

Nothing to do with your question, but why is the code formatted in such an odd way ? Try using Tools/Auto Format in the IDE to improve the format

18:22:27.056 -> 
18:22:27.056 -> 0.83
18:22:27.056 -> -0.32
18:22:27.056 -> -0.42
18:22:27.056 -> -0.97
18:22:27.056 -> 0.13
18:22:27.056 -> 0.24

There's an array out-of-bounds error in your code. There may be several of them.

Mix of < and <= loop conditions is not a good practice.

Step 1 is read the pinned post re 'How to get the most from the forum'. Step 2 is

For experimenting with a simple neural network on Arduino, I recommend this outstanding tutorial by Ralph Heymsfeld.

It runs even on the lowly Uno R3, and incidentally, shows how to print out the weights in a readable format.

#include (and #define) statements should be declared before setup().

…and I’d give the arrays global scope too…

Hints:

  1. Set compiler warnings the IDE Preferences to "ALL". You will see important warnings, like this one regarding the code:
"C:\\Users\\Jim\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-gcc" -Wall -Wextra -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections -mmcu=atmega328p -o "C:\\Users\\Jim\\AppData\\Local\\Temp\\arduino_build_935336/sketch_oct21a.ino.elf" "C:\\Users\\Jim\\AppData\\Local\\Temp\\arduino_build_935336\\sketch\\sketch_oct21a.ino.cpp.o" "C:\\Users\\Jim\\AppData\\Local\\Temp\\arduino_build_935336/core\\core.a" "-LC:\\Users\\Jim\\AppData\\Local\\Temp\\arduino_build_935336" -lm
C:\Users\Jim\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.3\cores\arduino\main.cpp: In function 'main':
C:\Users\Jim\Documents\Arduino\sketch_oct21a\sketch_oct21a.ino:67:51: warning: iteration 2 invokes undefined behavior [-Waggressive-loop-optimizations]
       OUTPUTS[count] = 1 / (1 + exp(-OUTPUTS[count]));
                                                   ^
C:\Users\Jim\Documents\Arduino\sketch_oct21a\sketch_oct21a.ino:65:27: note: within this loop
     for (count = 0; count <= 2 ; count++)
                           ^

  1. Use CTRL-T in the code editor to format the code for better readability:
#include<math.h>
bool finish = true;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(15200);

}

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

  int n, c, count;

  // NODES //

  float NODE[ ] = {0, 0 , 0};
  float OUTPUTS[ ] = {0, 0};

  // ERRORS //

  float ERRORH[ ] = {0, 0, 0};
  float ERRORO[ ] = {0, 0};
  int INPUTS[4] = {1, 0, 1, 0};

  float WEIGHTH[3][4] =
  {
    {0.1, 0.9, 0.5, 0.25},
    { -0.2, -0.1, 0.8, -0.45},
    {0.7, -0.6, -0.3, 0.4}
  };
  float WEIGHTO[2][3] =
  {
    {0.75, -0.4, -0.5},
    { -0.9, 0.2, 0.3}
  };

  int TARGET[2] = {1, 0};


  while (finish)
  {
    // HIDDEN LAYER //
    for (n = 0; n <= 2; n ++)
    {
      for (c = 0; c <= 3; c++)
      {
        NODE[n] = NODE[n] + (INPUTS[c] * WEIGHTH[n][c]);
      }
    }
    // SIGMOID FUNCTION //
    for (count = 0; count <= 2 ; count++)
    {
      NODE[count] = 1 / (1 + exp(-NODE[count]));
    }

    // OUTPUT LAYER //
    for (n = 0; n <= 1; n ++)
    {
      for (c = 0; c <= 2; c++)
      {
        OUTPUTS[n] = OUTPUTS[n] + (NODE[c] * WEIGHTO[n][c]);
      }
    }
    // SIGMOID FUNCTION //
    for (count = 0; count <= 2 ; count++)
    {
      OUTPUTS[count] = 1 / (1 + exp(-OUTPUTS[count]));
    }


    // Reverse Pass //
    // ERRORS //

    for (count = 0; count < 2; count++)
    {
      ERRORO[count] = OUTPUTS[count] * (1 - OUTPUTS[count]) * (TARGET[count] - OUTPUTS[count]);
    }

    // NEW WEIGHTS //

    for (n = 0; n <= 1; n ++)
    {
      for (c = 0; c <= 2; c++)
      {
        WEIGHTO[n][c] = WEIGHTO[n][c] + (ERRORO[n] * NODE[c]);
      }
    }
    Serial.println();
    Serial.println(WEIGHTO[0][0]);
    Serial.println(WEIGHTO[0][1]);
    Serial.println(WEIGHTO[0][2]);
    Serial.println(WEIGHTO[1][0]);
    Serial.println(WEIGHTO[1][1]);
    Serial.println(WEIGHTO[1][2]);
    finish = false;
  }
}
  1. The loop function loops automatically. You don't need while (finish) and code that runs once can go in setup(), which, as you might guess, runs once.

look this over. compare it to your version to see changes

  • note the use of constants, instead of hard-coded values for the array sizes and the use of those constants
  • note the range of the array value in the for loops, for example < N, not <= N
  • Capitalize Constants
  • keep things neat, but not overly spacious
#include <math.h>

// global variables
const int R = 3;
const int C = 2;
const int N = 4;

float node    [R] = {};                 // default initialization to zero
float outputs [C] = {};

float errorO  [C] = {};

int Inputs    [N] = { 1, 0, 1, 0};      // Capitalize Constants

float WeightH [R][N] = {
    {  0.1,  0.9,  0.5,  0.25 },
    { -0.2, -0.1,  0.8, -0.45 },
    {  0.7, -0.6, -0.3,  0.4  }
};

double weight0 [C][R] = {
    {  0.75, -0.4, -0.5 },
    { -0.9,   0.2,  0.3 }
};

int Target  [C] = { 1, 0 };

bool done = false;
char s [90];                    // print buffer

// -----------------------------------------------------------------------------
void loop ()
{
    while (! done) {
        // hidden layer
        for (int r = 0; r < R; r++) {
            for (int n = 0; n < N; n++) {
                node [r] += Inputs [n] * WeightH [r][n];
            }
        }

        // sigmoid function
        for (int r = 0; r < R ; r++) {
            node [r] = 1 / (1 + exp (-node [r]));
        }

        // output layeR
        for (int n = 0; n <= 1; n ++) {
            for (int c = 0; c < 2; c++) {
                outputs [n] = outputs [n] + (node [c] * weight0 [n] [c]);
            }
        }

        // sigmoid function
        for (int c = 0; c < 2 ; c++) {
            outputs [c] = 1 / (1 + exp (-outputs [c]));
        }

        // Reverse Pass
        // errors
        for (int c = 0; c < 2; c++) {
            errorO [c] = outputs [c] * (1 - outputs [c])
                                * (Target [c] - outputs [c]);
        }

        // new weights
        for (int n = 0; n <= 1; n ++) {
            for (int c = 0; c <= 2; c++) {
                weight0 [n] [c] = weight0 [n] [c] + (errorO [n] * node [c]);
            }
        }

        for (int c = 0; c < C; c++)  {  
            for (int r = 0; r < R; r++)  {
                sprintf (s, " %6.2lf", weight0 [c][r]);
                Serial.print (s);
            }
            Serial.println ("  weightO");
        }

        done = true;
    }
}

// --------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);
}

output

   0.82  -0.33  -0.43  weightO
  -0.96   0.14   0.24  weightO

why isn't the error [] = Target [] - output [] ?

looks like you're headed toward this

 output -  ----- weightO -----
   0.56 -   0.82  -0.33  -0.43
   0.39 -  -0.96   0.14   0.24
 output -  ----- weightO -----
   0.72 -   0.86  -0.29  -0.39
   0.44 -  -1.04   0.06   0.17
 output -  ----- weightO -----
   0.77 -   0.90  -0.25  -0.36
   0.41 -  -1.12  -0.02   0.09
 output -  ----- weightO -----
   0.78 -   0.93  -0.22  -0.33
   0.38 -  -1.19  -0.09   0.02

I believe it is set to 9600, and when I put the print code right after the arrays (before entering the while loop) it prints 2 of the values and then displays the strange symbols and squares again. I have mainly used a very basic document supplied by my university on Arduino programming so most of my practises have come from that I didn't even know auto format existed but I'll be using that now!

These are the values I was trying to print! Can I ask how you managed to write them?

This is the results from the serial monitor. The extra stuff in the error calculation factors in the sigmoid squashing function to provide the real error of the output.

Perhaps a simple question will help:
Before your code writes anything back, as you have defined the start conditions, what value exists at:
WEIGHTH[0][0]);

Okay, now what value exists at:
WEIGHTH[2][3]);
Hmm. Note, those indices are beyond the array defined at the beginning, which is only a 2x3 array. Array indices begin at 0, not 1, which you may have been used to in other languages.
When you have thought about it a bit, you will realize your code has been very sloppily writing to locations beyond the limits of the arrays defined, which C happily permits; that means all bets are off when you go to print values, as you've been 'scribbling all over the walls, not just on the whiteboard', as it were.
Sorry for the simple analogy, but it fits.

so when you run the code in post #10, it produces

and post #10 code produces

so not only is there

  • extraneous output before the normal output,
  • it's printing "?" instead of thet formated values

which version of the IDE are using?

and here's what I see using the 2.0.4 IDE

I have 2.3.6 IDE I believe. I continued writing out the rest of my backward pass and individually printed each of my weights and errors using a baud of 19200, which worked! However, the values are different (not hugely, within 0.1, but not ideal for a NN) and I am not sure why. Will having my values inn arrays do this or is there a problem with the maths side of it? I don't expect help for maths if that is the problem I would just quite like to know what to focus on as there doesn't seem to be an obvious reason!

Learn the rules of C/C++ programming, starting with array indexing. Turn on compiler warnings, pay attention and fix the problems it identifies.

ANY math error you identify is a serious problem that points to other errors in the code.

please confirm what the output is from the code in post #10.

it seems the primary problem is simply outputing formatted text and has nothing to do with 2d arrays

i updated to the 2.6.3 IDE and get the following at 9600 bps and same at 19200