Запись потока данных в массив

Danila
Offline
Зарегистрирован: 16.05.2013

Здравствуйте ! Подскажите пожалуйста как организовать запись потока данных от датчика расстояния в массив? ДАнные от датчика растояния сыпятся по 10 значений в секундцу, вот мне надо чтобы в массив записывались все показания датчика за каждую секунду. Дело в том, что на датчике иногда проскакивают неадекватные значения, чтобы их фильтровать я хочу писать каждую секунду данные в массив, и каждую же секунду высчитывать среднее значение из всех записанных значений с массиве. По моим предположениям неадекватные значения в таком случае сильного возмущения не принесут.
Всем спасибо ! 

Puhlyaviy
Puhlyaviy аватар
Offline
Зарегистрирован: 22.05.2013

хммм... ну если предположим что есть 9 значений  в районе 10 и одно НЕАДЕКВАТНОЕ в районе 1000... то среднее у вас получится 109... будет похоже на среднюю зарплату в России.. президент ей доволен, а большинство народу таких денег никогда не видело... Вы не родственики с президентом случайно?  а то образ мышления у вас похож :)

Danila
Offline
Зарегистрирован: 16.05.2013

Да, я троюродный отец матери сына бабушки мамы сестры путина, все верно друг мой!

Как бы то ни было, вы можете подсказать как записывать данные каждую 1/10 секунды в массив ?

и где тут поиск ? я первый раз на этом форуме.  

Michal
Michal аватар
Offline
Зарегистрирован: 26.04.2013

опрашивайте датчик каждуй 0.1с, проверяйте на адекватность полученные данные и  пишите в массив.... ваш кэп :)

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

нужно подругому искать ошибочные значения. если только одно ошибочное то можно смотреть по 3 значения и если ошибка - делить разницу между крайними на 2. Ошибку искать как - разница между 1 и 2 больше разницы между крайними(1 и 3) в 3 раза.

Вобщем надо пример показаний с ошибками, чтобы придумать фильтр для них.

Danila
Offline
Зарегистрирован: 16.05.2013

вот пример :
датчик показывает расстояние до кресла :
50

51

50

50

52

51

97

49

51

50

 

Видим цифру 97 - результат того что кресло чуть повернули и сигнал исказился там отразился от плутона туда сюда, пришло большое значение.
 

 

Danila
Offline
Зарегистрирован: 16.05.2013

дело в том что кресло может быть на расстоянии и 1 метр и 3 метра тоесть задавать какие то условия не получится, ибо в разное время кресло может быть в разном удалении.
 

Если бы была возможность каждое значение записывать в переменную, то переменные бы можно было сравнивать, и скажем если одна отличается от предыдущей на допустим более чем 30% то приравнивать её к предыдущей. Но и здесь, подскажите, как записывать данные из потока в переменные ? 

Geronimo
Offline
Зарегистрирован: 06.05.2013
flaot buf[100];
int pos = 0;

void loop()
{
 buf[pos++] = analogRead(1);
delay(100);
 if(pos == 99) pos = 0;
}

 

Danila
Offline
Зарегистрирован: 16.05.2013

буду пробовать, спасибо :) здесь я насколько понимаю данные пишутся каждую милисикунду с аналогово ввхода ?

Puhlyaviy
Puhlyaviy аватар
Offline
Зарегистрирован: 22.05.2013

давайте тогда двинемся в глубь идеи... я вижу как бы несколько вопросов..

1.зачем мы опрашиваем датчик 10 раз в секунду? мы что мчимся со страшной скоростью и нам грозит опасность столкновения и десятая доля секунды играет роль?

2. а будем ли мы успевать опрашивать датчик 10 раз в секунду, когда код разрастется в процесе обработки?

3. NeiroN    вам уже описал алгоритм вычисления неправильных данных

Danila
Offline
Зарегистрирован: 16.05.2013

1. предполагается использовать датчик в полете, поэтому условно да, нужна реакция.

2. Честно скажу - не знаю пока еще.

3.Да, я ему написал что с записью значений из потока в переменные у меня тоже нелады. 

Можно упростить, допустим 5 значений в секунду, как записывать значения в пять переменных, при чем так, чтобы они сменялись поочередно ? 

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013
float buf[3];

void loop() {
   if(i == 3) {
       i=0;
       float d1;
       float d2;
       d1 = buf[2]-buf[0];
       d2 = abs(buf[0]-buf[1]);
       if(d2 > abs(d1)*3){
          buf[1] = buf[0]+d1/2;
       }
       Serial.println(buf[0]);
       Serial.println(buf[1]);
       Serial.println(buf[2]);
   }
   buf[i] = analogRead();
   i++;
}

 

Danila
Offline
Зарегистрирован: 16.05.2013

Сбасибо, буду пробовать!

Danila
Offline
Зарегистрирован: 16.05.2013

в первом приблежинии вот что получается. почему то в массив не попадают переменные.

http://vk.com/doc433721_198466807?hash=32f37a24ba43a3af14&dl=0797049695558e4998

 

distance_sm  это переменная, которая и есть поток. значения в окошке 3 - это три сантиметра. нули это данные из массива

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

обявление и установку переменной надо вынести за цикл, чтобы оно не сбрасывало значения. проверяйте код пошагово - с пониманием для чего нужна каждая строка.

Danila
Offline
Зарегистрирован: 16.05.2013

Все сводится к фильтру калмана. 

Товарищи, кто-нибудь занимался фильтрованием сигналов ? Я из любопытства спрашиваю, ничего объяснять мне не надо :) 

 

 

 

Araris
Offline
Зарегистрирован: 09.11.2012

Я в подобной ситуации (датчик расстояния) воспользовался функцией отсюда : http://playground.arduino.cc/Main/DigitalSmooth

"A digital smoothing filter for smoothing sensor jitter
This filter accepts one new piece of data each time through a loop, which the
filter inputs into a rolling array, replacing the oldest data with the latest reading.
The array is then transferred to another array, and that array is sorted from low to high.
Then the highest and lowest %15 of samples are thrown out. The remaining data is averaged
and the result is returned."

Dimasik
Offline
Зарегистрирован: 03.02.2017

Добрый день. Извиняюсь за может не столь интересный вопрос, но столкнулся с проблемой можно сказать на прямом месте.

Создаю CW ключ морзе с памятью. Есть массив в который записывается нажатия 1й или 2й кнопки (1 или 2), и по задумке после 10ти нажатий эта последовательность символов улетает в EEPROM в определённую ячейку.

Вопросик:
Массив работает, но при каждой интерации цикла for записывается новая цифра,  а надо чтоб сразу 10ть символов улетела в память.
(примерто такого вида нужно EEPROM.writeLong(addrEeprom, 1212121211;)   а к сожелению записывается последняя цифра массива "1"
Как правильно организовать запись массива в память?
Заранее благодарю!

 

#include <EEPROMex.h>
#include "Arduino.h"

word addrEeprom = 6;  
unsigned long buf[10];
#define KLUCH_TOCHKA A3 //PB4 точка
#define KLUCH_TERE A4    //PB5 тере

void setup() { 
   unsigned long output = EEPROM.readLong(addrEeprom); //смотрим что записали
   Serial.print(output);
   Serial.println();
}

void loop() {
//определяем что нажали
if((analogRead(KLUCH_TOCHKA)/4 > 250) && (analogRead(KLUCH_TERE)/4 <= 0)){ //нажали на точку
  delay(100);
  tmp_Tochka_Tere_int = 1; // в переменную указываем что нажали на точку
}

if((analogRead(KLUCH_TERE) > 250) && (analogRead(KLUCH_TOCHKA) <= 0)){ //нажали на тере
  delay(100);
  tmp_Tochka_Tere_int = 2; // в переменную указываем что нажали на тере
}

if(tmp_Tochka_Tere_int != 0){ //если что-то нажали точку или тере то в массиве записываем это
  buf[schetchik++] = tmp_Tochka_Tere_int; //прибавляем счётчик при каждом нажатии точки или тере
  if(schetchik == maxSimvol){             //считаем, когда максимум то записываем набранное 
    for(int b=0; b < 10; b++){                 
      EEPROM.writeLong(addrEeprom, buf[b]);  //пишем код                 
      tone(BEEP_Pin, BEEP_Tone, 100);        //пикаем после записи
      //Serial.println(int(buf[b]));  
    }
    schetchik = 0;  
  } 
}
tmp_Tochka_Tere_int = 0; //обнуляем переменную
}

 

nik182
Offline
Зарегистрирован: 04.05.2015

https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B4%D0%B8%D0%B0%D0%BD%D0%BD%D1%8B%D0%B9_%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80

Вот здесь алгоритм обработки именно для таких случаев. 

А здесь даже реализация на Си есть http://chipenable.ru/index.php/embedded-programming/item/203-mediannyy-filtr.html

Dimasik
Offline
Зарегистрирован: 03.02.2017

Хм...  Изучив код примера.... Немного не понял... А причём тут МЕДИАННЫЙ ФИЛЬТР? Если вопрос идет о том как записать массив не с помощью последовательных интераций (может и так), а как-то иначе, чтоб EEPROM записал сразу 10 цифр а не перебирал, выбрав только одну....?

 

nik182
Offline
Зарегистрирован: 04.05.2015

Danila пишет:

Дело в том, что на датчике иногда проскакивают неадекватные значения, чтобы их фильтровать я хочу писать каждую секунду данные в массив, и каждую же секунду высчитывать среднее значение из всех записанных значений с массиве. По моим предположениям неадекватные значения в таком случае сильного возмущения не принесут.


Медианный фильтр убирает неадекватные значения. Это его предназначение. После него простого бегушего среднего будет достаточно для адекватного значения.

Dimasik
Offline
Зарегистрирован: 03.02.2017

А как же быть с моим вопросом, неужели никто не подскажет..?

Dimasik
Offline
Зарегистрирован: 03.02.2017

Все! Разобрался сам, просёрфив не одну тонну интернета.
Вот может кому и пригодится, к примеру таким искателям как я. Использовал стандартную библиотеку :#include <EEPROMex.h>

Приведён пример на все случаи жизни:

/*
 * EEPROMEx 
 *
 * Demonstrates reading, writing and updating data in the EEPROM
 * to the computer.
 * This example code is in the public domain.
 */

#include <EEPROMex.h>

#include "Arduino.h"
void issuedAdresses();
void readAndWriteByte();
void readAndWriteInt();
void readAndWriteLong();
void readAndWriteFloat();
void updateAndReadDouble();
void writeAndReadCharArray();
void writeAndReadByteArray();
void waitUntilReady();
void errorChecking(int adress);
void setup();
void loop();
const int maxAllowedWrites = 80;
const int memBase          = 350;

int addressByte;
int addressInt;
int addressLong;
int addressFloat;
int addressDouble;
int addressByteArray;
int addressCharArray;


void issuedAdresses() {
    Serial.println("-----------------------------------");     
    Serial.println("Following adresses have been issued");     
    Serial.println("-----------------------------------");      
    
    Serial.println("adress \t\t size");
    Serial.print(addressByte);      Serial.print(" \t\t "); Serial.print(sizeof(byte)); Serial.println(" (byte)");
    Serial.print(addressInt);       Serial.print(" \t\t "); Serial.print(sizeof(int));  Serial.println(" (int)");
    Serial.print(addressLong);      Serial.print(" \t\t "); Serial.print(sizeof(long)); Serial.println(" (long)"); 
    Serial.print(addressFloat);     Serial.print(" \t\t "); Serial.print(sizeof(float)); Serial.println(" (float)");  
    Serial.print(addressDouble);    Serial.print(" \t\t "); Serial.print(sizeof(double));  Serial.println(" (double)");    
    Serial.print(addressByteArray); Serial.print(" \t\t "); Serial.print(sizeof(byte)*7); Serial.println(" (array of 7 bytes)");     
    Serial.print(addressCharArray); Serial.print(" \t\t "); Serial.print(sizeof(char)*7); Serial.println(" (array of 7 chars)");    
}

// Test reading and writing byte to EEPROM
void readAndWriteByte() { 
    Serial.println("---------------------------");     
    Serial.println("storing and retreiving byte");     
    Serial.println("---------------------------");    
    
    byte input  = 120;
    byte output = 0;
    EEPROM.write(addressByte,input);   // same function as writeByte
    output = EEPROM.read(addressByte); // same function as readByte
    
    Serial.print("adress: ");
    Serial.println(addressByte);
    Serial.print("input: ");
    Serial.println(input);
    Serial.print("output: ");
    Serial.println(output);
    Serial.println("");
    
}

// Test reading and writing int to EEPROM
void readAndWriteInt() {  
    Serial.println("--------------------------");     
    Serial.println("writing and retreiving int");     
    Serial.println("--------------------------");    
            
    int input  = 30000;
    int output = 0;
    EEPROM.writeInt(addressInt,input);
    output = EEPROM.readInt(addressInt);
    
    Serial.print("adress: ");
    Serial.println(addressInt);
    Serial.print("input: ");
    Serial.println(input);
    Serial.print("output: ");
    Serial.println(output);
    Serial.println("");    
}

// Test reading and writing long to EEPROM
void readAndWriteLong() {    
    Serial.println("----------------------------");     
    Serial.println("writing and retreiving Long");     
    Serial.println("----------------------------");    
            
    long input  = 200000000;
    long output = 0;
    EEPROM.writeLong(addressLong,input);
    output = EEPROM.readLong(addressLong);
    
    Serial.print("adress: ");
    Serial.println(addressLong);
    Serial.print("input: ");
    Serial.println(input);
    Serial.print("output: ");
    Serial.println(output);
    Serial.println("");    
}

// Test reading and writing float to EEPROM
void readAndWriteFloat() { 
    Serial.println("----------------------------");     
    Serial.println("writing and retreiving float");     
    Serial.println("----------------------------");    
            
    double input  = 1010102.50;
    double output = 0.0;
    EEPROM.writeFloat(addressFloat,input);
    output = EEPROM.readFloat(addressFloat);
    
    Serial.print("adress: ");
    Serial.println(addressFloat);
    Serial.print("input: ");
    Serial.println(input);
    Serial.print("output: ");
    Serial.println(output);
    Serial.println("");
}

// Test reading and updating double to EEPROM
void updateAndReadDouble() { 
    Serial.println("------------------------------");     
    Serial.println("updating and retreiving double");     
    Serial.println("------------------------------");    
    
    double input  = 1000002.50;
    double output = 0.0;
    EEPROM.updateDouble(addressDouble,input);   
    output = EEPROM.readDouble(addressDouble);
    
    Serial.print("adress: ");
    Serial.println(addressDouble);
    Serial.print("input: ");
    Serial.println(input);
    Serial.print("output: ");
    Serial.println(output);
    Serial.println("");
}

// Test reading and updating a string (char array) to EEPROM
void writeAndReadCharArray() {
    Serial.println("---------------------------------");     
    Serial.println("writing and reading a char array");     
    Serial.println("---------------------------------");     
    
    char input[] = "Arduino";
    char output[] = "       ";

    EEPROM.writeBlock<char>(addressCharArray, input, 7);
    EEPROM.readBlock<char>(addressCharArray, output, 7);

    Serial.print("adress: ");
    Serial.println(addressCharArray);
    Serial.print("input: ");
    Serial.println(input);
    Serial.print("output: ");
    Serial.println(output);
    Serial.println("");
}

void writeAndReadByteArray() {

    Serial.println("---------------------------------");     
    Serial.println("updating and reading a byte array");     
    Serial.println("---------------------------------");     
    
    int itemsInArray = 7;
    byte initial[] = {1, 0, 4, 0, 16, 0 , 64 };
    byte input[]   = {1, 2, 4, 8, 16, 32, 64 };    
    byte output[sizeof(input)];

    EEPROM.writeBlock<byte>(addressByteArray, initial, itemsInArray);
    int writtenBytes = EEPROM.updateBlock<byte>(addressByteArray, input, itemsInArray);
    EEPROM.readBlock<byte>(addressByteArray, output, itemsInArray);

    Serial.print("input: ");
    for(int i=0;i<itemsInArray;i++) { Serial.print(input[i]); }
    Serial.println("");
    
    Serial.print("output: ");
    for(int i=0;i<itemsInArray;i++) { Serial.print(output[i]); }
    Serial.println("");
    
    Serial.print("Total of written bytes by update: "); 
    Serial.println(writtenBytes);    
    Serial.println("");
}

// Check how much time until EEPROM ready to be accessed
void waitUntilReady() { 
    Serial.println("-----------------------------------------------------");     
    Serial.println("Check how much time until EEPROM ready to be accessed");     
    Serial.println("-----------------------------------------------------");      
    int startMillis;
    int endMillis; 
    int waitMillis;

    // Write byte..       
    startMillis = millis();
    EEPROM.writeByte(addressByte,16);
    endMillis = millis();            
    // .. and wait for ready    
    waitMillis = 0;   
    while (!EEPROM.isReady()) { delay(1); waitMillis++; }

    Serial.print("Time to write 1 byte  (ms)                        : "); 
    Serial.println(endMillis-startMillis); 
    Serial.print("Recovery time after writing byte (ms)             : "); 
    Serial.println(waitMillis);    
            
    // Write long ..       
    startMillis = millis();
    EEPROM.writeLong(addressLong,106);
    endMillis = millis();               
    // .. and wait for ready    
    waitMillis = 0;   
    while (!EEPROM.isReady()) { delay(1); waitMillis++; }
    Serial.print("Time to write Long (4 bytes) (ms)                 : "); 
    Serial.println(endMillis-startMillis); 
    Serial.print("Recovery time after writing long (ms)             : "); 
    Serial.println(waitMillis);    
    
    // Read long ..
    startMillis = millis();
    EEPROM.readLong(addressLong);
    endMillis = millis();
    // .. and wait for ready      
    waitMillis = 0;   
    while (!EEPROM.isReady()) { delay(1); waitMillis++; }
    Serial.print("Time to read Long (4 bytes) (ms)                  : ");    
    Serial.println(endMillis-startMillis);     
    Serial.print("Recovery time after reading long (ms)             : "); 
    Serial.println(waitMillis);      
 
    // Write times arrays 
    int itemsInArray = 7;
    byte array7[]    = {64, 32, 16, 8 , 4 , 2 , 1 };
    byte arraydif7[] = {1 , 2 , 4 , 8 , 16, 32, 64};    
    byte arrayDif3[] = {1 , 0 , 4 , 0 , 16, 0 , 64};
    byte output[sizeof(array7)];

    // Time to write 7 byte array 
    startMillis = millis();
    EEPROM.writeBlock<byte>(addressByteArray, array7, itemsInArray);
    endMillis = millis(); 
    Serial.print("Time to write 7 byte array  (ms)                  : ");    
    Serial.println(endMillis-startMillis); 

    // Time to update 7 byte array with 7 new values
    startMillis = millis();    
    EEPROM.updateBlock<byte>(addressByteArray, arraydif7, itemsInArray);
    endMillis = millis(); 
    Serial.print("Time to update 7 byte array with 7 new values (ms): ");    
    Serial.println(endMillis-startMillis); 

    // Time to update 7 byte array with 3 new values
    startMillis = millis();    
    EEPROM.updateBlock<byte>(addressByteArray, arrayDif3, itemsInArray);
    endMillis = millis(); 
    Serial.print("Time to update 7 byte array with 3 new values (ms): ");    
    Serial.println(endMillis-startMillis);

    // Time to read 7 byte array
    startMillis = millis(); 
    EEPROM.readBlock<byte>(addressByteArray, output, itemsInArray);   
    endMillis = millis(); 
    Serial.print("Time to read 7 byte array (ms)                    : ");    
    Serial.println(endMillis-startMillis);
}

// Check if we get errors when writing too much or out of bounds
void errorChecking(int adress) {
    Serial.println("-------------------------------------------------------------");     
    Serial.println("Check if we get errors when writing too much or out of bounds");     
    Serial.println("-------------------------------------------------------------");   
    // Be sure that _EEPROMEX_DEBUG is enabled

    Serial.println("Write outside of EEPROM memory");
    EEPROM.writeLong(EEPROMSizeUno+10,1000);
    Serial.println();    
    
    Serial.println("Trying to exceed number of writes");        
    for(int i=1;i<=20; i++)
    {
        if (!EEPROM.writeLong(adress,1000)) { return; }    
    }
    Serial.println();    
}
    
  
void setup()
{
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  
  // start reading from position memBase (address 0) of the EEPROM. Set maximumSize to EEPROMSizeUno 
  // Writes before membase or beyond EEPROMSizeUno will only give errors when _EEPROMEX_DEBUG is set
  EEPROM.setMemPool(memBase, EEPROMSizeUno);
  
  // Set maximum allowed writes to maxAllowedWrites. 
  // More writes will only give errors when _EEPROMEX_DEBUG is set
  EEPROM.setMaxAllowedWrites(maxAllowedWrites);
  delay(100);
  Serial.println("");       
  
  // Always get the adresses first and in the same order
  addressByte      = EEPROM.getAddress(sizeof(byte));
  addressInt       = EEPROM.getAddress(sizeof(int));
  addressLong      = EEPROM.getAddress(sizeof(long));
  addressFloat     = EEPROM.getAddress(sizeof(float));
  addressDouble    = EEPROM.getAddress(sizeof(double));    
  addressByteArray = EEPROM.getAddress(sizeof(byte)*7);  
  addressCharArray = EEPROM.getAddress(sizeof(char)*7);  

  // Show adresses that have been issued
  issuedAdresses();

  // Read and write different data primitives
  readAndWriteByte(); 
  readAndWriteInt(); 
  readAndWriteLong(); 
  readAndWriteFloat();     
  updateAndReadDouble(); 

  // Read and write different data arrays
  writeAndReadCharArray();   
  writeAndReadByteArray();   
  
  // Test EEPROM access time
  waitUntilReady();
  
  // Test error checking
  errorChecking(addressLong);  
}

void loop()
{
  // Nothing to do during loop
}