понедельник, 28 октября 2013 г.

Комплексное число - продолжение

С чего все начиналось можно посмотреть тут. Я сильно дополнил его и советую сначала поиграться с ним в компиляторе, посмотреть отладочные текстовые файлы. Все функции, не представляющие особый интерес, я определил внутри класса, а функции связанные с методом CORDIC расписал отдельно.
Exported from Notepad++
#include <iostream> #include <fstream> #include <math.h> #include <limits.h> using namespace std; const double PI = M_PI; #define N 8 //number steps class complex { private: int re; int im; int module; float argument; public: complex(){ re = 0; im = 0; module = 0; argument = 0; } complex(int r, int i){ re = r; im = i; calc_cordic(module, argument); } complex(int mod, float arg){ module = mod; argument = arg; calc_cordic(re, im); } /*--------private variables get methods------------*/ int get_re(){return re;} int get_im(){return im;} int get_mod(){return module;} float get_arg(){return argument;} /*--------private variables set methods------------*/ void set_re(int r) { re = r; calc_cordic(module, argument); } void set_im(int i) { im = i; calc_cordic(module, argument); } void set_mod(int mod) { module = mod; calc_cordic(re, im); } void set_arg(float arg) { argument = arg; calc_cordic(re, im); } /*---------functions that are using includes-------*/ int calc_abs_val() { return sqrt(re*re+im*im); } float calc_arg() { float tmp_re = float(get_re()); float tmp_im = float(get_im()); return atan2f(tmp_im, tmp_re)*180.0/PI; } void calc_rotate(float arg) { float tmp_re = float(get_re())*cos(arg*PI/180)-float(get_im())*sin(arg*PI/180); float tmp_im = float(get_im())*cos(arg*PI/180)+float(get_re())*sin(arg*PI/180); set_re(int(tmp_re)); set_im(int(tmp_im)); calc_cordic(module, argument); } ///////////////////////////////////////////////////// /*--------------CORDIC functions-------------------*/ void calc_cordic(int& r, int& i); void calc_cordic(int& mod, float& arg); void calc_cordic_rotate(); //////////////////////////////////////////////////// }; void complex::calc_cordic(int& mod, float& arg) { ofstream creating_test("debug_constructor.txt", ios::out); float d_angle[N]; float sum_angles = .0f; creating_test << "number of iteration:\t" << N << endl; creating_test << "input Re:\t\t" << get_re() << endl; creating_test << "input Im:\t\t" << get_im() << endl; creating_test << "angles:\t\t" << endl; for(int k = 0; k < N; k++) { d_angle[k] = atan(1.0/pow(2,k)) * (180/PI); sum_angles += d_angle[k]; creating_test << d_angle[k] << endl; } float cordic_gain = .0f; for(int k =0; k < N; k++) { if(k == 0) { cordic_gain = cos(d_angle[k]*PI/180.0); } else { cordic_gain *= cos(d_angle[k]*PI/180.0); } } creating_test << "cordic gain:\t\t" << cordic_gain << endl; short Re[N+1]; short Im[N+1]; Re[0] = get_re(); Im[0] = get_im(); arg = 0.0f; int tmp = 0; if(Re[0] < 0 ) {//&& Im[0] >= 0) { Re[0] = -Re[0]; Im[0] = -Im[0]; arg = -180.0f; } else { if(Im[0] < 0) { arg = -360.0f; } } creating_test << "iteration\t\tRe[i+1]\t\tIm[i+1]\t\tArg" << endl; for(int k = 0; k < N; k++) { if(Im[k] >= 0) { Re[k+1] = Re[k] + (Im[k] >> k); Im[k+1] = Im[k] - (Re[k] >> k); arg -= d_angle[k]; } else { Re[k+1] = Re[k] - (Im[k] >> k); Im[k+1] = Im[k] + (Re[k] >> k); arg += d_angle[k]; } creating_test << "\t" << k << "\t\t" << Re[k+1] << "\t\t" << Im[k+1] << "\t\t" << -arg << endl; } arg = -arg; mod = Re[N] * cordic_gain; creating_test << "\n\tmodule of Z:\t\t" << module << endl; creating_test << "\n\targument of Z:\t\t" << arg << endl; creating_test.close(); } void complex::calc_cordic(int& r, int& i) { ofstream creating_test("debug_constructor.txt", ios::out); float d_angle[N]; float sum_angles = .0; creating_test << "number of iteration:\t" << N << endl; creating_test << "input module:\t\t" << get_mod() << endl; creating_test << "input argument:\t\t" << get_arg() << endl; creating_test << "angles:\t\t" << endl; for(int k = 0; k < N; k++) { d_angle[k] = atan(1.0/pow(2,k)) * (180/PI); sum_angles += d_angle[k]; creating_test << d_angle[k] << endl; } float cordic_gain = .0f; for(int k =0; k < N; k++) { if(k == 0) { cordic_gain = cos(d_angle[k]*PI/180.0); } else { cordic_gain *= cos(d_angle[k]*PI/180.0); } } short Re[N+1]; short Im[N+1]; float tmp = get_mod()* cordic_gain; float arg = .0f; if(get_arg() >= 90.0f && get_arg() < 270.0) { arg = 180.0f; Re[0] = -short(tmp); } else { Re[0] = short(tmp); if(get_arg() >= 270.0f && get_arg() < 360.0) arg = 360.0f; else arg = .0f; } Im[0] = 0; for(int k = 0; k < N; k++) { if(arg >= get_arg()) { Re[k+1] = Re[k] + (Im[k] >> k); Im[k+1] = Im[k] - (Re[k] >> k); arg -= d_angle[k]; } else { Re[k+1] = Re[k] - (Im[k] >> k); Im[k+1] = Im[k] + (Re[k] >> k); arg += d_angle[k]; } creating_test << "\t" << k << "\t\t" << Re[k+1] << "\t\t" << Im[k+1] << "\t\t" << arg << endl; } r = Re[N]; i = Im[N]; creating_test << "\n\tRe of Z:\t\t" << r << endl; creating_test << "\n\tIm of Z:\t\t" << i << endl; creating_test.close(); } void complex::calc_cordic_rotate() { /**/ } int main() { ofstream debug("debug_main.txt", ios::out); //complex *a = new complex(8192,.0f); complex *a = new complex(8192,0); float angle_rot = 45.0f; float sum_angle = 0; for(int k = 0; k < 8; k++) { a->calc_rotate(angle_rot); sum_angle += angle_rot; cout << a->calc_abs_val() << "\t" << a->calc_arg() << "\t" << a->get_arg() << endl; } debug.close(); return 0; }

Вывод писать не буду, заинтересованные потыкаются сами.

Нас в данном случае будут интересовать функции calc_cordic(int&, int&) и calc_cordic(int&, float&).
Если в функции calc_cordic в аргументах стоят две целочисленные переменные, то они интерпретируются как реальная и мнимая часть комплексного числа. Тогда вычисляется модуль и аргумент заданного слова. Я планирую использовать это дальнейшем при анализе сигналов, например при построении спектра.
Если в функции calc_cordic в аргументах стоит целочисленная переменная и переменная с плавающей точкой, то они представляются как модуль комплексного числа и аргумент, представляя запись комплексного числа в полярных системах координат. Результатом работы функции является расчет реальной и мнимой составляющий входного комплексного числа. И этим я планирую в перспективе воспользоваться. Например, изменяя аргумент комплексного числа с заданной скоростью, получаем квадратуры гармонического сигнала с определенной частотой. Фактически получается генерация синуса и косинуса в широкой полосе частот с заданной начальной фазой. А это близко к фазовой модуляции. Изменяя модуль комплексного числа при фиксированном росте аргумента, получаем амплитудную модуляцию. Комбинируя оба способа, получаем  QAM. Изменяя скорость роста аргумента, получаем частотную модуляцию. Ну и так далее.

Первым я начну портировать на Verilog конструктор void complex::calc_cordic(int& r, int& i), который считает Re и Im по заданным модулю и аргументу. Будет показано, как в ходе работы представится аргумент числа в целочисленной форме, как будут посчитаны углы и усиление метода CORDIC, а так же недостаток, с которым я столкнулся во время работы.

Комментариев нет:

Отправить комментарий