Solo per divertirmi e per dimostrarlo, ho terminato una routine di assemblaggio AVR per calcolare i risultati sin (x) in 24 bit (3 byte) con un bit di errore. L'angolo di input è in gradi con una cifra decimale, da 000 a 900 (0 ~ 90,0) solo per il primo quadrante. Utilizza meno di 210 istruzioni AVR e funziona in media 212 microsecondi, variando da 211us (angolo = 001) a 213us (angolo = 899).
Ci sono voluti diversi giorni per fare tutto, più di 10 giorni (ore libere) solo pensando al miglior algoritmo per il calcolo, considerando il microcontrollore AVR, senza virgola mobile, eliminando tutte le possibili divisioni. Ciò che ha richiesto più tempo è stato quello di creare i giusti valori di incremento per gli interi, per avere una buona precisione è necessario aumentare i valori da 1e-8 a interi binari 2 ^ 28 o più. Una volta trovati tutti gli errori colpevoli di precisione e arrotondamento, aumentato la loro risoluzione di calcolo di 2 ^ 8 o 2 ^ 16 in più, i risultati migliori sono stati raggiunti. Ho prima simulato tutti i calcoli su Excel avendo cura di avere tutti i valori come Int (x) o Round (x, 0) per rappresentare esattamente l'elaborazione del core AVR.
Ad esempio, nell'algoritmo l'angolo deve essere in radianti, l'ingresso è in gradi per facilitare l'utente. Per convertire gradi in radianti la formula banale è rad = gradi * PI / 180, sembra piacevole e facile, ma non lo è, PI è un numero infinito - se usando poche cifre si creeranno errori in uscita, la divisione per 180 richiede Manipolazione di bit AVR poiché non ha istruzioni di divisione e, inoltre, il risultato richiederebbe un punto in virgola mobile poiché coinvolge numeri molto al di sotto dell'intero 1. Ad esempio, il radiante di 1 ° (gradi) è 0,017453293. Poiché PI e 180 sono costanti, perché non invertire questa cosa per una semplice moltiplicazione? PI / 180 = 0,017453293, moltiplicalo per 2 ^ 32 e risulta come una costante 74961320 (0x0477D1A8), moltiplica questo numero per il tuo angolo in gradi, diciamo 900 per 90 ° e spostatelo di 4 bit a destra (÷ 16) per ottenere 4216574250 (0xFB53D12A), ovvero i radianti del 90 ° con espansione 2 ^ 28, adattarsi in 4 byte, senza una singola divisione (tranne il 4 spostamento del bit verso destra). In un certo senso, l'errore incluso in tale trucco è inferiore a 2 ^ -27.
Quindi, tutti gli ulteriori calcoli devono ricordare che è 2 ^ 28 più alto e se ne è preso cura. È necessario dividere i risultati in movimento per 16, 256 o anche 65536 solo per evitarlo utilizzare byte di fame in crescita non necessari che non aiuterebbero la risoluzione. È stato un lavoro scrupoloso, trovare la quantità minima di bit in ogni risultato di calcolo, mantenendo la precisione dei risultati intorno a 24 bit. Ognuno dei numerosi calcoli è stato eseguito in tentativo / errore con bit più alti o più bassi nel conteggio di Excel, osservando la quantità complessiva di bit di errore sul risultato in un grafico che mostra 0-90 ° con una macro che esegue il codice 900 volte, una volta al decimo di laurea. Quell'approccio "visivo" di Excel è stato uno strumento che ho creato, aiutato molto a trovare la soluzione migliore per ogni singola parte del codice.
Ad esempio, arrotondando questo particolare risultato di calcolo da 13248737,51 a 13248738 o semplicemente perdendo i decimali "0,51", quanto influenzerà la precisione del risultato finale per tutti i 900 angoli di input (00,1 ~ 90,0) test?
Sono stato in grado di mantenere l'animale contenuto entro 32 bit (4 byte) su ogni calcolo e ho finito con la magia per ottenere la precisione entro 23 bit dal risultato. Quando si controllano tutti i 3 byte del risultato, l'errore è ± 1 LSB, in sospeso.
L'utente può prendere uno, due o tre byte dal risultato per i propri requisiti di precisione. Naturalmente, se è sufficiente un solo byte, consiglierei di utilizzare una singola tabella sin da 256 byte e di utilizzare l'istruzione AVR "LPM" per afferrarla.
Una volta che la sequenza di Excel è stata eseguita senza intoppi, la traduzione finale da Excel in assembly AVR ha richiesto meno di 2 ore, come al solito dovresti pensare di più prima, lavorare meno dopo.
A quel tempo sono stato in grado di spremere ancora di più e ridurre l'utilizzo dei registri. Il codice effettivo (non finale) utilizza circa 205 istruzioni (~ 410 byte), esegue un calcolo sin (x) in media di 212us, clock a 16MHz. A quella velocità può calcolare 4700+ sin (x) al secondo. Non è importante, ma può eseguire un'onda sinusoidale precisa fino a 4700Hz con 23 bit di precisione e risoluzione, senza alcuna tabella di ricerca.
L'algoritmo di base si basa sulla serie di Taylor per sin (x), ma modificato molto per adattarsi alle mie intenzioni con il microcontrollore AVR e la precisione in mente.
Anche se l'utilizzo di una tabella di 2700 byte (900 voci * 3 byte) sarebbe attraente per la velocità, qual è l'esperienza divertente o di apprendimento su questo? Naturalmente, è stato anche considerato l'approccio CORDIC, forse più tardi, il punto qui è quello di spingere Taylor nel nucleo dell'AVR e prendere l'acqua da una roccia asciutta.
Mi chiedo se Arduino "sin (78.9 °)" può eseguire Processing (C ++) con 23 bit di precisione in meno di 212us e il codice necessario più piccolo di 205 istruzioni. Può essere se C ++ utilizza CORDIC. Gli schizzi di Arduino possono importare il codice assembly.
Non ha senso pubblicare qui il codice, in seguito modificherò questo post per includervi un collegamento web, possibilmente sul mio blog in questo URL . Il blog è principalmente in portoghese.
Questa avventura senza soldi è stata interessante, spingendo i limiti del motore AVR di quasi 16MIPS a 16MHz, senza istruzione di divisione, moltiplicazione solo in 8x8 bit. Permette di calcolare sin (x), cos (x) [= sin (900-x)] e tan (x) [= sin (x) / sin (900-x)].
Soprattutto, questo mi ha aiutato a mantenere lucido e oliato il mio cervello di 63 anni. Quando gli adolescenti dicono che gli "anziani" non sanno niente della tecnologia, rispondo "ripensaci, chi pensi abbia creato le basi per tutto ciò che ti piace oggi?".
Saluti