In altro thread ci era venuta la balzana idea di provare a migliorare la generazione di numeri casuali, senza usare particolari librerie. Ce ne sono già alcune, di cui una in particolare fa uso di registri a scorrimento lineari, una cosa abbastanza complessa anche se molto più efficiente ed affidabile).
Il problema principale è quale "seed" utilizzare per la reandomSeed() perché la generazione di numeri pseudocasuali dipende dal valore iniziale (stesso valore iniziale, stessa sequenza) che è un unsigned long.
Generalmente si fornisce come seed il valore di un pin analogico lasciato libero ("flottante") il quale restituisce valori non costanti in quanto dipendono da disturbi elettromagnetici di varia natura. Il problema è che questo valore va da 0 a 1023, quindi di fatto facendo ad esempio:
randomSeed(analogRead(A0));
si possono avere al massimo 1024 diverse sequenze pseudocasuali, non di più. Qualcuno suggeriva anche di usare millis() ma anche questo valore sarebbe troppo limitato e limitante in quanto all'accensione il valore restituito sarà più o meno sempre lo stesso.
Sicuramente ci sono stati studi sull'argomento, ma ci piaceva cercare di trovare una proposta migliorativa senza scavare in rete.
A questo punto era sorta l'idea di combinare 3 diverse letture da 10 bit ciascuna (scartandone alcune nel mezzo, per dare il tempo al convertitore di "assestarsi" su un valore probabilmente differente) in un unsigned long, e questo era un esempio di possibile codifica:
void randomize(int pin)
{
unsigned long seed = 0;
for (int i=0; i<=2; ++i)
{
seed += analogRead(pin)>>(i*8);
for (int j=0; j<=4; ++j)
{
delay(2);
analogRead(pin);
}
}
randomSeed(seed);
}
Il dubbio però è quanto l'analogRead() sia realmente "fluttuante" ossia non credo che il range sia proprio l'intero 0-1023, e da questo quindi se i seed così generati possano essere distribuiti in maniera sufficientemente uniforme all'interno del range previsto, o se invece la lettura analogRead() restituisca valori relativamente limitati come estensione.
Seguirà sperimentazione pratica, ma sono ben accette idee ed argomentazioni statistico-matematiche utili a migliorare quella funzione randomize()
Preso un Arduino NANO da una scatla, fatto girare una sola volta uno sketch di test che per ogni pin analogico fa 10 letture e stampa il risultato.
Ottenuto:
Senza librerie va bene
Ma io ho due scarpiere, sono anche loro profonde 33 come le librerie, le posso usare?
Seriamente, senza hw aggiuntivo nulla si fa, poniamo un limite massimo?
Ad esempio, usando un apparecchio (sicuro per costruzione) come l'alimentatore di qualche vecchio router d-link, che andavano a 9v ca
Un partitore per stare dentro nei 5 volt di Arduino
Si misura il valore della sinusuoide dell'alimentatore
Siccome frequenza di rete e accensione di Arduino sono fenomeni asincroni, il valore misurato è abbastanza casuale per i nostri scopi?
Beh, è segnale ad alta impedenza, non fa danni
Torno a pensare al trasformatore del router
A bassa impedenza, si può mettere un partitore, non saturerebbe
Oppure usare il tempo che ci mette il tuo filo dal valore che trova a scendere a zero e/o salire a 1023
Quindi misurare la fase della semionda, ma è parimenti asincrona con l'istante di accensione
La misura la fa l'ATmega, quindi dovrebbe cambiare poco se la scheda è originale o meno, almeno in base alla mia ignoranza
Comunque, ho provato a fare 3 letture per 3 volte, creando 3 unsignel long e a moltilicarli tra di loro. varianza bassa, il range restituito è sempre attorno al massimo della variabile perchè la probabilità di avere N zeri in testa è tanto più bassa quanti più zeri di fila si devono avere, quindi forse forse con questa tecnica si ha pure meno variabilità della lettura analogica a 10 bit un po' più casuale rispetto al pin fluttuante. Però, da questo prodotto, ho preso 8 bit nel mezzo e dividendo per 32, (che sono i bit di un long), e tenendo il resto, ho un numero variabile da 0 a 31, questo lo posso usare per crearmi una maschera che azzeri i bit più significativi. In questo modo dovrei poter accorciare in modo random il numero. Non è ancora una distribuzione lineare ma almeno è molto più ampia. Ho 1 probabilità su 32 di avere un numero binario lungo X bit. Sofisticando un po' si potrebbe anche arrivare ad una probabilità uguale per i singoli numeri, ma richiede un calcolo più articolato.
Me pare 'na porcheria pure a me ad una seconda lettura
Mi rimangio tutto, così attenua l'alcool della mensa che a stomaco pieno ha meno effetti collaterali
Finito l'effetto dell'alcool, per quel che mi riguarda questo codice:
void setup() {
Serial.begin(19200);
}
void loop() {
unsigned long w[6] = {0};
for(byte i = 0; i < 6; i++) {
unsigned long x = ((unsigned long)analogRead(A0))<<16;
unsigned long y = ((unsigned long)analogRead(A0))<<8;
unsigned long z = ((unsigned long)analogRead(A0));
w[i] = x + y + z;
}
unsigned long rnd = w[0] * w[1] * w[2] * w[3] * w[4] * w[5];
Serial.println(rnd);
}
potrebbe andare bene.
Ovvio che essendo la analogRead moooolto poco variabile, può generare facilmente lo stesso set di numeri producendo lo stesso numero finale ma da quel che ho visto è sufficientemente raro.
Già con l'antenna per captare disturbi elettromagnetici il problema si riduce quasi del tutto.
Però una cosa strana, sul mio nano cinese, l'ho vista.
Ho provato a variare il pin e con A0, A3 e A7 tutto ok.
Con A1, A2, A4, A5 dopo poche lettura va tutto a zero. Anche A3.
Con A6 va a zero come i precedenti ma ogni tot lettura da un segno di vita.
Invece di variare solo il seed, si potrebbero sfruttare i fili per generare direttamente una sequenza casuale.
Aggiungendo un paio di componenti, potremmo andare a pescare qualcosa nel range delle radio FM.
bella idea, complimenti
siamo a dove eravamo ieri:
senza HW aggiuntivo non possiamo fare nulla, il limite deve essere dato lato HW
per assurdo, se io prendo una sequenza puramemente deterministica, ma la prendo una volta sola, appare casuale
ovvero? ovvero leggo l'ora da un modulo dcf77, che più deterministico di così non si puo' (non è vero, basta prendere una sequenza di zeri...)
MA
SE la leggo una volta sola all'accensione di Arduino, essendo l'istante di accensione slegato dal segnale DCF
la lettura è completamente casuale, specialmente se ho l'accortezza di considerarla solo una sequenza di bit, e se li mischio prima di usarli
Si "torna" al mio thread di parecchio tempo fa, dove volevo costruire un generatore di impulsi casuali per "giocare" con l'oscilloscopio.
In effetti senza un minimo di hardware esterno si combina poco.