[Solved] Help running wavelet transform c code in Arduino Uno board

Hello.

This is the first time I post something in this forum.
This is my situation: I'm trying to use wavemin library developed by Rafat Hussain to perform wavelet transform in Arduino. I successfully checked the test codes provided by Rafat in Code::Blocks and also on the Arduino Mega. The problem is that it doesn't run on Arduino Uno. The result when I run in Arduino Mega is as espected, but the excecution of the code suddenly stops when it's running on Arduino Uno and I don't know why.

Initially, I tried to use the wavelib library also written by Rafat, but the test code was too big to run in arduino Uno so I switched to wavemin. Both test codes (from both libraries) work in Code::Blocks and (after some changes to replace the input vector with a simple 0,1,2,3...255 test vector) they work on the Arduino Mega also.

This is my code (almost the same you'll find in Rafat's test codes):

#include <string.h>
#include <math.h>
#include "wavemin.h"

double absmax(double *array, int N) {
  double max;
  int i;

  max = 0.0;
  for (i = 0; i < N; ++i) {
    if (fabs(array[i]) >= max) {
        max = fabs(array[i]);
    }
  }

  return max;
}

int main(void) {
  init();
  Serial.begin(9600);
  wave_object obj;
  wt_object wt;
  double *inp,*out,*diff;
  int N, i,J;

  char *name = "db4";
  obj = wave_init(name);// Initialize the wavelet
  N =256;

  inp = (double*)malloc(sizeof(double)* N);
  out = (double*)malloc(sizeof(double)* N);
  diff = (double*)malloc(sizeof(double)* N);
  //wmean = mean(temp, N);

  for (i = 0; i < N; ++i) {
    inp[i] = (double)i;
    Serial.println(inp[i]);
  }
  J = 3;

  wt = wt_init(obj, "dwt", N, J);// Initialize the wavelet transform object
  setDWTExtension(wt, "sym");// Options are "per" and "sym". Symmetric is the default option
  setWTConv(wt, "direct");
  
  dwt(wt, inp);// Perform DWT
  //DWT output can be accessed using wt->output vector. Use wt_summary to find out how to extract appx and detail coefficients
  
    for (i = 0; i < wt->outlength; ++i) {
    Serial.println(wt->output[i]);
  }
  idwt(wt, out);// Perform IDWT (if needed)
  // Test Reconstruction
  for (i = 0; i < wt->siglength; ++i) {
    diff[i] = out[i] - inp[i];
  }
  
  Serial.println(absmax(diff, wt->siglength)); // If Reconstruction succeeded then the output should be a small value.
  Serial.print("FIN");
  delay(100);
  return 0;
}

Rafat's wavelib

Rafat's wavemin

Sorry for my English.
Please tell me what's wrong.

Thank's in advance for your time and help.

When N=256 you aren't going to cram those arrays into an UNO.

  N =256;

  inp = (double*)malloc(sizeof(double)* N);
  out = (double*)malloc(sizeof(double)* N);
  diff = (double*)malloc(sizeof(double)* N);

On the UNO (and Mega) double is the same as float which is four bytes.
inp is 1kB
out is 1kB
diff is 1kB.
There's 3kB right there and an UNO only has 2kB.

Pete

Thank you for your answer el_supremo. I see what you say, but I tried taking out the out and diff and the wt related lines and it doesn't even show me the entire input vector. It stops 10 iterations before the loop finishes. When I had 256 the serial output was: 0.00,1.00,2.00...247.00,2 and stopped showing. The modified code (below) shows:0.00,1.00,2.00...10.00 and it also stops.

modified test code:

#include <string.h>
#include <math.h>
//#include "wavemin.h"

double absmax(double *array, int N) {
  double max;
  int i;

  max = 0.0;
  for (i = 0; i < N; ++i) {
    if (fabs(array[i]) >= max) {
        max = fabs(array[i]);
    }
  }

  return max;
}

int main(void) {
  init();
  Serial.begin(9600);
  double *inp;
  int N, i,J;

  N =20;

  inp = (double*)malloc(sizeof(double)* N);
  //wmean = mean(temp, N);

  for (i = 0; i < N; ++i) {
    inp[i] = (double)i;
    Serial.println(inp[i]);
  }
  J = 3;

 
  return 0;
}

I stared at that for a while...

What happens when you return from main? I think that ends the program (does it restart? die in a corner?) I've never overridden main, just used setup()/loop()

I suspect the return from main is your problem - when you print something with serial, it puts the character(s) printed into the output buffer, and then sends it in the background (as opposed to blocking waiting for the character to be transmitted, which is many times slower than anything else the arduino is doing. If the buffer fills up, Serial.print will block until there's room to put what you're printing into the buffer). So you've put all the right stuff into the serial output buffer - but then you return from main before it's been sent, and that prevents it from sending.

To test if that's what's happening, do Serial.flush() before you return from main to wait for everything to be printed to serial.

Are you sure you're not running out of memory when you do the full version with all the calculations and shit? Even an Arduino Mega only has 8k of ram. You might be better served by a more powerful (computationally) board - Due, Zero, Teensy, STM32, etc - something bigger than an AVR.

@DrAzzy's suggestion of using Serial.flush() appears to work on a NANO. Using "while(1);" instead also works so it would appear that returning from main is indeed the problem. It appears to shut things down before all the Serial output has been sent.

Pete

Thanks DrAzzy. Yes, it completly stops after return. The Serial.flush() function solved the display problem. As I said at first, that sketch (the one in my first post) does work (produces the same output as Code::Blocks) in Arduino Mega. Should I just use the Arduino Mega?

Sergio_Restrepo:
Thanks DrAzzy. Yes, it completly stops after return. The Serial.flush() function solved the display problem. As I said at first, that sketch (the one in my first post) does work (produces the same output as Code::Blocks) in Arduino Mega. Should I just use the Arduino Mega?

You're not going to get the first code to work on an Uno because you are trying to allocate more memory than it has.

You need a Mega (based on the atmega2560 with 8k of ram), an Atmega1284p based board, or something fancier than an ARM, I think - your three arrays take a total of 3K of RAM, and the '328p in the Uno/Nano/ProMini has only 2K of ram total.

The Atmega1284p isn't used in any official boards, but there are third party boards for it out there (use MCUDude/hansibul's MightyCore board def package), and library support is almost as good as the official AVR boards - it's got 128k flash, 29 usable I/O pins (1 reset and 2 for crystal), and 16k of RAM, the most in the AVR line. You can also make your own on perfboard, since there's a DIP version of the 1284p.

Ok, I understand, the main problem is the memory. Thank you all for your kindness and help.

Just for the record, I finally could run a super small 1 level wavelet transform in the arduino uno, just to test if it works (and it worked). It's not practical, but at least it's a functional thing.

This is the resulting, useless arduino uno wavelet transform working sketch:

#include <string.h>
#include <math.h>
#include "wavemin.h"

double absmax(double *array, int N) {
  double max;
  int i;
  max = 0.0;
  for (i = 0; i < N; ++i) {
    if (fabs(array[i]) >= max) {
      max = fabs(array[i]);
    }
  }
  return max;
}

int main() {
  Serial.begin(9600);
  wave_object obj;
  wt_object wt;
  double *inp, *out, *diff;
  int N, i, J;
  char *name = "db4";
  obj = wave_init(name);// Initialize the wavelet
  N = 14;  //Length of Signal
  inp = (double*)malloc(sizeof(double)* N); //Input signal
  out = (double*)malloc(sizeof(double)* N);
  diff = (double*)malloc(sizeof(double)* N);
  //wmean = mean(temp, N);
  for (i = 0; i < N; ++i) {
    inp[i] = i;
    Serial.println(inp[i]);
  }
  J = 1; //Decomposition Levels
  wt = wt_init(obj, "dwt", N, J);// Initialize the wavelet transform object
  setDWTExtension(wt, "sym");// Options are "per" and "sym". Symmetric is the default option
  setWTConv(wt, "direct");
  dwt(wt, inp);// Perform DWT
  //DWT output can be accessed using wt->output vector. Use wt_summary to find out how to extract appx and detail coefficients
  for (i = 0; i < wt->outlength; ++i) {
   Serial.println(wt->output[i]);
  }

  idwt(wt, out);// Perform IDWT (if needed)
  // Test Reconstruction
  for (i = 0; i < wt->siglength; ++i) {
    diff[i] = out[i] - inp[i];
  }

  Serial.println(absmax(diff, wt->siglength)); // If Reconstruction succeeded then the output should be a small value.
  Serial.println("FIN");
  Serial.flush();
  return 0;
}

Once again, thank you all.

1 Like

The Mega appears to be big enough to handle N=256 but is that a useful wavelet transform size? I'm just wondering what a "normal" size would be and whether a Mega would be sufficient for that.

Pete