foff_est = foff_est_neg - fmax - 1;
end
+ %printf("t_est: %d\n", t_est);
if verbose > 1
- %printf("t_est: %d\n", t_est);
figure(7); clf;
plot(abs(corr))
figure(8)
states.foff_est_hz = foff_est_hz;
endfunction
+function [rx_bits states aphase_est_pilot_log rx_np rx_amp] = ofdm_demod2(states, rxbuf_in)
+ ofdm_load_const;
+
+ % insert latest input samples into rxbuf
+
+ rxbuf(1:Nrxbuf-states.nin) = rxbuf(states.nin+1:Nrxbuf);
+ rxbuf(Nrxbuf-states.nin+1:Nrxbuf) = rxbuf_in;
+
+ % get latest freq offset estimate
+
+ woff_est = 2*pi*foff_est_hz/Fs;
+
+ % update timing estimate --------------------------------------------------
+
+ delta_t = 0;
+ if timing_en
+ % update timing at start of every frame
+
+ st = M+Ncp + Nsamperframe + 1 - floor(ftwindow_width/2) + (timing_est-1);
+ en = st + Nsamperframe-1 + M+Ncp + ftwindow_width-1;
+
+ ft_est = coarse_sync(states, rxbuf(st:en) .* exp(-j*woff_est*(st:en)), rate_fs_pilot_samples);
+ timing_est = timing_est + ft_est - ceil(ftwindow_width/2);
+
+ if verbose > 1
+ printf(" ft_est: %2d timing_est: %2d sample_point: %2d\n", ft_est, timing_est, sample_point);
+ end
+
+ % Black magic to keep sample_point inside cyclic prefix. Or something like that.
+
+ delta_t = ft_est - ceil(ftwindow_width/2);
+ sample_point = max(timing_est+Ncp/4, sample_point);
+ sample_point = min(timing_est+Ncp, sample_point);
+ end
+
+ % down convert at current timing instant----------------------------------
+
+ % todo: this cld be more efficent, as pilot r becomes r-Ns on next frame
+
+ rx_sym = zeros(1+Ns+1+1, Nc+2);
+
+ % previous pilot
+
+ st = M+Ncp + Nsamperframe + (-Ns)*(M+Ncp) + 1 + sample_point; en = st + M - 1;
+
+ for c=1:Nc+2
+ acarrier = rxbuf(st:en) .* exp(-j*woff_est*(st:en)) .* conj(W(c,:));
+ rx_sym(1,c) = sum(acarrier);
+ end
+
+ % pilot - this frame - pilot
+
+ for rr=1:Ns+1
+ st = M+Ncp + Nsamperframe + (rr-1)*(M+Ncp) + 1 + sample_point; en = st + M - 1;
+ for c=1:Nc+2
+ acarrier = rxbuf(st:en) .* exp(-j*woff_est*(st:en)) .* conj(W(c,:));
+ rx_sym(rr+1,c) = sum(acarrier);
+ end
+ end
+
+ % next pilot
+
+ st = M+Ncp + Nsamperframe + (2*Ns)*(M+Ncp) + 1 + sample_point; en = st + M - 1;
+ for c=1:Nc+2
+ acarrier = rxbuf(st:en) .* exp(-j*woff_est*(st:en)) .* conj(W(c,:));
+ rx_sym(Ns+3,c) = sum(acarrier);
+ end
+
+ % est freq err based on all carriers ------------------------------------
+
+ if foff_est_en
+ freq_err_rect = sum(rx_sym(2,:))' * sum(rx_sym(2+Ns,:));
+
+ % prevent instability in atan(im/re) when real part near 0
+
+ freq_err_rect += 1E-6;
+
+ %printf("freq_err_rect: %f %f angle: %f\n", real(freq_err_rect), imag(freq_err_rect), angle(freq_err_rect));
+ freq_err_hz = angle(freq_err_rect)*Rs/(2*pi*Ns);
+ foff_est_hz = foff_est_hz + foff_est_gain*freq_err_hz;
+ end
+
+ % OK - now estimate and correct phase ----------------------------------
+
+ aphase_est_pilot = 10*ones(1,Nc+2);
+ aamp_est_pilot = zeros(1,Nc+2);
+ for c=2:Nc+1
+
+ % estimate phase using average of 6 pilots in a rect 2D window centred
+ % on this carrier
+ % PPP
+ % DDD
+ % DDD
+ % PPP
+
+ cr = c-1:c+1;
+ aphase_est_pilot_rect = sum(rx_sym(2,cr)*pilots(cr)') + sum(rx_sym(2+Ns,cr)*pilots(cr)');
+
+ % use next step of pilots in past and future
+
+ aphase_est_pilot_rect += sum(rx_sym(1,cr)*pilots(cr)');
+ aphase_est_pilot_rect += sum(rx_sym(2+Ns+1,cr)*pilots(cr)');
+
+ aphase_est_pilot(c) = angle(aphase_est_pilot_rect);
+ aamp_est_pilot(c) = abs(aphase_est_pilot_rect/12);
+ end
+
+ % correct phase offset using phase estimate, and demodulate
+ % bits, separate loop as it runs across cols (carriers) to get
+ % frame bit ordering correct
+
+ aphase_est_pilot_log = [];
+ rx_bits = []; rx_np = []; rx_amp = [];
+ for rr=1:Ns-1
+ for c=2:Nc+1
+ if phase_est_en
+ rx_corr = rx_sym(rr+2,c) * exp(-j*aphase_est_pilot(c));
+ else
+ rx_corr = rx_sym(rr+2,c);
+ end
+ rx_np = [rx_np rx_corr];
+ rx_amp = [rx_amp aamp_est_pilot(c)];
+ if bps == 1
+ abit = real(rx_corr) > 0;
+ end
+ if bps == 2
+ abit = qpsk_demod(rx_corr);
+ end
+ rx_bits = [rx_bits abit];
+ end % c=2:Nc+1
+ aphase_est_pilot_log = [aphase_est_pilot_log; aphase_est_pilot(2:Nc+1)];
+ end
+
+ % Adjust nin to take care of sample clock offset
+
+ nin = Nsamperframe;
+ if timing_en
+ thresh = (M+Ncp)/8;
+ tshift = (M+Ncp)/4;
+ if timing_est > thresh
+ nin = Nsamperframe+tshift;
+ timing_est -= tshift;
+ sample_point -= tshift;
+ end
+ if timing_est < -thresh
+ nin = Nsamperframe-tshift;
+ timing_est += tshift;
+ sample_point += tshift;
+ end
+ end
+
+ states.rx_sym = rx_sym;
+ states.rxbuf = rxbuf;
+ states.nin = nin;
+ states.timing_est = timing_est;
+ states.sample_point = sample_point;
+ states.delta_t = delta_t;
+ states.foff_est_hz = foff_est_hz;
+endfunction
+
% Save test bits frame to a text file in the form of a C array
%
% ------------------------------------------------------------------
1;
-function pass = run_ofdm_test(Nframes,sample_clock_offset_ppm,foff_hz)
+function rx = ebno_awgn_channel(tx, Fs, Rb, EbNodB)
+ EbNo = 10^(EbNodB/10);
+ variance = Fs / (Rb*EbNo);
+ noise = sqrt(variance)*randn(1,length(tx));
+ avg = sum(abs(tx))/length(tx)
+ rx = noise.*avg + tx;
+end
+
+function nums = im_re_interleave(nim)
+ nums = zeros(1,length(nim)*2);
+ nums(1:2:length(nums)) = real(nim);
+ nums(2:2:length(nums)) = imag(nim);
+
+end
+
+function pass = run_ofdm_test(Nframes,sample_clock_offset_ppm,foff_hz,EbNodB = 100,nheadsamp = 0)
%Nframes = 30;
%sample_clock_offset_ppm = 100;
%foff_hz = 5;
% ---------------------------------------------------------------------
Ts = 0.018; Tcp = 0.002; Rs = 1/Ts; bps = 2; Nc = 16; Ns = 8;
+ Rb_real = 700;
states = ofdm_init(bps, Rs, Tcp, Ns, Nc);
ofdm_load_const;
- rand('seed',1);
+ rand('seed',2);
tx_bits = round(rand(1,Nbitsperframe));
% Run tx loop
rx_log = sample_clock_offset(tx_log, sample_clock_offset_ppm);
rx_log = freq_shift(rx_log, foff_hz, Fs);
+ #rx_log(1:nheadsamp) = zeros(nheadsamp,1);
+ rx_log_l = length(rx_log)
+ rx_log = [zeros(1,nheadsamp), rx_log];
+ rx_log = rx_log(1:rx_log_l);
+ rx_log = ebno_awgn_channel(rx_log, Fs, Rb_real, EbNodB);
+
+ rx_vec = fopen("tofdm_rx_vec","wb+");
+ fwrite(rx_vec,im_re_interleave(rx_log),"single");
+ fclose(rx_vec);
% Rx ---------------------------------------------------------------
states.sample_point = Ncp;
end
+ %states.foff_est_hz = 10;
for f=1:Nframes
% insert samples at end of buffer, set to zero if no samples
end
prx += lnew;
- [rx_bits states aphase_est_pilot_log arx_np arx_amp] = ofdm_demod(states, rxbuf_in);
+ [rx_bits states aphase_est_pilot_log arx_np arx_amp] = ofdm_demod2(states, rxbuf_in);
% log some states for comparison to C
pass = check(foff_hz_log, foff_hz_log_c', 'foff_est_hz') && pass;
pass = check(rx_bits_log, rx_bits_log_c, 'rx_bits') && pass;
+ figure(fg++)
+ stem(timing_est_log-timing_est_log_c')
+ figure(fg++)
+ stem(phase_est_pilot_log-phase_est_pilot_log_c)
end
-run_ofdm_test(30,100,.1)
\ No newline at end of file
+% This works best on my machine -- Brady
+graphics_toolkit('fltk')
+
+run_ofdm_test(60,100,.5,60 ,0)
\ No newline at end of file
#include "kiss_fft.h"
#include "modem_probe.h"
+/*
+ * Optimization TODOs
+ * CPU:
+ * [ ] Remove cexpf() from loops (can be replaced with single cexpf() and multiplication in loop)
+ * [ ] Look for/fix potential aliasing slowdowns (ie using array[i] as accumulator)
+ * [ ] Possibly dd a bunch of const arrays and maybe figure out restrict
+ * [ ] Run a bit of profiling on ofdm
+ *
+ * Mem:
+ * [ ] Make RX debug logs optional or modem probes
+ */
+
/* Concrete definition of 700D parameters */
const struct OFDM_CONFIG OFDM_CONFIG_700D_C = {
.Nc = 16,
.Ns = 8,
.M = 144,
.Ncp = 16,
+ .Fcenter = 1500,
.FtWindowWidth = 11,
.BitsPerFrame = 224,
.SampsPerFrame = 1280,
static complex float qpsk_mod(int *);
static void qpsk_demod(complex float, int *);
static void ofdm_txframe(struct OFDM *, complex float [], complex float *);
-static int coarse_sync(struct OFDM *, complex float *, int);
+//static int coarse_sync(struct OFDM *, complex float *, int);
+static int coarse_sync(struct OFDM *ofdm, complex float *rx, int length, float *foff_out);
/* Defines */
return sum;
}
+static int coarser_sync(struct OFDM *ofdm, complex float *rx, int length, float *foff_out, float *ratio_out) {
+ complex float csam;
+ const int Fs = ofdm->config.Fs;
+ const int M = ofdm->config.M;
+ const int Ncp = ofdm->config.Ncp;
+ const int SampsPerFrame = ofdm->config.SampsPerFrame;
+ const int Ncorr = length - (M + Ncp);
+
+ float corr[Ncorr];
+ float corr_t;
+ int NPSamp = M + Ncp;
+ int i, j;
+ float max_corr = 0;
+ float max_mag = 0;
+ float mag = 0.0f;
+ int t_est = 0;
+ int fmax = 60;
+ int pmax_i,nmax_i;
+ float pmax,nmax;
+ float foff_est;
+
+ for (i = 0; i < Ncorr; i++) {
+ complex float temp = 0.0f + 0.0f * I;
+
+ for (j = 0; j < (M + Ncp); j++) {
+ csam = conjf(ofdm->pilot_samples[j]);
+ temp = temp + (rx[i + j] * csam);
+ //temp = temp + (rx[i + j + SampsPerFrame] * csam);
+ }
+
+ corr_t = cabsf(temp);
+ /* Magnitude of incoming samples */
+ //mag = max( cabsf(rx[i]) , cabsf(rx[i+SampsPerFrame]) );
+ mag = cabsf(rx[i]);
+ max_mag = max(mag, max_mag);
+
+ /* find the max magnitude and its index */
+ if(corr_t > max_corr){
+ max_corr = corr_t;
+ t_est = i;
+ }
+ }
+
+ if(ratio_out != NULL)
+ *ratio_out = max_corr/max_mag;
+ //fprintf(stderr,"Ratio is %f; mag is %f corr is %f\n",max_corr/max_mag,max_mag,max_corr);
+
+ /* Skip coarse frequency est if we don't have anywhere to put result */
+ if(foff_out == NULL){
+ return t_est;
+ }
+
+ /* Coarse frequency estimation */
+ kiss_fft_cfg fftcfg = ofdm->sync_fft_cfg;
+ complex float fft_in[Fs];
+ complex float fft_out[Fs];
+ float C[Fs];
+ /* Zero FFT input array */
+ for(i = 0; i < Fs; i++){
+ fft_in[i] = 0;
+ }
+ /* shift and copy in NPsam samples to front of buffer for FFT'ing */
+ for(i = 0; i < NPSamp; i++){
+ fft_in[i] = rx[i + t_est] * conjf(ofdm->pilot_samples[i]);
+ }
+ kiss_fft(fftcfg,(kiss_fft_cpx*)fft_in,(kiss_fft_cpx*)fft_out);
+
+ /* Copy into output corr array, taking magnitude */
+ /* TODO: May be able to skip sqrt() in abs, since we're just looking for a maximum point down the line */
+ for(i = 0; i < Fs; i++){
+ C[i] = cabsf(fft_out[i]);
+ }
+
+ // /* shift and copy in NPsam samples to front of buffer for FFT'ing */
+ // for(i = 0; i < NPSamp; i++){
+ // fft_in[i] = rx[i + t_est + SampsPerFrame] * conjf(ofdm->pilot_samples[i]);
+ // }
+ // kiss_fft(fftcfg,(kiss_fft_cpx*)fft_in,(kiss_fft_cpx*)fft_out);
+
+ // /* Add into output corr array */
+ // for(i = 0; i < Fs; i++){
+ // C[i] += cabsf(fft_out[i]);
+ // }
+
+ pmax_i = 0;
+ nmax_i = Fs;
+ pmax = nmax = 0;
+ /* Search the positive and negative sides of the FFT to +/-fmax for peak */
+ for(i = 0; i < fmax; i++){
+ if(C[i] > pmax){
+ pmax = C[i];
+ pmax_i = i;
+ }
+ }
+ for(i = Fs-1; i > Fs-fmax; i--){
+ if(C[i] > nmax){
+ nmax = C[i];
+ nmax_i = i;
+ }
+ }
+ foff_est = (pmax > nmax) ? pmax_i : (nmax_i-Fs+1);
+
+ fprintf(stderr,"foff_est is %f, tpos is %d, ratio is %f\n",foff_est,t_est,max_mag/max_corr);
+
+ *foff_out = foff_est;
+
+ return t_est;
+}
+
/*
* Correlates the OFDM pilot symbol samples with a window of received
* samples to determine the most likely timing offset. Combines two
* frames pilots so we need at least Nsamperframe+M+Ncp samples in rx.
*/
-static int coarse_sync(struct OFDM *ofdm, complex float *rx, int length) {
+static int coarse_sync(struct OFDM *ofdm, complex float *rx, int length, float *foff_out) {
complex float csam;
const int Fs = ofdm->config.Fs;
const int M = ofdm->config.M;
const int Ncorr = length - (SampsPerFrame + (M + Ncp));
float corr[Ncorr];
+ float corr_t;
int NPSamp = M + Ncp;
int i, j;
+ float max_corr = 0;
+ float max_mag = 0;
+ float mag = 0.0f;
+ int t_est = 0;
+ int fmax = 60;
+ int pmax_i,nmax_i;
+ float pmax,nmax;
+ float foff_est;
for (i = 0; i < Ncorr; i++) {
complex float temp = 0.0f + 0.0f * I;
temp = temp + (rx[i + j + SampsPerFrame] * csam);
}
- corr[i] = cabsf(temp);
- }
-
- /* find the max magnitude and its index */
-
- float mag = 0.0f;
- int t_est = 0;
-
- for (i = 0; i < Ncorr; i++) {
- if (corr[i] > mag) {
- mag = corr[i];
+ corr_t = cabsf(temp);
+ /* Magnitude of incoming samples */
+ mag = max( cabsf(rx[i]) , cabsf(rx[i+SampsPerFrame]) );
+ max_mag = max(mag, max_mag);
+
+ /* find the max magnitude and its index */
+ if(corr_t > max_corr){
+ max_corr = corr_t;
t_est = i;
}
}
+ /* Skip coarse frequency est if we don't have anywhere to put result */
+ if(foff_out == NULL){
+ return t_est;
+ }
+
/* Coarse frequency estimation */
- /* TODO: Move FFT config to ofdm init and ofdm struct */
kiss_fft_cfg fftcfg = ofdm->sync_fft_cfg;
complex float fft_in[Fs];
complex float fft_out[Fs];
C[i] += cabsf(fft_out[i]);
}
- int fmax = 30;
- int pmax_i,nmax_i;
- float pmax,nmax;
- float foff_est;
- pmax_i = nmax_i = 0;
+ pmax_i = 0;
+ nmax_i = Fs;
pmax = nmax = 0;
/* Search the positive and negative sides of the FFT to +/-fmax for peak */
for(i = 0; i < fmax; i++){
pmax = C[i];
pmax_i = i;
}
- if(C[Fs-i-1] > nmax){
+ }
+ for(i = Fs-1; i > Fs-fmax; i--){
+ if(C[i] > nmax){
nmax = C[i];
nmax_i = i;
}
}
- foff_est = (pmax > nmax) ? pmax_i : (nmax_i - fmax);
- //fprintf(stderr,"foff_est is %f\n",foff_est);
+ foff_est = (pmax > nmax) ? pmax_i : (nmax_i-Fs+1);
+ //foff_est = pmax_i;
+ //`fprintf(stderr,"foff_est is %f, tpos is %d\n",foff_est,t_est);
+
+ *foff_out = foff_est;
return t_est;
}
*/
void **alloc_doubleary(size_t sx,size_t sy,size_t elem){
size_t i;
+ /* Allocate pointer array */
char ** ary = malloc(sizeof(void*) * sx);
if(ary == NULL){
return NULL;
}
+ /* Allocate data array. */
*ary = malloc(elem * sx * sy);
if(*ary == NULL){
free(ary);
return NULL;
}
+ /* Fill out pointer array to point to rows of data array */
for(i=0; i<sx; i++){
ary[i] = ((*ary) + (sy*i*elem));
}
/* TODO: validate config structure */
memcpy((void*)&ofdm->config,(void*)config,sizeof(struct OFDM_CONFIG));
const int Fs = ofdm->config.Fs;
- const int Rs = ofdm->config.Rs;
+ const float Rs = ofdm->config.Rs;
const int Nc = ofdm->config.Nc;
const int M = ofdm->config.M;
const int Ncp = ofdm->config.Ncp;
ofdm->rxbuf = malloc(sizeof(complex float) * ofdm->config.RxBufSize);
if(ofdm->rxbuf == NULL) goto ofdm_fail_cleanup;
+ ofdm->coarse_rxbuf = malloc(sizeof(complex float) * ofdm->config.RxBufSize);
+ if(ofdm->coarse_rxbuf == NULL) goto ofdm_fail_cleanup;
+
ofdm->w = malloc(sizeof(float) * (Nc+2));
if(ofdm->w == NULL) goto ofdm_fail_cleanup;
}
/* carrier tables for up and down conversion */
-
- int Nlower = floorf(( (float)(Fcenter) - Rs * ((float)Nc / 2)) / Rs);
+ float Fcf = (float)Fcenter;
+ float Ncf = (float)Nc;
+ float Fsf = (float)Fs;
+ int Nlower = floorf(( Fcf - Rs * (Ncf / 2)) / Rs);
for (i = 0, j = Nlower; i < (Nc + 2); i++, j++) {
/*
* j = 1 kHz to 2 kHz (1.5 kHz center)
*/
- ofdm->w[i] = TAU * (float) j / ((float)Fs / Rs);
+ ofdm->w[i] = TAU * (float) j / (Fsf / Rs);
}
ofdm->W = (complex float **) alloc_doubleary(Nc+2,M,sizeof(complex float));
ofdm->rx_sym[i][j] = 0.0f + 0.0f * I;
}
}
+
+ for(i = 0; i < ofdm->config.RxBufSize; i++){
+ ofdm->rxbuf[i] = 0;
+ }
/* default settings of options and states */
ofdm->sample_point = 0;
ofdm->timing_est = 0;
ofdm->nin = SampsPerFrame;
+ ofdm->sync_count = 0;
+ ofdm->frame_point = 0;
/* create the OFDM waveform */
free_nc(ofdm->pilots);
free_nc(ofdm->pilot_samples);
free_nc(ofdm->rxbuf);
+ free_nc(ofdm->coarse_rxbuf);
free_nc(ofdm->w);
free_nc(ofdm->rx_amp);
free_nc(ofdm->aphase_est_pilot_log);
const int BitsPerFrame = ofdm->config.BitsPerFrame;
int length = BitsPerFrame / Bps;
- complex float tx[SampsPerFrame];
+
+
+ /* Note: COMP and complex float have the same memory layout */
+ /* see iso/iec 9899:1999 sec 6.2.5.13 */
+ complex float * tx = (complex float *)&result[0];
+
complex float tx_sym_lin[length];
int dibit[2];
int s, i;
ofdm_txframe(ofdm, tx, tx_sym_lin);
/* convert to comp */
-
- for (i = 0; i < SampsPerFrame; i++) {
+ /* Note: COMP and complex float have the same memory layout */
+ /* see iso/iec 9899:1999 sec 6.2.5.13 */
+ /*for (i = 0; i < SampsPerFrame; i++) {
result[i].real = crealf(tx[i]);
result[i].imag = cimagf(tx[i]);
+ }*/
+}
+
+/*
+ * Like ofdm_demod, but handles sync and large frame offset
+ */
+void ofdm_demod_coarse(struct OFDM *ofdm, int *rx_bits, COMP *rxbuf_in){
+ const int SampsPerFrame = ofdm->config.SampsPerFrame;
+ const int RxBufSize = ofdm->config.RxBufSize;
+ const int Fs = ofdm->config.Fs;
+
+ int sync = ofdm->sync_count;
+ int frame_point = ofdm->frame_point;
+ int nin = ofdm->nin;
+ complex float * coarse_rxbuf = ofdm->coarse_rxbuf;
+ complex float rxbuf_temp[RxBufSize];
+
+ /* NCO for freq. shifting */
+ complex float shift_nco = 1;
+ complex float shift_nco_dph = 0;
+
+ /* Copy in nin samples to end of buffer */
+ memmove(&coarse_rxbuf[0],&coarse_rxbuf[nin],nin);
+ memcpy (&coarse_rxbuf[RxBufSize - nin],rxbuf_in,nin);
+
+ if(!sync) {
+
}
}
const int SampsPerFrame = ofdm->config.SampsPerFrame;
const int FtWindowWidth = ofdm->config.FtWindowWidth;
const int RxBufSize = ofdm->config.RxBufSize;
+ int nin = ofdm->nin;
float aphase_est_pilot[Nc + 2];
float aamp_est_pilot[Nc + 2];
float freq_err_hz;
int i, j, k, rr, st, en, ft_est;
+ complex float * rxbuf = ofdm->rxbuf;
+
+
+ //memmove(&rxbuf[0],&rxbuf[nin],nin);
+ //memcpy (&rxbuf[RxBufSize - nin],rxbuf_in,nin);
+
/* shift the buffer left based on nin */
for (i = 0, j = ofdm->nin; i < (RxBufSize - ofdm->nin); i++, j++) {
}
/* insert latest input samples onto tail of rxbuf */
-
+ /* Note: COMP and complex float have the same memory layout */
+ /* see iso/iec 9899:1999 sec 6.2.5.13 */
for (i = (RxBufSize - ofdm->nin), j = 0; i < RxBufSize; i++, j++) {
ofdm->rxbuf[i] = rxbuf_in[j].real + rxbuf_in[j].imag * I;
}
+
/*
* get user and calculated freq offset
*/
float woff_est = TAU * ofdm->foff_est_hz / (float)(Fs);
+ float freq_offset = -1;
/* update timing estimate -------------------------------------------------- */
work[j] = ofdm->rxbuf[i] * cexpf(-I * woff_est * i);
}
- ft_est = coarse_sync(ofdm, work, (en - st));
+ ft_est = coarse_sync(ofdm, work, (en - st), &freq_offset);
+
+ coarser_sync(ofdm, work, (en - st), &freq_offset, NULL);
+
+ //ofdm->foff_est_hz += (freq_offset/2);
ofdm->timing_est += (ft_est - ceilf(FtWindowWidth / 2));
if (ofdm->verbose > 1) {
fprintf(stdout, " ft_est: %2d timing_est: %2d sample_point: %2d\n", ft_est, ofdm->timing_est, ofdm->sample_point);
}
+
+ //fprintf(stderr," freq_est: %f timing_est: %d sample_pt: %d\n",freq_offset,ofdm->timing_est,ofdm->sample_point);
/* Black magic to keep sample_point inside cyclic prefix. Or something like that. */
freq_err_rect = freq_err_rect + 1E-6f;
- freq_err_hz = cargf(freq_err_rect) * Rs / (TAU * Ns);
+ freq_err_hz = cargf(freq_err_rect) * Rs / (TAU * (float)Ns);
ofdm->foff_est_hz += (ofdm->foff_est_gain * freq_err_hz);
}
#define TAU (2.0f * M_PI) /* mathematical constant */
-//#define OFDM_NCX 16 /* N Carriers */
-//#define OFDM_TS 0.018f /* Symbol time */
-//#define OFDM_RS (1.0f / OFDM_TS) /* Symbol rate */
-//#define OFDM_FS 8000.0f /* Sample rate */
-//#define OFDM_BPS 2 /* Bits per symbol */
-//#define OFDM_TCP 0.002f /* ? */
-//#define OFDM_NS 8 /* Symbols per frame (number of rows incl pilot) */
-//#define OFDM_CENTRE 1500.0f /* Center frequency */
-
-/* To prevent C99 warning */
-
-//#define OFDM_M 144 /* Samples per bare symbol (?) */
-//#define OFDM_NCP 16 /* Samples per cyclic prefix */
-//
-//#ifdef OLD_STYLE
-///* This will produce a warning in C99 as (int) makes these variable */
-//
-//#define OFDM_M ((int)(OFDM_FS / OFDM_RS))
-//#define OFDM_NCP ((int)(OFDM_TCP * OFDM_FS))
-//#endif
-
-///* ? */
-//#define OFDM_FTWINDOWWIDTH 11
-///* Bits per frame (duh) */
-//#define OFDM_BITSPERFRAME ((OFDM_NS - 1) * (OFDM_NCX * OFDM_BPS))
-///* Rows per frame */
-//#define OFDM_ROWSPERFRAME (OFDM_BITSPERFRAME / (OFDM_NCX * OFDM_BPS))
-///* Samps per frame */
-//#define OFDM_SAMPLESPERFRAME (OFDM_NS * (OFDM_M + OFDM_NCP))
-//
-//#define OFDM_MAX_SAMPLESPERFRAME (OFDM_SAMPLESPERFRAME + (OFDM_M + OFDM_NCP)/4)
-//#define OFDM_RXBUF (3 * OFDM_SAMPLESPERFRAME + 3 * (OFDM_M + OFDM_NCP))
-
-
-/* Dummy struct for now, will contain constant configuration for OFDM modem */
struct OFDM_CONFIG{
- int32_t Nc;
- float Ts;
- float Rs;
- int32_t Fs;
- int32_t bps;
- int32_t Tcp;
- int32_t Ns;
- int32_t Fcenter;
- int32_t M;
- int32_t Ncp;
- int32_t FtWindowWidth;
- int32_t BitsPerFrame;
- int32_t SampsPerFrame;
- int32_t SampsPerFrameMax;
- int32_t RxBufSize;
- int32_t RowsPerFrame;
+ int32_t Nc; /* N carriers*/
+ float Ts; /* Symbol time (S) (no CP) */
+ float Rs; /* Symbol rate (S) (no CP) */
+ int32_t Fs; /* Sample rate */
+ int32_t bps; /* Bits per symbol */
+ int32_t Tcp; /* Cyclic Prefix time (S) */
+ int32_t Ns; /* Symbols per frame, including pilot */
+ int32_t Fcenter; /* Center frequency */
+ int32_t M; /* Samples per symbol (no CP) */
+ int32_t Ncp; /* Samples of cyclic prefix */
+ int32_t FtWindowWidth; /* ? */
+ int32_t BitsPerFrame; /* Bits in a frame */
+ int32_t SampsPerFrame; /* Samples in a frame */
+ int32_t SampsPerFrameMax; /* Maximum samples per demod cycle */
+ int32_t RxBufSize; /* RX buffer size */
+ int32_t RowsPerFrame; /* Symbol depth per frame, no prefix */
};
struct OFDM {
- struct OFDM_CONFIG config;
- float foff_est_gain;
- float foff_est_hz;
+ struct OFDM_CONFIG config; /* OFDM configuration (see above) */
+ float foff_est_gain; /* ? */
+ float foff_est_hz; /* Estimated frequency offset */
- int verbose;
- int sample_point;
- int timing_est;
- int nin;
+ int verbose; /* Printing verbosity level */
+ int sample_point; /* Fine timing offset */
+ int timing_est; /* Ditto (?) (Coarse timing, maybe?) */
+ int nin; /* Samples expected next demod cycle */
+ int frame_point;
+ int sync_count;
- bool timing_en;
- bool foff_est_en;
- bool phase_est_en;
-
- //complex float pilot_samples[OFDM_M + OFDM_NCP];
- //complex float W[OFDM_NCX + 2][OFDM_M];
- //complex float rxbuf[OFDM_RXBUF];
- //complex float pilots[OFDM_NC + 2];
- //float w[OFDM_NC + 2];
+ bool timing_en; /* Enable fine timing estimation */
+ bool foff_est_en; /* Enable frequency offset estimation/tracking */
+ bool phase_est_en; /* Enable Phase offset estimation */
complex float ** W;
complex float * pilots;
complex float * pilot_samples;
complex float * rxbuf;
float * w;
- kiss_fft_cfg sync_fft_cfg;
+ kiss_fft_cfg sync_fft_cfg;
- /* Demodulator data */
+ complex float * coarse_rxbuf;
- //complex float rx_sym[OFDM_NS + 3][OFDM_NCX + 2];
- //complex float rx_np[OFDM_ROWSPERFRAME * OFDM_NCX];
- //float rx_amp[OFDM_ROWSPERFRAME * OFDM_NCX];
- //float aphase_est_pilot_log[OFDM_ROWSPERFRAME * OFDM_NCX];
+ /* Demodulator data */
complex float ** rx_sym;
float * rx_amp;
/* Check to see if the bits are outside of the demod buffer. If so, adjust and re-demod*/
/* Disabled for now; will re-enable when worked out better in head */
+ /* No, this is enabled. I have it more or less worked out */
if(f_valid && !repeat_demod){
if((f_start < bits_per_sym) || ((f_start+(bits_per_sym*frame_size)) > (bits_per_sym*(slot_size+1)))){
repeat_demod = true;
}while(repeat_demod);
i32 single_slot_offset = slot->slot_local_frame_offset;
- /* Flag indicating wether or not we should call the callback */
+ /* Flag indicating whether or not we should call the callback */
bool do_frame_found_call = false;
/* Do single slot state machine */
+ /* TODO: think about/play around with other fsk_clear_estimators() positions */
if( slot->state == rx_sync){
do_frame_found_call = true;
if(!f_valid){ /* on bad UW, increment bad uw count and possibly unsync */
#endif
/* If we are in master sync mode, don't adjust demod timing. we ARE demod timing */
+ /* TODO: check if any slots are in TX mode and if any have master sync. If we are
+ TXing and don't have master sync, lock sync offset. Otherwise, TX frames jitter
+ wildly */
+
if(tdma->state != master_sync){
/* Update slot offset to compensate for frame centering */
/* Also check to see if any slots are master. If so, take timing from them */
}
}
}
+ /* Check for zero here; otherwise we get div-by-zero errors */
offset_total = offset_slots>0 ? offset_total/offset_slots:0;
/* Use master slot for timing if available, otherwise take average of all frames */
if(master_max >= mode.mastersat_min){
}
}
+/* Attempt at 'plot modem' search for situations where no synchronization is had */
+/* This currently preforms worse than just running tdma_rx_pilot_sync on every frame */
+/* It may still be needed to acquire first frames -- more testing is needed */
void tdma_rx_no_sync(tdma_t * tdma, COMP * samps, u64 timestamp){
fprintf(stderr,"searching for pilot\n");
struct TDMA_MODE_SETTINGS mode = tdma->settings;
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+/*
+ TODO: Lock sync point while transmitting in non-master mode and no master
+ slot is detected
+*/
+
+/*
+ TODO: Further testing and refinement with julia test suite
+*/
+
#ifndef __CODEC_2_TDMA_H
#define __CODEC_2_TDMA_H
u32 pilot_sync_tol; /* UW errors allowed for a valid pilot sync */
u32 first_sync_tol; /* UW errors allowed for a valid first frame sync */
u32 frame_sync_tol; /* UW errors allowed to maintain a frame sync */
- u32 frame_sync_baduw_tol; /* How many bad UWs before calling a frame unsynced */
+ u32 frame_sync_baduw_tol; /* How many bad UWs before calling a slot unsynced */
i32 mastersat_max; /* Maximum count for master detection counter */
i32 mastersat_min; /* Minimum count before frame considered 'master' */
i32 loss_of_sync_frames; /* How many bad frames before going from 'sync' to 'no_sync' for entire modem */
#define OFDM_NC 16
-#define NFRAMES 30
+#define NFRAMES 60
//#define SAMPLE_CLOCK_OFFSET_PPM 100
//#define FOFF_HZ 5.0f
/* tx vector logging */
- memcpy(&tx_bits_log[OFDM_BITSPERFRAME*f], test_bits_ofdm, sizeof(int)*OFDM_BITSPERFRAME);
- memcpy(&tx_log[samples_per_frame*f], tx, sizeof(COMP)*samples_per_frame);
+ memcpy(&tx_bits_log[OFDM_BITSPERFRAME*f], test_bits_ofdm, sizeof(int)*OFDM_BITSPERFRAME);
+ memcpy(&tx_log[samples_per_frame*f], tx, sizeof(COMP)*samples_per_frame);
}
/* --------------------------------------------------------*\
freq_shift(rx_log, rx_log, foff_hz, &foff_phase_rect, samples_per_frame * NFRAMES);
+ FILE *cplin = fopen("tofdm_rx_vec","r");
+ size_t s = fread(rx_log,sizeof(COMP),samples_per_frame*NFRAMES,cplin);
+ fclose(cplin);
+ fprintf(stderr,"Read %d\n",s);
+
+
/* --------------------------------------------------------*\
Demod
\*---------------------------------------------------------*/
ofdm_set_timing_enable(ofdm, true);
ofdm_set_foff_est_enable(ofdm, true);
ofdm_set_phase_est_enable(ofdm, true);
+ //ofdm->foff_est_hz = 10;
for(f=0; f<NFRAMES; f++) {
/* For initial testng, timing est is off, so nin is always