kopia lustrzana https://github.com/xdsopl/qsstv
333 wiersze
13 KiB
C++
333 wiersze
13 KiB
C++
|
|
/*
|
|
* File getofdm.c
|
|
*
|
|
* Author PA0MBO - M.BOS
|
|
* DATE Feb 21st 2009
|
|
*
|
|
* implements more or less the get_ofdm_symbol
|
|
* MATLAB routine from diorama-1.1.1
|
|
*
|
|
*
|
|
*/
|
|
|
|
/*************************************************************************
|
|
*
|
|
* PA0MBO
|
|
*
|
|
* COPYRIGHT (C) 2009 M.Bos
|
|
*
|
|
* This file is part of the distribution package RXAMADRM
|
|
*
|
|
* This package is free software and you can redistribute is
|
|
* and/or modify it under the terms of the GNU General Public License
|
|
*
|
|
* More details can be found in the accompanying file COPYING
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <fftw3.h>
|
|
#include "drmproto.h"
|
|
#include "appglobal.h"
|
|
|
|
#define PI (atan(1.0)*4.0)
|
|
int getofdm( /*@null@ */ float *rs, float time_offset_fractional_init,
|
|
float freq_offset_init, float delta_time_offset_I_init, int Ts,
|
|
int Tu, /*@null@ */ float Zi[], /*@null@ */ float *out,
|
|
int init, int TIME_SYNC_ENABLE, int FREQ_SYNC_ENABLE)
|
|
{
|
|
float EPSILON = 1.0E-10;
|
|
float max_theta = 10.0;
|
|
// float max_time_offset_ctrl = 10.0;
|
|
// float max_delta_time_offset = 2.0;
|
|
float kP_small_timing_controller = 0.01;
|
|
float kP_large_timing_controller = 0.01;
|
|
float threshold_timing_small_large = 2.0;
|
|
float kI_timing_controller = 0.00020;
|
|
float kP_small_freq_controller = 0.750;
|
|
float threshold_freq_small_large = 0.75;
|
|
float kI_freq_controller = 0.0008;
|
|
int Tg, Tgh;
|
|
float phi_freq_correction_last;
|
|
float delta_time_offset_I;
|
|
float delta_time_offset_P;
|
|
float dfreq_offset_I;
|
|
float freq_offset, time_offset_fractional;
|
|
int i;
|
|
float temp1[] = { 0.0, 0.0 }, temp2, temp3, temp4;
|
|
float temp[] = { 0.0, 0.0 };
|
|
float temp5[] = { 0.0, 0.0 };
|
|
float temp6, temp7;
|
|
float temp8[] = { 0.0, 0.0 };
|
|
float temp9, temp10;
|
|
float theta_plus, theta_minus, delta_theta;
|
|
float time_offset_ctrl;
|
|
float delta_time_offset;
|
|
int delta_time_offset_integer;
|
|
float epsilon_ML, freq_offset_ctrl, dfreq_offset_P;
|
|
float kP_large_freq_controller, dfreq_offset;
|
|
float tmptheta, term1;
|
|
static float *exp_temp;
|
|
static float *out1;
|
|
|
|
static drmComplex s[288], S[288]; /* 288 = max Tu */
|
|
static fftwf_plan p = NULL;
|
|
|
|
if (init == 1)
|
|
|
|
{
|
|
|
|
/* malloc space for arrays */
|
|
if ((exp_temp = (float *)malloc(Tu * 2 * sizeof(float))) == NULL)
|
|
|
|
{
|
|
printf("cannot malloc space for exp_temp in get_ofdm_symbol\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
if ((out1 = (float *)malloc(Tu * 2 * sizeof(float))) == NULL)
|
|
|
|
{
|
|
printf("cannot malloc space for out1 in get_ofdm_symbol\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
if (p != NULL)
|
|
|
|
{
|
|
fftwf_destroy_plan(p);
|
|
}
|
|
p = fftwf_plan_dft_1d(Tu,(fftwf_complex *)s,(fftwf_complex *)S,FFTW_FORWARD, FFTW_ESTIMATE);
|
|
return (0);
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* fixed parameters */
|
|
EPSILON = 1.0E-10;
|
|
max_theta = 5.0;
|
|
// max_time_offset_ctrl = 10.0;
|
|
// max_delta_time_offset = 2.0;
|
|
kP_small_timing_controller = 0.01;
|
|
kP_large_timing_controller = 0.01;
|
|
threshold_timing_small_large = 2.0;
|
|
kI_timing_controller = 0.00005;
|
|
kP_small_freq_controller = 0.05;
|
|
kP_large_freq_controller = 0.75;
|
|
threshold_freq_small_large = 0.5;
|
|
kI_freq_controller = 0.0008;
|
|
Tg = Ts - Tu;
|
|
Tgh = (int) floor(Tg / 2 + 0.5);
|
|
if (Zi[0] < 0.0)
|
|
|
|
{
|
|
phi_freq_correction_last = 0.0;
|
|
delta_time_offset_I = delta_time_offset_I_init;
|
|
dfreq_offset_I = 0.0;
|
|
freq_offset = freq_offset_init;
|
|
time_offset_fractional = time_offset_fractional_init;
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
phi_freq_correction_last = Zi[1];
|
|
delta_time_offset_I = Zi[2];
|
|
dfreq_offset_I = Zi[3];
|
|
freq_offset = Zi[4];
|
|
time_offset_fractional = Zi[5];
|
|
}
|
|
if (TIME_SYNC_ENABLE == 1)
|
|
|
|
{
|
|
temp1[0] = 0.0;
|
|
temp1[1] = 0.0;
|
|
temp2 = 0.0;
|
|
temp3 = 0.0;
|
|
temp5[0] = 0.0;
|
|
temp5[1] = 0.0;
|
|
temp6 = 0.0;
|
|
temp7 = 0.0;
|
|
temp8[0] = 0.0;
|
|
temp8[1] = 0.0;
|
|
temp9 = 0.0;
|
|
temp10 = 0.0;
|
|
for (i = 0; i < Tg + 2; i++)
|
|
|
|
{
|
|
// logfile->addToAux(QString("tm1 %1 %2 %3 %4 %5").arg(rs[i * 2] ).arg(rs[(Tu + i) * 2]).arg(rs[i * 2 + 1]).arg(rs[(Tu + i) * 2 + 1]).arg(temp1[0]));
|
|
temp1[0] += rs[i * 2] * rs[(Tu + i) * 2] + rs[i * 2 + 1] * rs[(Tu + i) * 2 + 1]; /* real part */
|
|
temp1[1] += -rs[i * 2] * rs[(Tu + i) * 2 + 1] + rs[i * 2 + 1] * rs[(Tu + i) * 2]; /* imag part */
|
|
temp2 += rs[i * 2] * rs[i * 2] + rs[i * 2 + 1] * rs[i * 2 + 1];
|
|
temp3 += rs[(i + Tu) * 2] * rs[(i + Tu) * 2] + rs[(i + Tu) * 2 + 1] * rs[(i + Tu) * 2 + 1];
|
|
}
|
|
temp4 = (float) (EPSILON + 0.5 * (temp2 + temp3));
|
|
// logfile->addToAux(QString("tmp %1 %2 %3 %4 %5").arg(temp1[0]).arg(temp1[1]).arg(temp2).arg(temp3).arg(temp4));
|
|
|
|
/* time offset measurement : theta */
|
|
for (i = 0; i < 5; i++)
|
|
|
|
{
|
|
temp5[0] += rs[i * 2] * rs[(Tu + i) * 2] + rs[i * 2 + 1] * rs[(Tu + i) * 2 + 1]; /* 1-5 * Tu_1_5 */
|
|
temp5[1] += -rs[i * 2] * rs[(Tu + i) * 2 + 1] + rs[i * 2 +1] * rs[(Tu + i) * 2];
|
|
temp6 += rs[i * 2] * rs[i * 2] + rs[i * 2 + 1] * rs[i * 2 + 1]; /* 1-5 * 1-5' */
|
|
temp7 += rs[(i + Tu) * 2] * rs[(i + Tu) * 2] + rs[(i + Tu) * 2 + 1] * rs[(i + Tu) * 2 + 1]; /* Tu_1_5 * Tu_1_5' */ /* pa0mbo check for OK */
|
|
temp8[0] += rs[(i + Tg - 3) * 2] * rs[(i + Tu + Tg - 3) * 2] + rs[(i + Tg - 3) * 2 + 1] * rs[(i + Tu + Tg - 3) * 2 + 1]; /* Tg -2 +2 * Tg + Tu -2 +2 */
|
|
temp8[1] += -rs[(i + Tg - 3) * 2] * rs[(i + Tu + Tg - 3) * 2 + 1] + rs[(i + Tg - 3) * 2 + 1] + rs[(i + Tu + Tg - 3) * 2];
|
|
temp9 += rs[(i + Tg - 3) * 2] * rs[(i + Tg - 3) * 2] + rs[(i + Tg - 3) * 2 + 1] * rs[(i + Tg - 3) * 2 + 1]; /* Tg-2+2 * Tg-2+2 */
|
|
temp10 += rs[(i + Tg + Tu - 3) * 2] * rs[(i + Tg + Tu - 3) * 2] + rs[(i + Tg + Tu - 3) * 2 + 1] * rs[(i + Tg + Tu - 3) * 2 + 1]; /* TG+Tu-2+2 * Tg+Tu-2+2 */
|
|
}
|
|
theta_plus = (float) sqrt((temp1[0] - temp5[0]) * (temp1[0] - temp5[0]) + (temp1[1] - temp5[1]) * (temp1[1] - temp5[1]));
|
|
theta_plus -= (0.5 * (-temp6 - temp7));
|
|
theta_minus = (float) sqrt((temp1[0] - temp8[0]) * (temp1[0] - temp8[0]) + (temp1[1] - temp8[1]) * (temp1[1] - temp8[1]));
|
|
theta_minus -= (0.5 * (temp9 - temp10));
|
|
delta_theta = (theta_plus - theta_minus) * Tgh / temp4;
|
|
|
|
/* now limit the delta_theta value */
|
|
if (delta_theta < -max_theta) delta_theta = -max_theta;
|
|
if (delta_theta > max_theta) delta_theta = max_theta;
|
|
|
|
/* P-I controller for theta */
|
|
time_offset_ctrl = delta_theta - time_offset_fractional;
|
|
delta_time_offset_I += kI_timing_controller * time_offset_ctrl;
|
|
delta_time_offset_P = kP_large_timing_controller * time_offset_ctrl +
|
|
threshold_timing_small_large * (kP_small_timing_controller -kP_large_timing_controller) *
|
|
tanh(time_offset_ctrl / threshold_timing_small_large);
|
|
delta_time_offset = delta_time_offset_P + delta_time_offset_I + time_offset_fractional;
|
|
delta_time_offset_integer = (int) floor(delta_time_offset + 0.5);
|
|
// logfile->addToAux(QString("dt %1 %2 %3 %4 %5").arg(time_offset_ctrl).arg(delta_time_offset_I).arg(delta_time_offset_P).arg(delta_time_offset).arg(delta_time_offset_integer));
|
|
|
|
/* now limit delta_time_offset_integer */
|
|
if (delta_time_offset_integer < -1) delta_time_offset_integer = -1;
|
|
if (delta_time_offset_integer > 1) delta_time_offset_integer = 1;
|
|
time_offset_fractional = delta_time_offset - delta_time_offset_integer;
|
|
|
|
/* printf("delta_time_offset_integer as used in phi_freq_corr %d phifcl %g \n",
|
|
delta_time_offset_integer, phi_freq_correction_last); */
|
|
phi_freq_correction_last += (delta_time_offset_integer / Tu) * freq_offset;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
delta_time_offset_integer = 0;
|
|
time_offset_fractional = 0.0;
|
|
}
|
|
|
|
/* printf("in getofdm delta_time_offset_integer is %d time_offs_fract %g\n",
|
|
delta_time_offset_integer, time_offset_fractional); */
|
|
if (FREQ_SYNC_ENABLE == 1)
|
|
|
|
{
|
|
temp[0] = 0.0;
|
|
temp[1] = 0.0;
|
|
for (i = 0; i < Tg; i++)
|
|
|
|
{
|
|
temp[0] +=
|
|
rs[(i + 1 + delta_time_offset_integer) * 2] * rs[(i + 1 +
|
|
delta_time_offset_integer
|
|
+ Tu) * 2] +
|
|
rs[(i + 1 + delta_time_offset_integer) * 2 +
|
|
1] * rs[(i + 1 + delta_time_offset_integer + Tu) * 2 + 1];
|
|
temp[1] +=
|
|
rs[(i + 1 + delta_time_offset_integer) * 2 +
|
|
1] * rs[(i + 1 + delta_time_offset_integer + Tu) * 2] -
|
|
rs[(i + 1 + delta_time_offset_integer) * 2] * rs[(i + 1 +
|
|
delta_time_offset_integer
|
|
+ Tu) * 2 +
|
|
1];
|
|
}
|
|
epsilon_ML = (float) (atan2(temp[1], temp[0]));
|
|
|
|
/* filter epsilon_ML */
|
|
freq_offset_ctrl =
|
|
fmodf(epsilon_ML - freq_offset + PI + 100.0 * PI, 2 * PI) - PI;
|
|
dfreq_offset_I += kI_freq_controller * freq_offset_ctrl;
|
|
dfreq_offset_P =
|
|
kP_large_freq_controller * freq_offset_ctrl +
|
|
threshold_freq_small_large * (kP_small_freq_controller -
|
|
kP_large_freq_controller) *
|
|
tanh(freq_offset_ctrl / threshold_freq_small_large);
|
|
dfreq_offset = dfreq_offset_P + dfreq_offset_I;
|
|
freq_offset += dfreq_offset;
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* freq_offset =0.0 */
|
|
}
|
|
|
|
/* printf("in getofdm freq_offset = %g\n", freq_offset); */
|
|
|
|
/* get symbol and correct frequency */
|
|
for (i = 0; i < Tu; i++)
|
|
|
|
{
|
|
tmptheta = (freq_offset / Tu) * i + phi_freq_correction_last;
|
|
exp_temp[i * 2] = (float) cos(tmptheta);
|
|
exp_temp[i * 2 + 1] = (float) sin(tmptheta);
|
|
}
|
|
|
|
for (i = 0; i < Tu; i++)
|
|
{
|
|
(s[i]).re =
|
|
rs[(1 + delta_time_offset_integer + Tgh +
|
|
i) * 2] * exp_temp[i * 2] - rs[(1 +
|
|
delta_time_offset_integer +
|
|
Tgh + i) * 2 +
|
|
1] * exp_temp[i * 2 + 1];
|
|
(s[i]).im =
|
|
rs[(1 + delta_time_offset_integer + Tgh +
|
|
i) * 2] * exp_temp[i * 2 + 1] + rs[(1 +
|
|
delta_time_offset_integer
|
|
+ Tgh + i) * 2 +
|
|
1] * exp_temp[i * 2];
|
|
}
|
|
phi_freq_correction_last = (float) fmod(phi_freq_correction_last + (float) Ts / (float) Tu * freq_offset, (float)(2.0 * PI));
|
|
|
|
/* Now do fft and output symbol */
|
|
fftwf_execute(p);
|
|
for (i = 0; i <= Tu / 2; i++)
|
|
|
|
{
|
|
term1 = (float) (i * 2.0 * PI * (Tgh + time_offset_fractional) / Tu); /* Euler */
|
|
exp_temp[i * 2] = (float) cos(term1);
|
|
exp_temp[i * 2 + 1] = (float) sin(term1);
|
|
}
|
|
/* now calc out */
|
|
for (i = 0; i < Tu / 2; i++)
|
|
|
|
{
|
|
out1[i * 2] = (float) (((S[(Tu - 1 - i)]).re) * exp_temp[(i + 1) * 2] + ((S[(Tu - 1 - i)]).im) * exp_temp[(i + 1) * 2 + 1]); /* real = ac+bd */
|
|
out1[i * 2 + 1] = (float) (((S[(Tu - 1 - i)]).im) * exp_temp[(i + 1) * 2] - ((S[(Tu - 1 - i)]).re) * exp_temp[(i + 1) * 2 + 1]); /* imag bc -ad */
|
|
}
|
|
/* Now flip out1 to out */
|
|
for (i = 0; i < Tu / 2; i++)
|
|
|
|
{
|
|
out[i * 2] = out1[(Tu / 2 - 1 - i) * 2];
|
|
out[i * 2 + 1] = out1[(Tu / 2 - i - 1) * 2 + 1];
|
|
out[(Tu / 2 + i) * 2] =
|
|
(float) (((S[i]).re) * exp_temp[i * 2] -
|
|
((S[i]).im) * exp_temp[i * 2 + 1]);
|
|
out[(Tu / 2 + i) * 2 + 1] =
|
|
(float) (((S[i]).im) * exp_temp[i * 2] +
|
|
((S[i]).re) * exp_temp[i * 2 + 1]);
|
|
} Zi[0] = 1.0;
|
|
Zi[1] = phi_freq_correction_last;
|
|
Zi[2] = delta_time_offset_I;
|
|
Zi[3] = dfreq_offset_I;
|
|
Zi[4] = freq_offset;
|
|
Zi[5] = time_offset_fractional;
|
|
return (delta_time_offset_integer);
|
|
}
|
|
}
|