|
FFT на STM32F407 |
|
|
|
Apr 25 2012, 08:34
|

Местный
  
Группа: Свой
Сообщений: 381
Регистрация: 5-07-05
Из: Уфа
Пользователь №: 6 544

|
Порассуждаем. T - общее время оцифровки. В моем случае 512 отсчетов, между отсчетами 5 мкс, итого Т = (512 - 1) * 5 мкс = 2,555 мс. f = 1/T = 391 Гц. То есть это частота первой гармоники f1. Частота второй гармоники f2 = 2* f1 = 782 Гц. И так далее. Теперь смотрим в массив Output[], который представляет собой спектр амплитуд. Он состоит из 512 элементов. Чтобы вычислить амплитуду первой гармоники Am1 нужно выполнить следующее: Код am1 = 0; for(j = 0; j < 512; j++) am1 = am1 + Output[j] * sin(3.14 * j) / (512 - 1));
Am1 = (2 * am1 / (512 - 1)); Для второй гармоники: Код am2 = 0; for(j = 0; j < 512; j++) am2 = am2 + Output[j] * sin(2 * 3.14 * j) / (512 - 1));
Am2 = (2 * am2 / (512 - 1)); Обобщенно для первых пяти гармоник: Код float32_t Am[5];
for(i = 0; i < 5; i++) { am = 0; for(j = 0; j < 512; j++) am = am + Output[j] * sin(i * 3.14 * j) / (512 - 1));
Am[i] = (2 * am / (512 - 1)); } Это верно?
|
|
|
|
|
Apr 26 2012, 04:42
|

Местный
  
Группа: Свой
Сообщений: 381
Регистрация: 5-07-05
Из: Уфа
Пользователь №: 6 544

|
Понадобилось провести линейную интерполяцию над данными, полученными из АЦП. В библиотеке есть пример. Пытаюсь понять как же его использовать. В начале идет инициализация структуры: Код arm_linear_interp_instance_f32 S = {188495, -3.141592653589793238, 0.00005f, &arm_linear_interep_table[0]}; Структура определена как: Код typedef struct { uint32_t nValues; float32_t x1; float32_t xSpacing; float32_t *pYData; /**< pointer to the table of Y values */ } arm_linear_interp_instance_f32; nValues - размер массива данных, *pYData - адрес массива данных, xSpacing - это видимо шаг по оси Х, в случае массива - шаг индекса массива, x1 - вот это не понятно что такое. Вопрос в том, как правильно инициализировать эту структуру, иначе дальнейшие действия не имеют смысла?
|
|
|
|
|
Jun 14 2012, 04:51
|

Местный
  
Группа: Свой
Сообщений: 381
Регистрация: 5-07-05
Из: Уфа
Пользователь №: 6 544

|
Вновь возвращаюсь с вопросом. Необходимо провести FFT над данными из АЦП. Часть кода такова: Код int16_t analysis_arr[512]; //данные с АЦП int16_t spec_ana_arr[1024]; int16_t amplitude_arr[512];
arm_status status; arm_rfft_instance_q15 S; arm_cfft_radix4_instance_q15 S_CFFT; status = ARM_MATH_SUCCESS;
status = arm_rfft_init_q15(&S, &S_CFFT, 512, 0, 1);
arm_rfft_q15(&S, analysis_arr, spec_ana_arr);
arm_cmplx_mag_q15(spec_ana_arr, amplitude_arr, 512); В функции arm_cmplx_mag_q15 выполняется: Код /* C[0] = sqrt(A[0] * A[0] + A[1] * A[1]) */ real = *pSrc++; imag = *pSrc++; acc0 = __SMUAD(real, real); acc1 = __SMUAD(imag, imag); /* store the result in 2.14 format in the destination buffer. */ arm_sqrt_q15((q15_t) (((q63_t) acc0 + acc1) >> 17), pDst++); Вопрос в том, для чего нужно сдвигать сумму квадратов аж на 17 разрядов? Еще вопросы. После выполнения arm_rfft_q15 исходный массив analysis_arr меняется. Почему? Выходной формат функции arm_rfft_q15 9.7, что это означает?
|
|
|
|
|
Jul 4 2012, 06:56
|
Участник

Группа: Участник
Сообщений: 15
Регистрация: 29-03-11
Из: Санкт-Петербург
Пользователь №: 63 968

|
Цитата(011119xx @ Jun 14 2012, 08:51)  Вновь возвращаюсь с вопросом. Необходимо провести FFT над данными из АЦП. Часть кода такова:
real = *pSrc++; imag = *pSrc++; acc0 = __SMUAD(real, real); acc1 = __SMUAD(imag, imag); /* store the result in 2.14 format in the destination buffer. */ arm_sqrt_q15((q15_t) (((q63_t) acc0 + acc1) >> 17), pDst++);[/code] Вопрос в том, для чего нужно сдвигать сумму квадратов аж на 17 разрядов?
Еще вопросы. После выполнения arm_rfft_q15 исходный массив analysis_arr меняется. Почему? Выходной формат функции arm_rfft_q15 9.7, что это означает? сдвиг нужен для приведения форматов чисел. 9.7 означает, что 9 бит отводится под целую часть числа, а 7 бит под дробную. посмотрите описание функций, там должны быть входные и выходные форматы данных.
|
|
|
|
|
Mar 2 2013, 09:46
|
Участник

Группа: Участник
Сообщений: 61
Регистрация: 13-02-12
Пользователь №: 70 242

|
Цитата(scifi @ Apr 17 2012, 10:00)  Видимо да, правильно. Вот реальный работающий пример: Код arm_rfft_instance_f32 rffti; arm_cfft_radix4_instance_f32 cffti; arm_rfft_init_f32(&rffti, &cffti, 2048, 0, 1); arm_rfft_f32(&rffti, f, g); Запускаю так: Код arm_q15_to_float(testInput_q15_512, f, 512); arm_rfft_instance_f32 rffti; arm_cfft_radix4_instance_f32 cffti; arm_rfft_init_f32(&rffti, &cffti, 2048, 0, 1); arm_rfft_f32(&rffti, f, g); arm_cmplx_mag_squared_f32(g, f, 512); То есть делаю FFT для real f32, как привел пример scifi - все великолепно. Вижу хорошую палку на 10 индексе. Тестовые отсчеты сгенерированы в MatLab в формате q15. 512 - отсчетов, 10 периодов синуса, целочисленно укладывающихся в заданное окно. Размах от 0xC000 до 0x3FFF Тоже самое пытаюсь сделать для real q15 Код arm_rfft_instance_q15 rffti; arm_cfft_radix4_instance_q15 cffti; arm_rfft_init_q15( &rffti, &cffti, 512, 0, 1); arm_rfft_q15( &MyS, testInput_q15_512, testOutput); arm_cmplx_mag_q15(testOutput, amplitude_arr, 512); - полный бред на выходе, больше похожий на белый шум. Если задать третью строчку в коде так: arm_rfft_init_q15( &rffti, &cffti, 512, 1, 1); - то есть обратное преобразование вместо прямого, то картина становится лучше. Появляется не очень внятный и размазанный пик на нужном месте http://electronix.ru/forum/style_emoticons...t/smile3046.gif . Тестовые отсчеты сгенерированы в MatLab в формате q15. 512 - отсчетов, 10 периодов синуса, целочисленно укладывающихся в заданное окно. Голова сломана, выходные проходят бездарно! дошел до перекомпиляции последней версии CMSIS DSP. Результат тот же! Направьте на истинный путь !
|
|
|
|
|
Mar 2 2013, 12:54
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(Allregia @ Mar 2 2013, 11:42)  3) безотносительно FIR - как на этом проце максимально быстро преобразовать переменную типа char задом наперед ? (т.е. реверс битов сделать). Можно изобразить на ассемблере, используя инструкцию RBIT. Она меняет местами биты в 32-битном регистре, но очевидно, что после операции самый старший байт регистра будет содержать реверсированный младший. Объявление функции может выглядеть как: uint8_t reverse_8bits(uint8_t value);а код в ассемблерном файле (с учетом соглашения на передачу параметров, когда R0 - есть первый параметр): Код reverse_8bits PROC EXPORT reverse_8bits [WEAK]
RBIT R0, R0 REV R0, R0 BX LR
ENDP P.S. Код на работоспособность сам еще не проверял. P.P.S. Проверил под симулятором: работает.
Сообщение отредактировал KnightIgor - Mar 2 2013, 13:07
|
|
|
|
|
Mar 2 2013, 14:18
|
Местный
  
Группа: Участник
Сообщений: 226
Регистрация: 10-07-09
Пользователь №: 51 126

|
Цитата(Allregia @ Mar 2 2013, 13:42)  реверс битов сделать Код b = __REV(__RBIT(a));
|
|
|
|
|
Mar 3 2013, 18:36
|

Профессионал
    
Группа: Свой
Сообщений: 1 202
Регистрация: 26-08-05
Из: Донецк, ДНР
Пользователь №: 7 980

|
Ламерский вопрос - какую либу подключать - arm_cortexM4lf_math.lib (Little endian and Floating Point Unit on Cortex-M4) или arm_cortexM4bf_math.lib (Big endian and Floating Point Unit on Cortex-M4) ? Никак не врублюсь, какой индеец в этом STM32F407  Или есть у кого нормальный пример, как из выборки АЦП спектр получить? Спасибо.
--------------------
Чтобы возить такого пассажира, необходим лимузин другого класса. (с) Мария Эдуарда
|
|
|
|
|
Mar 4 2013, 07:31
|

Профессионал
    
Группа: Свой
Сообщений: 1 202
Регистрация: 26-08-05
Из: Донецк, ДНР
Пользователь №: 7 980

|
Цитата(_Артём_ @ Mar 3 2013, 22:52)  Little...по умолчанию... Спасибо. Подключил пока arm_cortexM4lf_math.lib, посмотрю, что будет ... По мотивам прочитанного здесь насочинял такое (но ещё не закочил): CODE // выходной спектр FFT uint8_t SpectrumOut [N_WAVE_HALF/2];
// N_WAVE_HALF = 2048 static q15_t t [ N_WAVE_HALF ]; static float32_t f [ N_WAVE_HALF ], g [ N_WAVE_HALF * 2 ];
// Выполнение FFT // pInData - входные данные (выборка FFT) - N_WAVE_HALF void DoFFT ( uint8_t *pInData ) { arm_rfft_instance_f32 rffti; arm_cfft_radix4_instance_f32 cffti; int i; // 1. Подготовка входных данных for ( i = 0; i < N_WAVE_HALF; i ++ ) t [ i ] = pInData [i]; // 1-й арг - int32_t arm_q15_to_float ( t, f, N_WAVE_HALF ); // 2. Инициализация FFT arm_rfft_init_f32 ( &rffti, &cffti, N_WAVE_HALF, 0, 1 ); // 3. FFT arm_rfft_f32 ( &rffti, f, g ); // 4. Спектр arm_cmplx_mag_squared_f32(g, f, 2048); } // DoFFT
Будет ли работать - не знаю  ....
--------------------
Чтобы возить такого пассажира, необходим лимузин другого класса. (с) Мария Эдуарда
|
|
|
|
|
Mar 4 2013, 19:24
|

Профессионал
    
Группа: Свой
Сообщений: 1 202
Регистрация: 26-08-05
Из: Донецк, ДНР
Пользователь №: 7 980

|
Получилось вот такое: CODE bool DoFFT ( uint8_t *pInData ) { arm_rfft_instance_f32 rffti; arm_cfft_radix4_instance_f32 cffti; arm_status stat; int i; // 1. Подготовка входных данных for ( i = 0; i < N_WAVE; i ++ ) t [ i ] = pInData [i]; // 1-й арг - int32_t t -> f arm_q15_to_float ( t, f, N_WAVE ); // 2. Инициализация FFT stat = arm_rfft_init_f32 ( &rffti, &cffti, N_WAVE, 0, 1 ); if ( stat != ARM_MATH_SUCCESS ) return false; // 3. FFT f -> g arm_rfft_f32 ( &rffti, f, g ); // 4. Спектр g -> f arm_cmplx_mag_squared_f32 ( g, f, N_WAVE ); for ( i= 0; i < N_WAVE/2; i ++) { SpectrumOut[i] = (uint8_t) f[i]; } // fof return true; } // DoFFT В результате в массиве f почти все числа меньше 1, соответственно в выходном целочисленном SpectrumOut одни нули Помогите, кто может. Входной массив, поступающий в функцию нормальный. По нему осциллограмму рисую, огна нормальная. Спасибо.
Сообщение отредактировал IgorKossak - Mar 6 2013, 07:27
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
--------------------
Чтобы возить такого пассажира, необходим лимузин другого класса. (с) Мария Эдуарда
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|