С чего все начиналось можно посмотреть тут. Я сильно дополнил его и советую сначала поиграться с ним в компиляторе, посмотреть отладочные текстовые файлы. Все функции, не представляющие особый интерес, я определил внутри класса, а функции связанные с методом CORDIC расписал отдельно.
Exported from Notepad++
Вывод писать не буду, заинтересованные потыкаются сами.
Нас в данном случае будут интересовать функции 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, а так же недостаток, с которым я столкнулся во время работы.
#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, а так же недостаток, с которым я столкнулся во время работы.
Комментариев нет:
Отправить комментарий