Форум программистов, компьютерный форум, киберфорум
Наши страницы
Цифровая обработка сигналов
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 5.00/74: Рейтинг темы: голосов - 74, средняя оценка - 5.00
Ebis
0 / 0 / 0
Регистрация: 03.03.2010
Сообщений: 94
Завершенные тесты: 1
1

Автокорреляционная функция и частота основного тона (ЧОТ)

05.04.2013, 06:54. Просмотров 13477. Ответов 21
Метки нет (Все метки)

Добрый день!

Пытаюсь написать выделитель ЧОТ с приминением АКФ, но когда подаю гармонический сигнал (200Гц), то значение ЧОТ колеблется(хотя должно быть статично 200Гц) и определяется не правильно.

Ниже приведена функция для выделения ЧОТ
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
double TON (short in[208]) //размер массива равен двум максимальным периодам ОТ
{
    int fd = 8000; //Частота дискретизации
    int minOT   = fd * 0.0030f; // минимальный шаг - 3 мс (330 Гц)
    int maxOT   = fd * 0.013f;  // максимальный шаг - 13 мс (77 Гц)
    int deltaOT = fd * 0.0001f; // шаг - 0,1 мс
    if (deltaOT==0) deltaOT=1;
    
        int OT=0;//ЧОТ
    int maxAC=-10000L;
 
    for (int pitch=minOT;pitch<=maxOT;pitch+=deltaOT)
    {
        double max=-10000L,val=0;
        
                for(int j=0;j<=2*maxOT;j++)
        {
            double p=in[j];
            double q=in[j+pitch];
 
            val=p*q;       //Считаем значение автокорреляции
            if(val>max) max=val; //находим максимум при данном значении ОТ
        }
 
        if (max>maxAC)//находим максимум АКФ
        {
            maxAC=max;
            OT=pitch;
        }
    }
    return (double)fd/(OT); //возвращаем ЧОТ
}
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
05.04.2013, 06:54
Ответы с готовыми решениями:

Выделение основного тона
Здравствуйте. Я разрабатываю аплет нахождения основного тона, по ходу дела...

Кепстральный метод оценки периода основного тона речевого сигнала
Всем доброго времени суток) Задача в общем такая: разбить входной сигнал на...

Автокорреляционная функция дискретного сигнала
Помогите, пожалуйста, понять как работает автокорреляционная функция...

Зависимость частоты основного тона струны от её параметров
Найдите зависимость частоты колебаний основного тона струны от её длины...

Автокорреляционная функция
Помогите создать программу на Паскале по этой теме: Сгенерировать случайную...

21
vital792
2002 / 1274 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
05.04.2013, 09:38 2
Цитата Сообщение от Ebis Посмотреть сообщение
определяется не правильно.
странно что вообще работает.
Цитата Сообщение от Ebis Посмотреть сообщение
double q=in[j+pitch];
в этой строке явно выход за границу массива. А по поводу самого метода - надо искать не первый максимум, а второй. Первый должен быть на нуле...

Добавлено через 4 минуты
Цитата Сообщение от vital792 Посмотреть сообщение
надо искать не первый максимум
а, ну да, правильно, первый отсекается. Тогда попробуйте просто во втором цикле
Цитата Сообщение от Ebis Посмотреть сообщение
for(int j=0;j<=2*maxOT;j++)
убрать двойку...
1
Ebis
0 / 0 / 0
Регистрация: 03.03.2010
Сообщений: 94
Завершенные тесты: 1
05.04.2013, 09:58  [ТС] 3
Убрал двойку, стало правильно находить частоту, но иногда вместо 200гц выскакивает значение на 100ГЦ, хаотичным образом.
0
vital792
2002 / 1274 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
05.04.2013, 10:23 4
Цитата Сообщение от Ebis Посмотреть сообщение
выскакивает значение на 100ГЦ, хаотичным образом.
покажите вызов функции и генерацию сигнала. Видимо проблема где то там
1
Ebis
0 / 0 / 0
Регистрация: 03.03.2010
Сообщений: 94
Завершенные тесты: 1
05.04.2013, 11:23  [ТС] 5
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
int main(int argc, char* argv[])
{
    FILE *f,*fton;
    int size;
    short *buf;
 
 
 
 
    if (!argv[1])   {   cout<<"Enter the name of file!"<<endl;      system("pause");        return -1;  }
 
    f=fopen(argv[argc-1],"rb"); //исходный файл с голосом
    if (f==NULL){   cout<<"Open error!"<<endl;      system("pause");        return -1;  }
 
    fseek(f,0,2);
    size=ftell(f)/sizeof(short);//Кол-во отсчетов
 
    fseek(f,0,0);
    buf=(short*)malloc(size*sizeof(short));
    fread(buf,sizeof(short),size,f); //считываем отсчеты
    int bs=(int)(2*fd * 0.013f);
    short in[208];//bs
    int t;
    fton=fopen("Freq.pcm","w");
 
    for(int i=0;i<size/bs;i++)
    {
        for(int j=0;j<=bs;j++)
        {in[j]=buf[i*bs+j];}
 
        t=(int)TON(in);
        fprintf(fton,"%d \n ",t);
    }
    
 
    fclose(f);
    fclose(fton);
    return 0;
}
freq.pcm - значение ЧОТ
ton.pcm - сигнал (200Гц)
0
Вложения
Тип файла: zip Freq.zip (81.4 Кб, 38 просмотров)
Ebis
0 / 0 / 0
Регистрация: 03.03.2010
Сообщений: 94
Завершенные тесты: 1
05.04.2013, 11:35  [ТС] 6
забыл сказать, формат сигнала 8000Гц-частота дискр., 16бит
вот прикрепил, заново созданный сигнал и его ЧОТ.
111.pcm - сигнал
0
Вложения
Тип файла: zip 111.zip (47.0 Кб, 38 просмотров)
vital792
2002 / 1274 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
05.04.2013, 12:07 7
Цитата Сообщение от Ebis Посмотреть сообщение
забыл сказать, формат сигнала 8000Гц-частота дискр., 16бит
да, я догадался по коду) Сигнал посмотрел в звуковом редакторе - ниче не понял, сгенерил новый. Просто тон 200 гц. Придираться к стилю написания кода не буду) ошибки были все также из-за выхода за границы
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <stdio.h>
#include <iostream>
 
using namespace std;
 
int fd = 8000; //Частота дискретизации
 
double TON (const short *in) //размер массива равен двум максимальным периодам ОТ
{
    int minOT   = fd * 0.0030f; // минимальный шаг - 3 мс (330 Гц)
    int maxOT   = fd * 0.013f;  // максимальный шаг - 13 мс (77 Гц)
    int deltaOT = fd * 0.0001f; // шаг - 0,1 мс
    if (deltaOT==0) deltaOT=1;
 
        int OT=0;//ЧОТ
    int maxAC=-10000L;
 
    for (int pitch=minOT;pitch<=maxOT;pitch+=deltaOT)
    {
        double max=-10000L,val=0;
 
                for(int j=0;j<maxOT;j++)
        {
            double p=in[j];
            double q=in[j+pitch];
 
            val=p*q;       //Считаем значение автокорреляции
            if(val>max) max=val; //находим максимум при данном значении ОТ
        }
 
        if (max>maxAC)//находим максимум АКФ
        {
            maxAC=max;
            OT=pitch;
        }
    }
    return (double)fd/(OT); //возвращаем ЧОТ
}
 
int main(int argc, char* argv[])
{
    FILE *f,*fton;
    int size;
    short *buf;
 
//    if (!argv[1])   {   cout<<"Enter the name of file!"<<endl;      system("pause");        return -1;  }
 
    f=fopen("ton200.pcm", "rb"); //исходный файл с голосом
    if (f==NULL)
    {
        cout<<"Open error!"<<endl;
        system("pause");
        return -1;
    }
 
    fseek(f,0,2);
    size=ftell(f)/sizeof(short);//Кол-во отсчетов
 
    fseek(f,0,0);
    buf=(short*)malloc(size*sizeof(short));
    fread(buf,sizeof(short),size,f); //считываем отсчеты
    int bs=(int)(2*fd * 0.013f);
    short in[208];//bs
    int t;
    fton=fopen("Freq.pcm","w");
 
    for(int i=0;i<size/bs;i++)
    {
        for(int j=0;j<bs;j++)
        {in[j]=buf[i*bs+j];}
 
        t=(int)TON(in);
        fprintf(fton,"%d \n ",t);
    }
 
 
    fclose(f);
    fclose(fton);
    return 0;
}
ton.zip
1
vital792
2002 / 1274 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
05.04.2013, 12:09 8
кажется не тот файл прикрепил. В общем ton200.pcm - просто синус 200 гц 8 кгц fs 16 бит
0
vital792
2002 / 1274 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
05.04.2013, 14:17 9
я кажется понял почему у вас перескакивала частота. Оказалось все просто: акф периодической функции тоже периодическая, с тем же периодом. Соответственно ваша задача - найти положения первого максимума акф относительно центрального пика. Он и будет определять частоту сигнала. Но! Вы анализируете временной интервал длительностью 2 периода. По идее акф должна медленно убывать, но в вашем случае уровень пиков акф настолько близок, что происходит перескок между ними и соответственно частота делится на 2(т.к. второй пик относительно первого на таком же расстоянии). Вот как выглядят отсчеты вашей акф:
Автокорреляционная функция и частота основного тона (ЧОТ)

Чтобы этого избежать, возможно следует сократить временное окно по длительности... Попробуйте уменьшить первый цикл отсчетов на 20-30
1
Ebis
0 / 0 / 0
Регистрация: 03.03.2010
Сообщений: 94
Завершенные тесты: 1
05.04.2013, 18:16  [ТС] 10
Вобщем протестировал эту программку на сигналах до 150ГЦ включительно, она все определяет правильно, если частота сигнала больше, то появляются выбросы, и они не всегда кратны 2.
Уменшил цикл и ЧОТ стал определяться не правильно
0
Ebis
0 / 0 / 0
Регистрация: 03.03.2010
Сообщений: 94
Завершенные тесты: 1
06.04.2013, 12:41  [ТС] 11
Сгенерировал в один файл несколько тонов различно частоты начиная от 10ГЦ и до 370Гц, и результат получился не очень
Ошибки определения нижних (до 77Гц) и высоких (после 330 Гц) понятны, так как они не входят в диапазон искомой ЧОТ, а вот почему некоторые частоты правильно определяет, а некоторые нет, не могу понять

В прикрепленном архиве сигнал allton.pcm и его ЧОТ
0
Вложения
Тип файла: zip allTon.zip (281.1 Кб, 18 просмотров)
vital792
2002 / 1274 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
06.04.2013, 15:48 12
да, метод далеко не идеален. Я немного переписал функцию, может будет лучше работать, хотя и она не без греха. Сначала рассчитываю акф целиком. В этом случае она получается гарантированно убывающей от середины в обе стороны. Затем нахожу положение второго максимума и по нему определяю частоту:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
double ton(const short in[], int frameLength)
{
    int pitch, j, OT = 0, max = 0;
    int beginSampleToFindMax = 20;//frameLength/2;
 
    int *corrFunc = (int*)calloc(frameLength*2, sizeof(int));
 
    for(pitch=0; pitch<frameLength; pitch++)
    {
        for(j=0; j<frameLength; j++)
        {
            corrFunc[pitch+j] += (int)in[pitch]*in[frameLength-j];
        }
    }
 
    for(j=frameLength+beginSampleToFindMax; j<frameLength*2; j++)
    {
        if(corrFunc[j] > max)
        {
            max = corrFunc[j];
            OT = j;
        }
    }
    free(corrFunc);
 
    return (double)fd / (OT-frameLength);
}
Для низких частот само собой работать не будет - в окно анализа должен попасть минимум период, а лучше два, иначе второго пика вообще не будет. Для высоких частот в акф получается много пиков и трудно выбрать именно второй. Я ввел переменную beginSampleToFindMax, с помощью которой отсекаю первый пик - ее значение тоже зависит от частоты, при малой частоте значения 20 будет не достаточно, при большой она отсечет и второй пик. По хорошему, конечно этот код либо должен работать на известном узком диапазоне частот, либо его можно унифицировать следующим образом: сначала сглаживаете сигнал нч фильтром(опять же надо знать верхний предел, чтобы не отфильтровать основной тон). Далее получаете его акф, в ней ищите перегибы соответствующие максимумам, сортируете их по убыванию и ищите разницу между первыми двумя(или еще лучше усредненную разницу между всеми)
0
Ebis
0 / 0 / 0
Регистрация: 03.03.2010
Сообщений: 94
Завершенные тесты: 1
06.04.2013, 15:55  [ТС] 13
Вообще определитель ЧОТ я пишу для детектора речи в диапазоне от 80 до 300ГЦ. При старой функции он работал вполне сносно, но когда я начал проверять функцию определения ЧОТ гармоническими сигнала из указанного диапазона частот, то увидел что он криво работает, а мне надо чтобы он четко определял ЧОТ, чтобы с помощью него анализировать реакцию на помехи.

Щас попробую использовать вашу функцию, и отпишусь о результате.
0
vital792
2002 / 1274 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
06.04.2013, 15:59 14
хм, от 80 до 300 придется подбирать значения длины окна и соответственно ему переменной beginSampleToFindMax. Но это завтра, а сегодня мне пора...
0
Ebis
0 / 0 / 0
Регистрация: 03.03.2010
Сообщений: 94
Завершенные тесты: 1
06.04.2013, 16:07  [ТС] 15
Ну как прочитал в описании метода, длина окна должна включать в себя минимум 2 периода ОТ, тобишь около 26мс при fd=8000(13 мс = мин. частота 77Гц)
0
Ebis
0 / 0 / 0
Регистрация: 03.03.2010
Сообщений: 94
Завершенные тесты: 1
09.04.2013, 09:57  [ТС] 16
Возник такой вопрос, если настроить данный модуль ЧОТ, так чтобы он правильно определял частоты гармонических функций, он будет также правильно определять ЧОТ голоса?
Вопрос возник потому, что у меня пока не получается удовлетворить обоим случаям, вот и спрашиваю возможно ли?
0
raxp
10188 / 6571 / 492
Регистрация: 28.12.2010
Сообщений: 21,166
Записей в блоге: 1
09.04.2013, 10:19 17
...при работе с речью используют понятие формант, нет там одного основного тона.
0
Ebis
0 / 0 / 0
Регистрация: 03.03.2010
Сообщений: 94
Завершенные тесты: 1
09.04.2013, 11:24  [ТС] 18
в данном случае мне нужно выделить ЧОТ речи с помощью автокорреляции
0
vital792
2002 / 1274 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
09.04.2013, 14:18 19
Цитата Сообщение от Ebis Посмотреть сообщение
если настроить данный модуль ЧОТ, так чтобы он правильно определял частоты гармонических функций, он будет также правильно определять ЧОТ голоса?
далеко не факт. Не понимаю, почему вы вообще взялись проверять на синусоиде, а не сразу на фрагменте речевого сигнала
0
Ebis
0 / 0 / 0
Регистрация: 03.03.2010
Сообщений: 94
Завершенные тесты: 1
09.04.2013, 14:55  [ТС] 20
Цитата Сообщение от vital792 Посмотреть сообщение
далеко не факт. Не понимаю, почему вы вообще взялись проверять на синусоиде, а не сразу на фрагменте речевого сигнала
Просто я хотел поглядеть как будет вести себя ЧОТ в зависимости от разного рода сигналов(с речью более меня работает), сперва решил проверить на синусойде, а в идеале хотел проверить реакцию на импульсную помеху
0
09.04.2013, 14:55
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
09.04.2013, 14:55

Автокорреляционная функция
Добрый день! Есть сигнал first_step=0; step_t=0.01; last_step=1; N_=101;...

Автокорреляционная функция
Здравствуйте! Есть массив (String) в виде &quot;1&quot; и &quot;0&quot;. Т.е. последовательность...

Автокорреляционная функция С/А-кода
Добрый день) Сформировала с/а-код и написала алгоритм который строит автокор....


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru