Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.57/47: Рейтинг темы: голосов - 47, средняя оценка - 4.57
1 / 1 / 0
Регистрация: 06.02.2019
Сообщений: 217

Преобразование Фурье

09.06.2020, 20:21. Показов 9609. Ответов 15

Студворк — интернет-сервис помощи студентам
Всем привет!
Решил я как-то разобраться с быстрым преобразованием Фурье. Нашел в Интернете код на C++. Как он работает, пока не понимаю. Но я накидал простенькую программку, которая генерирует сигнал и вычисляет его амплитуды и частоты. Вот код:
Файл FFT.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#ifndef FFT_H
#define FFT_H
 
#include <complex>
#include <vector>
 
typedef std::complex<double> base;
 
class FFT
{
    static const int mod = 7340033;
    static const int root = 5;
    static const int root_1 = 4404020;
    static const int root_pw = 1 << 20;
public:
    static void fft(std::vector<base> & a, bool invert);
    static void multiply(const std::vector<int> & a, const std::vector<int> & b, std::vector<int> & res);
    static void fft(std::vector<int> & a, bool invert);
};
 
#endif // !FFT_H
Файл FFT.cpp
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
81
82
83
84
85
86
87
88
89
90
91
92
93
#include "FFT.h"
 
#include <algorithm>
#include <cmath>
#define PI 3.1415926535897932384626433832795
 
using namespace std;
 
void FFT::fft(vector<base> & a, bool invert)
{
    int n = (int)a.size();
 
    for (int i = 1, j = 0; i < n; ++i)
    {
        int bit = n >> 1;
        for (; j >= bit; bit >>= 1)
            j -= bit;
        j += bit;
        if (i < j)
            swap(a[i], a[j]);
    }
 
    for (int len = 2; len <= n; len <<= 1)
    {
        double ang = 2 * PI / len * (invert ? -1 : 1);
        base wlen(cos(ang), sin(ang));
        for (int i = 0; i < n; i += len)
        {
            base w(1);
            for (int j = 0; j < len / 2; ++j)
            {
                base u = a[i + j], v = a[i + j + len / 2] * w;
                a[i + j] = u + v;
                a[i + j + len / 2] = u - v;
                w *= wlen;
            }
        }
    }
    if (invert)
        for (int i = 0; i < n; ++i)
            a[i] /= n;
}
 
void FFT::multiply(const vector<int> & a, const vector<int> & b, vector<int> & res) {
    vector<base> fa(a.begin(), a.end()), fb(b.begin(), b.end());
    size_t n = 1;
    while (n < max(a.size(), b.size()))
        n <<= 1;
    n <<= 1;
    fa.resize(n), fb.resize(n);
 
    fft(fa, false), fft(fb, false);
    for (size_t i = 0; i < n; ++i)
        fa[i] *= fb[i];
    fft(fa, true);
 
    res.resize(n);
    for (size_t i = 0; i < n; ++i)
        res[i] = int(fa[i].real() + 0.5);
}
 
void FFT::fft(vector<int> & a, bool invert) {
    int n = (int)a.size();
 
    for (int i = 1, j = 0; i < n; ++i) {
        int bit = n >> 1;
        for (; j >= bit; bit >>= 1)
            j -= bit;
        j += bit;
        if (i < j)
            swap(a[i], a[j]);
    }
 
    for (int len = 2; len <= n; len <<= 1) {
        int wlen = invert ? root_1 : root;
        for (int i = len; i < root_pw; i <<= 1)
            wlen = int(wlen * 1ll * wlen % mod);
        for (int i = 0; i < n; i += len) {
            int w = 1;
            for (int j = 0; j < len / 2; ++j) {
                int u = a[i + j], v = int(a[i + j + len / 2] * 1ll * w % mod);
                a[i + j] = u + v < mod ? u + v : u + v - mod;
                a[i + j + len / 2] = u - v >= 0 ? u - v : u - v + mod;
                w = int(w * 1ll * wlen % mod);
            }
        }
    }
    /*if (invert) {
        int nrev = reverse(n, mod);
        for (int i = 0; i < n; ++i)
            a[i] = int(a[i] * 1ll * nrev % mod);
    }*/
}
Файл main.cpp
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
#include <iostream>
#include <vector>
 
#include "FFT.h"
 
using namespace std;
 
int main()
{
    vector< complex<double> > d;
    for (double i = 0; i < 1024.0; i += 0.5)
    {
        double temp = 5.35 * sin(2.0 * 3.1415926535897932384626433832795 * 5.0 * i / 1024.0) +
                      3.0 * cos(2.0 * 3.1415926535897932384626433832795 * 10.0 * i / 1024.0) +
                      7.0 * sin(2.0 * 3.1415926535897932384626433832795 * 12.0 * i / 1024.0 + 3.1415926535897932384626433832795 / 3.0);
        d.push_back((complex<double>)(temp));
    }
 
    vector< complex<double> > g(d);
 
    FFT::fft(g, false);
 
    double dt = 1.0 / (double)g.size();
    for (double i = 0; i < (double)g.size() / 2; i += 1)
    {
        double fi = double(i) / dt / (double)g.size();
        double ai = 2.0 / (double)g.size() / (double)g.size() / dt * sqrt(g[i].real() * g[i].real() + g[i].imag() * g[i].imag());
        if (ai > 0.001)
            cout << fi << "    " << ai << endl;
    }
    cout << endl << endl;
    cout << d.size() << endl << endl;
    system("PAUSE");
 
    FFT::fft(d, true);
 
    for (int i = 0; i < int(d.size()); i++)
    {
        if (d[i].real() - g[i].real() > 0.001)
            cout << "ERROR! " << abs(d[i].real() - g[i].real()) << endl;
    }
 
    system("PAUSE");
    return 0;
}
Суть вопроса в следующем:
Код в таком исполнении, вроде как, работает. Амплитуды и частоты выдает. Но только если значения частот целые. Если пытаюсь сгенерировать дробные значения частот:
C++
1
2
3
4
5
6
7
for (double i = 0; i < 1024.0; i += 0.5)
    {
        double temp = 5.35 * sin(2.0 * 3.1415926535897932384626433832795 * 5.2 * i / 1024.0) +
                      3.0 * cos(2.0 * 3.1415926535897932384626433832795 * 10.0 * i / 1024.0) +
                      7.0 * sin(2.0 * 3.1415926535897932384626433832795 * 12.0 * i / 1024.0 + 3.1415926535897932384626433832795 / 3.0);
        d.push_back((complex<double>)(temp));
    }
метод перестает работать. Я подумал, что не правильно работаю с частотами, но после прямого и обратного преобразования Фурье исходный сигнал не восстанавливается. Насколько я понимаю, это уже проблема алгоритма. Верно?
Пробовал увеличить частоту дискретезации (по теореме Котельникова):
C++
1
for (double i = 0; i < 1024.0; i += 0.1)
Тогда алгоритм вообще входит в бесконечный цикл. Помогите, пожалуйста, разобраться с проблемой! Заранее благодарю.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
09.06.2020, 20:21
Ответы с готовыми решениями:

Дискретное преобразование фурье
Провел прямое преобразование фурье сигнала, получил комплексные числа Правильно ли я понимаю что искомые значения амплитуды в децибеллах...

Найти преобразование Фурье
Всем доброго времени суток! Помогите, плиз, найти преобразование функции Ps это 2 уравнения в системе, извиняюсь, что пишу не...

Посчитать обратное преобразование Фурье
Совершенно не пойму, каким образом подойти к этому интегралу. Расскажу, что пробовала: 1. Домножила на сопряжённое. 2.Делила на три...

15
 Аватар для FFPowerMan
2158 / 1238 / 509
Регистрация: 11.10.2018
Сообщений: 6,271
09.06.2020, 20:24
Где нашли код?

Добавлено через 46 секунд
Насколько я разбирался оно очень неявное. Из кода ничего никогда не поймешь. Обязательно нужно объяснение.
0
1 / 1 / 0
Регистрация: 06.02.2019
Сообщений: 217
09.06.2020, 20:25  [ТС]
Вот ссылка:
https://e-maxx.ru/algo/fft_multiply
0
 Аватар для FFPowerMan
2158 / 1238 / 509
Регистрация: 11.10.2018
Сообщений: 6,271
09.06.2020, 20:43
Удалено.
0
1 / 1 / 0
Регистрация: 06.02.2019
Сообщений: 217
09.06.2020, 22:23  [ТС]
Цитата Сообщение от FFPowerMan Посмотреть сообщение
Удалено.
Что удалено?
0
 Аватар для FFPowerMan
2158 / 1238 / 509
Регистрация: 11.10.2018
Сообщений: 6,271
10.06.2020, 09:36
Это нужно было удалить модераторам.

Добавлено через 10 минут
Там по ссылке, которую Вы дали перемножение многочленов, а само преобразование не описано. Поэтому трудно сделать выводы.

Добавлено через 53 секунды
Попробуйте нарисовать график для целых значений и для дробных. Мы посмотрим.
0
1 / 1 / 0
Регистрация: 06.02.2019
Сообщений: 217
10.06.2020, 20:50  [ТС]
Цитата Сообщение от FFPowerMan Посмотреть сообщение
Там по ссылке, которую Вы дали перемножение многочленов, а само преобразование не описано. Поэтому трудно сделать выводы.
Да, просто реализацию функции я брал из этой статьи. Возможно, она не правильная. Кстати, перемножение многочленов у меня не заработало. Возможно, сделал что-то не так. А может, как раз из-за этого бага и не работает.
Цитата Сообщение от FFPowerMan Посмотреть сообщение
Попробуйте нарисовать график для целых значений и для дробных. Мы посмотрим.
График зависимости чего от чего? Что по X и что по Y должно быть? Или Вы спектр имеете ввиду?
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
10.06.2020, 22:21
Цитата Сообщение от YagDen Посмотреть сообщение
Но только если значения частот целые. Если пытаюсь сгенерировать дробные значения частот:
Не вникая в код - все потому что "Как он работает, пока не понимаю".

Фурье работает на ортогональных функциях. Это такие функции, которые если их перемножить и сунуть результат в интеграл на некотором интервале, то интеграл выйдет нулем. Ключевое слово - "некотором". Чтобы используемые в Фурье синусоиды были ортогональны, нужно чтобы интервал интегрирования был кратен периоду этих самых синусоид. Чем хуже с кратностью, тем большая будет получаться фигня. А при дробных частотах кратность как раз и поедет.
0
1 / 1 / 0
Регистрация: 06.02.2019
Сообщений: 217
10.06.2020, 23:13  [ТС]
Цитата Сообщение от Renji Посмотреть сообщение
Не вникая в код - все потому что "Как он работает, пока не понимаю".
Для этого я и пришел сюда.
Цитата Сообщение от Renji Посмотреть сообщение
Чтобы используемые в Фурье синусоиды были ортогональны, нужно чтобы интервал интегрирования был кратен периоду этих самых синусоид.
Разве преобразование Фурье не создано для того, что бы узнавать амплитуды на частотах? Получается, что бы узнать частоту, нужно уже знать частоту исходного сигнала? В чем тогда смысл? И остается еще вопрос. Почему обратное преобразование Фурье не дает исходный сигнал? Почему при дробных значениях периода иногда происходит зацикливание программы?
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
10.06.2020, 23:48
Цитата Сообщение от YagDen Посмотреть сообщение
Разве преобразование Фурье не создано для того, что бы узнавать амплитуды на частотах?
Фурье это грубо говоря набор камертонов резонирующих каждый на своей ноте. Вы можете посмотреть какой камертон резонирует и сказать "это нота до". Но на до-бемоль зазвенят сразу несколько соседних камертонов. Другой вопрос что камертон для "до" зазвенит значительно сильнее чем камертон для "ми". Так что полутон вы распознать не сможете, но можете сказать "вроде бы на ноту до похоже".

Хотите точнее знать частоту - нужно больше "камертонов". То есть, интервал интегрирования брать побольше.
Цитата Сообщение от YagDen Посмотреть сообщение
Почему обратное преобразование Фурье не дает исходный сигнал?
Потому что Фурье раскладывает сигнал на фиксированный набор синусоид. Как ты sin(t) с sin(2*t) не складывай, а sin(1.5*t) не получится. Нужно чтобы полуторный синус тоже был в разложении.
0
1 / 1 / 0
Регистрация: 06.02.2019
Сообщений: 217
11.06.2020, 00:02  [ТС]
Цитата Сообщение от Renji Посмотреть сообщение
Хотите точнее знать частоту - нужно больше "камертонов". То есть, интервал интегрирования брать побольше.
Насколько я понимаю, интервал интегрирования в данной функции - весь массив, передаваемый в нее? Т.е что бы увеличить интервал интегрирования, нужно больше точек.
Этот код выполняется корректно:
C++
1
2
3
4
5
6
7
for (double i = 0; i < 1024.0; i += 0.5)
    {
        double temp = 5.35 * sin(2.0 * 3.1415926535897932384626433832795 * 5.0 * i / 1024.0) +
                      3.0 * cos(2.0 * 3.1415926535897932384626433832795 * 10.0 * i / 1024.0) +
                      7.0 * sin(2.0 * 3.1415926535897932384626433832795 * 12.0 * i / 1024.0 + 3.1415926535897932384626433832795 / 3.0);
        d.push_back((complex<double>)(temp));
    }
Все частоты целые числа, интервал интегрирования 1024 точки. Если заменить частоту 5,0 на 5,5 - все перестает работать:
C++
1
2
3
4
5
6
7
for (double i = 0; i < 1024.0; i += 0.5)
    {
        double temp = 5.35 * sin(2.0 * 3.1415926535897932384626433832795 * 5.5 * i / 1024.0) +
                      3.0 * cos(2.0 * 3.1415926535897932384626433832795 * 10.0 * i / 1024.0) +
                      7.0 * sin(2.0 * 3.1415926535897932384626433832795 * 12.0 * i / 1024.0 + 3.1415926535897932384626433832795 / 3.0);
        d.push_back((complex<double>)(temp));
    }
Шаг интегрирования 0,5, частота 5,5 кратна 0,5, так что все должно работать. Пробую увеличить предел интегрирования с 1024 точек до 2048:
C++
1
2
3
4
5
6
7
for (double i = 0; i < 2048.0; i += 0.5)
    {
        double temp = 5.35 * sin(2.0 * 3.1415926535897932384626433832795 * 5.5 * i / 2048.0) +
                      3.0 * cos(2.0 * 3.1415926535897932384626433832795 * 10.0 * i / 2048.0) +
                      7.0 * sin(2.0 * 3.1415926535897932384626433832795 * 12.0 * i / 2048.0 + 3.1415926535897932384626433832795 / 3.0);
        d.push_back((complex<double>)(temp));
    }
Почему-то все равно не работает.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
11.06.2020, 00:15
Цитата Сообщение от YagDen Посмотреть сообщение
Шаг интегрирования 0,5, частота 5,5 кратна 0,5, так что все должно работать.
Максимальный аргумент синуса минус минимальный аргумент синуса должно быть кратно двум пи. Что при дробном множителе не соблюдается. Если только не крутить цикл до i==2048, не меняя прочих коэффициентов. Шаг интегрирования же здесь влияет только на точность подсчета интеграла.
0
1 / 1 / 0
Регистрация: 06.02.2019
Сообщений: 217
11.06.2020, 00:23  [ТС]
Цитата Сообщение от Renji Посмотреть сообщение
Максимальный аргумент синуса минус минимальный аргумент синуса должно быть кратно двум пи.
А как тогда на практике преобразование Фурье применяется? Например при обработке звука с микрофона? Там есть все гармоники. Никто же специальный звук не подбирает, что бы выполнялись эти условия. К тому же, микрофон может записать белый шум, спектр которого - прямая линия на всех частотах, и на целых, и на дробных. Там же все работает.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
11.06.2020, 00:37
Цитата Сообщение от YagDen Посмотреть сообщение
А как тогда на практике преобразование Фурье применяется? Например при обработке звука с микрофона?
Обрабатываем одну десятую долю секунды за раз и получаем частоты с шагом в десять герц. Человеческая речь - где-то в районе ста герц. Первая музыкальная октава - от двухсот с чем-то герц. Для них погрешности от шага в десять герц уже не особо критичны.
0
 Аватар для FFPowerMan
2158 / 1238 / 509
Регистрация: 11.10.2018
Сообщений: 6,271
11.06.2020, 10:25
Цитата Сообщение от YagDen Посмотреть сообщение
Кстати, перемножение многочленов у меня не заработало.
- а в чем вообще смысл перемножения многочленов при помощи преобразования Фурье? Кто-нибудь может объяснить?

Добавлено через 2 минуты
Цитата Сообщение от YagDen Посмотреть сообщение
Что по X и что по Y должно быть?
- по Х время, по Y значения отсчетов временной диаграммы. Надо основы подучить, еще рано за преобразование Фурье браться.

Добавлено через 5 минут
Цитата Сообщение от YagDen Посмотреть сообщение
В чем тогда смысл?
- смысл в том, что Вы еще учитесь и не сможете определить частоту неизвестного сигнала.
0
1 / 1 / 0
Регистрация: 06.02.2019
Сообщений: 217
14.06.2020, 12:33  [ТС]
Спасибо. Буду пробовать разбираться. Если появятся вопросы - напишу.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
14.06.2020, 12:33
Помогаю со студенческими работами здесь

Найти преобразование Фурье функции
Найти преобразование Фурье функции f(x)=\begin{cases} &amp; \text sin(x) { if } -\pi &lt;x&lt;\pi \\ &amp; \text 0 { if } \left| x\right|&gt;\pi ...

Найти преобразование Фурье и записать интеграл
f(x)={█(3x-3,&amp;x∈(-1,1)@0,&amp;x (-1,1))┤

Назовите условия, при которых к непериодическому сигналу можно применить преобразование Фурье
Всем привет. Запутался, товарищи. В лабе задали вопрос: &quot;Назовите условия, при которых к непериодическому сигналу можно применить...

Разложить функцию в ряд Фурье и построить график суммы ряда Фурье
Здравствуйте. Дана задача: На интервале (-π;π) задана периодическая (с периодом 2π) функция f(x). Нужно разложить ее в ряд Фурье и...

Преобразование Фурье
Подскажыте пожалста , возможно ли функцию |sin(x)| разложить в ряд фурэ через експотенциалбную формулу... мне нужно написать прогу на с ,...


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

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Новые блоги и статьи
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru