Go Down

Topic: Mi servono 6-7 decimali ma float non va.... (Read 9852 times) previous topic - next topic

menniti

Mi sto incartando.... in realtà prima avevo impostato la BN su 4 cifre decimali, ora l'ho portata a 10; la questione dipende anche dalla matematica, ho beccato a c... un paio di frequenze che /400 davano giusto un decimale, che spariva; ora ho fatto alcune modifiche, ma devo prima arrivare ad una lettura seria e poi ti riesco a dare risposta.
Comunque senza la BN, all'origine, impostando BT 10 secondi leggevo senza problemi segnali 0,1Hz, poi ho deciso di rinunciare alle frequenze <1 in favore della semplicità dello strumento.
Manuale "Arduino e le tecniche di programmazione dei microcontrollori ATMEL"
http://www.michelemenniti.it/manuale_di_programmazione.html
http://www.michelemenniti.it/offerta.html
Articoli ElettronicaIN
http://www.michelemenniti.it/elettronica_in.html

menniti

Allora i decimali escono in base (ovviamente) al valore applicato in ingresso, ma la situazione non è migliorata; ho verificato che la questione non può basarsi su tics, in quanto la risposta sull'intero range di frequenza è completamente sballata, cioè io faccio la taratura iniziale su una frequenza, più mi allontanto da essa (in + o in -) e più perdo in precisione. Il comportamento ±1 della parte intera della formula Allora, confermo, applico 799333330, all'ingresso del micro arrivano 1998333,325
la formula Hz = f_freq/(f_tics/1000) mi restituisce 1998334 o 5,0000000000
la rimoltiplicazione x400 mi dà 799334000,0000000000
Se applico il valore della prova precedente 123794610 al micro arrivano 309486,525
la formula Hz = f_freq/(f_tics/1000) mi restituisce 309177.513000309
la rimoltiplicazione x400 mi dà 123671005,200123
verificato con altri valori, quindi il sistema sull'intera scala è anche impreciso, per cui chiaro che quell'f_tics viene usato per un calcolo ben preciso assieme a qualcos'altro, e non per il ricavo della frequenza assoluta.
Pausa pranzo.... :D
Manuale "Arduino e le tecniche di programmazione dei microcontrollori ATMEL"
http://www.michelemenniti.it/manuale_di_programmazione.html
http://www.michelemenniti.it/offerta.html
Articoli ElettronicaIN
http://www.michelemenniti.it/elettronica_in.html

lestofante

f_tics è il numero di millisecondi, calcolato usando il timer0, se non erro. Quindi la sua precisione (e dunque la precisione dell'intervallo di lettura) è fortemente legata al timer0, che è fortmente legato al crtistallo/oscillatore.

Secondo me, se usi qualcosa tipo tempo di carica/scarica di un condensatore pre-calcolato con strumenti precisi, oppure già una 2009 con quarzo, vedi la differenza.
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

menniti

Il mio schema è la migliore soluzione possibile, non sto lavorando con Arduino ma con uno stand-alone con oscillatore quarzato esterno, molto più stabile e preciso di un clock basato su un normale quarzo esterno, come Arduino 2009.
Ho fatto altre prove ma niente da fare, devo rinunciare a questa cosa, almeno non ho più il cruccio di non averci provato.
I tuoi suggerimenti mi hanno permesso di imparare ad usare questa lib che potrebbe tornare utile in diverse altre occasion.
Il problema è purtroppo insito alla fonte, ecco perché non è superabile in alcun modo.
Ti ringrazio moltissimo della pazienza che hai avuto, ringrazio anche nid per i suoi preziosi suggerimenti.
Ciao
Manuale "Arduino e le tecniche di programmazione dei microcontrollori ATMEL"
http://www.michelemenniti.it/manuale_di_programmazione.html
http://www.michelemenniti.it/offerta.html
Articoli ElettronicaIN
http://www.michelemenniti.it/elettronica_in.html

nid69ita

Di nulla.  :D
Domanda sul software. Non ho visto il tuo sketch. Ti serve passare un float a un BigNumber? Se si, sei passato attraverso una stringa?
my name is IGOR, not AIGOR

menniti

No, da un UL, ma ho fatto la prova anche con un float, il comando ultoa(frq, buf, 10); trasforma i numeri in stringhe "buf" che poi dò in pasto alla BigNumbers; dovendo poi moltiplicare per un fattore numerico ho usato  BigNumber m = 400; solo se ci sono decimali il valore numerico va racchiuso tra "", p.es.  BigNumber m = "400,123456";
Ieri sera a casa avevo fatto tutta una serie di prove in preparazione alla modifica del mio sketch, ed infatti tutto è andato bene, il problema è quello spiegato, la precisione che voglio manca all'origine, non me la posso inventare, posso solo leggermente barare, ma a quel punto non ha alcun significato.
Manuale "Arduino e le tecniche di programmazione dei microcontrollori ATMEL"
http://www.michelemenniti.it/manuale_di_programmazione.html
http://www.michelemenniti.it/offerta.html
Articoli ElettronicaIN
http://www.michelemenniti.it/elettronica_in.html

lestofante

il tuo problema è la durata dell'analisi.
In un secondo hai troppi pochi campioni per sapere l'esatta frequenza IN SECONDI.

SECONDO ME, il metodo va completamente invertito: anzichè contare il numero di cambi stato in un secondo, si potrebbe contare quanto tempo passa per fare X letture.. ti faccio uno sketch al volo!

(mi hai fatto prendere bene, mannggia a te!)
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

lestofante

#37
Jul 07, 2013, 06:05 pm Last Edit: Jul 07, 2013, 06:17 pm by lesto Reason: 1
eccomi di nuovo quì.

Code: [Select]
/*
WRITTEN BY lesto AT 07/07/2013
arduino.cc
*/

#include "BigNumber.h"

/*FOR ARDUINO UNO
 id=0 -> pin=2
 id=1 -> pin=3
 for other and explanation see: http://arduino.cc/en/Reference/AttachInterrupt
*/
const int interruptId = 0;
const int interruptPin = 2;

volatile uint16_t letture = 0;
volatile uint32_t tempo = 0;

void setup(){
 Serial.begin(11900);
 delay(1000);
 BigNumber.begin(10);
}



void loop(){
 if (letture == 0){ //if no reading going on
   /*************/  
   //print result, if tehre are any valid
   if (tempo != 0){
     BigNumber v = "65536"; //uint16_t max value
   
     char buf[sizeof(unsigned long)*8+1];
     ultoa(tempo, buf, 10); //this is what String use, base 10
   
     BigNumber t = buf;
     Serial.println("Numero RISING intercettati: "+v);
     Serial.println("Tempo impiegato: "+tempo );
     Serial.println("Frequanza calcolata: "+(v/t));
   }

   /*************/    
   //waif for an impulse to be applied
   while(!digitalRead(interruptPin)){
     ;//do nothing
   }

   /*************/    
   //start a new reading
   letture = 1;
   tempo = micros(); //we use micros
   attachInterrupt(interruptId, contaRising, RISING);
 }
}

void contaRising(){
 if (letture == 0){ //if it is the first reading take the time
    tempo = micros(); //i do it here because attachInterrupt take many micros, and will break all
 }
 letture ++;
 if (letture == 0){ //if overflow occured!
    tempo = tempo-micros(); //don'w worry about time taken by micros(): it is compesanted by tame taken from the first call
    //stop! let the loop print our result
    detachInterrupt(interruptId);
 }
}


conto 65536 impulsi per sfruttare l'interrupt. Quindi ogni 65536 impulsi si prende il tempo utilizzato (in micros(), quindi con una precisione di 4microsecondi) e si calcola la frequenza.
Quindi per frequenze più veloci si può usare un unsigned long, con 4294967296 impulsi, mentre per i più lenti si può usare la micros.
In oltre, visto che sarebbe complicato aumentare la precione della micros() usando i registi, è più conveniente modificare il tipo di variabile di letture per essere più grande (e quindi splamare l'errore), non bisogna usare per forza l'overflow (lo ammetto, è una piccola chicca messa perchè non sapevo che valore usare)

edit: è non testato perchè non ho sorgenti di clock, verifica se v/t è effettuato correttamente facendo ilconto a mano, e ancheche quel "while" per apsettare il segnale altro non ti dia fastidio. Serve per non scartare la prima lettura, ma in realtà funziona solo la prima volta, poi è molto probabile che con questo sistema rimaga la lettura "in corso" quando stacchi il segnale.

ridit: probabilmente con quetsa ersione non conti frequenze così alte come l'altra, ma considera questa come una bozza. Puoi persino (ma diventa un casino) mischiare l'idea di contare le frequenze al secondo, facendo una media di tutte le misure effettuare e printandola a video ogni tot... vedresti quindi un valore che mano a mano che passano i secondi diventa sempre più vicino alla realtà, e persino via SW dire che se la miusra non cambia per più di tot MS(diciamo un secodo) di X (diciamo 0.01Hz), la misurazione viene considerata stabile.. inzomma veda lei  :smiley-mr-green:
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

menniti

Questo sketch posso provarlo a volo con il mio Arduino, non certo sullo stand-alone, collegamenti tutti diversi.
Ma cosa devo collegare ai pn 2 e 3?
Manuale "Arduino e le tecniche di programmazione dei microcontrollori ATMEL"
http://www.michelemenniti.it/manuale_di_programmazione.html
http://www.michelemenniti.it/offerta.html
Articoli ElettronicaIN
http://www.michelemenniti.it/elettronica_in.html

lestofante

#39
Jul 07, 2013, 06:27 pm Last Edit: Jul 07, 2013, 06:35 pm by lesto Reason: 1
al pin 2 la frequenza da misurare, le indicazioni sono per cambiare pin  :smiley-mr-green:

edit: se devi misurare una frequenza di 1998333,325 dovresti ottenere, con 65536, circa 30 letture al secondo (30,4921466827392578125), portato in micros: 30492146
peròi micros vanno di 4 in 4, quindi otteresti:
30492144 -> * 65536 = 1998333149184 = 1998333.149184
oppure
30492148 -> * 65536 = 1998333411328 = 1998333.411328

usando un unsigned long avresti invece l'overflow a 4294967296, che / 1998333,325 = 2149,2747192213291043424900097685 (ovvero 2000 secondi per una lettura, un pò troppo direi, considerando che c'è anche l'verflow di micros() direi che non ci stiamo)

secondo me per quella frequenza, la cosa ideale è usare un unsigned long che parte da 100.000, e se la misurazione dura meno di un secondo incrementare il valore. Ovviamente salvando e applicando le misurazioni precedenti, in tal modo non "butti via" misurazioni
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

menniti

quello che hai realizzato è un periodimetro ;) comunque per mio problema ho docuto settare la seriale a 9600, ma vedo solo le scritte, i numeri appaiono come simboli strani. e non si capisce nulla.
Manuale "Arduino e le tecniche di programmazione dei microcontrollori ATMEL"
http://www.michelemenniti.it/manuale_di_programmazione.html
http://www.michelemenniti.it/offerta.html
Articoli ElettronicaIN
http://www.michelemenniti.it/elettronica_in.html

lestofante

uff mi sa che quel + fa casino,  fai così:
Code: [Select]

Serial.print("Numero RISING intercettati: ");
Serial.println(v);
Serial.print("Tempo impiegato: ");
Serial.println(tempo);
Serial.println("Frequanza calcolata: ");
Serial.println(v/t);
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

menniti

ormai sono rientrato, fine lab, se ne parla fine settimana, su tttropp incasinat :smiley-sweat:
Comunque, aspetta, praticamente tu hai scritto una lib, ma un conto è fare prove sul tuo codice un conto è implementarla nel mio codice che, tanto per cominciare, impegna già i due interrupt dei pin 2 e 3.
Il mio progetto, dal punto di vista hardware è praticamente perfetto, mentre il software è quello che è, per colpa delle scarse prestazioni del micro e delle mie scarse competenze. Sono sicuro che se potessimo lavorare assieme anche una sola giornata arriveremmo ad una soluzione eccellente, ma questo è impossibile.
Per cui l'unica possibilità, che mi sembra francamente un po' troppo come richiesta :D è che tu faccia una lib che sostituisca la FreqCounter, con i seguenti vincoli: a) deve fare letture di 1 secondo; e deve restituire nel mio sketch: b) un valore espresso in Hz ma con 4 decimali max, b) una variabile di compensazione per rendere il valore letto preciso; in pratica deve fare le stesse cose di quella attuale ma con una maggiore risoluzione; inoltre non deve usare risorse aggiuntive rispetto a quelle attuali (p.es. il watch dog, che sto usando per i pulsanti, visto che i timer sono tutti impegnati dalla lib).

A parte questo la prossima settimana riprovo questo tuo lavoro (con le modifiche di stasera) e ti faccio sapere.
Manuale "Arduino e le tecniche di programmazione dei microcontrollori ATMEL"
http://www.michelemenniti.it/manuale_di_programmazione.html
http://www.michelemenniti.it/offerta.html
Articoli ElettronicaIN
http://www.michelemenniti.it/elettronica_in.html

lestofante

bhe prioma dobbiamo capire qualemetodo funziona, senza le varie limitazioni. Poi il resti è un lavoro di limatura  :smiley-mr-green:
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

menniti


bhe prioma dobbiamo capire qualemetodo funziona, senza le varie limitazioni. Poi il resti è un lavoro di limatura  :smiley-mr-green:

ok, appena riesco a provare le tue modifiche posto i risultati qui, in particolare il range di lettura ed il margine di precisione. Grazie mille per l'impegno.
Manuale "Arduino e le tecniche di programmazione dei microcontrollori ATMEL"
http://www.michelemenniti.it/manuale_di_programmazione.html
http://www.michelemenniti.it/offerta.html
Articoli ElettronicaIN
http://www.michelemenniti.it/elettronica_in.html

Go Up