Тестирование АЦП ардуино, ENOB, разгон и усреднение.
- Войдите на сайт для отправки комментариев
Втр, 04/07/2017 - 21:29
Ставилась задача проверки эффективности и целесообразности разгона АЦП. Для прецезионного измерения битового разрешения АЦП в разных режимах использовался метод БПФ.
Аппаратные ресурсы;
1. ардуино МЕГА2560. АЦП на всех атмегах один и тот-же, мега выбрана из за размера памяти для БПФ.
2. генератор сигналов внутренний DSO Hantek (12-bit ). За неименеем лучшего, возможно результаты завалены при >12 битах.
3. буфферный усилитель - фильтр ФНЧ на MCP6022. Необязательно, два резистора и конденсатор может быть достаточно.
Результаты БЕЗ усреднения - аверейжинга.
/* averaging "u1"
Single Ended A-0:
9.6 ksps, default
125 k clock: a7a w11101111 Input 299 Hz
Peak number: 32 magnitude: 240171.70 Total: 194.1609802246 SINAD: 61.847 ENOB: 9.981
Peak number: 32 magnitude: 240183.71 Total: 199.3041534423 SINAD: 61.621 ENOB: 9.944
Peak number: 32 magnitude: 240184.25 Total: 194.2451019287 SINAD: 61.844 ENOB: 9.981
Peak number: 32 magnitude: 240144.79 Total: 196.1327209472 SINAD: 61.758 ENOB: 9.967
250 k clock: a7a w11101110 Input 599 Hz
Peak number: 32 magnitude: 239964.40 Total: 199.7442169189 SINAD: 61.593 ENOB: 9.939
Peak number: 32 magnitude: 239939.14 Total: 195.4058380126 SINAD: 61.783 ENOB: 9.971
Peak number: 32 magnitude: 239921.18 Total: 201.1040802001 SINAD: 61.533 ENOB: 9.929
Peak number: 32 magnitude: 239960.48 Total: 198.1329498291 SINAD: 61.664 ENOB: 9.951
500 k clock: a7a w11101101 Input 1198 Hz
Peak number: 32 magnitude: 239571.87 Total: 219.0831146240 SINAD: 60.777 ENOB: 9.803
Peak number: 32 magnitude: 239586.81 Total: 223.4446868896 SINAD: 60.606 ENOB: 9.775
Peak number: 32 magnitude: 239582.04 Total: 210.8227691650 SINAD: 61.111 ENOB: 9.859
Peak number: 32 magnitude: 239564.92 Total: 205.2021331787 SINAD: 61.345 ENOB: 9.898
1 M clock: a7a w11101100 Input 2396 Hz
Peak number: 32 magnitude: 232223.76 Total: 280.3315429687 SINAD: 58.365 ENOB: 9.403
Peak number: 32 magnitude: 232196.04 Total: 274.4304199218 SINAD: 58.548 ENOB: 9.433
Peak number: 32 magnitude: 232206.81 Total: 272.7705383300 SINAD: 58.602 ENOB: 9.442
Peak number: 32 magnitude: 232200.46 Total: 277.9204711914 SINAD: 58.439 ENOB: 9.415
Как видим, исходные почти 10 падают до 9.4 на 1МГц оверклока (х8). Совсем немного, часто приходиться читать что зависимость чуть ли не бит на каждое х2, т.е. на х8 где-то -4 бита. НЕ правда. АЦП хороший.
Усреднение на 8, вытягиваем 11-й бит
*********************************************************************************************
Averaging : u8
125 k clock: a7a w11101111 Input 38 Hz
Peak number: 32 magnitude: 1990554.87 Total: 894.6037597656 SINAD: 66.947 ENOB: 10.828
Peak number: 32 magnitude: 1990505.50 Total: 848.9946899414 SINAD: 67.401 ENOB: 10.904
Peak number: 32 magnitude: 1990401.37 Total: 873.2562866210 SINAD: 67.156 ENOB: 10.863
Peak number: 32 magnitude: 1990372.00 Total: 861.5628662109 SINAD: 67.273 ENOB: 10.883
250 k clock: a7a w11101110 Input 74 Hz
Peak number: 32 magnitude: 1995603.12 Total: 813.4340209960 SINAD: 67.795 ENOB: 10.969
Peak number: 32 magnitude: 1995438.75 Total: 813.6396484375 SINAD: 67.792 ENOB: 10.969
Peak number: 32 magnitude: 1995528.50 Total: 829.5065917968 SINAD: 67.625 ENOB: 10.941
Peak number: 32 magnitude: 1995513.25 Total: 805.1755371093 SINAD: 67.883 ENOB: 10.984
500 k clock: a7a w11101101 Input 149 Hz
Peak number: 32 magnitude: 1997099.12 Total: 818.8202514648 SINAD: 67.744 ENOB: 10.961
Peak number: 32 magnitude: 1997197.87 Total: 847.3858642578 SINAD: 67.447 ENOB: 10.911
Peak number: 32 magnitude: 1997172.75 Total: 850.2013549804 SINAD: 67.418 ENOB: 10.907
Peak number: 32 magnitude: 1997167.62 Total: 855.7623291015 SINAD: 67.361 ENOB: 10.897
1 M clock: a7a w11101100 Input 299 Hz
Peak number: 32 magnitude: 1997380.50 Total: 1038.3681640625 SINAD: 65.682 ENOB: 10.618
Peak number: 32 magnitude: 1997360.00 Total: 1056.1708984375 SINAD: 65.534 ENOB: 10.594
Peak number: 32 magnitude: 1997487.00 Total: 1018.9625244140 SINAD: 65.847 ENOB: 10.646
Peak number: 32 magnitude: 1997276.50 Total: 1013.6557006835 SINAD: 65.891 ENOB: 10.653
11 бит легко, но понятно что результаты до 1 МГц за счёт снижения сэмплинг рейта. Но 10.6 бит полученые на 1 МГц это лучше чем исходные 9.9.
Разгон АЦП увеличивает разрядность, но затраты процессора тоже немного растут.
И напоследок, 12-бит (и более) при снижении рейта. Проверка статистических методов.
*********************************************************************************************
Averaging : u64
125 k clock: a7a w11101111 Input 37 Hz
Peak number: 252 magnitude: 14582499.00 Total: 2508.2463378906 SINAD: 75.289 ENOB: 12.214
Peak number: 252 magnitude: 14582683.00 Total: 2400.3217773437 SINAD: 75.671 ENOB: 12.278
Peak number: 252 magnitude: 14582477.00 Total: 2438.2145996093 SINAD: 75.535 ENOB: 12.255
Peak number: 252 magnitude: 14582293.00 Total: 2494.9956054687 SINAD: 75.335 ENOB: 12.222
250 k clock: a7a w11101110 Input 37 Hz
Peak number: 126 magnitude: 15749849.00 Total: 3190.2336425781 SINAD: 73.869 ENOB: 11.978
Peak number: 126 magnitude: 15749567.00 Total: 3170.6799316406 SINAD: 73.922 ENOB: 11.987
Peak number: 126 magnitude: 15749587.00 Total: 3187.1323242187 SINAD: 73.877 ENOB: 11.980
Peak number: 126 magnitude: 15749524.00 Total: 3273.5866699218 SINAD: 73.645 ENOB: 11.941
500 k clock: a7a w11101101 Input 149 Hz
Peak number: 254 magnitude: 14624333.00 Total: 2407.5144042968 SINAD: 75.670 ENOB: 12.277
Peak number: 254 magnitude: 14624361.00 Total: 2361.1406250000 SINAD: 75.839 ENOB: 12.305
Peak number: 254 magnitude: 14624002.00 Total: 2536.6623535156 SINAD: 75.216 ENOB: 12.202
Peak number: 254 magnitude: 14623783.00 Total: 2483.3261718750 SINAD: 75.401 ENOB: 12.233
1 M clock: a7a w11101100 Input 149 Hz
Peak number: 127 magnitude: 15809414.00 Total: 3351.8518066406 SINAD: 73.473 ENOB: 11.912
Peak number: 127 magnitude: 15809325.00 Total: 3369.1030273437 SINAD: 73.428 ENOB: 11.905
Peak number: 127 magnitude: 15809365.00 Total: 3308.0595703125 SINAD: 73.587 ENOB: 11.931
Peak number: 127 magnitude: 15809180.00 Total: 3314.6928710937 SINAD: 73.569 ENOB: 11.928
64 должна теоретически дать 3-бита, т.е. 12.9 ожидаемый результат. Не хватает, варианты разные, низкое качество генератора сигналов как основной подозреваемый. Надо будет разобраться. Частоты использовались не те, надо бы 4.7 Гц - генератор завалил, поэтому только 2 частоты вместо сетки из 4-х, и более высокие чем /8 если для сравнительного анализа.
Код для всех желающих перепроверить результаты на след. посте. Там скорость АЦП через регистры выставлять надо, знание архитектуры и битов обязательно. Читайте дата шит.
Вкладка основная
/* averaging "u1" Single Ended A-0: 9.6 ksps, default 125 k clock: a7a w11101111 Input 299 Hz Peak number: 32 magnitude: 240171.70 Total: 194.1609802246 SINAD: 61.847 ENOB: 9.981 Peak number: 32 magnitude: 240183.71 Total: 199.3041534423 SINAD: 61.621 ENOB: 9.944 Peak number: 32 magnitude: 240184.25 Total: 194.2451019287 SINAD: 61.844 ENOB: 9.981 Peak number: 32 magnitude: 240144.79 Total: 196.1327209472 SINAD: 61.758 ENOB: 9.967 250 k clock: a7a w11101110 Input 599 Hz Peak number: 32 magnitude: 239964.40 Total: 199.7442169189 SINAD: 61.593 ENOB: 9.939 Peak number: 32 magnitude: 239939.14 Total: 195.4058380126 SINAD: 61.783 ENOB: 9.971 Peak number: 32 magnitude: 239921.18 Total: 201.1040802001 SINAD: 61.533 ENOB: 9.929 Peak number: 32 magnitude: 239960.48 Total: 198.1329498291 SINAD: 61.664 ENOB: 9.951 500 k clock: a7a w11101101 Input 1198 Hz Peak number: 32 magnitude: 239571.87 Total: 219.0831146240 SINAD: 60.777 ENOB: 9.803 Peak number: 32 magnitude: 239586.81 Total: 223.4446868896 SINAD: 60.606 ENOB: 9.775 Peak number: 32 magnitude: 239582.04 Total: 210.8227691650 SINAD: 61.111 ENOB: 9.859 Peak number: 32 magnitude: 239564.92 Total: 205.2021331787 SINAD: 61.345 ENOB: 9.898 1 M clock: a7a w11101100 Input 2396 Hz Peak number: 32 magnitude: 232223.76 Total: 280.3315429687 SINAD: 58.365 ENOB: 9.403 Peak number: 32 magnitude: 232196.04 Total: 274.4304199218 SINAD: 58.548 ENOB: 9.433 Peak number: 32 magnitude: 232206.81 Total: 272.7705383300 SINAD: 58.602 ENOB: 9.442 Peak number: 32 magnitude: 232200.46 Total: 277.9204711914 SINAD: 58.439 ENOB: 9.415 ********************************************************************************************* Averaging : u8 125 k clock: a7a w11101111 Input 38 Hz Peak number: 32 magnitude: 1990554.87 Total: 894.6037597656 SINAD: 66.947 ENOB: 10.828 Peak number: 32 magnitude: 1990505.50 Total: 848.9946899414 SINAD: 67.401 ENOB: 10.904 Peak number: 32 magnitude: 1990401.37 Total: 873.2562866210 SINAD: 67.156 ENOB: 10.863 Peak number: 32 magnitude: 1990372.00 Total: 861.5628662109 SINAD: 67.273 ENOB: 10.883 250 k clock: a7a w11101110 Input 74 Hz Peak number: 32 magnitude: 1995603.12 Total: 813.4340209960 SINAD: 67.795 ENOB: 10.969 Peak number: 32 magnitude: 1995438.75 Total: 813.6396484375 SINAD: 67.792 ENOB: 10.969 Peak number: 32 magnitude: 1995528.50 Total: 829.5065917968 SINAD: 67.625 ENOB: 10.941 Peak number: 32 magnitude: 1995513.25 Total: 805.1755371093 SINAD: 67.883 ENOB: 10.984 500 k clock: a7a w11101101 Input 149 Hz Peak number: 32 magnitude: 1997099.12 Total: 818.8202514648 SINAD: 67.744 ENOB: 10.961 Peak number: 32 magnitude: 1997197.87 Total: 847.3858642578 SINAD: 67.447 ENOB: 10.911 Peak number: 32 magnitude: 1997172.75 Total: 850.2013549804 SINAD: 67.418 ENOB: 10.907 Peak number: 32 magnitude: 1997167.62 Total: 855.7623291015 SINAD: 67.361 ENOB: 10.897 1 M clock: a7a w11101100 Input 299 Hz Peak number: 32 magnitude: 1997380.50 Total: 1038.3681640625 SINAD: 65.682 ENOB: 10.618 Peak number: 32 magnitude: 1997360.00 Total: 1056.1708984375 SINAD: 65.534 ENOB: 10.594 Peak number: 32 magnitude: 1997487.00 Total: 1018.9625244140 SINAD: 65.847 ENOB: 10.646 Peak number: 32 magnitude: 1997276.50 Total: 1013.6557006835 SINAD: 65.891 ENOB: 10.653 ********************************************************************************************* Averaging : u64 125 k clock: a7a w11101111 Input 37 Hz Peak number: 252 magnitude: 14582499.00 Total: 2508.2463378906 SINAD: 75.289 ENOB: 12.214 Peak number: 252 magnitude: 14582683.00 Total: 2400.3217773437 SINAD: 75.671 ENOB: 12.278 Peak number: 252 magnitude: 14582477.00 Total: 2438.2145996093 SINAD: 75.535 ENOB: 12.255 Peak number: 252 magnitude: 14582293.00 Total: 2494.9956054687 SINAD: 75.335 ENOB: 12.222 250 k clock: a7a w11101110 Input 37 Hz Peak number: 126 magnitude: 15749849.00 Total: 3190.2336425781 SINAD: 73.869 ENOB: 11.978 Peak number: 126 magnitude: 15749567.00 Total: 3170.6799316406 SINAD: 73.922 ENOB: 11.987 Peak number: 126 magnitude: 15749587.00 Total: 3187.1323242187 SINAD: 73.877 ENOB: 11.980 Peak number: 126 magnitude: 15749524.00 Total: 3273.5866699218 SINAD: 73.645 ENOB: 11.941 500 k clock: a7a w11101101 Input 149 Hz Peak number: 254 magnitude: 14624333.00 Total: 2407.5144042968 SINAD: 75.670 ENOB: 12.277 Peak number: 254 magnitude: 14624361.00 Total: 2361.1406250000 SINAD: 75.839 ENOB: 12.305 Peak number: 254 magnitude: 14624002.00 Total: 2536.6623535156 SINAD: 75.216 ENOB: 12.202 Peak number: 254 magnitude: 14623783.00 Total: 2483.3261718750 SINAD: 75.401 ENOB: 12.233 1 M clock: a7a w11101100 Input 149 Hz Peak number: 127 magnitude: 15809414.00 Total: 3351.8518066406 SINAD: 73.473 ENOB: 11.912 Peak number: 127 magnitude: 15809325.00 Total: 3369.1030273437 SINAD: 73.428 ENOB: 11.905 Peak number: 127 magnitude: 15809365.00 Total: 3308.0595703125 SINAD: 73.587 ENOB: 11.931 Peak number: 127 magnitude: 15809180.00 Total: 3314.6928710937 SINAD: 73.569 ENOB: 11.928 */ #include <avr/pgmspace.h> #define ADMUX (*(uint8_t*)0x7C) #define ADCSRB (*(uint8_t*)0x7B) #define ADCSRA (*(uint8_t*)0x7A) #define FFT_SIZE 1024 #define MIRROR FFT_SIZE / 2 #define INBUF FFT_SIZE String in_String = ""; boolean end_input = false; uint8_t debug_osm = 0; int16_t inp[INBUF] = {0}; float f_r[INBUF] = {0}; volatile uint8_t flag = 0; uint8_t adres_reg = 0; int16_t bin_numbr = 0; float max_magnt = 0; float tot_magnt = 0; int16_t dc_offset = 512; float sinad = 0.0; float enobs = 0.0; const uint8_t int_cntrl = 0x01; //PORT D mask, Digital 21 //const uint8_t averaging = 0; uint8_t averaging = 0; void setup() { Serial.begin(115200); in_String.reserve(200); adc_init(); pinMode( 21, OUTPUT); // ADC-test pinMode( 20, OUTPUT); //flag-test pinMode( 19, OUTPUT); //float-fft pinMode( 18, OUTPUT); //get-magnt } void loop() { int16_t temp = 0; char * pEnd; if( flag ) { digitalWrite(20, HIGH); for( uint16_t i = 0; i < INBUF; i++) { int16_t tempr = inp[i]; f_r[i] = tempr;// -4096;// -512; } // Test float // Peak:41 magnitude: 261632.40 Tot: 0.4767234802 SINAD: 114.789 ENOB: 18.775 Bl-Hr Wnd if(debug_osm) { for(int i = 0; i < FFT_SIZE; i++){ double wave = cos(( i *41.0 *( 2 *3.1415926535) /FFT_SIZE)); f_r[i] = 511.0 * wave; } } // 2.Windowing BlackMan-Harris 4-term double base_angle = 2.0 *M_PI / (FFT_SIZE -1); for( uint16_t i = 0; i < FFT_SIZE; i++ ) { double angle = i *base_angle; float temp = 0.35875 -(0.48829*cos(angle)) +(0.14128*cos(2*angle)) -(0.01168*cos(3*angle)); f_r[i] *= temp; } digitalWrite(19, HIGH); rev_bin( f_r, (int16_t) FFT_SIZE); rfft33( f_r, FFT_SIZE); digitalWrite(19, LOW); digitalWrite(18, HIGH); get_MagnitF( f_r); digitalWrite(18, LOW); flag = 0; ADCSRA |= ((1<< ADIF) | (1<< ADIE)); digitalWrite(20, LOW); } serialEvent(); if( end_input) { char cmd = in_String[0]; in_String[0] = '+'; if( cmd == 'd' ) { debug_osm = 1 - debug_osm; if(debug_osm) Serial.print(F("\nDebug aktiv.")); else Serial.print(F("\nDebug de-aktiv.")); } if( cmd == 'u' ) { temp = strtol( in_String.c_str(), &pEnd, 10); averaging = temp; Serial.print(F("\n\taveraging: ")); Serial.print(averaging, DEC); dc_offset = 512UL * averaging; } /* if( cmd == 'u' ) { // averaging 8 averaging = 8 - averaging; if(averaging) { dc_offset = 4096; Serial.print(F("\naveraging ON.")); } else { dc_offset = 512; Serial.print(F("\naveraging Off")); } } */ // "x" command - print a table of incomming buffer. if( cmd == 'x' ) { Serial.print("\n\t"); for( uint16_t i = 0; i < INBUF; i++) { int16_t tempr = inp[i]; Serial.print(tempr, DEC); Serial.print("\t"); if ((i+1)%16 == 0) Serial.print("\n\t"); } Serial.println("\n\t"); } // "f" command - print a table of fft results. if( cmd == 'f' ) { Serial.print("\n\t"); for( uint16_t i = 0; i < MIRROR; i++) { Serial.print(f_r[i], 1); Serial.print("\t"); if ((i+1)%16 == 0) Serial.print("\n\t"); } Serial.println("\n\t"); } // "e" command. if( cmd == 'e' ) { enob(f_r); Serial.print(F("\n\tPeak number:\t")); Serial.print(bin_numbr, DEC); Serial.print(F("\tmagnitude:\t")); Serial.print(max_magnt, 2); Serial.print(F("\tTotal:\t")); Serial.print(tot_magnt, 10); Serial.print(F("\tSINAD:\t")); Serial.print(sinad, 3); Serial.print(F("\tENOB:\t")); Serial.print(enobs, 3); } if( cmd == 'a' ) { adres_reg = strtol( in_String.c_str(), &pEnd, 16); Serial.print(F("\n\tReg: ")); Serial.print(adres_reg, HEX); Serial.print(F("\tvalue: ")); temp = (*(uint8_t*)adres_reg); Serial.print(temp, BIN); } if( cmd == 'r' ) { Serial.print(F("\n\tReg: ")); Serial.print(adres_reg, HEX); Serial.print(F("\tvalue: ")); temp = (*(uint8_t*)adres_reg); Serial.print(temp, BIN); } if( cmd == 'w' ) { Serial.print(F("\n\tReg: ")); Serial.print(adres_reg, HEX); Serial.print(F("\tvalue: ")); temp = (*(uint8_t*)adres_reg); Serial.print(temp, BIN); temp = strtol( in_String.c_str(), &pEnd, 2); (*(uint8_t*)adres_reg) = temp; Serial.print(F("\tnew value: ")); temp = (*(uint8_t*)adres_reg); Serial.print( temp, BIN); } in_String = ""; end_input= false; } } void serialEvent() { while (Serial.available()) { char inChar = (char)Serial.read(); in_String += inChar; if (inChar == '\n') { end_input= true; } } }Вторая таб - называется АЦП
//ISR(TIMER1_COMPB_vect) ISR(ADC_vect) { static uint16_t n_sampl = 0; static uint8_t n_sampl2 = 0; static uint16_t accum = 0; // digitalWrite(21, HIGH); PORTD |= int_cntrl; // pin High int16_t temp = ADCL; temp += (ADCH << 8); accum += temp; // uint8_t last = 0; // if(averaging) if(++n_sampl2 >= averaging) { // if(++n_sampl2 > 31) { // if(++n_sampl2 > 0) { // if(++n_sampl2 > 15) { // if(++n_sampl2 > 63) { temp = accum -dc_offset; // /8; n_sampl2 = 0; accum = 0; inp[n_sampl++] = temp; if( n_sampl >= INBUF ) { flag = 1; n_sampl = 0; ADCSRA &= ~(1<< ADIE); } } // digitalWrite(21, LOW); PORTD &= ~(int_cntrl); // pin Low } void adc_init(void) { ADMUX = 0x40; //temp_reg; /* ADMUX = ((1<<REFS1)| // Reference Selection Bits (1<<REFS0)| // 2.56V Internal (0<<ADLAR)| // ADC Left Adjust Result (1<< MUX4)| (0<< MUX3)| // Gain / Channel Selection Bits (0<< MUX2)| (0<< MUX1)| // (1) 10000 ADC8<->ADC9 Gain = 1x. (0<< MUX0)); */ ADCSRA = ((1<< ADEN)| // 1 = ADC Enable (1<< ADSC)| // ADC Start Conversion (1<<ADATE)| // 1 = ADC Auto Trigger Enable (1<< ADIF)| // ADC Interrupt Flag (1<< ADIE)| // ADC Interrupt Enable (1<<ADPS2)| (1<<ADPS1)| // ADC Prescaler : MHz. (1<<ADPS0)); ADCSRB = ((0<< MUX5)| //=1 for 8-15 channels (0<<ADTS2)| // Sets Auto Trigger source Timer/Counter1 Compare Match B (0<<ADTS1)| (0<<ADTS0)); DIDR1 = 0xFF; DIDR2 = 0xFF; } /* void tmr_init() { // Set up TIMER 1 - ADC sampler TIMSK1 = 0x00; TCCR1A = 0; TCCR1B = 0; TCCR1C = 0; TCCR1A = ((1<<WGM11) | (1<<WGM10)); // Mode 15, Fast PWM TCCR1B = ((1<<WGM13) | (1<<WGM12)); // Mode 15, Fast PWM TCCR1B |= (1<<CS10); // clk/1 prescaling. OCR1A = SMP_TMR1; OCR1B = SMP_TMR1; TCNT1 = 0; TIFR1 |= (1<<OCF1B); TIMSK1 |= (1<<OCIE1B); } */Третья - ДСП
#define Leakage 10 void enob(float data[]) { float temp = 0.0; bin_numbr = 0; max_magnt = 0; tot_magnt = 0; for ( int i = Leakage; i < MIRROR; i++) { temp = f_r[i]; if (temp > max_magnt) { max_magnt = temp; bin_numbr = i; } } max_magnt = 0; if ((bin_numbr > Leakage) && (bin_numbr < (MIRROR - Leakage))) { int16_t lefts = bin_numbr - Leakage; int16_t right = bin_numbr + Leakage; for ( int i = Leakage; i < MIRROR; i++) { temp = f_r[i]; if ((i > lefts) && (i < right)) { max_magnt += temp; } else { tot_magnt += (temp * temp); } } tot_magnt = sqrt(tot_magnt /0.35875); // RSS vs RMS + Noise Shaping by Windowing MUST be accounted. // root-sum-square (rss) if (tot_magnt == 0) tot_magnt = 0.000001; sinad = (20.0 * log10(max_magnt / (tot_magnt))); // -10 *log(FFT_SIZE /2); IF RMS calculated, than process GAIN must be subtructed. enobs = (sinad - 1.76) / 6.02; } else { sinad = 0.0; enobs = 0.0; } } /* fft-gain dB = 10 *log(M /2) = 10 *log(256) = 24.082399653; */4-я флоат ФФТ
void rfft33(float X[], int N) { /**************************************************************************** * rfft(float X[],int N) * * A real-valued, in-place, split-radix FFT program * * Decimation-in-time, cos/sin in second loop * * Length is N=2**M (i.e. N must be power of 2--no error checking) * * * * Original Fortran code by Sorensen; published in H.V. Sorensen, D.L. Jones,* * M.T. Heideman, C.S. Burrus (1987) Real-valued fast fourier transform * * algorithms. IEEE Trans on Acoustics, Speech, & Signal Processing, 35, * * 849-863. Adapted to C by Bill Simpson, 1995 wsimpson@uwinnipeg.ca * * --------------------------------------------------------------------------* * C/C++ language bugs fixing & correction: * * 1. C-style array start adress [0]; * * 2. SIN() and COS tweed factors change place; * * 3. Rev Bin - replaced by new fastest version. * * made by Anatoly Kuzmenko, 2017, anatolyk69@gmail.com * ****************************************************************************/ int I, I0, I1, I2, I3, I4, I5, I6, I7, I8, IS, ID; int J, K, M, N2, N4, N8; float A, A3, CC1, SS1, CC3, SS3, E, R1; float T1, T2, T3, T4, T5, T6; M = (int)(log(N) / log(2.0)); /* N=2^M */ /* ----Length two butterflies--------------------------------------------- */ IS = 0; ID = 4; do { for (I0 = IS; I0 < N; I0 += ID) { I1 = I0 + 1; R1 = X[I0]; X[I0] = R1 + X[I1]; X[I1] = R1 - X[I1]; } IS = 2 * ID - 2; ID = 4 * ID; } while (IS < N); /* ----L shaped butterflies----------------------------------------------- */ N2 = 2; for (K = 1; K < M; K++) { N2 = N2 * 2; N4 = N2 / 4; N8 = N2 / 8; E = (float) 6.2831853071719586f / N2; IS = 0; ID = N2 * 2; do { for ( I = IS; I < N; I += ID) { I1 = I; // + 1; I2 = I1 + N4; I3 = I2 + N4; I4 = I3 + N4; T1 = X[I4] + X[I3]; X[I4] = X[I4] - X[I3]; X[I3] = X[I1] - T1; X[I1] = X[I1] + T1; if (N4 != 1) { I1 += N8; I2 += N8; I3 += N8; I4 += N8; T1 = (X[I3] + X[I4]) * .7071067811865475244f; T2 = (X[I3] - X[I4]) * .7071067811865475244f; X[I4] = X[I2] - T1; X[I3] = -X[I2] - T1; X[I2] = X[I1] - T2; X[I1] = X[I1] + T2; } } IS = 2 * ID - N2; ID = 4 * ID; } while ( IS < N ); A = E; for ( J = 1; J < N8; J++) { //, A s4itat Do trigonometrii !!! A = (float)J * E; A3 = 3.0 * A; CC1 = cos( A); SS1 = sin( A); CC3 = cos(A3); SS3 = sin(A3); IS = 0; ID = 2 * N2; do { for ( I = IS; I < N; I += ID) { I1 = I + J; I2 = I1 + N4; I3 = I2 + N4; I4 = I3 + N4; I5 = I + N4 - J;// + 2; I6 = I5 + N4; I7 = I6 + N4; I8 = I7 + N4; T1 = X[I3] * CC1 + X[I7] * SS1; T2 = X[I7] * CC1 - X[I3] * SS1; T3 = X[I4] * CC3 + X[I8] * SS3; T4 = X[I8] * CC3 - X[I4] * SS3; T5 = T1 + T3; T6 = T2 + T4; T3 = T1 - T3; T4 = T2 - T4; T2 = X[I6] + T6; X[I3] = T6 - X[I6]; X[I8] = T2; T2 = X[I2] - T3; X[I7] = -X[I2] - T3; X[I4] = T2; T1 = X[I1] + T5; X[I6] = X[I1] - T5; X[I1] = T1; T1 = X[I5] + T4; X[I5] = X[I5] - T4; X[I2] = T1; } IS = 2 * ID - N2; ID = 4 * ID; } while ( IS < N ); } } } void rev_bin( float *fr, int16_t fft_n) { int m, mr, nn, l; float tr; mr = 0; nn = fft_n - 1; for (m = 1; m <= nn; ++m) { l = fft_n; do { l >>= 1; } while (mr + l > nn); mr = (mr & (l - 1)) + l; if (mr <= m) continue; tr = fr[m]; fr[m] = fr[mr]; fr[mr] = tr; } } void get_MagnitF(float *fr) { for (int i = 1; i < MIRROR; i++) { float real = fr[i]; float imag = fr[FFT_SIZE - i]; float Magnit = (float) (sqrt((real * real) + (imag * imag))); fr[i] = Magnit; } }5-я - справка, создайте если надо для основных регистров, проще чем по дата шиту туда-сюда шариться
Инструкция по применению;
подать переменку 5В пик-пик центрованую на 2.5 постоянки на пин А0. Проверить коммандой х, чем ближе к +-512 тем лучше, но не клиппить.
комманды f e u сами разберётесь зачем. a w r тоже, а7а - установить указатель на ADCSRA, w11101100 записать ну и так далее.
Падение на 1бит точности при росте скорости х2 идет ПОСЛЕ частоты АЦП в 1Мгц. Попробуйте свой тест на делителях 1:2 (Если ваша мега его вообще потянет) - скорость АЦП = 8Мгц, 1:4, 1:8 .. и убедитесь, что потеря нехилая даже для последовательных замеров с одной единственной ноги и даже не в режиме "диф х200".
Да, и на таких скоростях чтение АЦП в обработчике прерывания - безнадежно. Только в основном коде, только "free running mode" .. в общем поиграйтесь.
Частота оцифровки 592кГц при тактовой камня 16Мгц (1:2) вполне достижима. Проверено. :)
Тесторовал АЦП AtMega328 (arduino nano) две штуки.
Вход ADC0, резисторный делитель 1/3 (от А0 на минус 5кОм, на вход 10кОм)(что было под рукой), на AREF конденсатор 470нФ, опорное AVCC.
Программа визуализации http://out.arduino.ru/?redirect=https%3A%2F%2Fyadi.sk%2Fd%2Fp-BCHLQFs2kdB&baseU=http%3A%2F%2Farduino.ru%2Fforum%2Fproekty%2Fvyzhimaem-maksimum-usb-ostsillograf-na-arduino
Взято отсюда http://arduino.ru/forum/proekty/vyzhimaem-maksimum-usb-ostsillograf-na-arduino
Ардуиновский код переписан на Си, компилировался в Proteus 8.5 (плагин arduino 1.0.5), оптимизация -О0 (иначе глюки), там же дебажился и от туда же заливался.
В результате в одной Mega328 делитель 1/2 работает и получается 615384 семпла/секунду, эффективных 7 бит. Во второй меге работает только начиная с делителя 1/4, на 1/2 выдает код FF с редким мусором, почему непонятно.
После ~30Кгц входного сигнала (генерировался функцией tone(); arduino Mega2560), видно что полоса пропускания входа АЦП начинает хромать, график становится похожим на кривую пилу.
код:
#include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> //****************************************************** byte oldADC, newADC; byte ADC_BUF[270]; //буфер обьявляем с запасом byte Rb = 255; byte count = 0; //****************************************************** void uSend (byte data); //***************************************************** int main (void) { volatile register byte *N asm ("r28"); //указатель на адрес буфера АЦП оже регистровая пара Y volatile register byte adcTemp asm ("r9"); //не используется (его не видит компилятор(кричит Warning!) //нужен для ассемблерной вставки (чтобы компилятор не использовал) ADCSRA = (1 << ADEN) | (0 << ADSC) | (0 << ADATE) | (0 << ADIF) | (0 << ADIE) | (0 << ADPS2) | (1 << ADPS1) | (0 << ADPS0); ADMUX = (0 << REFS1) | (1 << REFS0) | (1 << ADLAR) | (0 << MUX3) | (0 << MUX2) | (0 << MUX1) | (0 << MUX0) ; DIDR0 = (1<<ADC0D); // REFS1:REFS0 //00 AREF //01 AVcc, с внешним конденсатором на AREF //10 Резерв //11 Внутренний 2.56В источник, с внешним конденсатором на AREF //настройка UART 256000 бод 8-N-1 UBRR0H=0x0; //256000=0x00; UBRR0L=0x03; //256000=0x03; UCSR0B=(1<<RXEN0|1<<TXEN0); UCSR0C=(1<<UCSZ01|1<<UCSZ00); //********************************************************************** asm ("sei"); while(1) { ADCSRA |= (1<<ADSC); //запуск АЦП без прерываний while (ADCSRA & (1<<ADSC)) {} //ждем пока АЦП закончит oldADC = ADCH; //делаем старое значение АЦП ADCSRA |=(1<<ADSC); //запуск преобразования while (ADCSRA& (1<<ADSC)){} //ждем пока АЦП закончит newADC = ADCH; //делаем новое значение АЦП while (newADC>oldADC) //ждем пока закончится фронт { ADCSRA |=(1<<ADSC); while (ADCSRA& (1<<ADSC)){} oldADC=newADC; newADC=ADCH; } while (newADC<=oldADC) //ждем пока закончится спад { ADCSRA |=(1<<ADSC); while (ADCSRA& (1<<ADSC)){} oldADC=newADC; newADC=ADCH; } N = ADC_BUF; //передаем адрес начала буфера ADCSRA |= (1<<ADSC|1<<ADATE|1<<ADIE); //разрешаем прерывания АЦП free running mode while (N<(ADC_BUF+255)) //ждем пока соберется буфер АЦП { } ADCSRA &=~(1<<ADATE|1<<ADIE); //останавливаем АЦП uSend(15); uSend(0); uSend(15) ; for (count = 0; count<255; count++) { uSend (ADC_BUF[count]); } uSend(OCR1A); //Не используются по видимому в проге ПК uSend(OCR1B); //Не используются по видимому в проге ПК uSend(0); //Начальная точка uSend(1); uSend(15);uSend(1); if (UCSR0A&(1<<RXC0)) //читаем и меняем предделитель тактирования АЦП { Rb = UDR0; ADCSRA = (ADCSRA >> 3) << 3 | Rb ; } //******************************************************* } } ISR(ADC_vect, ISR_NAKED) { //вход 7 тактов asm volatile ( "LDS R9, 0x0079 \n" //забираем из ADCH //3 такта "ST Y+, R9 \n" //ложим в массив ADC_BUF //2 такта "RETI \n" //сваливаем //4 такта ); //итого 16тактов } void uSend (byte data) //отправка в UART { while (!(UCSR0A & (1<<UDRE0))) {} UDR0=data; }Может кому понадобится, код для Mega2560 (другой не было под рукой), в принципе пойдет любая Ардуина.
Отправка частоты (точнее F/255) использовалась терминалка программы FlProg (отправка в DEC).
В ответ придет "I recived" и отправленное число, и частота генерации.
Компилировалась в ARDUINO 1.8.1
byte incomingByte = 1; // для данных, поступающих через последовательный порт void setup() { Serial.begin(9600); } void loop() { if (Serial.available() > 0) { incomingByte = Serial.read(); // считываем входящий байт // показываем, что именно мы получили: Serial.print("I received: "); Serial.println(incomingByte, DEC); Serial.print("\n"); Serial.println((unsigned int)incomingByte*255); //показываем частоту генерации } tone(8,(unsigned int)incomingByte*255); }