Pages: 1 ... 6 7 [8] 9 10   Go Down
Author Topic: Aumentar la frecuencia de muestreo (Solucionado)  (Read 25372 times)
0 Members and 1 Guest are viewing this topic.
Madriz
Offline Offline
Full Member
***
Karma: 0
Posts: 176
Glober Arduiner
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

cuenta con ello smiley-wink
Logged

Argentina
Offline Offline
Full Member
***
Karma: 1
Posts: 104
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

No se que pueda aportar, solo la inspiración  smiley. Con mucho gusto Igor, al menos en la introducción pondré alguna cosa.
Logged


0
Offline Offline
Edison Member
*
Karma: 16
Posts: 1579
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Pues lo prometido es deuda! Nos hemos juntado para hacer un pequeño manual de introducción de todo lo expuesto por aquí. Podeís encontrar una breve explicación de los puntos importantes de la configuración, así como el código para tener el Arduino muestreando y enviando por serie a unos 66.5 kHz. Los resultados son mostrados gráficamente utilizando magnífico soft libre KST en "tiempo real"... el "osciloscopio del pobre" !!  smiley-wink

http://real2electronics.blogspot.com/2011/09/arduino-adc-muestreo-alta-velocidad.html


Saludos


Igor R.
« Last Edit: September 04, 2011, 05:50:46 am by Igor R » Logged


Ciudad Real
Offline Offline
God Member
*****
Karma: 1
Posts: 751
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

digno de playground ...
Logged

Madriz
Offline Offline
Full Member
***
Karma: 0
Posts: 176
Glober Arduiner
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

PROBLEM---> solution

Haciendo unas pruebas para validar el script de python me he dado cuenta de que no consegúi de ninguna manera la velocidad de muestreo que buscábamos. El problema radica en que enviamos 66500 bytes por segundo, cada uno de ellos lo tratamos para hacerlo numero y todo esto de uno en uno. Total, que no da. Si hacéis la prueba conseguiréis resultados diversos dependiendo de vuestro pc.

la solución que he encontrado tienes dos pasos:

1.- Aumentar el tamaño del buffer de la librería serial (depende sel SO, usando W7 he podido usando Spyder, pero fuera de spyder usa el archivo compilado)
2.- modificar el script para que sea algo así:
Code:

while 1:
    try:
        n=ser.read(1)
#       
       
        file.write(str(ord(n)))
        file.write('\n')
        print ser.inWaiting()
       
    except KeyboardInterrupt:
         
       
        j=(ser.inWaiting())
        g=j
        for h in range(int(j)):
            n=ser.read(1)
            file.write(str(ord(n)))
            file.write('\n')
            print(g)
            g=g-1
           
        ser.close()
       
     
        file.write(str(time.clock()))
        file.flush()
        file.close()
        exit("Finalizando aplicacion")
        sys.exit(0)




MORALEJA--> de este modo no podemos muestrear en tiempo real smiley-sad



Logged

0
Offline Offline
Edison Member
*
Karma: 16
Posts: 1579
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Puedes explicar mejor tus pruebas? Cuesta de creer...
Has medido el tiempo que le cuesta hacerlo?
« Last Edit: September 09, 2011, 10:59:46 am by Igor R » Logged


Madriz
Offline Offline
Full Member
***
Karma: 0
Posts: 176
Glober Arduiner
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Si, usando time.clock

pero puedes hacer la prueba a lo bestia, pon el script a funcionar durante 10 segundos, deberías obtener 10*66500 datos (aprox), pero queda muy lejos.


además, al aumentar el buffer, he ido monitorizando la cantidad de datos por leer con serial.inWaiting()  y es brutal. te dejo un trozo del log, primera columna bytes en el buffer, segunda tiempo en segundos:


19822 0.610013596532
19821 0.617693660752
19820 0.625642165364
23787 0.632586713176
23786 0.643446487203
23785 0.652635566248
27752 0.662374871105
« Last Edit: September 09, 2011, 11:26:53 am by aero_yo » Logged

0
Offline Offline
Edison Member
*
Karma: 16
Posts: 1579
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Salen 8-10 ms ?
Yo siempre he probado en Ubuntu. Y no he notado nada...Por ejemplo un tono, no se ven que falten datos y la FFT me sale perfecta, por lo que la frecuencia de muestreo cuadra.
Ahora estoy fuera, ya probare... pero cuesta de creer que un micro de 8 bits ponga a prueba un PC....je,je,je
Estaria bien investigar si es cosa de la libreria de python o que pasa.... Probare lo de inwaiting...

 smiley-eek-blue
« Last Edit: September 09, 2011, 11:46:17 am by Igor R » Logged


Madriz
Offline Offline
Full Member
***
Karma: 0
Posts: 176
Glober Arduiner
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Igual es cosa del Güindos...
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

He encontrado algunas diferencias en los datos transmitidos con estos 2 códigos:
 - "datos no rápidos": es como yo lo hacía antes
 - "datos rápidos": es como lo quiero hacer ahora
Después de los códigos pongo el resultado.

Code:
// ********************
//  datos no rápidos
// ********************

#define mysize 200
#define PINS_SENSOR_BARRIER  4

unsigned long tStart;
unsigned long tEnd;
byte mydata[mysize];

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  Serial.println("");
  Serial.println("esperando corte...");
  mydata[0] =analogRead(PINS_SENSOR_BARRIER);
  while (analogRead(PINS_SENSOR_BARRIER)>mydata[0]-10){};
  tStart=micros();
  for (int i=1; i<mysize;i++)
  {
     mydata[i]=analogRead(PINS_SENSOR_BARRIER);
  }
  tEnd=micros();
 
    for (int i=0; i<mysize;i++)
  {
    Serial.print(mydata[i],DEC);
    Serial.print(" ");     
  }
  Serial.println("");     
  Serial.println("NEW ACQUISITION");
  Serial.print("tStart=");
  Serial.println(tStart);
  Serial.print("tEnd=");
  Serial.println(tEnd);
  Serial.print("Tiempo: ");
  Serial.println(tEnd-tStart);
  Serial.print("nPoints=");
  Serial.println(mysize);
}
tengo una duda
El resultado de este 1º código es:
"esperando corte...
108 74 56 40 29 22 19 16 17 17 16 17 16 17 17 17 19 21 29 44 61 77 92 100 103 106 106 106 107 107 107 107 107 106 108 107 107 108 108 108 108 108 107 108 108 107 108 108 108 108 108 108 108 108 107 108 108 108 107 108 107 108 107 107 107 107 108 107 106 107 107 107 107 107 107 107 107 107 107 107 107 106 107 107 107 107 107 106 107 107 107 107 107 107 107 107 107 107 108 107 107 107 107 106 107 106 108 107 108 107 108 107 108 107 108 108 107 107 108 108 108 108 108 107 108 108 108 108 108 108 108 108 108 108 108 108 107 108 108 108 107 108 108 107 107 108 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 106 107 107 107 107 106 107 107 106 107 106 107 107 106 107 107 106 107 107 106 107 107 106 107 107 107 107 107 107 108 107 107 107 107 107 107 107 107 108
NEW ACQUISITION
tStart=1129752
tEnd=1152040
Tiempo: 22288
nPoints=200

esperando corte..."

Code:
// ********************
//  datos rápidos
// ********************

#define mysize 200

unsigned long tStart;
unsigned long tEnd;
byte mydata[mysize];

void setup()
{
  Serial.begin(115200);
 
  //Prescaler
  //ADPS2 - ADPS1 - ADPS0 - Division Factor
  //0         0        0        ->2
  //0         0        1        ->2
  //0         1        0        ->4
  //0         1        1        ->8
  //1         0        0        ->16
  //1         0        1        ->32
  //1         1        0        ->64
  //1         1        1        ->128
  //Configure to Prescaler=32
  bitWrite(ADCSRA,ADPS2,1); // sbi(ADCSRA, ADPS2);
  bitWrite(ADCSRA,ADPS1,0); // cbi(ADCSRA, ADPS1);
  bitWrite(ADCSRA,ADPS0,1); // sbi(ADCSRA, ADPS0);
 
 // Input Channel Selections
 
//  MUX3210    Single Ended Input
//     0000          ADC0
//     0001          ADC1
//     0010          ADC2
//     0011          ADC3
//     0100          ADC4
//     0101          ADC5
//     0110          ADC6
//     0111          ADC7
//     1000          ACD8

// Entrada A4
ADMUX=(1<<ADLAR)|(0<<REFS1)|(1<<REFS0)|(0<<MUX3)|(1<<MUX2)|(0<<MUX1)|(0<<MUX0);
}

void loop()
{

  Serial.println("espero corte:");
  mydata[0] =analogReadFast();
  while (analogReadFast()>mydata[0]-10){};
  tStart=micros();
  for (int i=1; i<mysize;i++)
  {
     mydata[i]=analogReadFast();
  }
  tEnd=micros();
 
    for (int i=0; i<mysize;i++)
  {
    Serial.print(mydata[i],DEC);
    Serial.print(" ");
  }
  Serial.println("");
  Serial.println("NEW ACQUISITION");
  Serial.print("tStart=");
  Serial.println(tStart);
  Serial.print("tEnd=");
  Serial.println(tEnd);
  Serial.print("Tiempo: ");
  Serial.println(tEnd-tStart);
  Serial.print("nPoints=");
  Serial.println(mysize);
}

int analogReadFast()
{
ADCSRA|=(1<<ADSC); //  sbi(ADCSRA, ADSC);
// ADSC is cleared when the conversion finishes
while (bit_is_set(ADCSRA, ADSC));
        return ADCH;
}

Y el resultado de éste código es:
"espero corte:
27 16 15 15 14 13 12 11 10 10 9 8 8 7 7 7 6 6 5 5 5 5 5 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 6 6 7 7 8 8 9 10 11 11 12 13 14 15 15 16 17 18 19 19 20 21 22 22 23 23 24 24 24 25 25 25 25 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 27 26 26 26 26 26 27 27 26 27 26 27 26 27 27 27 27 26 27 26 27 27 27 27 26 27 27 27 27 27 27 26 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 26 27 27 27 27
NEW ACQUISITION
tStart=2726484
tEnd=2732068
Tiempo: 5584
nPoints=200
espero corte:"

Es verdad que se gana en rapidez, pero en ambos casos he usado la misma barrera IR, con las mismas condiciones de luz, y cuando uso el método rápido los datos del sensor son mas pequeños. ¿donde está el fallo?
Logged

0
Offline Offline
Edison Member
*
Karma: 16
Posts: 1579
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hola,

La configuración y función analogReadFast() está preparado para que el ADC funcione con una resolución de 8 bits. Como este script era para mandar por serie en tiempo real, de esta forma se gana mucha velocidad ya que sólo recoges 1 byte y envias el mismo por serie.
La función analogRead() de Arduino, funciona con toda la resolución del ADC, que son 10 bits (necesitas 2 bytes para guardar la info). O deberías usar la función map para guardarlo en 1 byte.


Saludos



Igor R.

Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hola Igor R,
Sabía que la función analogReadFast() devolvía solo el byte ADCH (como has dicho), pero yo me aseguraba previamente que el valor del sensor estuviera entre 0 y 254, como puedes ver en los datos recogidos por el 1º método.  Por eso definí el tipo de varible como byte mydata[mysize].
Es decir, en el caso de que analogRead() diera un valor de 100, que ocupa 2 bytes, pero por su valor se podría representar con 1 byte; el byte ADCH que envia la funcion analogReadFast() ¿no contendría el mismo valor?. Pensaba que, en este caso, ADCH contendría el valor 100 y ADCL contendría el valor 0
Logged

0
Offline Offline
Edison Member
*
Karma: 16
Posts: 1579
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

En el ejemplo "fast" el bit ADLAR (registro ADMUX) es el que te cambia la representación del ADC (justificación a la izquierda).

Me refiero, un 108 en resolución 10 bits es similar a un 27 en resolución 8 bits. [ Voltaje= ADC*Vcc/(2^n -1) ]


smiley-wink
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bien, creo que empiezo a entender algo. Lo que describes se explica bien en la siguiente imagen:



 - Es decir, Si ADLAR=1 la información que se envia desde el sensor se va a desplazar 2 bits a la izquierda, de forma que el bit 0 y el bit 1 se eliminan. Entiendo que esto supone un pequeño error, pues 4 números distintos se corresponderán con el mismo nº después de suprimir estos bits:
1100100 -- 100
1100101 -- 101   ---- tras la conversión (ADC) todos dan ---> 11001 -- 25
1100110 -- 102
1100111 -- 103
 - Pero viendo otra vez la imagen, si pongo ADLAR=0  y me aseguro que la información del sensor sea menor de 255, y después, en vez de coger el byte ADCH, escojo el byte ADCL. ¿estaría resuelto el problema? .

Si lo anterior es correcto y quiero poner ADLAR=0, en la siguiente linea ¿bastaría con  sustituir (1<<ADLAR) por (0<<ADLAR), o hay que cambiar algo mas?

ADMUX=(1<<ADLAR)|(0<<REFS1)|(1<<REFS0)|(0<<MUX3)|(1<<MUX2)|(0<<MUX1)|(0<<MUX0);
Logged

0
Offline Offline
Edison Member
*
Karma: 16
Posts: 1579
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

La función analogRead() de Arduino te devuelte un word (ADCH y ADCL). No sé exactamente que pasa cuando fuerzas un cast a un byte en:
 mydata[ i ]=analogRead(PINS_SENSOR_BARRIER);
No tienes más que probar, así que ya nos dirás... smiley-wink
Yo tengo como costumbre hacer en esos casos (byte bajo de un word) => mybyte=(byte)(myword & 0xFF);


En el ejemplo FAST, pierdes resolución (de 10 bits a 8 bits), puedes leerte la entrada que escribí:
http://real2electronics.blogspot.com/2011/09/arduino-adc-muestreo-alta-velocidad.html

Por otro lado,en dicho ejemplo (FAST), no puedes quitar ADLAR=1, ya que cómo puedes ver, sólo recoge ADCH, con la captura que has puesto anteriormente, puedes ver que pasaría....
Code:
int analogReadFast()
{
ADCSRA|=(1<<ADSC); //  sbi(ADCSRA, ADSC);
// ADSC is cleared when the conversion finishes
while (bit_is_set(ADCSRA, ADSC));
        return ADCH;
}

Por cierto, no se por qué puse en su día un int a devolver.... debería ser uint8_t


smiley-wink
« Last Edit: December 18, 2011, 01:01:16 pm by Igor R » Logged


Pages: 1 ... 6 7 [8] 9 10   Go Up
Jump to: