diff --git a/common/radio/CalcSincFilter.m b/common/radio/CalcSincFilter.m new file mode 100755 index 0000000..cbd2f07 --- /dev/null +++ b/common/radio/CalcSincFilter.m @@ -0,0 +1,4 @@ +function y = CalcSincFilter(scale, freq, N) + +t = linspace(-(N-1)/2, (N-1)/2, N); +y = scale*sinc(freq*t); diff --git a/common/radio/FIRCalcBandpass.m b/common/radio/FIRCalcBandpass.m new file mode 100755 index 0000000..cb124dc --- /dev/null +++ b/common/radio/FIRCalcBandpass.m @@ -0,0 +1,5 @@ +function y = FIRCalcBandpass(omega, bw, N); +% +% y = FIRCalcLowpass(omega, N); + +y = CalcSincFilter(bw, bw, N).*wkaiser(N, 8.0).*cos(2*pi*omega.*(0:N-1)); diff --git a/common/radio/FIRCalcHighpass.m b/common/radio/FIRCalcHighpass.m new file mode 100755 index 0000000..039132c --- /dev/null +++ b/common/radio/FIRCalcHighpass.m @@ -0,0 +1,14 @@ +function y = FIRCalcHighpass(omega, N); +% +% y = FIRCalcHighpass(omega, N); + +y_lp = CalcSincFilter(omega, omega, N); +y_hp = -y_lp; + +if mod(N, 2) == 0 + error ('Even N is not supported'); +else + y_hp((N-1)/2+1) = 1 + y_hp((N-1)/2+1); +end + +y = (y_hp).*wkaiser(N, 8.0); diff --git a/common/radio/FIRCalcLowpass.m b/common/radio/FIRCalcLowpass.m new file mode 100755 index 0000000..eccc337 --- /dev/null +++ b/common/radio/FIRCalcLowpass.m @@ -0,0 +1,5 @@ +function y = FIRCalcLowpass(omega, N); +% +% y = FIRCalcLowpass(omega, N); + +y = CalcSincFilter(omega, omega, N).*wkaiser(N, 8.0); diff --git a/common/radio/agc_eval.m b/common/radio/agc_eval.m new file mode 100755 index 0000000..ff91a5f --- /dev/null +++ b/common/radio/agc_eval.m @@ -0,0 +1,30 @@ +function agc_eval() +% +% Super peak-based AGC + +N = 2000; +k_noise = 1E-3; + +t = (0:N-1)/N; +x = sin(100*pi*t) + k_noise*randn(1, N); +w = 1; +K = 2; +mu = 0.01; + +max1 = maxlist_filterstate(1000, 1E12, 1); + +for n=1:N, + d1 = w*x(n); + [d2, max1] = maxlist_filter(d1, max1); + e = K - d2; + w = w + mu*e*abs(x(n)); + d1_(n) = d1; + e_(n) = e; +end; + +subplot(3, 1, 1) +plot(t, x); grid; legend('x'); +subplot(3, 1, 2) +plot(t, d1_); grid; legend('d_{1}'); +subplot(3, 1, 3) +plot(t, 20*log10(abs(e_)+1e-12)); legend('20*log10(error)'); grid; diff --git a/common/radio/calcfir_srrc.m b/common/radio/calcfir_srrc.m new file mode 100755 index 0000000..b3b6b77 --- /dev/null +++ b/common/radio/calcfir_srrc.m @@ -0,0 +1,27 @@ +function [b, kn] = calcfir_srrc(fa, Tsym, a, N) + +if mod(N,2) ~= 0 + delay = (N-1)/2; +else + delay = N/2; +end + +k = sqrt(2/Tsym); +k0 = 0.5*Tsym*fa; +kn = 1/k0; + +for n=0:N-1, + phi = (n-delay)/fa; + if phi == 0.0 + b(n+1) = -k * (pi*(a-1.0) - 4*a) /(pi*fa); + else + if abs(abs(8*a*phi/Tsym) - 1.0) < sqrt(eps) + b(n+1) = k / (2*pi*fa) * (pi*(a+1.0) * sin(pi*(a+1.0)/(4*a)) - 4*a * sin(pi*(a-1.0)/(4*a)) + pi*(a-1.0) * cos(pi*(a-1.0)/(4*a))); + else + term = 8*a*phi/Tsym; + b(n+1) = -4*a/fa * ( cos((1.0+a)*2*pi*phi/Tsym) + sin((1.0-a)*2*pi*phi/Tsym) / (8*a*phi/Tsym)) / (pi * sqrt(1.0/(2/Tsym)) * (term*term - 1.0)); + end + end + b(n+1) = b(n+1) * k * k0; +end; + diff --git a/common/radio/decim_eval.m b/common/radio/decim_eval.m new file mode 100755 index 0000000..0f70b35 --- /dev/null +++ b/common/radio/decim_eval.m @@ -0,0 +1,30 @@ +function y2 = decim_eval(N, M) + +x = [1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0]; +x = randn(1, 1000); +x = 1:20; +w = FIRCalcLowpass(0.5, N); +w = 1:N; + +y = filter(w, 1, x)'; +y_dec = y(1:M:lge(y)) +y_dec2 = decim(w, M, N, x)' + +y2 = y_dec2 - y_dec; + +function [y] = decim(w, M, N, x) +Nout = lge(x(1:M:lge(x))); + +for k=0:M-1 + nz = fix(k/M) + (k > 0); + d = (M-k) * (k > 0); + xp = [zeros(1, nz) x(d+1:M:lge(x))] +% xp = [zeros(1, k) x]; +% xp = xp(1:M:lge(x)) + wp = w(k+1:M:N); + yp = filter(wp, 1, xp); + summer(k+1, :) = yp(1:Nout); +end; +y = sum(summer, 1); + +return; diff --git a/common/radio/downconvert.m b/common/radio/downconvert.m new file mode 100755 index 0000000..8e13ceb --- /dev/null +++ b/common/radio/downconvert.m @@ -0,0 +1,27 @@ +function downconvert() +omega_lp = 0.48; +N_lp = 101; + +N = 10000; +w = 2*pi; +n = (0:N-1); + +rf = 0.4*cos(0.25*w*n); +lo_r = cos(0.25*w*n); +lo_i = -sin(0.25*w*n); +w_lp = FIRCalcLowpass(omega_lp, N_lp); + +im = 2*rf .*lo_r + i*2*rf.*lo_i; +im_f = filter(w_lp, 1, real(im)) + i*filter(w_lp, 1, imag(im)); + +subplot(2, 1, 1) +plot(n, rf, '-*'); grid; +axis ([0 N-1 -1 1]); + +subplot(2, 1, 2) +plot(n, real(im_f), '-*', n, imag(im_f), '-*'); grid; +axis ([0 N-1 -1 1]); + +wavwrite(rf, 48000, 16, 'ddc_rf.wav'); +wavwrite(im, 48000, 16, 'ddc_im.wav'); +wavwrite(im_f, 48000, 16, 'ddc_imf.wav'); diff --git a/common/radio/eval_farrow.m b/common/radio/eval_farrow.m new file mode 100755 index 0000000..730dffe --- /dev/null +++ b/common/radio/eval_farrow.m @@ -0,0 +1,79 @@ +function P = eval_farrow() +M = 5; +Nb = 33; +R = 32; +Np = R*(Nb+1); +sr = 1; +SRRC_ROLLOFF = 0.35; +nsamplespersym = 2; + +if (mod(Nb, 2) ~= 0) + offset = R/2; +else + offset = R/2; +end; +% Simulation +Ni = 1000; + +close all; + +[hp, kn] = calcfir_srrc(R*nsamplespersym*sr, 2/sr, SRRC_ROLLOFF, Np); +hp = R*kn*hp; %.*kaiser(Np, 8)'; +%hp = gen_basefir(N, R, 0.125).*hann(R*N+1)'; + +hb = hp(offset+1:R:Np); +freqz(hb); + +P = fir_polyfit(M, R, hp, Nb, offset); + +for k=1:Nb, + pv((k-1)*Ni+1:k*Ni) = polyval(P(k,:), (0:Ni-1)/Ni); +end; + +figure; +plot(offset:R:Np-1, hb, 'ro', 0:Np-1, hp, 'b+', R*(0:Nb*Ni-1)/Ni, pv, 'g-'); +legend('Base FIR', 'Prototype FIR', 'Interpolation'); +grid; + +for pp=1:M, + figure; + pt = sprintf('C_{%d}', M-pp); + plot(0:Nb-1, P(1:Nb, pp)); + title(pt); + grid on; +end; + +Nd = 11; +x = [1 zeros(1, Nb)]; +for d=1:Nd, + mu(d) = (Nd-d)/(Nd-1); + y(d,:) = farrow(x, P, mu(d)); +end; + +figure; +for d=0:R + plot(hp(offset+1+d:R:offset+R*Nb+d)); grid on; hold on; +end + +figure; + +for d=1:Nd, + pt = sprintf('mu = %f', mu(d)); + plot(y(d,:)); grid on; hold on; +% freqz(y(d,:)); + legend(pt); + F(d) = getframe; +end; + +fid = fopen('farrow_coeff.dat','wb'); + +fwrite(fid,M,'uint'); +fwrite(fid,Nb,'uint'); +fwrite(fid,P,'float'); + +fclose(fid); +%for mm=1:M + % for nn=1:Nb + + +movie(F,3, 12) \ No newline at end of file diff --git a/common/radio/farrow.m b/common/radio/farrow.m new file mode 100755 index 0000000..e3c510a --- /dev/null +++ b/common/radio/farrow.m @@ -0,0 +1,26 @@ +function y = farrow(x, P, mu) + +D = size(P); +N = D(1); +M = D(2); + +% Partial filter responses +for pp=1:M, + hp(pp, :) = filter(P(1:N, pp), 1, x); +end; + +h = hp'; +% Combine +for k=1:length(x), + y(k) = horner(h(k,:), mu); +end; + +function y = horner(a,x) + % Input a is the polynomial coefficient vector, x the value to be evaluated at. + % The output y is the evaluated polynomial and b the divided coefficient vector. + b(1) = a(1); + for i = 2:length(a) + b(i) = a(i)+x*b(i-1); + end + y = b(length(a)); + b = b(1:length(b)-1); diff --git a/common/radio/fir_polyfit.m b/common/radio/fir_polyfit.m new file mode 100755 index 0000000..53ec88e --- /dev/null +++ b/common/radio/fir_polyfit.m @@ -0,0 +1,8 @@ +function P = fir_polyfit(M, R, hp, Nb, offset) + +Np = length(hp); +order = M - 1; + +for k=1:Nb, + P(k,:) = polyfit((0:R)/R, hp(offset+(k-1)*R+1:offset+k*R+1), order); +end; diff --git a/common/radio/fse_eval.m b/common/radio/fse_eval.m new file mode 100755 index 0000000..1d5a4f3 --- /dev/null +++ b/common/radio/fse_eval.m @@ -0,0 +1,55 @@ +function fse_eval() + +N = 7; +M = 2; +L = 5000; +mu = 0.05; + +% Model source +j = sqrt(-1); +s(1:2:L) = 0.5-(rand(L/2,1)) + (0.5-(rand(L/2,1)))*j; +s(2:2:L) = 2*(0.5-round(rand(L/2,1))) + 2*(0.5-round(rand(L/2,1)))*j; +s = 1/sqrt(2)*s'; + + +% Model channel +cb = 1; +ca = [1 0.7]; +hd = zeros(N,1); +hd(fix(N/2)) = 1; + +% Filter source +r = [zeros(1,N-1) filter(cb,ca,s)']'; +awgn = 2*(0.5-randn(L+N-1,1)) + 2*(0.5-randn(L+N-1,1))*j; +r = r + 0.0004*awgn; +f = [0 zeros(1, N-1)]'; +d = filter(hd,1,s(2:M:L)); + +k = 0; +for n=1:M:L-N + k = k + 1; + x = r(N+n-1:-1:n); + y(k) = f'*x; + e(k) = d(k) - y(k); + f = f + mu*conj(e(k))*x; +end; +ss = filter(f,1,r); + +close all; +figure(1) +plot(abs(e)) +grid + +figure(2) +plot(r,'g+') +hold on +plot(ss,'bx') +plot(s,'ro') +hold off +grid + +figure(3) +plot(1:k, abs(y)); +grid + +f \ No newline at end of file diff --git a/common/radio/interpol_eval.m b/common/radio/interpol_eval.m new file mode 100755 index 0000000..c3e75ec --- /dev/null +++ b/common/radio/interpol_eval.m @@ -0,0 +1,32 @@ +function interpol_eval(N, L) + +x = [0 1 0 0]; +x_int = []; + +for i=1:lge(x) + x_int = [x_int x(i) zeros(1, L-1)]; +end; + +if mod(N, 2) == 0 + LN = L*N; +else + LN = L*(N-1)+1; +end + +w = FIRCalcLowpass(0.35, LN); +w = 1:LN; + +y_int = filter(w, 1, x_int)' + +y_int2 = interpol(w, L, LN, x)' + +function [y] = interpol(w, L, N, x) +Nout = L*lge(x); + +for k=0:L-1 + wp = w((L-k-1)+1:L:N); + yp = filter(wp, 1, x)'; + y((L-k-1)+1:L:Nout) = yp; +end; + +return; diff --git a/common/radio/lagrange.m b/common/radio/lagrange.m new file mode 100755 index 0000000..b04f730 --- /dev/null +++ b/common/radio/lagrange.m @@ -0,0 +1,20 @@ +function lgip(order) + +Nlg = order + 1; +Npts = 11; +t = Nlg/2 + ((0:Npts-1)/(Npts-1)-0.5) +xk = [0 0.5 0]; +for k=1:Npts, + y(k) = 0; + for i=0:Nlg-1, + hlg = 1; + for j=0:Nlg-1, + if (i ~= j) + hlg = hlg * (t(k) - j)/((i)-(j)); + end; + end; + y(k) = y(k) + xk(i+1) * hlg; + end; +end; +plot(y); grid; + diff --git a/common/radio/lgip.m b/common/radio/lgip.m new file mode 100755 index 0000000..c7ce6ac --- /dev/null +++ b/common/radio/lgip.m @@ -0,0 +1,20 @@ +function lgip(order) + +Nlg = order + 1; +Npts = 100; +t = (0:Npts-1)/Npts; +xk = [0 0.5 0]; +for k=1:Npts, + y(k) = 0; + for i=0:Nlg-1, + hlg = 1; + for j=0:Nlg-1, + if (i ~= j) + hlg = hlg * (Nlg/2 - 0.5 + t(k) - j)/(i-j); + end; + end; + y(k) = y(k) + xk(i+1) * hlg; + end; +end; +plot(t, y); grid; + diff --git a/common/radio/maxlist.m b/common/radio/maxlist.m new file mode 100755 index 0000000..ea21f10 --- /dev/null +++ b/common/radio/maxlist.m @@ -0,0 +1,46 @@ +function [xmax lsize] = maxlist(x, L, L_max, mode) + +P = 1E24; +u = zeros(L, 1); +p = zeros(L, 1); +u_last = zeros(L, 1); +p_last = zeros(L, 1); + +OFF = 1; + +u_last(1 + OFF) = P; +u_last(0 + OFF) = 0; +p_last(0 + OFF) = 0 + OFF; +N = 0 + OFF; + +x = mode*x; + +for k=1:lge(x), + if (p_last(N) == (L + OFF)) + m = 0; + u_last(N) = P; + else + m = 1; + end + N = min(L_max, N + m); + + ii = 0; + while x(k) >= u_last(ii+1+OFF) + ii = ii + 1; + end + N = N - ii; + + for jj=(1 + OFF):(N -1) + u(jj+1) = u_last(jj+ii); + p(jj+1) = p_last(jj+ii) + 1; + end + u(N+1) = P; + p(N+1) = 0; + u(1 + OFF) = x(k); + p(1 + OFF) = 1 + OFF; + xmax(k) = mode*u(N); + pmax = p(N); + lsize(k) = find(u == P, 1); + u_last(1:lsize(k)) = u(1:lsize(k)); + p_last(1:lsize(k)) = p(1:lsize(k)); +end; diff --git a/common/radio/maxlist_eval.m b/common/radio/maxlist_eval.m new file mode 100755 index 0000000..a7b860d --- /dev/null +++ b/common/radio/maxlist_eval.m @@ -0,0 +1,51 @@ +function [xmin, xmax] = maxlist_eval(x, L) + +mode = 1; +for s=1:2 + mode = -mode; + + P = mode*1234; + u = zeros(L, 1); + p = zeros(L, 1); + u_last = zeros(L, 1); + p_last = zeros(L, 1); + + OFF = 1; + + u_last(1 + OFF) = P; + u_last(0 + OFF) = 0; + p_last(0 + OFF) = 0 + OFF; + N = 0 + OFF; + + for k=1:lge(x), + if (p_last(N) == (L + OFF)) + m = 0; + u_last(N) = P; + else + m = 1; + end + + ii = 0; + while mode*x(k) >= mode*u_last(ii+1+OFF) + ii = ii + 1; + end + N = N - ii + m; + + for jj=(1 + OFF):(N -1) + u(jj+1) = u_last(jj+ii); + p(jj+1) = p_last(jj+ii) + 1; + end + u(N+1) = P; + u(1 + OFF) = x(k); + p(1 + OFF) = 1 + OFF; + u_last = u; + p_last = p; + if (mode < 0) + xmin(k) = u(N); + pmmin = p(N); + else + xmax(k) = u(N); + pmax = p(N); + end + end; +end; diff --git a/common/radio/maxlist_filter.m b/common/radio/maxlist_filter.m new file mode 100755 index 0000000..ed3a09b --- /dev/null +++ b/common/radio/maxlist_filter.m @@ -0,0 +1,30 @@ +function [xmax,zf] = maxlist_filter(x, zi) + +OFF = 1; +x = zi.mode*x; + +m = 1; +if (zi.p_last(zi.N) == (zi.L + OFF)) + m = 0; + zi.u_last(zi.N) = zi.P; +end + +ii = 0; +while x >= zi.u_last(ii+1+OFF) + ii = ii + 1; +end +zi.N = zi.N - ii + m; + +for jj=(1 + OFF):(zi.N -1) + zi.u(jj+1) = zi.u_last(jj+ii); + zi.p(jj+1) = zi.p_last(jj+ii) + 1; +end +zi.u(zi.N+1) = zi.P; +zi.p(zi.N+1) = 0; +zi.u(1 + OFF) = x; +zi.p(1 + OFF) = 1 + OFF; +lsize = find(zi.u == zi.P, 1); +zi.u_last(1:lsize) = zi.u(1:lsize); +zi.p_last(1:lsize) = zi.p(1:lsize); +xmax = zi.mode*zi.u(zi.N); +zf = zi; diff --git a/common/radio/maxlist_filterstate.m b/common/radio/maxlist_filterstate.m new file mode 100755 index 0000000..c7ca10a --- /dev/null +++ b/common/radio/maxlist_filterstate.m @@ -0,0 +1,18 @@ +function s = maxlist_filterstate(L, P, mode) +s = struct('p', 'u', 'p_last', 'u_last', 'N', 'L', 'P', 'mode'); + +OFF = 1; + +s.p = zeros(L, 1); +s.u = zeros(L, 1); +s.p_last = zeros(L, 1); +s.u_last = zeros(L, 1); + +s.u_last(1 + OFF) = P; +s.u_last(0 + OFF) = 0; +s.p_last(0 + OFF) = 0 + OFF; +s.N = 0 + OFF; + +s.L = L; +s.P = P; +s.mode = mode; \ No newline at end of file diff --git a/common/radio/pmf_eval.m b/common/radio/pmf_eval.m new file mode 100755 index 0000000..827842e --- /dev/null +++ b/common/radio/pmf_eval.m @@ -0,0 +1,27 @@ +% function pmf_eval(M, mu) + +function pmf_eval(M, mu) + +% Symbol rate +fs = 6000; +Ts = 1/fs; + +% Samples per symbol +N = 4; + +% Number of polyphase taps +Nh1 = 31 + +% Polyphase upconversion +Nh2 = M*(Nh1+0) + +h1 = firrcos(Nh1, 1/Ts, 0.35, N*fs, 'rolloff'); +h2 = M*firrcos(Nh2, 1/Ts, 0.35, M*N*fs, 'rolloff'); +index = mod(mu,M); + +h2a = h2(1+index:M:Nh2); +nh2a = length(h2a) +close all; +sum(h1) +plot(1:Nh1, h1(1:Nh1), '-x', 1:nh2a, h2a(1:nh2a), '-o'); +grid; diff --git a/common/radio/pointtracker_eval.m b/common/radio/pointtracker_eval.m new file mode 100755 index 0000000..e8c9b75 --- /dev/null +++ b/common/radio/pointtracker_eval.m @@ -0,0 +1,24 @@ +function pointtracker_eval() + +N = 10000; + +mu = 0.5; + +variance = 0.01; +IQ = [0.707; 0.707]; +IQ_n = repmat(IQ, 1, N) + variance*randn(2,N)/sqrt(12); +size(IQ_n) +ref = [1; 1]; + +for n=1:N, + d(n) = sqrt(sum((IQ_n(n) - ref).^2)); + ref = ref + mu*(IQ_n(n)-ref); +end; + +ref +close all; +plot(IQ_n(1,:), IQ_n(2,:), '.', ref(1), ref(2), 'r.'); grid; + +figure; + +plot(1:N, d); grid; \ No newline at end of file diff --git a/common/radio/qtbl.m b/common/radio/qtbl.m new file mode 100755 index 0000000..1d2bb78 --- /dev/null +++ b/common/radio/qtbl.m @@ -0,0 +1,46 @@ +function qtbl(N) + +j = sqrt(-1); +signI = [+1 -1 -1 +1] +signQ = [+1 +1 -1 -1] +rot = pi/4; +Ns = sqrt(N) +Nq = N/4 +Nsq = sqrt(Nq) +stepIQ = sqrt(2)/(Ns-1) + + +qq = 1/sqrt(2); +ii = 1/sqrt(2); + +even = 1; +c = 1; +close all; +figure(1); +axis ([-1 1 -1 1]); +grid; +hold; +for m=1:Nsq + for n=1:Nsq + I = ii; + Q = qq; + for q = 0:3, + IQ(Nq*q+c) = I*signI(q+1) + j*Q*signQ(q+1); + T = I; + I = Q; + Q = T; + end; + ii = ii - even*stepIQ; + c = c + 1; + end; + qq = qq - stepIQ; + ii = ii + even*stepIQ; + even = -even; +end; + +for c=1:N, +sym = c - 1 + plot(IQ(c), '+'); + pause; +end; +IQ diff --git a/common/radio/result_rx.m b/common/radio/result_rx.m new file mode 100755 index 0000000..98ef316 --- /dev/null +++ b/common/radio/result_rx.m @@ -0,0 +1,380 @@ +% dpll.m +% +% dpll(fa, fc, sr, mode, file, do_plot) +% Example: dpll(48000, 12000, 6000, 'Costas', 'qam.dat', 1); +% Mode : Normal | Costas + +function result_rx(name) + +plot_psd = 0; +do_plot = 1; +fa = 48000; +file = sprintf('%s_rf.dat',name); + +fid = fopen(file,'r'); +m = fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_bitclk.dat'],'r'); +bitClk= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_modulus.dat'],'r'); +modulus= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_softsym_eq_i.dat'],'r'); +softsym_eq_i= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_softsym_eq_q.dat'],'r'); +softsym_eq_q= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_softsym_i.dat'],'r'); +softsym_i= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_softsym_q.dat'],'r'); +softsym_q= fread(fid, 'float32'); +fclose(fid); + +softsym_eq = softsym_eq_i + i*softsym_eq_q; +softsym = softsym_i + i*softsym_q; + +close all; + +if (do_plot) + +fid = fopen([name '_symstat_p.dat'],'r'); +symstat_p = fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_symstat_err_mag.dat'],'r'); +symstat_err_mag = fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_symstat_err_phi.dat'],'r'); +symstat_err_phi = fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_loi.dat'],'r'); +lo_I = fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_loq.dat'],'r'); +lo_Q = fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_i.dat'],'r'); +I = fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_q.dat'],'r'); +Q = fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_if.dat'],'r'); +IF = fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_qf.dat'],'r'); +QF= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_ircf.dat'],'r'); +IRCF = fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_qrcf.dat'],'r'); +QRCF= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_ircf_rm.dat'],'r'); +IRCF_RM = fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_qrcf_rm.dat'],'r'); +QRCF_RM= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_ted.dat'],'r'); +TED= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_perr.dat'],'r'); +perr= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_domega.dat'],'r'); +dOmega = fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_agc_mag.dat'],'r'); +agc_mag = fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_agc_bal.dat'],'r'); +agc_bal = fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_pwr_I.dat'],'r'); +pwr_I = fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_pwr_Q.dat'],'r'); +pwr_Q = fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_vco_lock.dat'],'r'); +vco_lock= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_str_lock.dat'],'r'); +str_lock= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_vld_var1.dat'],'r'); +vld_var1= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_vld_var2.dat'],'r'); +vld_var2= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_domega.dat'],'r'); +domega_nco= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_cma_i.dat'],'r'); +cma_i= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_cma_q.dat'],'r'); +cma_q= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_cma_eq_i.dat'],'r'); +cma_eq_i= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_cma_eq_q.dat'],'r'); +cma_eq_q= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_cef_real.dat'],'r'); +cef_r= fread(fid, 'float32'); +fclose(fid); + +fid = fopen([name '_cef_imag.dat'],'r'); +cef_i= fread(fid, 'float32'); +fclose(fid); + +cef = cef_r + i*cef_i; + +fid = fopen([name '_impulse_armfilter.dat'],'r'); +armfilter = fread(fid, 1024, 'float32'); +fclose(fid); + +N = lge(m); +K = lge(lo_I); +S = lge(perr); +nSymbols = length(softsym_eq); + +plot(0:length(cef)-1, real(cef), 0:length(cef)-1, imag(cef)); +legend('Real','Imag'); +grid; +figure; + +freqz(abs(cef)); +figure; +subplot(2,1,1) +plot(1:K,lo_I,'b',1:K,lo_Q,'g'); +legend('Local Osc I','Local Osc Q'); +grid; + +subplot(2,1,2) +plot(1:S,dOmega,'r'); +legend('dOmega'); +xlabel('n'); +ylabel('-'); +grid; + +figure; +freqz(armfilter'); +title('Arm filter I'); + +figure +subplot(3,1,1) +plot(1:S, agc_mag, 'b', 1:S, agc_bal, 'g', 1:S, min(2, pwr_I./pwr_Q), 'r') +legend('AGC gain','AGC err', 'AGC I/Q'); +grid; + +subplot(3,1,2) +plot(1:S, vld_var1, 'b-', 1:S, vld_var2, 'g-'); +legend('Magnitude noise','Phase noise'); +ylabel('dB'); +grid; + +subplot(3,1,3) +plot(1:S, 0.99*vco_lock, 'b-',1:S, 0.99*str_lock, 'g-'); +legend('VCO Lock','STR Lock'); +grid; + +slices = find(bitClk); +n_slices = length(slices); +bc_amp_i = bitClk(slices).*IRCF(slices); +bc_amp_q = bitClk(slices).*QRCF(slices); + +figure +subplot(3,1,1) +plot(1:K,IRCF ,'b',1:K,QRCF ,'g',slices,bc_amp_i,'r+',slices,bc_amp_q,'ro'); +legend('Resampled I','Resampled Q','Clock','Clock'); +grid; + +subplot(3,1,2) +plot(1:K,TED ,'b'); +legend('TED_{n}'); +grid; + +subplot(3,1,3) +plot(1:K,QRCF_RM ,'g',1:K,IRCF_RM ,'b'); +legend('mu', 'm_{n}'); +grid; + +%figure +%len_w = length(cef_w); +%plot(0:len_w-1, cef_w); +%title('Channel Estimation Filter Weights'); +%xlabel('n'); +%grid; + +figure +subplot(3,1,1) +plot(1:S, cma_eq_i, 1:S, cma_i); +title('SNR'); +legend('Online', 'Offline'); +grid; +subplot(3,1,2) +plot(1:S, cma_eq_q, 'b-', 1:S, cma_q, 'r-'); +title('CEF SNR Distance'); +legend('Distance','Updates'); +grid; +subplot(3,1,3) +plot(1:S,perr); +title('Phase error'); +xlabel('n'); +legend('Phi(Err_{I},Err_{Q})'); +grid; + +figure; +subplot(2,1,1) +plot(1:lge(modulus),modulus); +title('Modulus'); +xlabel('n'); +legend('Modulus'); +grid; +subplot(2,1,2) +bar(hist(modulus, 20)); +title('Hist'); +xlabel('Magnitude'); +legend('Hist'); +grid; + +figure; +plot_range = fix(length(softsym_eq)/2+1):length(softsym_eq); +%plot(IRCF + i* QRCF,'cx'); +hold on; +plot(softsym(plot_range), 'cx') +plot(softsym_eq(plot_range), 'bx') +hold off; +title('Diagram demodulated data') +axis([-1.0 1.0 -1.0 1.0]); +xlabel('Re(mod)'); +ylabel('Im(mod)'); +grid; + +mean2 = mean(abs(softsym_eq(plot_range)).^2); +mean4 = mean(abs(softsym_eq(plot_range)).^4); +R2 = mean4/mean2; +R4 = mean4/(mean2*mean2); + +mean_soft_i = mean(real(softsym)) +mean_soft_q = mean(imag(softsym)) +mean_soft_eq_i = mean(real(softsym_eq)) +mean_soft_eq_q = mean(imag(softsym_eq)) + +figure; +nConst = length(symstat_p); + +subplot(3,1,1), +bar(0:nConst-1, symstat_p); +axis([0 nConst-1 0 1.1*max(symstat_p)]); +title('Symbol Probability'); +grid; + +subplot(3,1,2), +bar(0:nConst-1, symstat_err_mag); +axis([0 nConst-1 0 1.1*max(symstat_err_mag)]); +title('Symbol Magnitude Error'); +grid; + +subplot(3,1,3), +bar(0:nConst-1, symstat_err_phi); +axis([0 nConst-1 0 1.1*max(symstat_err_phi)]); +title('Symbol Phase Error'); +xlabel('Symbol'); +ylabel('rad'); +grid; + +if(plot_psd == 1) + figure; + lenI = length(I); + lenQ = length(Q); + lenI_fft = length(fix(lenI/2):fix(3*lenI/4)); + lenQ_fft = length(fix(lenQ/2):fix(3*lenQ/4)); + lenI_f = fix(lenI_fft/2); + lenQ_f = fix(lenQ_fft/2); + I_f = 1/sqrt(lenI_fft)*abs(fft(I(fix(lenI/2):fix(3*lenI/4)))); + Q_f = 1/sqrt(lenQ_fft)*abs(fft(Q(fix(lenQ/2):fix(3*lenQ/4)))); + plot(fa*(0:lenI_f-1)/lenI_fft, 10*log10(I_f(1:lenI_f).^2),fa*(0:lenQ_f-1)/lenQ_fft, 10*log10(Q_f(1:lenQ_f).^2)); + title('Power Spectral Density of baseband before arm filters'); + xlabel('f'); + ylabel('dB'); + legend('I-Channel','Q-Channel'); + grid; + + figure; + lenIF = length(IF); + lenQF = length(QF); + lenIF_fft = length(fix(lenIF/2):fix(3*lenIF/4)); + lenQF_fft = length(fix(lenQF/2):fix(3*lenQF/4)); + lenIF_f = fix(lenIF_fft/2); + lenQF_f = fix(lenQF_fft/2); + IF_f = 1/sqrt(lenIF_fft)*abs(fft(IF(fix(lenIF/2):fix(3*lenIF/4)))); + QF_f = 1/sqrt(lenQF_fft)*abs(fft(QF(fix(lenQF/2):fix(3*lenQF/4)))); + plot(fa*(0:lenIF_f-1)/lenIF_fft, 10*log10(IF_f(1:lenIF_f).^2),fa*(0:lenQF_f-1)/lenQF_fft, 10*log10(QF_f(1:lenQF_f).^2)); + title('Power Spectral Density of baseband after arm filters'); + xlabel('f'); + ylabel('dB'); + legend('I-Channel','Q-Channel'); + grid; + + figure; + lenIRCF = length(IRCF); + lenQRCF = length(QRCF); + lenIRCF_fft = length(fix(lenIRCF/2):fix(3*lenIRCF/4)); + lenQRCF_fft = length(fix(lenQRCF/2):fix(3*lenQRCF/4)); + lenIRCF_f = fix(lenIRCF_fft/2); + lenQRCF_f = fix(lenQRCF_fft/2); + IRCF_f = 1/sqrt(lenIRCF_fft)*abs(fft(IRCF(fix(lenIRCF/2):fix(3*lenIRCF/4)))); + QRCF_f = 1/sqrt(lenQRCF_fft)*abs(fft(QRCF(fix(lenQRCF/2):fix(3*lenQRCF/4)))); + plot(fa*(0:lenIRCF_f-1)/lenIRCF_fft, 10*log10(IRCF_f(1:lenIRCF_f).^2),fa*(0:lenQRCF_f-1)/lenQRCF_fft, 10*log10(QRCF_f(1:lenQRCF_f).^2)); + title('Power Spectral Density of baseband after matched filters'); + xlabel('f'); + ylabel('dB'); + legend('I-Channel','Q-Channel'); + grid; +end; + +end; \ No newline at end of file diff --git a/common/radio/rx.m b/common/radio/rx.m new file mode 100755 index 0000000..bf723d8 --- /dev/null +++ b/common/radio/rx.m @@ -0,0 +1,40 @@ +% rx(cfg_file, mode) +% + +function rx(name, mode) +cfg_file = [name '.cfg']; + +fid = fopen(cfg_file, 'r'); + +[str] = FGETL(fid); +name = sscanf(str, 'project :%s'); +[str] = FGETL(fid); +fa = sscanf(str, 'fa :%f'); +[str] = FGETL(fid); +fc = sscanf(str, 'fc :%f'); +[str] = FGETL(fid); +sr = sscanf(str, 'sr :%f'); +[str] = FGETL(fid); +nBitsPerSym = sscanf(str, 'nBitsPerSym :%f'); + +fclose(fid); + +commandStr = sprintf('mpsk_rx\\mpsk_rx.exe %g %g %g %d %s %s',fa,fc,sr, nBitsPerSym, mode, name); + +disp(commandStr); +dos(commandStr); + +dat2wav([name '_perr'], 2*sr, 16, 0.95); +dat2wav([name '_domega'], 2*sr, 16, 0.95); +dat2wav([name '_i'], fa, 16, 0.95); +dat2wav([name '_q'], fa, 16, 0.95); +dat2wav([name '_if'], fa, 16, 0.95); +dat2wav([name '_qf'], fa, 16, 0.95); +dat2wav([name '_ircf'], 2*sr, 16, 0.95); +dat2wav([name '_qrcf'], 2*sr, 16, 0.95); +dat2wav([name '_ircf_rm'], 2*sr, 16, 0.95); +dat2wav([name '_qrcf_rm'], 2*sr, 16, 0.95); +dat2wav([name '_cma_i'], 2*sr, 16, 0.95); +dat2wav([name '_cma_q'], 2*sr, 16, 0.95); + +%result_rx(name); \ No newline at end of file diff --git a/common/radio/rx_mpsk.m b/common/radio/rx_mpsk.m new file mode 100755 index 0000000..afb14b8 --- /dev/null +++ b/common/radio/rx_mpsk.m @@ -0,0 +1,23 @@ +% [IQ] = rx_mpsk(fa, mode, nBitsPerSym, sr, fc, name) +% + +function [IQ] = rx_mpsk(fa, mode, nBitsPerSym, sr, fc, name) + +commandStr = sprintf('mpsk_rx\\mpsk_rx.exe %g %g %g %d %s %s',fa,fc,sr, nBitsPerSym, mode, name); + +disp(commandStr); +dos(commandStr); + +dat2wav([name '_i'], fa, 16, 0.99); +dat2wav([name '_q'], fa, 16, 0.99); +dat2wav([name '_if'], fa, 16, 0.99); +dat2wav([name '_qf'], fa, 16, 0.99); +dat2wav([name '_ircf'], 2*sr, 16, 0.99); +dat2wav([name '_qrcf'], 2*sr, 16, 0.99); +dat2wav([name '_ircf_rm'], 2*sr, 16, 0.99); +dat2wav([name '_qrcf_rm'], 2*sr, 16, 0.99); +dat2wav([name '_perr'], 2*sr, 16, 0.99); +dat2wav([name '_domega'], 2*sr, 16, 0.99); +dat2wav([name '_cma_i'], 2*sr, 16, 0.99); +dat2wav([name '_cma_q'], 2*sr, 16, 0.99); + diff --git a/common/radio/sliding_minmax_eval.m b/common/radio/sliding_minmax_eval.m new file mode 100755 index 0000000..309cd94 --- /dev/null +++ b/common/radio/sliding_minmax_eval.m @@ -0,0 +1,14 @@ +function [xmin, xmax] = sliding_minmax_eval(xin, L) + +x = [1E12*ones(L,1)' xin']'; +for k=1:(lge(x)-L) + for ll=1:L + xmin(k) = min(x(1+k:L+k)); + end +end +x = [-1E12*ones(L,1)' xin']'; +for k=1:(lge(x)-L) + for ll=1:L + xmax(k) = max(x(1+k:L+k)); + end +end \ No newline at end of file diff --git a/common/radio/test.m b/common/radio/test.m new file mode 100755 index 0000000..62b6094 --- /dev/null +++ b/common/radio/test.m @@ -0,0 +1,16 @@ +function test (N) + +h1 = sinc((-N/2:N/2-1)/77).*hann(N)'; +h2 = sinc((-N/2:N/2-1)/100).*hann(N)'; + +h1 = zeros(1,N); +h1(N/2+1) = 0.5; + +v1 = sum((h1)) + +h2p = [h2 zeros(1,N/2)]; +h12 = filter(h1,1,h2p); + +plot(1:N, h12(N/2+1:N+N/2)/v1, 1:N, h1, 1:N, h2) +grid; + diff --git a/common/radio/tx_mpsk.m b/common/radio/tx_mpsk.m new file mode 100755 index 0000000..5d81518 --- /dev/null +++ b/common/radio/tx_mpsk.m @@ -0,0 +1,76 @@ +% [IQ] = tx_mpsk(nBytes, nBitsPerSym, sr, fc, name, kawgn_db, ch, rs) +% + +function [IQ] = tx_mpsk(nBytes, nBitsPerSym, sr, fc, name, kawgn_db, ch, rs, payload) +if fc > sr + fa = 4*fc +else + fa = 4*sr; +end; +k_am = 0.0; +f_am = 0.2; +rf_gain = 0.7; + +% Write settings file +fid = fopen([name '.cfg'], 'w'); +fprintf(fid, 'project : %s\n', name); +fprintf(fid, 'fa : %f\n', fa); +fprintf(fid, 'fc : %f\n', fc); +fprintf(fid, 'sr : %f\n', sr); +fprintf(fid, 'nBitsPerSym : %d\n', nBitsPerSym); +fprintf(fid, 'ch : %d\n', ch); +fprintf(fid, 'rs : %d\n', rs); +fprintf(fid, 'kawgn_db : %d\n', kawgn_db); +fclose(fid); + +name_rf = sprintf('%s_rf',name); +name_i = sprintf('%s_tx_i',name); +name_q = sprintf('%s_tx_q',name); +file_rf = sprintf('%s.dat',name_rf); +file_i = sprintf('%s.dat',name_i); +file_q = sprintf('%s.dat',name_q); + +if (isempty(payload)) + commandStr = sprintf('mpsk_tx\\mpsk_tx.exe %g %g %g %d %d %s',fa,fc,sr, nBitsPerSym, nBytes, name); +else + commandStr = sprintf('mpsk_tx\\mpsk_tx.exe %g %g %g %d %d %s %s',fa,fc,sr, nBitsPerSym, nBytes, name, payload); +end + +disp(commandStr); +dos(commandStr); + +fid = fopen(file_rf, 'rb'); +rfdata = fread(fid, 'float32'); +fclose(fid); + +dat2wav(name_i, fa, 16, 0.9); +dat2wav(name_q, fa, 16, 0.9); + +if (rs==1) + rfdata = RESAMPLE(rfdata,fa,fix(1.002*fa)); +end; + +len = length(rfdata); +kawgn = 10^(kawgn_db/10) +awgn = sqrt(kawgn)*randn(len,1); +am = cos(2*pi*f_am/fa.*(0:len-1))'; + +if (ch==1) + hch_a = [1.0 0.7]; + hch_b = [1]; +else + hch_a = [1.0]; + hch_b = [1.0]; +end + +rf = rf_gain.*((1+k_am*am).*filter(hch_b,hch_a,rfdata) + awgn); +rf_level = 10*log10(var(rf)); +SNR_DB = round(rf_level-kawgn_db) + +fid = fopen(file_rf, 'wb'); +fwrite(fid, rf, 'float32'); +fclose(fid); + +dat2wav(name_rf, fa, 16, 0.9) +disp('Adding Noise to RF...'); + \ No newline at end of file diff --git a/common/radio/wkaiser.m b/common/radio/wkaiser.m new file mode 100755 index 0000000..37cc355 --- /dev/null +++ b/common/radio/wkaiser.m @@ -0,0 +1,37 @@ +function [w, idx] = wkaiser(n, b) + +% function [w, idx] = wkaiser(n, b) + +k1 = 1.0/besselizero(b); +k2 = 1 - mod(n, 2); +ende = fix((n + 1)/2); + +idx = zeros(n, 1); +% Calculate window coefficients +for k=0:ende-1, + tmp = (2*k + k2) / (n - 1.0); + tmp2 = k1 * besselizero(b*sqrt(1.0 - tmp*tmp)); + mm = ende-(mod(not(k2), 2))+k+1; + nn = ende-k; + w(mm) = tmp2; + w(nn) = tmp2; + idx(nn) = idx(nn) + 1; + idx(mm) = idx(mm) + 1; +end; + +function sum = besselizero(x) + BIZ_EPSILON = 1E-21; % Max error acceptable + sum = 1.0; + u = 1.0; + halfx = x/2.0; + n = 1; + while(1) + temp = halfx/n; + u = u * temp * temp; + sum = sum + u; + n = n + 1; + if (u < (BIZ_EPSILON * sum)) + break; + end; + end; +