From 2a04c6b44c33334be1740a88fc0865c9df51f6da Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Sat, 26 Jul 2014 18:34:33 +0000 Subject: [PATCH] - improved TX - added TX windowing - added RX git-svn-id: http://moon:8086/svn/matlab/trunk@3 801c6759-fa7c-4059-a304-17956f83a07c --- ofdm/ofdm_rx.m | 126 +++++++++++++++++++ ofdm/ofdm_tx.m | 308 +++++++++++++++++++++++++++++++++++----------- ofdm/txwin_eval.m | 10 ++ 3 files changed, 371 insertions(+), 73 deletions(-) create mode 100644 ofdm/ofdm_rx.m create mode 100644 ofdm/txwin_eval.m diff --git a/ofdm/ofdm_rx.m b/ofdm/ofdm_rx.m new file mode 100644 index 0000000..12b4ceb --- /dev/null +++ b/ofdm/ofdm_rx.m @@ -0,0 +1,126 @@ +% function ofdm_sync(x, nsym, ngrd) +% Example: ofdm_sync(x, 1152, 128) +function ofdm_rx(x, offset, nsym_soll, ngrd) + +% Init +fa = 48000; +fc = fa/4; +F1 = 750; +F2 = 2250; +F3 = 3000; +close all; +do_evaluate = 1; +alpha = 0.05; + +x = real(x); +% Detection +display('Sync detection'); +nsym_ist = nsym_soll; +xi = zeros(ngrd, 1); +range_max = 24; +range_min = 4; +range_forget = 0.5; +range = range_max; +err = 0; +k = 0; +kk = 1; +remain = length(x); +progress_ival = 1; +progress_last = -1; +nfft = nsym_soll-ngrd + +bin_c = fix(nfft*fc/fa)+1 +bin_f1 = fix(nfft*(fc+F1)/fa)+1 +bin_f2 = fix(nfft*(fc+F2)/fa)+1 +bin_f3 = fix(nfft*(fc+F3)/fa)+1 +k_fft = 3/sqrt(nfft); + +phi_c_last = 0; +phi_f1_last = 0; +phi_f2_last = 0; +phi_f3_last = 0; + +while remain > 2*nsym_ist, + xsym = x(offset+k*nsym_ist+1:offset+k*nsym_ist+nsym_ist+range); + [xcor, imax, jmax, xi] = xcc(xsym, nsym_ist, ngrd, -range, range, -range, range, xi); + remain = remain - (length(offset+k*nsym_ist+1:offset+k*nsym_ist+nsym_ist+range)); + err = -imax + jmax; + offset = offset + imax; + nsym_ist = max(round(nsym_ist + err), ngrd) + sl_offset(kk) = offset; + sl_err(kk) = err; + sl_nsym_ist(kk) = nsym_ist; + range = min(max(fix(range + abs(err) - range_forget), range_min), range_max); + progress = round(100*(length(x)-remain)/length(x)); + if (progress ~= progress_last) + progress_last = progress_last + progress_ival; + progress = progress + end; + if (do_evaluate == 1) + X0 = k_fft*fft(xsym(1:nsym_ist-ngrd), nfft); + phi_c(kk) = (1-alpha)*phi_c_last + alpha*angle(X0(bin_c)); + phi_f1(kk) = (1-alpha)*phi_f1_last + alpha*angle(X0(bin_f1)); + phi_f2(kk) = (1-alpha)*phi_f2_last + alpha*angle(X0(bin_f2)); + phi_f3(kk) = (1-alpha)*phi_f3_last + alpha*angle(X0(bin_f3)); + phi_c_last = phi_c(kk); + phi_f1_last = phi_f1(kk); + phi_f2_last = phi_f2(kk); + phi_f3_last = phi_f3(kk); + %pause; + end; + k = k + 1; + kk = kk + 1; +end; + +% Result +display('Results:'); + +offset_stddev = sqrt(var(sl_offset)) +err_mean = mean(sl_err) +nsym_ist_mean = mean(nsym_ist) + +% Diagrams +figure; +plot(1:length(sl_offset), sl_offset); title('offset'); legend('offset'); grid; + +figure; +subplot(2,1,1) +plot(1:length(sl_err), sl_err); title('error'); legend('error'); grid; +subplot(2,1,2) +plot(1:length(sl_nsym_ist), sl_nsym_ist, 1:length(sl_nsym_ist), nsym_soll*ones(size(sl_nsym_ist))); title('Tracking'); legend('nsym_{ist}', 'nsym_{soll}'); grid; + +figure +plot(1:length(phi_c), phi_c, 1:length(phi_f1), phi_f1, 1:length(phi_f2), phi_f2, 1:length(phi_f3), phi_f3); grid; legend('phi_{c}', 'phi_{f1}', 'phi_{f2}', 'phi_{f3}'); title('Phase'); + +% custom function +% Correlation +function [ccm, imax, jmax, xo] = xcc(x, Ns, Ng, i_low, i_high, j_low, j_high, xi) + +Nu = Ns - Ng; +off = length(xi); + +xo = x(length(x)-off+1:length(x)); +xs = [xi' x']'; + +ccm = 0; +imax = 0; +jmax = 0; +for i_off=i_low:i_high, + ii = off+i_off+1:off+Ng+i_off; + xm_i = mean(xs(ii)); + xi = xs(ii)-xm_i; + var_i = var(xi); + for j_off=j_low:j_high, + jj = off+Nu+j_off+1:off+Nu+Ng+j_off; + xm_j = mean(xs(jj)); + xj = xs(jj) - xm_j; + var_j = var(xj); + cc = sum(xi.*xj)./sqrt(var_i*var_j); + if (cc > ccm) + imax = i_off; + jmax = j_off; + ccm = cc; + end; + end; +end; + diff --git a/ofdm/ofdm_tx.m b/ofdm/ofdm_tx.m index ceea0b5..7486929 100644 --- a/ofdm/ofdm_tx.m +++ b/ofdm/ofdm_tx.m @@ -1,9 +1,9 @@ -% function ofdm_tx(N_data) -function yv = ofdm_tx(N_data) +% function ofdm_tx(N_frames) +function [yv xv] = ofdm_tx(N_frames) -j = sqrt(-1); -WORK_BANDPASS = 1; -do_evaluate = 0; +WITH_DATA = 0; +WITH_FREQ_REF = 1; +WITH_TIME_REF = 1; % Params fa = 48000; @@ -12,25 +12,81 @@ F1 = 750; F2 = 2250; F3 = 3000; -N_Carrier = 226; -M_qam = 64; -N_lp = 301; -TSym = 21.3330E-3 -TGrd = 5.333E-3 -TFrm = TSym+TGrd -NGrd = round(TGrd*fa) -NSym = round(TSym*fa) -NFrm = round(TFrm*fa) -N_fft = NSym +SPEC_OCC_4k5 = 1; +SPEC_OCC_5k0 = 2; +SPEC_OCC_9k0 = 3; +SPEC_OCC_10k = 4; +SPEC_OCC_18k = 5; +SPEC_OCC_20k = 6; -bin_c = fix(N_fft*fc/fa)+1; -bin_f1 = fix(N_fft*(fc+F1)/fa)+1; -bin_f2 = fix(N_fft*(fc+F2)/fa)+1; -bin_f3 = fix(N_fft*(fc+F3)/fa)+1; +DRM_MODE_A = 1; +DRM_MODE_B = 2; +DRM_MODE_C = 3; +DRM_MODE_D = 4; +DRM_MODE_E = 5; + +ofdm_spec_occ_drm(DRM_MODE_A, SPEC_OCC_4k5) = struct('kmin', 2, 'kmax', 102); +ofdm_spec_occ_drm(DRM_MODE_A, SPEC_OCC_5k0) = struct('kmin', 2, 'kmax', 114); +ofdm_spec_occ_drm(DRM_MODE_A, SPEC_OCC_9k0) = struct('kmin', -102, 'kmax', 102); +ofdm_spec_occ_drm(DRM_MODE_A, SPEC_OCC_10k) = struct('kmin', -114, 'kmax', 114); +ofdm_spec_occ_drm(DRM_MODE_A, SPEC_OCC_18k) = struct('kmin', - 98, 'kmax', 314); +ofdm_spec_occ_drm(DRM_MODE_A, SPEC_OCC_20k) = struct('kmin', -110, 'kmax', 350); + +ofdm_spec_occ_drm(DRM_MODE_B, SPEC_OCC_4k5) = struct('kmin', 1, 'kmax', 91); +ofdm_spec_occ_drm(DRM_MODE_B, SPEC_OCC_5k0) = struct('kmin', 1, 'kmax', 103); +ofdm_spec_occ_drm(DRM_MODE_B, SPEC_OCC_9k0) = struct('kmin', - 91, 'kmax', 91); +ofdm_spec_occ_drm(DRM_MODE_B, SPEC_OCC_10k) = struct('kmin', -103, 'kmax', 103); +ofdm_spec_occ_drm(DRM_MODE_B, SPEC_OCC_18k) = struct('kmin', - 87, 'kmax', 279); +ofdm_spec_occ_drm(DRM_MODE_B, SPEC_OCC_20k) = struct('kmin', - 99, 'kmax', 311); + +ofdm_spec_occ_drm(DRM_MODE_C, SPEC_OCC_4k5) = struct('kmin', 0, 'kmax', 0); +ofdm_spec_occ_drm(DRM_MODE_C, SPEC_OCC_5k0) = struct('kmin', 0, 'kmax', 0); +ofdm_spec_occ_drm(DRM_MODE_C, SPEC_OCC_9k0) = struct('kmin', 0, 'kmax', 0); +ofdm_spec_occ_drm(DRM_MODE_C, SPEC_OCC_10k) = struct('kmin', - 69, 'kmax', 69); +ofdm_spec_occ_drm(DRM_MODE_C, SPEC_OCC_18k) = struct('kmin', 0, 'kmax', 0); +ofdm_spec_occ_drm(DRM_MODE_C, SPEC_OCC_20k) = struct('kmin', - 67, 'kmax', 213); + +ofdm_spec_occ_drm(DRM_MODE_D, SPEC_OCC_4k5) = struct('kmin', 0, 'kmax', 0); +ofdm_spec_occ_drm(DRM_MODE_D, SPEC_OCC_5k0) = struct('kmin', 0, 'kmax', 0); +ofdm_spec_occ_drm(DRM_MODE_D, SPEC_OCC_9k0) = struct('kmin', 0, 'kmax', 0); +ofdm_spec_occ_drm(DRM_MODE_D, SPEC_OCC_10k) = struct('kmin', - 44, 'kmax', 44); +ofdm_spec_occ_drm(DRM_MODE_D, SPEC_OCC_18k) = struct('kmin', 0, 'kmax', 0); +ofdm_spec_occ_drm(DRM_MODE_D, SPEC_OCC_20k) = struct('kmin', - 43, 'kmax', 135); + +ofdm_spec_occ_drm(DRM_MODE_E, SPEC_OCC_4k5) = struct('kmin', -106, 'kmax', 106); +ofdm_spec_occ_drm(DRM_MODE_E, SPEC_OCC_5k0) = struct('kmin', 0, 'kmax', 0); +ofdm_spec_occ_drm(DRM_MODE_E, SPEC_OCC_9k0) = struct('kmin', 0, 'kmax', 0); +ofdm_spec_occ_drm(DRM_MODE_E, SPEC_OCC_10k) = struct('kmin', 0, 'kmax', 0); +ofdm_spec_occ_drm(DRM_MODE_E, SPEC_OCC_18k) = struct('kmin', 0, 'kmax', 0); +ofdm_spec_occ_drm(DRM_MODE_E, SPEC_OCC_20k) = struct('kmin', 0, 'kmax', 0); + +ofdm_params_drm(DRM_MODE_A) = struct('nu', 288, 'ng', 32, 'nspf', 15); +ofdm_params_drm(DRM_MODE_B) = struct('nu', 256, 'ng', 64, 'nspf', 15); +ofdm_params_drm(DRM_MODE_C) = struct('nu', 176, 'ng', 64, 'nspf', 20); +ofdm_params_drm(DRM_MODE_D) = struct('nu', 112, 'ng', 88, 'nspf', 24); +ofdm_params_drm(DRM_MODE_E) = struct('nu', 27, 'ng', 3, 'nspf', 40); + +ofdm_params = ofdm_params_drm(DRM_MODE_B) +ofdm_spec_occ = ofdm_spec_occ_drm(DRM_MODE_B, SPEC_OCC_10k) + +N_Carrier = 226; +M_qam = 4; +N_lp = 301; +T = 4/fa; +Tu = ofdm_params.nu * T +Tg = ofdm_params.ng * T +Ts = Tu+Tg +Ng = round(Tg*fa) +Nu = round(Tu*fa) +Ns = round(Ts*fa) +N_fft = Nu +SubCarrierspacing_HZ = fa/N_fft + +% TX window +[txwin Nt] = txwin_eval(Nu, Ng, 0.05); % Source qlut = qamtable(M_qam); -s = round(M_qam*rand(N_data,1)+0.5); % Band pass for transmission f_lp = N_Carrier*fa/N_fft @@ -39,64 +95,50 @@ hbp = hbp/sum(hbp.^2).*Hanning(N_lp)'; hlp = sinc((-(N_lp-1)/2:(N_lp-1)/2)*f_lp/fa); hlp = hlp/sum(hlp.^2).*Hanning(N_lp)'; -t = 1; -if (WORK_BANDPASS == 1) - bin_range = N_fft/4-N_Carrier/2:N_fft/4+N_Carrier/2; -else - bin_range = 1:N_Carrier; -end; +k_fft = 2*sqrt(N_fft); +xv = []; +xt = zeros(1, Nt); -N_bins = length(bin_range); -for k=1:N_data/N_bins, - - % DC - X = zeros(N_fft,1); - X(1) = 0; - - for m=1:N_bins, - % Data - X(bin_range(m)) = qlut(s(t)); - t = t + 1; - end; - - % Additional carrier - if (WORK_BANDPASS == 1) - X(bin_c) = 1.0; - X(bin_f1) = 1.0 + j*1.0; - X(bin_f2) = 1.0 - j*1.0; - X(bin_f3) = -1.0 + j*1.0; - end; - - % Make conj. symmetric in F => real in T - X(N_fft:-1:N_fft/2+1) = conj(X(2:N_fft/2+1)); - - % Modulate - x = ifft(X); - xgrd = x(NSym-NGrd+1:NSym); - xt = [xgrd' x']'; - xv((k-1)*(NFrm)+1:k*(NFrm)) = xt; +for k=1:N_frames + for s=0:ofdm_params.nspf-1, - if (do_evaluate == 1) - xf = fft(xt(NGrd+1:NSym+NGrd), N_fft); - plot(xf, '+'); grid; - pause; - end; + X = zeros(N_fft,1); + + % Data + if WITH_DATA == 1 + data_i = c2i(N_fft, ofdm_spec_occ.kmin:1:ofdm_spec_occ.kmax); + X(data_i) = 0.20*qlut(round(M_qam*rand(1, length(data_i))+0.5)); + end; +% X(78) = 0.20*qlut(round(M_qam*rand(1, 1)+0.5)); + if WITH_FREQ_REF == 1 + [ref_i ref_p ref_a] = getRefFreq(N_fft, DRM_MODE_B, s); + X(ref_i) = 0.20*ref_a.*exp(-2*pi*i*ref_p/1024); + end; + + + if (s==0) & (WITH_TIME_REF == 1) + [ref_i ref_p ref_a] = getRefTime(N_fft, DRM_MODE_B); + X(ref_i) = 0.20*ref_a.*exp(-2*pi*i*ref_p/1024); + end; + +% X(1) = 0.2; + + % Modulate + xu = k_fft*ifft(X, N_fft)'; + xs = [xu(Nu-Ng+1:Nu) xu xu(1:Nt)] .* txwin; + xs(1:Nt) = xs(1:Nt) + xt(1:Nt); + xt = xs(Ng+Nu+1:Ng+Nu+Nt); + xv = [xv xs(1:Ng+Nu)]; + end; end; -k_fft = 0.3333*sqrt(N_fft); +% Modulate on carrier +yc = 0.5*exp(-i*2*pi.*(0:length(xv)-1)*fc/fa) .* filter(hlp,1,xv); +yv = real(yc) + imag(yc); -% Pulse shape -if (WORK_BANDPASS == 1) - yv = real(filter(hbp,1,k_fft*xv)); - % yv = k_fft*xv; -else - yc = cos(2*pi*(0:length(xv)-1)*fc/fa); - yF1 = 1.0/N_fft*cos(2*pi*(0:length(xv)-1)*F1/fa); - yF2 = 1.0/N_fft*cos(2*pi*(0:length(xv)-1)*F2/fa); - yF3 = 1.0/N_fft*cos(2*pi*(0:length(xv)-1)*F3/fa); - yv = yc.*(0.025 + filter(hlp,1,k_fft*xv) + yF1 + yF2 + yF3); -end; +xv = xv'; +yv = yv'; % Output close all; @@ -104,4 +146,124 @@ close all; figure; freqz(hlp); -wavwrite(yv,fa,16,'yv.wav') \ No newline at end of file +wavwrite(0.9*yv,fa,16,'yv.wav') +wavwrite(0.9*[real(xv) imag(xv)],fa,16,'xv.wav') + +function index = c2i(N_fft, carriers) + ri = []; + ri = [ri find(carriers == 0)]; + carriers(ri) = []; + index = mod(carriers, 1024) + 1; + +function [ref_i ref_p ref_a] = getRefFreq(N_fft, drmMode, s) + +ref_A_c = [18 54 72]; +ref_A_p = [205 836 215]; +ref_A_a = sqrt(2)*ones(1,3); + + +ref_B_c = [16 48 64]; +ref_B_p = [331 651 555]; +ref_B_a = sqrt(2)*ones(1,3); + +ref_C_c = [11 33 44]; +ref_C_p = [214 392 242]; +ref_C_a = sqrt(2)*ones(1,3); + +ref_D_c = [ 7 21 28]; +ref_D_p = [788 1014 332]; +ref_D_a = sqrt(2)*ones(1,3); + +ref_E_c = []; +ref_E_p = []; +ref_E_a = []; + +switch drmMode + case 1 + ref_i = c2i(N_fft, ref_A_c); + ref_p = ref_A_p; + ref_a = ref_A_a; + + case 2 + ref_i = c2i(N_fft, ref_B_c); + ref_p = ref_B_p; + ref_a = ref_B_a; + + case 3 + ref_i = c2i(N_fft, ref_C_c); + ref_p = ref_C_p; + ref_a = ref_C_a; + + case 4 + ref_i = c2i(N_fft, ref_D_c); + ref_p = ref_D_p; + ref_a = ref_D_a; + + case 5 + ref_i = c2i(N_fft, ref_E_c); + ref_p = ref_E_p; + ref_a = ref_E_a; +end; + +function [ref_i ref_p ref_a] = getRefTime(N_fft, drmMode) + +ref_B_c = [14 18 20 24 26 32 36 42 44 49 50 54 56 62 66 68]; +ref_B_p = [304 108 620 192 704 44 432 588 844 651 651 460 460 944 940 428]; +ref_B_a = sqrt(2)*ones(1,16); + +switch drmMode + case 1 + ref_i = []; + ref_p = []; + ref_a = []; + + case 2 + ref_i = c2i(N_fft, ref_B_c); + ref_p = ref_B_p; + ref_a = ref_B_a; + + case 3 + ref_i = []; + ref_p = []; + ref_a = []; + + case 4 + ref_i = []; + ref_p = []; + ref_a = []; + + case 5 + ref_i = []; + ref_p = []; + ref_a = []; +end; + +function [ref_i ref_p ref_a] = getRefGain(N_fft, spec_occ, drmMode, s) +switch drmMode + case 1 + ref_c = []; + ref_p = []; + ref_a = []; + + case 2 + ref_c = 1 + 2*mod(s,3)+6*(spec_occ.kmin:1:spec_occ.kmax); + ref_i = c2i(N_fft, ref_c); + ref_p = ref_B_p; + ref_a = sqrt(2)*ones(1,length(ref_i)); + + case 3 + ref_c = []; + ref_p = []; + ref_a = []; + + case 4 + ref_c = []; + ref_p = []; + ref_a = []; + + case 5 + ref_c = []; + ref_p = []; + ref_a = []; +end; + diff --git a/ofdm/txwin_eval.m b/ofdm/txwin_eval.m new file mode 100644 index 0000000..871120d --- /dev/null +++ b/ofdm/txwin_eval.m @@ -0,0 +1,10 @@ +function [p Nt] = txwin_eval(Nu, Ng, Alpha) + +Nfft = Nu; % FFT size +CP = Ng; % Nb. samples in Cyclic Prefix +%Alpha = 1/32; % RX Alpha +Nt = 2*round(Nfft*Alpha/2); % Nb. samples in taper region +p = 1/2*(1+cos(pi*[-Nt+1/2:Nt-1/2]/Nt)); % Raised-Cosine in TD +p = [p(1:Nt), ones(1,Nfft+CP-Nt), p(Nt+1:2*Nt)]; % Add ones in middle + +