During my research for my "secret" project i decided to benchmark sine wave and sine wave LOOK UP TABLE's generation, the different methods and approximations, both mathematically and methods for discrete time systems like uC's.
For research purposes, and initial development i have been actually using the Arduino Due, due to its ease of testing and debugging initial stages of ideas , for which the DAC helps a lot.
I been guessing already some limitations speed performance (considering what i want to achieve) in later stages, but for now it has been a brilliant tool.
As the ARM in the DUE was a new thing to me, and to shorten the time, i had to look around for some initial guidance regarding the registers/tmers and interrupts in order to get started.
In that sense Duane B.'s work and Groovuino's with their QUICK 'N' DIRTY synth were invaluable.
At the moment, im quite advanced, and it came to mind to use some "live" sine calculations for some other purposes other than the Pure-tone sinewave itself ( complex sinusoids and subsequent modulation, etc).
So decided to benchmark both thei sinewavetable generation and a somewhat adapted version i used previously.
And using the millis() in Arduino, there was almost a halving of time taken to generate 512 samples of wavetable.
Duane's version took 27/28 Ms contrasting with 16/17 Ms.
Now, while this is not relevant for their synths, it is to me. Specially when im trying to squeeze as many cycles as i can already with the arduino Due, due to all the layers that the "easy way" places in between, massively contributing to the decrease in performance of speed/time. :)
Its easy to see where the optimization is, slightly reducing the cycles needed !
Some surprises soon, and some more on this as well...
Table_1 test code
#define WAVE_SAMPLES 512 long previousMillis = 0; // default int is 32 bit, in most cases its best to use uint32_t but for large arrays its better to use smaller // data types if possible, here we are storing 12 bit samples in 16 bit ints #define offset 2047 // In this case is the same as the Amplitude uint16_t sin_data[WAVE_SAMPLES]; float w ; // ψ float yi ; float phase; int sign_samp; int i; void create2nd_sine (){ // Serial.println(" "); // Serial.println("Sine table2"); w=(2.0 * PI)/WAVE_SAMPLES; for (i = 0; i <= 511; i++) { yi= offset*sin(phase); // Offset is the same as the Amplitude phase=phase+w;
sign_samp=offset+yi; // dc offset translated for a 12 bit DAC sin_data[i]=sign_samp; // write value into array // Serial.println(i); // Serial.println(sin_data[i]); } } // void setup() { // put your setup code here, to run once: Serial.begin(9600); } void loop() { // put your main code here, to run repeatedly: unsigned int result; unsigned long currentMillis = millis(); create2nd_sine (); result=currentMillis - previousMillis; previousMillis = currentMillis; Serial.println(result); }Table_2 test code
// Duane's
#define WAVE_SAMPLES 512 // default int is 32 bit, in most cases its best to use uint32_t but for large arrays its better to use smaller // data types if possible, here we are storing 12 bit samples in 16 bit ints uint16_t nSineTable[WAVE_SAMPLES]; long previousMillis = 0; void createSineTable() { // Serial.println(" "); // Serial.println("Sine table"); for(uint32_t nIndex = 0;nIndex < WAVE_SAMPLES;nIndex++) { // normalised to 12 bit range 0-4095 nSineTable[nIndex] = (uint16_t) (((1+sin(((2.0*PI)/WAVE_SAMPLES)*nIndex))*4095.0)/2); // Serial.println(nIndex); // Serial.println(nSineTable[nIndex]); } } // void setup() { // put your setup code here, to run once: Serial.begin(9600); } void loop() { // put your main code here, to run repeatedly: unsigned int result; unsigned long currentMillis = millis(); createSineTable(); result=currentMillis - previousMillis; previousMillis = currentMillis; Serial.println(result); }For a more detailed explanation of a sinewave generator, and a few diff methods, check below link
(1) http://dubworks.blogspot.co.uk/p/blog-page.html
No comments:
Post a Comment
Feel free to contact me with any suggestions, doubts or requests.
Bless