|
|
  |
как это сделано: FFT4096, 100-6500Hz, freq.resolution 0.001Hz, как достигнуто такое разрешение по частоте? |
|
|
|
Oct 23 2011, 18:50
|
Знающий
   
Группа: Свой
Сообщений: 888
Регистрация: 25-09-08
Из: Питер
Пользователь №: 40 458

|
Цитата(ys05 @ Oct 22 2011, 11:04)  Интересно, спасибо. А еще, мне всегда казалось, что струна выдает не чистую синусоиду, а все-таки с гармониками, как минимум с четными, то есть у струны отдельно есть колебания ее половины, четверти... Ессно гармоники есть, но при определении частоты по фурье они не мешают. А вот близкие частоты мод возбуждения - мешают сильно, поскольку сбивают форму распределения (оно перестает быть гауссовским) и снижают точность определения частоты. Т.е. если есть моды с частотами 1 кГц и 1.001 кГц, то погрешность определения частоты может достигать 1 Гц. Даже формально в этом случае непонятно, что называть резонансной частотой датчика. А подобное наблюдалось - неправильное крепление струны приводит к появлению сильно разнесенных по частоте мод. Спасает только селективное возбуждение только одной из них - а это уже не ударное возбуждение, а долгая (более 1 сек) накачка соответствующей частотой.
|
|
|
|
|
Nov 12 2011, 10:31
|
Местный
  
Группа: Участник
Сообщений: 200
Регистрация: 30-10-10
Пользователь №: 60 531

|
Если кому ещё интересна эта тема, вот хороший материальчик: http://stackoverflow.com/questions/4633203...-between-framesМетод уточнения частоты с использованием данных о фазе (нужно брать 2 фурье, лучше с нахлёстом): Код const double freqPerBin = SAMPLE_RATE / FFT_N; const double phaseStep = 2.0 * M_PI * FFT_STEP / FFT_N;
// process phase difference double delta = phase - m_fftLastPhase[k]; m_fftLastPhase[k] = phase; delta -= k * phaseStep; // subtract expected phase difference delta = remainder(delta, 2.0 * M_PI); // map delta phase into +/- M_PI interval delta /= phaseStep; // calculate diff from bin center frequency double freq = (k + delta) * freqPerBin; // calculate the true frequency лучше будет работать на искусственных линейно изменяющихся сигналах, но и для реальных есть смысл.
|
|
|
|
|
Nov 13 2011, 06:51
|

Эксперт
    
Группа: Свой
Сообщений: 1 467
Регистрация: 25-06-04
Пользователь №: 183

|
QUOTE (tmtlib @ Nov 12 2011, 13:31)  Если кому ещё интересна эта тема, вот хороший материальчик: http://stackoverflow.com/questions/4633203...-between-framesМетод уточнения частоты с использованием данных о фазе (нужно брать 2 фурье, лучше с нахлёстом): CODE const double freqPerBin = SAMPLE_RATE / FFT_N; const double phaseStep = 2.0 * M_PI * FFT_STEP / FFT_N;
// process phase difference double delta = phase - m_fftLastPhase[k]; m_fftLastPhase[k] = phase; delta -= k * phaseStep; // subtract expected phase difference delta = remainder(delta, 2.0 * M_PI); // map delta phase into +/- M_PI interval delta /= phaseStep; // calculate diff from bin center frequency double freq = (k + delta) * freqPerBin; // calculate the true frequency лучше будет работать на искусственных линейно изменяющихся сигналах, но и для реальных есть смысл. Хороший алгоритм по типу штангенциркуля. Только Вы забыли сказать, что такое k. Из-за этого, если не читать матерьяльчик, то непонятно, что здесь написано. Здесь k - это номер бина в котором максимум энергии. В матерьяльчике автор показывает, что правильную частоту можно получить не только по этому "максимальному" бину но и по FFT_N/FFT_STEP соседних. Поэтому не возникает проблем с частотами на границе между бинами при перекрытии блоков FFT. Без нахлёста с такими пограничными частотами алгоритм работать не будет, шумы не дадут. Систематическая ошибка у алгоритма отсутствует. Интересно посмотреть как алгоритм ведёт себя по отношению к шуму - судя по всему выйдет на точность оценки максимального правдоподобия CRLB, особенно если ещё и научиться делать взвешенную оценку по нескольким значениям возле максимума (остальные FFT_N/FFT_STEP оценок из-за малой энергии бинов реально утонут под шумом)
|
|
|
|
|
Nov 13 2011, 10:24
|
Местный
  
Группа: Участник
Сообщений: 350
Регистрация: 16-11-08
Пользователь №: 41 680

|
Цитата(tmtlib @ Nov 12 2011, 14:31)  Если кому ещё интересна эта тема, вот хороший материальчик: http://stackoverflow.com/questions/4633203...-between-framesМетод уточнения частоты с использованием данных о фазе (нужно брать 2 фурье, лучше с нахлёстом): Код const double freqPerBin = SAMPLE_RATE / FFT_N; const double phaseStep = 2.0 * M_PI * FFT_STEP / FFT_N;
// process phase difference double delta = phase - m_fftLastPhase[k]; m_fftLastPhase[k] = phase; delta -= k * phaseStep; // subtract expected phase difference delta = remainder(delta, 2.0 * M_PI); // map delta phase into +/- M_PI interval delta /= phaseStep; // calculate diff from bin center frequency double freq = (k + delta) * freqPerBin; // calculate the true frequency лучше будет работать на искусственных линейно изменяющихся сигналах, но и для реальных есть смысл. А можно этот код расписать иначе? Так как в матлабе не силён. Если можно то блок схемой или просто словами.
|
|
|
|
|
Nov 13 2011, 12:50
|
Местный
  
Группа: Участник
Сообщений: 200
Регистрация: 30-10-10
Пользователь №: 60 531

|
Цитата(ivan219 @ Nov 13 2011, 13:24)  А можно этот код расписать иначе? Так как в матлабе не силён. Если можно то блок схемой или просто словами. Я планирую выложить примерчик с интересными методами здесь. Но думаю это будет не скоро. А пока попробую на словах, например, для фурье на 1024 отсчёта: 1) Берём FFT и получаем массивы амплитуд мнимой и действительной части по 512 элементов в каждом Im[0..511], Re[0..511]. 2) Для каждого из 512 элемента считаем фазу. Если по простому, то фаза[i]:=ArcTan(Im[i] / Re[i]); Можно сделать получше, расписав разные случаи (если Re[i]=0 и т.д.) 3) храним фазы за предыдущий проход FFT и за текущий. m_fftLastPhase[i] - это старая фаза, а phase - это на самом деле phase[i], т.е. фаза[i] от текущего FFT. Заметил, что метод лучше работает если применить сглаживающее окно. Забыл написать: например, константа SAMPLE_RATE=44100, FFT_N =1024, FFT_STEP = 100 (количество точек, на которые смещаем исходные данные. 100 намного меньше 1024, поэтому результат лучше)
Сообщение отредактировал tmtlib - Nov 13 2011, 14:06
|
|
|
|
|
Nov 13 2011, 20:33
|
Местный
  
Группа: Участник
Сообщений: 350
Регистрация: 16-11-08
Пользователь №: 41 680

|
И всё таки не много не понятно. Что делает эта функция? Код delta = remainder(delta, 2.0 * M_PI); // map delta phase into +/- M_PI interval
|
|
|
|
|
Nov 14 2011, 03:19
|
Местный
  
Группа: Участник
Сообщений: 200
Регистрация: 30-10-10
Пользователь №: 60 531

|
Цитата(ivan219 @ Nov 14 2011, 00:33)  И всё таки не много не понятно. Что делает эта функция? Код delta = remainder(delta, 2.0 * M_PI); // map delta phase into +/- M_PI interval Фазу приводят к диапазону -3.14...+3.14, пример в градусах: это что-то наподобие того, что 350 градусов привратится в -10 и т.д. Т.е. вектор (Im,Re) всегда в правом полукруге от -90 до 90 градусов.
|
|
|
|
|
Nov 14 2011, 07:35
|

Эксперт
    
Группа: Свой
Сообщений: 1 467
Регистрация: 25-06-04
Пользователь №: 183

|
QUOTE (tmtlib @ Nov 14 2011, 06:19)  Фазу приводят к диапазону -3.14...+3.14, пример в градусах: это что-то наподобие того, что 350 градусов привратится в -10 и т.д. Т.е. вектор (Im,Re) всегда в правом полукруге от -90 до 90 градусов. Именно на этом этапе алгоритм перестанет работать, если нет перекрытия. Как показывает автор "матерьяльчика" в последней табличке (Pass 4) для отсутствия перекрытия. http://www.dspdimension.com/admin/pitch-sh...g-using-the-ft/Для частот на границе бинов получаем 2 значения частоты для примерно одинаковых величин спектральной мощности, и только одно из них правильное. Поскольку максимум двух равных величин при реальных вычислениях определяется шумом, то в этом случае алгоритм будет выбирать правильное значение с вероятностью 0.5. Впрочем можно попытаться определить частоту другим методом по каждому из блоков отдельно и потом взять то значение которое ближе к этой оценке, но это уже как бы гибрид QUOTE (tmtlib @ Nov 13 2011, 15:50)  2) Для каждого из 512 элемента считаем фазу. Если по простому, то фаза[i]:=ArcTan(Im[i] / Re[i]); Можно сделать получше, расписав разные случаи (если Re[i]=0 и т.д.) 3) храним фазы за предыдущий проход FFT и за текущий. m_fftLastPhase[i] - это старая фаза, а phase - это на самом деле phase[i], т.е. фаза[i] от текущего FFT. Заметил, что метод лучше работает если применить сглаживающее окно. Для определения частоты вам не нужны все FFT_N значений фазы, поскольку только FFT_N/FFT_STEP значений фазы около максимума спектральной мощности правильные, а остальные искажены врэпингом на 2*pi (Pass 5). Более того в реальной ситуации присутствуют шумы и большинство из этих FFT_N/FFT_STEP правильных оценок (если их много) будут реально сильно зашумлены из-за очень быстрого падения уровня сигнала в бине при отклонении от центрального. Мы помним, что отклик бинов на синусоиду падает в соответствии с функцией спектрального окна, и в лучшем случае он будет спадать как синк или быстрее. В реальной ситуации только 2-4 центральных бина будут давать значимую оценку частоты, причем наименее искажены шумом будут только одна (если частота близко к центру бина) или две (если частота на границе бинов) оценки для центральных бинов (где максимум спектральной мощности). Остальные "утонут" под шумом Все 512 значений могут представлять интерес только для визуализации "сонограм", поскольку они, в большинстве, шумоподобны. Поэтому приведеный алгоритм "недоделаный" - мало того что он неэффективен, но он не содержит последнего шага, поскольку он генерирует FFT_N значений частоты из которых в лучшем случае (отсутствие шума) только FFT_N/FFT_STEP правильны и не сказано, как правильные выбрать из массива оценок, большинство из которых неправильны, см. таблички у автора http://www.dspdimension.com/admin/pitch-sh...g-using-the-ft/По смыслу понятно, что выбирать нужно где-то возле максимума спектральной мощности С учетом сказанного простейший алгоритм будет выглядеть так: 1) Берём FFT и получаем массивы амплитуд мнимой и действительной части по 512 элементов в каждом Im[0..511], Re[0..511]. 2) Вычисляем энергию для каждого k E[k]=Re*Re+Im*Im 3) Находим максимум E[k] - пусть будет E() для kmax. Здесь вообще-то нужно проверять что kmax не прыгает. Если изменение kmax от фрейма к фрейму больше 1 по модулю - то это не синусоида, выход по ошибке 4) Для элементов kmax, kmax-1, kmax+1 считаем фазу. фаза[]:=ATAN2(Im[], Re[]); другие элементы на самом деле не нужны, в них отсутствует полезная информация 3) храним посчитаные фазы за предыдущий проход FFT и за текущий. m_fftLastPhase[i] - это старая фаза, а phase - это на самом деле phase[kmax], т.е. фаза[kmax] от текущего FFT. Поскольку kmax гарантировано не меняется больше чем на 1, то в любом случае значение фазы для kmax посчитаны и для предыдущего фрейма и есть в массиве Если перекрытие FFT_N/FFT_STEP >2 то оценку можно немного улучшить если использовать не одно значение максимума, а два первых максимума и построить взвешенную оценку для частоты по этим двум оценкам. Если главный максимальный бин k0=kmax, а следующий по энергии k1=arg max(E(kmax-1), E(kmax+1)), то можно построить оценку типа (f(k1)*E(k1)+f(k0)*E(k0))/(E(k0)+E(k1)) с большим иммунитетом к шуму, главным образом для частот на границе бинов (поскольку в этом случае будет две равноценных оценки) А так да, идея алгоритма на вскидку смотрится очень хорошо
|
|
|
|
|
Nov 15 2011, 06:16
|
Знающий
   
Группа: Свой
Сообщений: 521
Регистрация: 12-05-06
Пользователь №: 17 030

|
Цитата(fontp @ Nov 14 2011, 10:35)  ... (f(k1)*E(k1)+f(k0)*E(k0))/(E(k0)+E(k1)) с большим иммунитетом к шуму, главным образом для частот на границе бинов (поскольку в этом случае будет две равноценных оценки) f(k1) это измеренная частота для бина k1 ? А что если приращение фазы измерять по нескольким бинам в окрестности максимума? Взвешивание получится автоматически. Код delta = angle( X_1(kmax-n:kmax+n)' * X(kmax-n:kmax+n) ) X_1 - предидущий выход FFT (вектор столбец), X - текущий выход FFT, kmax - индекс бина с максимальной энергией, n - число 0...3
--------------------
ну не художники мы...
|
|
|
|
|
Nov 15 2011, 06:59
|

Эксперт
    
Группа: Свой
Сообщений: 1 467
Регистрация: 25-06-04
Пользователь №: 183

|
QUOTE (alex_os @ Nov 15 2011, 09:16)  f(k1) это измеренная частота для бина k1 ? А что если приращение фазы измерять по нескольким бинам в окрестности максимума? Взвешивание получится автоматически. CODE delta = angle( X_1(kmax-n:kmax+n)' * X(kmax-n:kmax+n) ) X_1 - предидущий выход FFT (вектор столбец), X - текущий выход FFT, kmax - индекс бина с максимальной энергией, n - число 0...3 Можно бы и по всем. только не все бины одинаково полезны. Поэтому это будет не оптимально. Усреднять надо в соответствии с уровнем сигнала каждого бина. Вычисление фазы в бинах с низким уровнем сигнала по отношению к шуму бесмысленны - это уже фаза компоненты шума а не сигнала. А уровень сигнала убывает при отклонении от центральных бинов достаточно быстро (быстрее чем 1/n), в то время как шум остается постоянным. Поэтому при низком уровне сигнал/шум лучше усреднять по 2-3-м, причем с учетом энергии (можно даже расписать точные формулы, выписывая плотность вероятности ошибки фазы в бине как функцию отношения сигнал/шум - это можно найти в учебниках по спектральному анализу или статрадиофизике - и максимизмизируя произведение вероятностей). При очень высоком уровне сигнал/шум, хотя бы 20дб, действительно усреднять вроде можно по всем четырём (FFT_N/FFT_STEP в общем случае перекрытия, но тоже с учетом энергии бина), поскольку ошибки измерения фазы статистически независимы, но различны для разных бинов, в зависимости от энергии да, f(k) - измеренная частота для бина k. Я не максимизировал функцию вероятности, а просто написал на вскидку формулу, которая будет вести себя оптимально для частот и посередине бина (f(k0)) и на границе бинов (f(k0)+f(k1))/2, если этого не сделать, то точность упадёт на границе ЗЫ. Вообще-то вычисление фазы через квадратуры всегда усиливает шум и помехи. Поэтому при вычислении частоты через фазу не стоит пренебрегать использованием спектральных окон, как в примере - чтобы подавить хвосты от возможных синусовых помех. Они и всегда мешают, а этому методу будут особенно
|
|
|
|
|
Nov 15 2011, 07:40
|
Знающий
   
Группа: Свой
Сообщений: 521
Регистрация: 12-05-06
Пользователь №: 17 030

|
Цитата(fontp @ Nov 15 2011, 09:59)  Поэтому при низком уровне сигнал/шум лучше усреднять по 2-3-м, причем с учетом энергии (можно даже расписать точные формулы, выписывая плотность вероятности ошибки фазы в бине как функцию отношения сигнал/шум - это можно найти в учебниках по спектральному анализу или статрадиофизике - и максимизмизируя произведение вероятностей). Так предлагаемое скалярное произведение и учитывает энергию бинов (может быть даже оптимальным образом  ). Бины с большей энергией вносят больший вклад в результирующую фазу, чем бины с меньшей энергией.
--------------------
ну не художники мы...
|
|
|
|
|
Nov 15 2011, 13:37
|
Знающий
   
Группа: Свой
Сообщений: 521
Регистрация: 12-05-06
Пользователь №: 17 030

|
Цитата(fontp @ Nov 15 2011, 10:43)  Виноват. Про angle (в Матлабе?) не знал, думал среднее арифметическое фазы. Сорри, не написал что матлаб. angle -аргумент комплексного числа.
--------------------
ну не художники мы...
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|