Commiting current OFDM work; no major milestone hit;
authorbaobrien <baobrien@01035d8c-6547-0410-b346-abe4f91aad63>
Sun, 21 Jan 2018 21:01:28 +0000 (21:01 +0000)
committerbaobrien <baobrien@01035d8c-6547-0410-b346-abe4f91aad63>
Sun, 21 Jan 2018 21:01:28 +0000 (21:01 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@3391 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/octave/ofdm_lib.m
codec2-dev/octave/tofdm.m
codec2-dev/src/ofdm.c
codec2-dev/src/ofdm_internal.h
codec2-dev/src/tdma.c
codec2-dev/src/tdma.h
codec2-dev/unittest/tofdm.c

index 32dd02f176d736dec054294be8cfb13ba9f1b6fd..a618bda35e4181ad56d917d7c9ea4044faea6cb2 100644 (file)
@@ -91,8 +91,8 @@ function [t_est foff_est] = coarse_sync(states, rx, rate_fs_pilot_samples)
       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)
@@ -428,6 +428,166 @@ function [rx_bits states aphase_est_pilot_log rx_np rx_amp] = ofdm_demod(states,
   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
 % 
index 7fab085838acd4df0654e8a64bef8d00addd606d..88a6dd6676c31d496077fd757e744e1274c5acfd 100644 (file)
@@ -6,7 +6,22 @@
 % ------------------------------------------------------------------
 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;
@@ -20,10 +35,11 @@ function pass = run_ofdm_test(Nframes,sample_clock_offset_ppm,foff_hz)
   % ---------------------------------------------------------------------
 
   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
@@ -38,6 +54,15 @@ function pass = run_ofdm_test(Nframes,sample_clock_offset_ppm,foff_hz)
 
   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 ---------------------------------------------------------------
 
@@ -63,6 +88,7 @@ function pass = run_ofdm_test(Nframes,sample_clock_offset_ppm,foff_hz)
     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
@@ -78,7 +104,7 @@ function pass = run_ofdm_test(Nframes,sample_clock_offset_ppm,foff_hz)
     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
 
@@ -161,7 +187,14 @@ function pass = run_ofdm_test(Nframes,sample_clock_offset_ppm,foff_hz)
   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
index a3d5c1a2f249fc087101ecb5a763850f4972891a..bcca1effc164eef99d21db41d59b492419796739 100644 (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,
@@ -51,6 +63,7 @@ const struct OFDM_CONFIG OFDM_CONFIG_700D_C = {
     .Ns = 8,
     .M = 144,
     .Ncp = 16,
+    .Fcenter = 1500,
     .FtWindowWidth = 11,
     .BitsPerFrame = 224,
     .SampsPerFrame = 1280,
@@ -70,7 +83,8 @@ static complex float vector_sum(complex float *, int);
 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 */
 
@@ -162,13 +176,122 @@ static complex float vector_sum(complex float *a, int num_elements) {
     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;
@@ -177,8 +300,17 @@ static int coarse_sync(struct OFDM *ofdm, complex float *rx, int length) {
     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;
@@ -189,23 +321,24 @@ static int coarse_sync(struct OFDM *ofdm, complex float *rx, int length) {
             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];
@@ -237,11 +370,8 @@ static int coarse_sync(struct OFDM *ofdm, complex float *rx, int length) {
         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++){
@@ -249,13 +379,18 @@ static int coarse_sync(struct OFDM *ofdm, complex float *rx, int length) {
             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;
 }
@@ -337,15 +472,18 @@ static void ofdm_txframe(struct OFDM *ofdm, complex float tx[],
  */
 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));
     }
@@ -396,7 +534,7 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG * config) {
     /* 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;
@@ -417,6 +555,9 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG * config) {
     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;
     
@@ -436,8 +577,10 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG * config) {
     }
 
     /* 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++) {
         /*
@@ -445,7 +588,7 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG * config) {
          * 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));
@@ -466,6 +609,10 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG * config) {
             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 */
 
@@ -479,6 +626,8 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG * config) {
     ofdm->sample_point = 0;
     ofdm->timing_est = 0;
     ofdm->nin = SampsPerFrame;
+    ofdm->sync_count = 0;
+    ofdm->frame_point = 0;
 
     /* create the OFDM waveform */
 
@@ -511,6 +660,7 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG * config) {
     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);
@@ -588,7 +738,12 @@ void ofdm_mod(struct OFDM *ofdm, COMP result[], const int *tx_bits) {
     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;
@@ -612,10 +767,38 @@ void ofdm_mod(struct OFDM *ofdm, COMP result[], const int *tx_bits) {
     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) {
+
     }
 }
 
@@ -639,12 +822,19 @@ void ofdm_demod(struct OFDM *ofdm, int *rx_bits, COMP *rxbuf_in) {
     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++) {
@@ -652,16 +842,19 @@ void ofdm_demod(struct OFDM *ofdm, int *rx_bits, COMP *rxbuf_in) {
     }
 
     /* 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 -------------------------------------------------- */
 
@@ -683,12 +876,18 @@ void ofdm_demod(struct OFDM *ofdm, int *rx_bits, COMP *rxbuf_in) {
             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. */
 
@@ -877,7 +1076,7 @@ void ofdm_demod(struct OFDM *ofdm, int *rx_bits, COMP *rxbuf_in) {
 
         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);
     }
 
index 8f88620735153bb44722db3504c35774b59e5f92..bf1f1e83e0ec5e448a92e68d830f11c30e13a361 100644 (file)
@@ -45,93 +45,51 @@ extern "C" {
 
 #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;
index 8be2a8a251161623d5064a971b283ed39d5d84a8..b3cee92d355cce655eb289a42d7fddafea132fe5 100644 (file)
@@ -439,6 +439,7 @@ void tdma_rx_pilot_sync(tdma_t * tdma){
 
             /* 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;
@@ -462,10 +463,11 @@ void tdma_rx_pilot_sync(tdma_t * tdma){
         }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 */
@@ -526,6 +528,10 @@ void tdma_rx_pilot_sync(tdma_t * tdma){
         #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 */
@@ -552,6 +558,7 @@ void tdma_rx_pilot_sync(tdma_t * tdma){
                     }
                 }
             }
+            /* 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){
@@ -588,6 +595,9 @@ void tdma_rx_pilot_sync(tdma_t * tdma){
     }
 }
 
+/* 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;
index 4b3fe832a592ccfceacd024f7179a79589bc8387..b3333c682ba04ee4451dbb57c14d9a7578111601 100644 (file)
   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
 
@@ -103,7 +112,7 @@ struct TDMA_MODE_SETTINGS {
     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 */
index 61c16de3056babbe051397ed1b6eaf5886ca169b..b4ad25043f8b7e70dc6242317003909a0f4e1c61 100644 (file)
@@ -46,7 +46,7 @@
 
 #define OFDM_NC 16
 
-#define NFRAMES 30
+#define NFRAMES 60
 //#define SAMPLE_CLOCK_OFFSET_PPM 100
 //#define FOFF_HZ 5.0f
 
@@ -202,8 +202,8 @@ int main(int argc, char *argv[])
 
         /* 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);
     }
 
     /* --------------------------------------------------------*\
@@ -216,6 +216,12 @@ int main(int argc, char *argv[])
 
     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
     \*---------------------------------------------------------*/
@@ -243,6 +249,7 @@ int main(int argc, char *argv[])
     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