Skocz do zawartości

Sipeed Tang Nano 4k z ADC - Gowin FPGA Designer


Gieneq

Pomocna odpowiedź

Dnia 5.05.2022 o 20:44, Elvis napisał:

Konfigurując DMA w trybie circular z przerwaniem w połowie mamy sporo czasu na obsługę przerwania, więc kolejny transfer może się rozpocząc nawet podczas wykonywanie procedury obsługi przerwania od poprzedniego.

Cześć @Elvis walczyłem z tym kilka godzin, faktycznie tryb circular rozwiązał problemy, wygenerowałem też zegar 10 MHz z PWM timera i podałem na ADS1256 i działa. Tak 256 taktów się zgadza. Timer i SPI mają te same źródło taktowania więc są zsynchronizowane.

Mam tylko problemy, które mogą wynikać z niezrozumienia tematu - nie jestem ekspertem.

Cytat

Jeśli zmiast 24 bitów zadziała czytanie 32 bitów, sprawa dodatkowo się upraszcza

Widzę że w Cubie jest 32 przy memory, 16 w peripheral, coś testowałem ale nie wyszło. Odpuściłem, zostałem przy 8 bitach.

Tryb circular cały czas coś wysyła. Do odczytu potrzeba wysłać sekwencję 24 taktów zegara z 0 na MOSI. Zrobiłem więc bufor który trzyma cały cykl:

  • Fclk = 10 MHz,
  • sampling rate = 10 MHz/256= 39,0625 kHz
  • SPIclk = 10 MHz/4 = 2,5 MHz,
  • Liczna cykli SPIclk/sampling_rate = 64 z czego część to DRDY w stanie wysokim (stała liczba, ale nie zanotowałem)

Więc zrobiłem taki bufor 64 bitów:

const uint8_t spi_ads_data[8] = {0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF};

Tylko problem w tym że wysyłanie cały czas SPIclk powoduje jakieś problemy: pomiary się nie udają, odczyt nie działa i widać że sygnał DRDY ma różną długość. Domyślam się, że w czasie konwersji nie może dziać się cokolwiek na SPI.

I tak się zastanawiam co z tym zrobić żeby circular zostawić, ale móc jakoś zatrzymać komunikację. Mam tu kilka pomysłów:

  • zamienić sprzętowy NSS na programowy CS i na czas konwersji odłączać układ, albo inaczej włączać tylko gdy wysyłam 24 zer - nie wiem czy to pomoże, tylko jak to zrobić?
  • kluczować sygnał SPIclk np układem na przerzutniku zachowującym pełne cykle zegara.

Mam też inny dylemat: jak synchronizować transmisję - tak by sekwencja 24 zer rozpoczęła się np 2 takty po przejściu DRDY z high na low? Może timer wyzwalany od DRDY i wtedy np zmiana CS na czas wysłania 24 zer.

  • Lubię! 1
Link do komentarza
Share on other sites

Cześć @Gieneq

Pisałem na szybko, więc może nieco nieprecyzyjnie się wyraziłem.

Chodziło mi o sprawdzenie jak zachowuje się ADS1256, kiedy odbierasz z niego 32 bity, czyli 4 bajty w trybie DMA. Dla SPI nie ma różnicy czy to 4x8b czy 1x32b, DMA jest ważne, żeby między danymi nie było przerw.

Nie mam niestety tego układu, więc nie mogę przetestować, ale ciekaw jestem jak zachowa się pin DRDY jeśli będziemy odbierać >24 bity. Kolejny test to byłoby odebranie 8 bajtów i obserwacja DRDY.

Przy odrobinie szczęścia i taktowaniu ADS1256 z 8MHz oraz ustawieniu SPI na 1MHz, mogłoby się udać odbierać dane w bajtach, bezpośrednio z ADS1256 do pamięci RAM. Używając DMA można byłoby ustawić transfer 4x liczba próbek i tyle. Po zakończeniu transmisji w pamięci będą 3 bajty danych dla pierwszej próbki, później jeden śmieci, dalej znowu 3 bajty danych itd.

Edit: jeśli prosta / ciągła transmisja faktycznie nie zadziała, to proponuję użyć timera w trybie PWM do generowania sygnału CS. Transmisję SPI po DMA można byłoby też wyzwalać tym timerem. Nie jest nawet potrzebny tryb circular, można od razu przesyłać dane z SPI do RAM, wtedy nawet nie będzie śmieci w co 4 bajcie.

Edit2: O ile dobrze pamiętam, można uruchomić SPI tylko do odbierania danych, wtedy nie będzie problemu co ma być na MOSI.

  • Lubię! 1
  • Pomogłeś! 1
Link do komentarza
Share on other sites

44 minuty temu, Elvis napisał:

Dla SPI nie ma różnicy czy to 4x8b czy 1x32b, DMA jest ważne, żeby między danymi nie było przerw.

@Elvis aaa rozumiem. Nie ma problemu z odczytem 32 bitów. Dopóki konwersja jest zakończona (czyli stan który objawia się tym, że na DRDY jest 0) można odczytywać ile się chce. Tylko z moich eksperymentów wyszło że odczyt SPI gdy ADS dokonuje pomiaru kończy się zaburzeniem pomiaru i ADS nie podaje nic na MISO. Dlatego rozumiem pomysł ze spowolnieniem taktowania SPIclk żeby rozciągnąć cykl w trybie circular na cały okres działania ADS ale:

  1. jak to zsynchronizować z czasem gdy ADS dokonuje pomiarów? Wiem że wystarczy raz zsynchronizować, ale trzeba by wiedzieć ile cykli zegara jest pomiędzy wywołaniem funkcji a pierwszym taktem zegara SPI.
47 minut temu, Elvis napisał:

O ile dobrze pamiętam, można uruchomić SPI tylko do odbierania danych, wtedy nie będzie problemu co ma być na MOSI.

Tak można, tylko w dokumentacji jest napisane, że w trybie ciągłego odczytu odebranie danych polega na wysłaniu 3 bajtów 0x00 (24 takty zegara z 0 na MOSI) i jednoczesnym odczytaniem MISO. Czyli z tego co rozumiem ma to być użycie funkcji ReadTransmit.

52 minuty temu, Elvis napisał:

jeśli prosta / ciągła transmisja faktycznie nie zadziała, to proponuję użyć timera w trybie PWM do generowania sygnału CS.

i to chyba najbardziej mi się podoba. Synchronizacja tego byłaby nawet prosta - mogę aktywować timer po wystąpieniu zbocza na DRDY i nigdy nie trafię na czas w którym ADS dokonuje pomiaru.

Będę działał z tematem, dam znać jak będę miał efekty. Dzięki za pomoc 🙂 

  • Lubię! 1
Link do komentarza
Share on other sites

To chyba temat ADS pogrzebany. Ostatnie problemy wynikały z tego, że scalak się zepsuł - znowu były tragiczne problemy z komunikacją wynikające nie wiem z czego, odpaliłem sprawdzony kod dla Arduino i niestety cisza. Mam pomysł. Odpalę ADC wbudowane w STMa, będzie prościej.

 

Może i dobrze, że tak się skończyło. Skorzystam z wbudowanego ADC, 12bitów jest ok, a wybór częstotliwości próbkowania dość duży. Trafiłem też na poradnik: https://community.st.com/s/article/configuring-dsp-libraries-on-stm32cubeide jak dodać biblioteki DSP do projektu w Cubie. Skompilowało się i wygląda jakby miało działać. Tu kawałek szybkiego testowego kodu:

/* FFT settings */
#define SAMPLES					512 			/* 256 real party and 256 imaginary parts */
#define FFT_SIZE				SAMPLES / 2		/* FFT size is always the same size as we have samples, so 256 in our case */

#define FFT_BAR_MAX_HEIGHT		120 			/* 120 px on the LCD */

/* Global variables */
float32_t Input[SAMPLES];
float32_t Output[FFT_SIZE];
uint16_t result[FFT_SIZE/2];
int led = 0;

	arm_cfft_radix4_instance_f32 S;	/* ARM CFFT module */
	float32_t maxValue;				/* Max FFT value is stored here */
	uint32_t maxIndex;				/* Index in Output array where max value is */
	uint16_t i;

	int fs = 60e3;
	int sig_f1 = 1e3;

	for (i = 0; i < SAMPLES; i += 2) {
		/* Each 22us ~ 45kHz sample rate */
//		Delay(21);

		/* We assume that sampling and other stuff will take about 1us */

		/* Real part, make offset by ADC / 2 */
		Input[(uint16_t)i] = (float32_t)(sinf(2*3.1415*sig_f1*i/fs));
		/* Imaginary part */
		Input[(uint16_t)(i + 1)] = 0;
	}

	/* Initialize the CFFT/CIFFT module, intFlag = 0, doBitReverse = 1 */
	arm_cfft_radix4_init_f32(&S, FFT_SIZE, 0, 1);

	/* Process the data through the CFFT/CIFFT module */
	arm_cfft_radix4_f32(&S, Input);

	/* Process the data through the Complex Magniture Module for calculating the magnitude at each bin */
	arm_cmplx_mag_f32(Input, Output, FFT_SIZE);

	/* Calculates maxValue and returns corresponding value */
	arm_max_f32(Output, FFT_SIZE, &maxValue, &maxIndex);

	/* Display data on LCD */
	for (i = 0; i < FFT_SIZE / 2; i++) {
		/* Draw FFT results */
		result[i] = Output[(uint16_t)i];
	}

		/* We want to turn led ON only when low frequencies are active */
		/* Output[0] = Signals DC value */
		if ((Output[1] + Output[2] + Output[3] + Output[4] + Output[5] + Output[6] + Output[7]) > 120) {
			led = 1;
		} else {
			led = 2;
		}

Widać że w danych jest górka przy niskich częstotliwościach:

image.thumb.png.138c94dc3cfc6c84a3c268ad08f9c53a.png

Szczyt na 8 i 9 elemencie tablicy to chyba błąd - to za daleko jak na 1kHz, ale niewykluczone że źle napisałem generowanie próbek. Później sprawdzę.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

(edytowany)

Jest niewielki postęp. Wziąłem zalegającą płytkę STM32F303VCT6 Discovery i stwierdziłem że skoro ma ultraszybki przetwornik ADC to może się przydać.

ADC działa, DMA działa, wybrałem częstotliwość próbkowania 44 kHz.

Napisałem notatnik do testów poprawności FFT biblioteki CMSIS:

  • generuję listę próbek i wypisuję jako kawałek kodu C do wklejenia do kodu dla STM32F3,
  • wyznaczam FFT używając bibliotek Pythona,
  • odtwarzam sygnał używając odwróconego FFT,
  • wyznaczam i rysuję funkcję zamiany kubełków w pasma wyświetlacza,
  • stosując kubełki rysuję symulację.

Tu wspomniana funkcja i symulacja działania wyświetlacza:

bins_to_bands.thumb.png.c40c8007f0a36eee703f21658340312d.pngsym_display.thumb.png.e9635aad10fd100ed08c5c8ef5d13203.png

Zrobiłem kilka testów dla częstotliwości taktowania 36 i 64MHz oraz liczby punktów FFT 256 i 1024. Wyniki są rewelacyjne nawet porównując z mocniejszym układem ESP32.

Optymalizacja - ciekawe bo tylko -Os daje poprawę szybkości przetwarzania.

Zmiana częstotliwości taktowania poprawiła szybkość o 27,5%

Przykład dla 64MHz, 256 punktów i -Os:

samples.thumb.png.1e6c39ef27cad3d4c26a2ac22e879f9c.pngtime_base_comparison.thumb.png.4d33ddb88671d6f7df1f6fca644e0bf6.png

magnitudes_comparison.thumb.png.ad8506d6ca5b3ffa92a33661d3013d07.pngtime_base_comparison_zoom.thumb.png.175f8fd011a272dd8c0202b49b2fac12.png

Tu nie ma dyskusji, wyniki są identyczne.

Napisałem taki jakby benchmark dla STM32F3 i tu są wyniki:

START INPUT SIGNAL 256:
0.000000, 0.032471, -0.045520, 0.088455, -0.073852, 0.120411, -0.073269, 0.120905, -0.041235, 0.092502, 0.014791, 0.046949, 0.079723, 0.001443, 0.135646, -0.026836, 0.167505, -0.026184, 0.167892, 0.005909, 0.139399, 0.061957, 0.093794, 0.126861, 0.048283, 0.182703, 0.020037, 0.214446, 0.020740, 0.214707, 0.052872, 0.186105, 0.108924, 0.140430, 0.173780, 0.094895, 0.229524, 0.066663, 0.261131, 0.067398, 0.261247, 0.099552, 0.232517, 0.155588, 0.186753, 0.220377, 0.141175, 0.276003, 0.112940, 0.307457, 0.113687, 0.307408, 0.145843, 0.278531, 0.201845, 0.232660, 0.266548, 0.187021, 0.322037, 0.158763, 0.353319, 0.159505, 0.353087, 0.191644, 0.324046, 0.247593, 0.278049, 0.312192, 0.232330, 0.367526, 0.204031, 0.398616, 0.204749, 0.398184, 0.236853, 0.368960, 0.292731, 0.322818, 0.357208, 0.277002, 0.412368, 0.248644, 0.443249, 0.249319, 0.442597, 0.281370, 0.413172, 0.337159, 0.366868, 0.401495, 0.320936, 0.456463, 0.292501, 0.487117, 0.293117, 0.486228, 0.325097, 0.456584, 0.380778, 0.410101, 0.444955, 0.364036, 0.499714, 0.335507, 0.530123, 0.336045, 0.528980, 0.367937, 0.499100, 0.423493, 0.452420, 0.487494, 0.406205, 0.542026, 0.377564, 0.572173, 0.378008, 0.570758, 0.409794, 0.540625, 0.465208, 0.493731, 0.529016, 0.447350, 0.583304, 0.418580, 0.613172, 0.418912, 0.611469, 0.450576, 0.581066, 0.505831, 0.533942, 0.569429, 0.487377, 0.623457, 0.458463, 0.653030, 0.458667, 0.651022, 0.490192, 0.620334, 0.545273, 0.572963, 0.608645, 0.526200, 0.662396, 0.497125, 0.691658, 0.497186, 0.689330, 0.528556, 0.658340, 0.583446, 0.610708, 0.646576, 0.563730, 0.700035, 0.534479, 0.728970, 0.534381, 0.726307, 0.565582, 0.695001, 0.620266, 0.647092, 0.683139, 0.599885, 0.736291, 0.570443, 0.764884, 0.570172, 0.761871, 0.601188, 0.730234, 0.655651, 0.682034, 0.718253, 0.634583, 0.771083, 0.604937, 0.799320, 0.604477, 0.795943, 0.635295, 0.763960, 0.689523, 0.715456, 0.751840, 0.667748, 0.804334, 0.637883, 0.832202, 0.637222, 0.828447, 0.667828, 0.796106, 0.721808, 0.747284, 0.783825, 0.699305, 0.835971, 0.669209, 0.863456, 0.668334, 0.859311, 0.698714, 0.826599, 0.752433, 0.777446, 0.814139, 0.729185, 0.865924, 0.698845, 0.893014, 0.697743, 0.888465, 0.727886, 0.855371, 0.781332, 0.805876, 0.842714, 0.757320, 0.894126, 0.726725, 0.920809, 0.725385, 0.915846, 0.755279, 0.882357, 0.808440, 0.832509, 0.869488, 0.783648, 0.920515, 0.752786, 0.946780, 0.751198, 0.941392, 0.780833, 0.907499, 0.833698, 0.857287, 0.894400, 0.808110, 0.945032, 0.776972, 0.970870, 0.775124, 0.965047, 0.804490, 0.930739, 0.857050, 0.880154, 0.917396, 0.830651,
STOP INPUT SIGNAL

START MAGNITUDES 128:
126.387619, 37.651615, 18.316603, 12.151031, 9.098612, 7.274357, 6.060698, 5.194928, 4.546216, 4.042053, 3.638999, 3.309439, 3.034978, 2.802890, 2.604086, 2.431905, 2.281353, 2.148608, 2.030703, 1.925293, 1.830505, 1.744816, 1.666990, 1.595997, 1.530985, 1.471234, 1.416138, 1.365179, 1.317916, 1.273960, 1.232986, 1.194704, 1.158859, 1.125231, 1.093625, 1.063864, 1.035797, 1.009285, 0.984206, 0.960448, 0.937911, 0.916506, 0.896153, 0.876775, 0.858308, 0.840688, 0.823861, 0.807775, 0.792384, 0.777643, 0.763512, 0.749955, 0.736939, 0.724430, 0.712400, 0.700821, 0.689669, 0.678918, 0.668547, 0.658536, 0.648861, 0.639508, 0.630458, 0.621693, 0.613201, 0.604961, 0.596963, 0.589191, 0.581633, 0.574276, 0.567106, 0.560111, 0.553280, 0.546601, 0.540061, 0.533649, 0.527353, 0.521160, 0.515059, 0.509036, 0.503078, 0.497171, 0.491302, 0.485454, 0.479610, 0.473753, 0.467862, 0.461916, 0.455891, 0.449761, 0.443494, 0.437058, 0.430414, 0.423514, 0.416310, 0.408741, 0.400739, 0.392215, 0.383078, 0.373210, 0.362474, 0.350708, 0.337722, 0.323300, 0.307211, 0.289252, 0.269355, 0.247911, 0.226603, 0.210571, 0.212650, 0.255756, 0.367342, 0.588098, 1.031145, 2.162975, 9.713075, 6.290182, 2.816689, 1.980560, 1.609673, 1.403804, 1.275765, 1.191044, 1.133375, 1.094218, 1.068811, 1.054476,
STOP MAGNITUDES

START REAL 256:
126.387619, -4.458682, -1.445946, -0.903184, -0.714295, -0.627046, -0.579691, -0.551142, -0.532608, -0.519892, -0.510785, -0.504035, -0.498889, -0.494871, -0.491669, -0.489072, -0.486933, -0.485146, -0.483634, -0.482340, -0.481220, -0.480242, -0.479378, -0.478609, -0.477919, -0.477292, -0.476720, -0.476195, -0.475707, -0.475251, -0.474822, -0.474417, -0.474029, -0.473658, -0.473299, -0.472951, -0.472611, -0.472278, -0.471949, -0.471623, -0.471298, -0.470974, -0.470649, -0.470322, -0.469991, -0.469656, -0.469316, -0.468969, -0.468615, -0.468253, -0.467881, -0.467500, -0.467107, -0.466701, -0.466282, -0.465849, -0.465400, -0.464934, -0.464449, -0.463946, -0.463421, -0.462874, -0.462303, -0.461705, -0.461082, -0.460424, -0.459738, -0.459016, -0.458257, -0.457458, -0.456616, -0.455729, -0.454790, -0.453799, -0.452748, -0.451635, -0.450452, -0.449195, -0.447856, -0.446428, -0.444902, -0.443271, -0.441523, -0.439645, -0.437626, -0.435450, -0.433100, -0.430555, -0.427793, -0.424789, -0.421512, -0.417926, -0.413992, -0.409659, -0.404871, -0.399558, -0.393639, -0.387010, -0.379551, -0.371110, -0.361496, -0.350469, -0.337718, -0.322842, -0.305304, -0.284378, -0.259052, -0.227879, -0.188715, -0.138242, -0.071047, 0.022339, 0.160094, 0.382077, 0.795823, 1.825750, 8.641259, -5.787557, -2.651747, -1.895364, -1.559155, -1.372196, -1.255743, -1.178599, -1.126042, -1.090333, -1.067153, -1.054071, -1.049835, -1.054072, -1.067152, -1.090333, -1.126042, -1.178599, -1.255743, -1.372196, -1.559155, -1.895364, -2.651747, -5.787557, 8.641259, 1.825750, 0.795822, 0.382076, 0.160094, 0.022339, -0.071047, -0.138242, -0.188714, -0.227879, -0.259052, -0.284378, -0.305304, -0.322843, -0.337719, -0.350469, -0.361496, -0.371110, -0.379551, -0.387010, -0.393639, -0.399557, -0.404871, -0.409659, -0.413992, -0.417926, -0.421511, -0.424789, -0.427793, -0.430555, -0.433099, -0.435450, -0.437626, -0.439645, -0.441523, -0.443271, -0.444902, -0.446428, -0.447856, -0.449195, -0.450452, -0.451634, -0.452749, -0.453799, -0.454790, -0.455729, -0.456617, -0.457458, -0.458257, -0.459015, -0.459737, -0.460425, -0.461082, -0.461706, -0.462303, -0.462874, -0.463421, -0.463946, -0.464449, -0.464934, -0.465400, -0.465849, -0.466282, -0.466701, -0.467106, -0.467500, -0.467881, -0.468253, -0.468615, -0.468968, -0.469315, -0.469656, -0.469991, -0.470321, -0.470649, -0.470975, -0.471298, -0.471623, -0.471948, -0.472278, -0.472611, -0.472951, -0.473299, -0.473658, -0.474029, -0.474417, -0.474822, -0.475251, -0.475707, -0.476195, -0.476721, -0.477292, -0.477919, -0.478609, -0.479378, -0.480242, -0.481220, -0.482340, -0.483634, -0.485146, -0.486933, -0.489073, -0.491669, -0.494870, -0.498889, -0.504035, -0.510785, -0.519892, -0.532608, -0.551142, -0.579690, -0.627046, -0.714295, -0.903184, -1.445946, -4.458682,
STOP REAL

START IMAG 256:
0.000000, 37.386684, 18.259441, 12.117417, 9.070530, 7.247281, 6.032911, 5.165609, 4.514910, 4.008479, 3.602973, 3.270831, 2.993694, 2.758858, 2.557250, 2.382220, 2.228781, 2.093120, 1.972271, 1.863894, 1.766118, 1.677424, 1.596575, 1.522544, 1.454479, 1.391662, 1.333486, 1.279435, 1.229067, 1.181995, 1.137892, 1.096469, 1.057473, 1.020683, 0.985902, 0.952956, 0.921691, 0.891970, 0.863670, 0.836679, 0.810898, 0.786236, 0.762614, 0.739954, 0.718193, 0.697266, 0.677119, 0.657700, 0.638961, 0.620860, 0.603356, 0.586410, 0.569991, 0.554066, 0.538605, 0.523579, 0.508965, 0.494738, 0.480876, 0.467358, 0.454161, 0.441269, 0.428664, 0.416331, 0.404251, 0.392413, 0.380796, 0.369393, 0.358187, 0.347166, 0.336319, 0.325632, 0.315094, 0.304695, 0.294422, 0.284266, 0.274215, 0.264257, 0.254383, 0.244581, 0.234839, 0.225145, 0.215489, 0.205858, 0.196237, 0.186614, 0.176974, 0.167301, 0.157576, 0.147781, 0.137896, 0.127895, 0.117754, 0.107442, 0.096922, 0.086158, 0.075095, 0.063687, 0.051861, 0.039534, 0.026609, 0.012959, -0.001575, -0.017196, -0.034174, -0.052871, -0.073786, -0.097628, -0.125443, -0.158838, -0.200430, -0.254779, -0.330620, -0.447075, -0.655689, -1.159783, -4.435365, 2.463853, 0.949723, 0.574643, 0.400101, 0.296218, 0.225134, 0.171728, 0.128724, 0.092130, 0.059510, 0.029217, 0.000000, -0.029217, -0.059510, -0.092130, -0.128724, -0.171728, -0.225135, -0.296218, -0.400101, -0.574643, -0.949723, -2.463852, 4.435365, 1.159783, 0.655689, 0.447075, 0.330620, 0.254779, 0.200430, 0.158838, 0.125442, 0.097628, 0.073786, 0.052871, 0.034174, 0.017195, 0.001575, -0.012960, -0.026609, -0.039534, -0.051860, -0.063686, -0.075095, -0.086158, -0.096923, -0.107441, -0.117755, -0.127896, -0.137896, -0.147782, -0.157576, -0.167300, -0.176974, -0.186614, -0.196237, -0.205857, -0.215489, -0.225145, -0.234839, -0.244580, -0.254383, -0.264257, -0.274215, -0.284266, -0.294423, -0.304695, -0.315094, -0.325632, -0.336319, -0.347166, -0.358188, -0.369393, -0.380796, -0.392413, -0.404251, -0.416331, -0.428665, -0.441269, -0.454160, -0.467357, -0.480876, -0.494739, -0.508966, -0.523580, -0.538605, -0.554066, -0.569991, -0.586411, -0.603356, -0.620860, -0.638961, -0.657700, -0.677119, -0.697266, -0.718193, -0.739954, -0.762614, -0.786236, -0.810898, -0.836679, -0.863670, -0.891970, -0.921691, -0.952956, -0.985903, -1.020684, -1.057473, -1.096471, -1.137893, -1.181995, -1.229067, -1.279435, -1.333486, -1.391661, -1.454479, -1.522544, -1.596575, -1.677424, -1.766118, -1.863895, -1.972271, -2.093120, -2.228781, -2.382221, -2.557250, -2.758858, -2.993694, -3.270831, -3.602973, -4.008479, -4.514910, -5.165609, -6.032911, -7.247281, -9.070530, -12.117415, -18.259441, -37.386684,
STOP IMAG

START TEST, IT WILL TAKE 10000 MS...
STOP TEST! DONE 15657 ITERATIONS AND WITH 256 FFT POINTS GOT 1565 Hz, T = 638 US.

Na początku podany jest sygnał, który skopiowałem z notatnika. Później wynik jako moduły i biorące udział wartości rzeczywiste i urojone. Na koniec test szybkości - 1565 Hz bije na głowe moje cudowne biblioteki ArduinoFFT dla ESP32. Moduły kopiuję do notatnika i generuję analizę porównawczą. Ale to nie koniec. Testuję np 1024 punkty i też świetne wyniki:

samples.thumb.png.f51b4a7ce2f2bb75ee175b6bf58e2bd7.pngtime_base_comparison.thumb.png.bb312d6a03e6d0312422b3f846b42769.png

magnitudes_comparison.thumb.png.c806b2ae07cd89de9efe5da6b171d992.pngtime_base_comparison_zoom.thumb.png.e4fd4b80a9c552de3e1b33e00fc0e685.png

Benchmark dał wynik:

START TEST, IT WILL TAKE 10000 MS...
STOP TEST! DONE 3385 ITERATIONS AND WITH 1024 FFT POINTS GOT 338 Hz, T = 2954 US.

Więcej ale to nie problem. Myślę że dla 2048 byłoby idealnie ale... jest problem. Dla 512 i 2046 i prawdopodobnie inych ze skokiem co 4x jest problem i funkcja arm_cmplx_mag_f32 zwraca błąd w czasie działania. Przeszukałem Googla i są podobne przypadki opisane dość mętnie. Funkcje mają dopisek deprecated więc możliwe że trzeba to inaczej napisać. Przejrzę jeszcze dokumentację i sprawdzę czy da się to naprawić.

Funkcja testująca:

void benchmark(){
//	https://www.keil.com/pack/doc/CMSIS/DSP/html/group__ComplexFFT.html
	arm_cfft_radix4_instance_f32 S;	/* ARM CFFT module */
	float32_t maxValue;				/* Max FFT value is stored here */
	uint32_t maxIndex;				/* Index in Output array where max value is */
	int i = 0;

	for (i = 0; i < SAMPLES; i+=2) {
		/* Real part, make offset by ADC / 2 */
		Input[i] = (float32_t)(test_signal[i/2]);
	}

	for (i = 1; i < SAMPLES; i+=2) {
		/* Imaginary part */
		Input[i] = 0;
	}

	/* Initialize the CFFT/CIFFT module, intFlag = 0, doBitReverse = 1 */
	arm_cfft_radix4_init_f32(&S, FFT_SIZE, 0, 1);

	/* Process the data through the CFFT/CIFFT module */
	arm_cfft_radix4_f32(&S, Input);

	/* Process the data through the Complex Magniture Module for calculating the magnitude at each bin */
	arm_cmplx_mag_f32(Input, Output, FFT_SIZE);

	/* Calculates maxValue and returns corresponding value */
	arm_max_f32(Output, FFT_SIZE, &maxValue, &maxIndex);

	printf("START INPUT SIGNAL %d:\n", TEST_SAMPLES_COUNT);
	for (i = 0; i < TEST_SAMPLES_COUNT; i++) {
		printf("%f, ",  test_signal[i]);
	}
	printf("\n");
	printf("STOP INPUT SIGNAL\n\n");


	printf("START MAGNITUDES %d:\n", FFT_SIZE / 2);
	for (i = 0; i < FFT_SIZE / 2; i++) {
		printf("%f, ",  Output[i]);
	}
	printf("\n");
	printf("STOP MAGNITUDES\n\n");


	printf("START REAL %d:\n", SAMPLES / 2);
	for (i = 0; i < SAMPLES; i+=2) {
		printf("%f, ",  Input[i]);
	}
	printf("\n");
	printf("STOP REAL\n\n");


	printf("START IMAG %d:\n", SAMPLES / 2);
	for (i = 1; i < SAMPLES; i+=2) {
		printf("%f, ",  Input[i]);
	}
	printf("\n");
	printf("STOP IMAG\n\n");


	printf("START TEST, IT WILL TAKE %d MS...\n", INTERVAL);
	uint32_t start_millis = HAL_GetTick();
	float delta_millis = 0;
	int counter = 0;

	while(HAL_GetTick() - start_millis < INTERVAL) {
		/* Process the data through the CFFT/CIFFT module */
		arm_cfft_radix4_f32(&S, Input);

		/* Process the data through the Complex Magniture Module for calculating the magnitude at each bin */
		arm_cmplx_mag_f32(Input, Output, FFT_SIZE);

		/* Calculates maxValue and returns corresponding value */
		arm_max_f32(Output, FFT_SIZE, &maxValue, &maxIndex);
		++counter;
	}

	delta_millis = HAL_GetTick() - start_millis;
	printf("STOP TEST! DONE %d ITERATIONS AND WITH %d FFT POINTS GOT %d Hz, T = %d US.\n", counter, FFT_SIZE, (int)(counter*1000.0/delta_millis), (int)(delta_millis*1000.0/counter));

}

Istotnym krokiem jest dodanie odpowiednich bibliotek CMSIS DSP do projektu:https://community.st.com/s/article/configuring-dsp-libraries-on-stm32cubeide

ASD_V2_STM32_FFT_sim_1024_samples.zip notatnik z wklejonymi wynikami dla 1024 punktów.

Edytowano przez Gieneq
  • Lubię! 1
Link do komentarza
Share on other sites

Dnia 18.05.2022 o 11:54, Gieneq napisał:

Dla 512 i 2046 i prawdopodobnie inych ze skokiem co 4x jest problem i funkcja arm_cmplx_mag_f32 zwraca błąd w czasie działania.

Problem było używanie przestarzałych funkcji. Oczywiście nie załatwiło to sprawy, bo pojawił się inny problem - FFT było jakby przeskalowane w osi częstotliwości, ale w końcu zauważyłem że źle liczyłem próbki - w bibliotece na wejściu trzeba podać tablicę długości 2x większej od sygnału, w której na zmianę jest pomiar i 0 jako część urojona pomiaru. W wyniku otrzymuję FFT z którego trzeba uciąć połowę wyników - coś co np. funkcji scipy robi sama. Czyli wynikowa długość jest 4x mniejsza a nie 2x jak to jest zazwyczaj.

Ostatecznie odpaliłem kod na płytce nucleoSTM32F4 i działa rewelacyjnie 🙂 512 punktów FFT w 97 us!

START TEST, IT WILL TAKE 10000 MS...
STOP TEST! DONE 102170 ITERATIONS AND WITH 512 FFT POINTS GOT 10217 Hz, T = 97 US.

image.thumb.png.18011c441bfc371382ed908068b52cb1.pngimage.thumb.png.45459614f9ea4315cabd69d40a07f0f9.pngimage.thumb.png.f664ca18800cc307200ab56092e0b5b5.png

i testuję dalej, max mogę dać 212 próbek. Już 512 jest wystarczającą liczbą - i tak zawężę je do 19 zakresów, ale tak duża liczba przyda się szczególnie do usypania pierwszych 3 pasm których indeksy są problematyczne. Szczególnie drugi zakres dla 256 próbek przy niektórych ustawieniach wykładnika nie ma żadnego przyporządkowania przez zaokrąglanie.

 

  • Lubię! 1
Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.