Reproduce code from SD card raw data

Hi, I need some help with the following problem: During a Arduino-based electromyographic feedback session I stored raw-data output on a SD card as .txt file using println (Fig1, output of 2 channels are separated by a comma). At the same time, visual feedback about muscle activity was given after performing a FFT.
However FFT output was not saved and now I would like to reproduce the output based on the SD-card raw data, whereas always 64 data points should be used to perform one FFT (1-64, 65-128,…). I could load the raw data from SD card and show it in the serial plotter/monitor using Serial.println(dataFile.readStringUntil('\n'). Unfortunately, I couldn’t read/store (without using println) the data and use it in the FFT (I think its because its ASC II?). However, I only would like to plot the FFT output separate for both channels in the serial monitor/plotter.
Can anybody help me?

ACTUAL CODE (not separated in channels):

#include <SPI.h>
#include <SD.h>
const int chipSelect = 4;

#include "arduinoFFT.h"
#define SAMPLES 64             //Must be a power of 2
#define SAMPLING_FREQUENCY 1000 //Hz, must be less than 10000 due to ADC
 
arduinoFFT FFT = arduinoFFT();
unsigned int sampling_period_us;
unsigned long microseconds;
double vReal[SAMPLES];
double vImag[SAMPLES];
double vReal2[SAMPLES];
double vImag2[SAMPLES];



void setup()
{
  Serial.begin(115200);
  Serial.setTimeout(1);

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
  }
}

 void loop(){

 File dataFile = SD.open("myfile.txt");

 int actual=0;

  for(int i=actual; i<64; i++)       {
     
      vReal[i]=Serial.println(dataFile.readStringUntil('\n'));
      actual=i;
  }


/*FFT*/
FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
int total1=0;
    
  for(int i=4; i<7; i++)
{
   total1 += vReal[i];
  }
   int gesamt1=(total1/3);
          
     
     Serial.print(gesamt1);
   Serial.print(" ");
           
}

ORIGINAL FEEDBACK CODE (without saving SSD card)

unsigned long startMillis1;  //some global variables available anywhere in the program
unsigned long currentMillis1;
const unsigned long period1 = 400;  //the value is a number of milliseconds
unsigned long startMillis2;  //some global variables available anywhere in the program
unsigned long currentMillis2;
const unsigned long period2 = 10; //period for SD card 

#include <SPI.h>
#include <SD.h>
const int chipSelect = 4;

#include "arduinoFFT.h"
#define SAMPLES 64             //Must be a power of 2
#define SAMPLING_FREQUENCY 1000 //Hz, must be less than 10000 due to ADC
 
arduinoFFT FFT = arduinoFFT();
unsigned int sampling_period_us;
unsigned long microseconds;
double vReal[SAMPLES];
double vImag[SAMPLES];
double vReal2[SAMPLES];
double vImag2[SAMPLES];



void setup()
{
  Serial.begin(115200);
  Serial.setTimeout(1);
  startMillis1 = millis();  //initial start time
  startMillis2 = millis();  //initial start time
   
  sampling_period_us = round(1000000*(1.0/SAMPLING_FREQUENCY));

  while (!Serial) 
        {
        ; // wait for serial port to connect. Needed for native USB port only
        }
        // see if the card is present and can be initialized:
        if (!SD.begin(chipSelect)) {
                             }
                File dataFile = SD.open("myoware.txt", O_CREAT | O_APPEND | O_WRITE);
                dataFile.println("Messungsbeginn");
                dataFile.close();
}

 void loop(){

  currentMillis1 = millis();  //get the current "time" (actually the number of milliseconds since the program started)
  if (currentMillis1 - startMillis1 >= period1)  //test whether the period has elapsed
  {
          for(int i=0; i<SAMPLES; i++)
         
            {
              microseconds = micros();    //Overflows after around 70 minutes!
     
                vReal[i] = analogRead(0);
                vImag[i] = 0;

                vReal2[i] = analogRead(1);
                vImag2[i] = 0;

                while(micros() < (microseconds + sampling_period_us)){
                }
            }
 
    /*FFT*/
    FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
    FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
    FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);

    FFT.Windowing(vReal2, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
    FFT.Compute(vReal2, vImag2, SAMPLES, FFT_FORWARD);
    FFT.ComplexToMagnitude(vReal2, vImag2, SAMPLES);

int total1=0;
int total2=0;
        for(int i=4; i<7; i++)
    {
         
          total1 += vReal[i];
          total2 += vReal2[i];

    }
          int gesamt1=(total1/3);
          int gesamt2=(total2/3);
     
          Serial.print(gesamt1);
          Serial.print(" ");
          Serial.print(gesamt2);
          Serial.println();
         
     startMillis1 = currentMillis1;  //IMPORTANT to save the start time of the current LED state.
                  
     }
}

what do you expect this to do?vReal[i]=Serial.println(dataFile.readStringUntil('\n'));At the moment you store in vReal the result of the call to Serial.println() which is the number of bytes printed (of type size_t).. I guess this is NOT what you want to achieve...

You need to read one line into a buffer, parse the buffer to transform the ASCII text into numbers and then feed that to vReal

Thank you for your tip. I understand your recommendation and now wrote a buffer. However, I’ve problems to parse the data due although I tried to fix the code due to other chats. Could you may help me with this?

This is the actual part of the code…with the lack of parsing the data to data_parse

char incomingData=0;
char data[7];

void loop(){

 File dataFile = SD.open("myfile.txt");

  int actual=0;
  for(int i=actual; i<64; i++)       {

  incomingData = dataFile.read(); 
          if(incomingData=='\n') {
          for(int i=0; i < 8; i++) {
          data[i] = dataFile.read();
          }
          else {
          incomingData = dataFile.read();   
          }

    //Serial.println(data);
    
    vReal[i]=data_parse;
    actual=i;
  }
}
 }

You need to convert the numbers in the SD file from ASCII, comma separated values back to binary. There are several ways to do that.

My approach would be to collect a line of data, use strtok() to find the comma, and atoi() to convert the ASCII numbers back to binary.

Here is an Arduino example showing how to do that:

// example atoi() and strtok() to read CSV data

char delim[] = ", ";  //substring delimiters, either comma OR blank!

void setup() {
  // put your setup code here, to run once:
  char* pch;  //pointer to character string
 
 // example data line
  char message[] = " ,1235, 5678";
  
  Serial.begin(9600);
  
  Serial.print("message >");
  Serial.print(message);
  Serial.println("<");
  
  pch = strtok(message, delim);  //find first delimiter
  Serial.print("strtok returns >");
  Serial.print(pch);  //print the string
  Serial.println("<");
  
  Serial.print("atoi returns: ");  //get the data
  Serial.println(atoi(pch));
  
  pch = strtok(NULL, delim);  //find second delimiter
  Serial.print("strtok returns >");
  Serial.print(pch);
  Serial.println("<");
  
  Serial.print("atoi returns: ");  //second data element
  Serial.println(atoi(pch));
  
}

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

}

Thanks again…but I need a little more help. I’ve implemented now strtok() and atoi() in a while loop reading the data in steps of i+6 (my SD card .txt input is 356,353 than a new line 363,357 …) However, instead of a feedback of 356 or 353, I always get this output (no matter if Serial.println Part0 or Part1):
3
35
3
3
3

What’s my mistake using strtok and atoi? Is this the rigth way to read the .txt ascii line by line?

char *data;
char *data2;
int i=0;

void loop(){
 File dataFile = SD.open("MYOWARE.txt");
  while (dataFile.available()) {
      
          data[i]=dataFile.read();
          i++;
          if (i==i+6); {
        // for(int i=0; i < 5; i++) {
         data2=data;
         int Part0 =atoi(strtok(data2, ","));  // Ersten Inhalt (Part0) vor "," holen
         int Part1 =atoi(strtok(NULL, "\n"));   
         Serial.println(Part1); }
               }
 }
data[i]=dataFile.read()

How big is the memory area “data” points to?

if (i==i+6); Double oops

Sorry, not sure, whether I understand your intention....

The inputdata MYOWARE.txt has 585 lines with a String structure like "356,353", however number length sometimes is also "299,3).

Well, you didn’t post all your code, so I can’t see where you assign a value to the pointer “data”.

The “double oops” is supposed to make you stop and ask yourself:
a) how any value can ever equal the same value plus any constant other than zero.

and

b) “what is that semicolon doing there?”.

I would read in an entire line of data from the SD card, then do the data conversion.

Surely there is a carriage return or line feed character (or both, numerical character value 10 or 13) at the end of each line.

To start, first write a program that reads and prints the file one line at a time, and go from there.

if (i==i+6);

Oh, of course a silly mistake!!! Sorry for my beginner’s mistakes!
This is my actual CODE (without the planned FFT), where I onyl read 3 lines?! However, I get again the ouput
3
35
3

#include <SPI.h>
#include <SD.h>
const int chipSelect = 4;

#include "arduinoFFT.h"
#define SAMPLES 64             //Must be a power of 2
#define SAMPLING_FREQUENCY 1000 //Hz, must be less than 10000 due to ADC
 
arduinoFFT FFT = arduinoFFT();
unsigned int sampling_period_us;
unsigned long microseconds;
double vReal[SAMPLES];
double vImag[SAMPLES];
double vReal2[SAMPLES];
double vImag2[SAMPLES];

char *str = "This,is,a,test";
char *data;
char *data2;
int i=0;

void setup()
{
  Serial.begin(115200);
  Serial.setTimeout(1);

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
  }
 
}

 void loop(){
 File dataFile = SD.open("MYOWARE.txt");
  while (dataFile.available()) {
       
        if (i<3) {
                // if (i<i+7)
          data[i]=dataFile.read();
              i++;
       // if (i<1) {
       data2=data;
       int Part0 =atoi(strtok(data, ","));  
       int Part1 =atoi(strtok(NULL, "\0"));   
       Serial.println(Part0); }
  }
 }

Ok you’ve still got the problem that “data” isn’t initialised.

Hi guys, thank you for your help. I could solve my problem now using this library: :https://www.somosioticos.com/archivos/separador.zip

This is now my code, which works good:

#include <SPI.h>
#include <SD.h>
#include "Separador.h"
Separador s;

const int chipSelect = 4;

int i=0;
String Buffer_Read_Line = "       ";
String Sub_String_A = "";
String Sub_String_B = ""; 
int LastPosition=0;

void setup()
{
  Serial.begin(115200);
  Serial.setTimeout(1);

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
  }
 {

 File dataFile = SD.open("MYOWARE.txt");
 int totalBytes = dataFile.size();
   while (dataFile.available()){
    //for(LastPosition=0; LastPosition<= totalBytes; LastPosition++){
      char caracter=dataFile.read();
      Buffer_Read_Line=Buffer_Read_Line+caracter;
      if(caracter=='\r'){            //ASCII new line
        Sub_String_A=s.separa(Buffer_Read_Line,',',0);
        Sub_String_B=s.separa(Buffer_Read_Line,',',1);
        //Serial.println(Sub_String_A);
        Serial.println(Sub_String_B);
        Buffer_Read_Line="";      //string to 0
   
      //}
   }
 }
}
}

 void loop(){

 }

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.