- •Пояснительная записка
- •1 Постановка задачи
- •2 Теоретический материал
- •2.1 Двумерное преобразование Фурье
- •2.1.1 Определение двумерного дпф в алгебре комплексных чисел и в четырехмерных алгебрах
- •2.1.2 Алгоритм двумерного дпф по основанию 2
- •2.1.3 Алгоритм двумерного дпф по основанию 4
- •2.2 Алгебра гиперкомплексных чисел
- •2.3 Прямая сумма комплексных алгебр
- •3 Описание разработанного алгоритма
- •3.1 Описание работы программы
- •4 Исследование алгоритма
- •Приложение а. Текст программы
- •Приложение б. Принцип работы программы
3 Описание разработанного алгоритма
3.1 Описание работы программы
Заданный алгоритм был реализован программно с помощью технологии Microsoft .NET Frameworkна языке программированияC++.
Написанное приложение состоит из двух сборок: библиотеки классов FFT, содержащей все необходимое для вычисления ДПФ по формуле и БПФ.
Также присутствует консольный модуль, реализующий пользовательский интерфейс:
Рисунок 1 Основное меню программы
После выбора алгоритма пользователь видит консоль с предложением ввести размер квадратного массива:
Рисунок 2 Консоль ввода массива
В результате генерируется файл с подаваемым на вход сигналом, на выходе получаем файл с исходным спектром в комплексном представлении. Далее представлены примеры выполненной работы алгоритмов БПФ и ДПФ для длины преобразования 64:
Рисунок 3 Пример работы алгоритма вычисления БПФ-64
Рисунок 4 Пример работы алгоритма вычисления ДПФ-64
4 Исследование алгоритма
Для наглядного представления приведем таблицу и график сравнения алгоритмов БПФ и ДПФ.
Проведем сравнение результатов непосредственного вычисления дискретного преобразования Фурье и результатов быстрых алгоритмов для длин преобразований 2, 4, 8, 16, 32, 64, 128, 256.
Таблица 2 Сравнение времени выполнения БПФ и ДПФ
N |
Время вычисления БПФ, с |
Время вычисления ДПФ, с |
8 |
0,001322 |
0,001686 |
16 |
0,007954 |
0,018803 |
32 |
0,047996 |
0,455932 |
64 |
0,287401 |
8,510700 |
128 |
1,714250 |
160,6980 |
256 |
8,678940 |
3559,830 |
Рисунок 5 Зависимость времени выполнения алгоритма от длины преобразования
Из Рисунка 5 видно, что быстрый алгоритм Фурье имеет значительное преимущество в скорости перед непосредственным дискретным преобразованием, хотя для небольшого объёма данных различия несущественны. Так же присутствует погрешность, связанная с машинными характеристиками, которая напрямую влияет на скорость алгоритмов.
Приложение а. Текст программы
Class Hypercomplex
#include "StdAfx.h"
#include "Hypercomplex.h"
#include <iostream>
#include <math.h>
#include <float.h>
Hypercomplex::Hypercomplex()
{
W = 0.0;//1.0
X = 0.0;
Y = 0.0;
Z = 0.0;
}
Hypercomplex::Hypercomplex(const double w, const double x, const double y, const double z)
{
W = w;
X = x;
Y = y;
Z = z;
}
void Hypercomplex::PrintOn(ostream &strm) const
{
Hypercomplex q(W, X, Y, Z);
if(abs(q.getW()) < 0.000001)
{
q.setW(0.0);
}
if(abs(q.getX()) < 0.000001)
{
q.setX(0.0);
}
if(abs(q.getY()) < 0.000001)
{
q.setY(0.0);
}
if(abs(q.getZ()) < 0.000001)
{
q.setZ(0.0);
}
strm << "(" << q.W << "," << q.X << "," << q.Y << "," << q.Z << ")";
}
Hypercomplex operator * (const Hypercomplex &a, const Hypercomplex &b)
{
double w,x,y,z;
w = a.W*b.W - (a.X*b.X + a.Y*b.Y + a.Z*b.Z);
x = a.W*b.X + b.W*a.X + a.Y*b.Z + a.Z*b.Y;
y = a.W*b.Y + b.W*a.Y + a.Z*b.X + a.X*b.Z;
z = a.W*b.Z + b.W*a.Z + a.X*b.Y + a.Y*b.X;
return Hypercomplex(w,x,y,z);
}
const Hypercomplex& Hypercomplex::operator *= (const Hypercomplex &q)
{
double w = W, x = X, y = Y, z = Z;
double qW = q.W, qX = q.X, qY = q.Y, qZ = q.Z;
W = w*qW - (x*qX + y*qY + z*qZ);
X = w*qX + qW*x + y*qZ + z*qY;
Y = w*qY + qW*y + z*qX + x*qZ;
Z = w*qZ + qW*z + x*qY + y*qX;
return *this;
}
Hypercomplex operator + (const Hypercomplex &a, const Hypercomplex &b)
{
double w,x,y,z;
w = a.W+b.W;
x = a.X+b.X;
y = a.Y+b.Y;
z = a.Z+b.Z;
return Hypercomplex(w,x,y,z);
}
const Hypercomplex& Hypercomplex::operator += (const Hypercomplex &q)
{
W = W+q.W;
X = X+q.X;
Y = Y+q.Y;
Z = Z+q.Z;
return *this;
}
Hypercomplex operator - (const Hypercomplex &a, const Hypercomplex &b)
{
double w,x,y,z;
w = a.W-b.W;
x = a.X-b.X;
y = a.Y-b.Y;
z = a.Z-b.Z;
return Hypercomplex(w,x,y,z);
}
const Hypercomplex& Hypercomplex::operator -= (const Hypercomplex &q)
{
W = W-q.W;
X = X-q.X;
Y = Y-q.Y;
Z = Z-q.Z;
return *this;
}
Hypercomplex Hypercomplex::operator = (const Hypercomplex &q)
{
W = q.W;
X = q.X;
Y = q.Y;
Z = q.Z;
return *this;
}
const Hypercomplex& Hypercomplex::operator ~ ()
{
X = -X;
Y = -Y;
Z = -Z;
return *this;
}
const Hypercomplex& Hypercomplex::exp()
{
double Mul;
double Length = sqrt(X*X + Y*Y + Z*Z);
if (Length > 1.0e-4)
Mul = sin(Length)/Length;
else
Mul = 1.0;
W = cos(Length);
X *= Mul;
Y *= Mul;
Z *= Mul;
return *this;
}
const double& Hypercomplex::arg()
{
return acos(W/sqrt(W*W + X*X + Y*Y + Z*Z));
}
const Hypercomplex& Hypercomplex::sgn()
{
Hypercomplex q = *this;
return (1/sqrt(W*W + X*X + Y*Y + Z*Z))*q;
}
const Hypercomplex& Hypercomplex::log()
{
double Length;
Length = sqrt(X*X + Y*Y + Z*Z);
Length = atan(Length/W);
W = 0.0;
X *= Length;
Y *= Length;
Z *= Length;
return *this;
}
const Hypercomplex& Hypercomplex::u(Hypercomplex& q)
{
Hypercomplex u = q;
u.W = 0;
return u;
}
const Hypercomplex Hypercomplex::pow(int k)
{
Hypercomplex b(1,0,0,0);
Hypercomplex a = *this;
while (k)
{
if (k & 1)
{
b *= a;
}
a *= a;
k >>= 1;
}
return b;
}
const Hypercomplex Hypercomplex::toHypercomplex(const double &d)
{
double w, x, y, z;
w = d;
x = 0;
y = 0;
z = 0;
return Hypercomplex(w,x,y,z);
}
const Hypercomplex Hypercomplex::toHypercomplex(const std::complex<double> &c)
{
double w,x,y,z;
w = c.real();
x = c.imag();
y = 0;
z = 0;
return Hypercomplex(w,x,y,z);
}
const Hypercomplex& Hypercomplex::Initialize(const double& w, const double& x, const double& y, const double& z)
{
W = w;
X = x;
Y = y;
Z = z;
return *this;
}
void Hypercomplex::setW(const double &value)
{
W = value;
}
void Hypercomplex::setX(const double &value)
{
X = value;
}
void Hypercomplex::setY(const double &value)
{
Y = value;
}
void Hypercomplex::setZ(const double &value)
{
Z = value;
}
double Hypercomplex::getW()
{
return W;
}
double Hypercomplex::getX()
{
return X;
}
double Hypercomplex::getY()
{
return Y;
}
double Hypercomplex::getZ()
{
return Z;
}
Class DPF
#pragma once
#include <iostream>
#include <fstream>
#include <complex>
#include "Hypercomplex.h"
#include <conio.h>
#include <math.h>
using namespace std;
#ifndef PI
#define PI 3.14159265358979323846
#endif
class DPF
{
private:
int N1, N2;
Hypercomplex w1, w2;
Hypercomplex** mas_w;
public:
DPF();
~DPF(void);
double** loadMatrix(char name[]);
void writeComplexMatrix(char name[], complex<double>** complex_matrix, int&);
template<typename T>
T* binInverse(T* x, int& n)
{
int dl = n/2;
int st = n - 1;
int j = 0;
T s0 = 0;
int k = 0;
for(int i = 0; i < st; i++)
{
if(i < j)
{
s0 = x[i];
x[i] = x[j];
x[j] = s0;
}
k = dl;
while(k <= j)
{
j -= k;
k >>= 1;
}
j += k;
}
return x;
}
template<typename T>
T** binMtrInverse(T** matr, int& N)
{
int size = 0;
size = N;
for(int i = 0; i < size; i++)
{
binInverse(matr[i], size);
}
T* v = new T[size];
for(int i=0; i<size; i++)
{
for(int j=0; j<size; j++)
{
v[j] = matr[j][i];
}
binInverse(v, size);
for(int j=0; j<size; j++)
{
matr[j][i] = v[j];
}
}
delete v;
return matr;
}
Hypercomplex** matrInv(Hypercomplex** q, int& N);
void genMatr(int N, char name[]);
Hypercomplex** _dpf(Hypercomplex** matrix);
Hypercomplex** Q44(Hypercomplex&, Hypercomplex&, Hypercomplex&, Hypercomplex&, Hypercomplex&, Hypercomplex&,
Hypercomplex&, Hypercomplex&, Hypercomplex&, Hypercomplex&, Hypercomplex&, Hypercomplex&, Hypercomplex&, Hypercomplex&, Hypercomplex&, Hypercomplex&);
Hypercomplex butterfly2(Hypercomplex&, Hypercomplex&, Hypercomplex&, Hypercomplex&, int&, int&, int&);
Hypercomplex Q_dft_basis4(Hypercomplex**, int&, const int&, const int&);
int pos(int a);
Hypercomplex** HyperMatrix(const int&);
Hypercomplex** toHyperMatrix(double**, int&);
Hypercomplex** Q_ftfbs(Hypercomplex**, int &size);
Hypercomplex Q00(Hypercomplex**, int&, int&, int&);
Hypercomplex Qab(Hypercomplex**, int&, int&, int&, const int&, const int&);
void shift(Hypercomplex**, int, int);
void clcCoordinates(int&, int&, int, int);
void clcMasW(int&);
void clearMasW();
Hypercomplex** Q_algftf(Hypercomplex** , int&);
void fft2(Hypercomplex**,int&);
void fft4(Hypercomplex**,int&);
complex<double> toComplex(Hypercomplex&);
const Hypercomplex automorphism(Hypercomplex&, const int&);
complex<double>** allocPartSpectr(Hypercomplex**, int&);
complex<double>** getComplexSpectr(Hypercomplex**, int&);
void set(int& N);
int get_N1();
int get_N2();
void setW1(int);
void setW2(int);
};