Podstawy transmisji radiowej
Autorzy: Wiesław Ludwin, Jacek Wszołek, Tomasz Zieliński
Pliki: rozdzial_22.zip
Przykład 22.1
W przykładzie 22.1 (plik przyklad_22_1.m) zaprezentowano program w języku MATLAB realizujący pracę kodera modulatora dla modulacji M-PSK oraz 16QAM (tab. 22.1 i 22.2).%% Przykład 22.1 -- Koder modulatora dla M-PSK oraz 16 QAM A=2; % Amplituda M=4; % wartościowowść modulacji M-PSK n=1:M; I = A*cos((2*n)*pi/M); % wartość składowej synfazowej Q = A*sin((2*n)*pi/M); % wartość składowej kwadraturowej fi=0:0.01:2*pi; % tytul = strcat(num2str(M), '-PSK'); figure(1); plot(I,Q,'ro',A*cos(fi),A*sin(fi),'b-'); xlabel('I'); ylabel('Q'); title(tytul); grid on; %% Koder modulatora dla 16QAM (w tablicy) Iqam(1) = 0.4472; Qqam(1) =0.4472; Iqam(2) = 0.4472; Qqam(2) =1.3416; Iqam(3) = 1.3416; Qqam(3) =0.4472; Iqam(4) = 1.3416; Qqam(4) =1.3416; Iqam(5) = 0.4472; Qqam(5) =-0.4472; Iqam(6) = 0.4472; Qqam(6) =-1.3416; Iqam(7) = 1.3416; Qqam(7) =-0.4472; Iqam(8) = 1.3416; Qqam(8) =-1.3416; Iqam(9) = -0.4472; Qqam(9) =0.4472; Iqam(10) = -0.4472; Qqam(10) =1.3416; Iqam(11) = -1.3416; Qqam(11) =0.4472; Iqam(12) = -1.3416; Qqam(12) =1.3416; Iqam(13) = -0.4472; Qqam(13) =-0.4472; Iqam(14) = -0.4472; Qqam(14) =-1.3416; Iqam(15) = -1.3416; Qqam(15) =-0.4472; Iqam(16) = -1.3416; Qqam(16) =-1.3416; Aqam = unique(abs(Iqam + 1i*Qqam)); % wartości amplitud figure(2); plot2 = plot(Iqam,Qqam,'ro'); xlabel('I'); ylabel('Q'); title(tytul); grid on; title ('16QAM'); hold on for k=1:length(Aqam) plot(Aqam(k)*cos(fi),Aqam(k)*sin(fi),'b-') end hold off
Przykład 22.2
W przykładzie 22.2(1) (plik przyklad_22_2.m) przedstawiono implementację uproszczonego modelu transmisji radiowej przez kanał AWGN w paśmie radiowym. Program został napisany z wykorzystaniem dokumentacji i przykładów prezentowanych na stronie internetowej www.mathworks.com/.%% Przykład 22.2 - #1. Transmisja radiowa %% Nadajnik % Koder modulatora M = 4; % wartościowość modulacji SigLen = 4000; % długość sekwencji Fc = 4e6; % częstotliwość nośna (Hz) SymRate = 1e6; % liczba symboli na sekundę nSamps = 16; % Liczba próbek na symbol Fs = SymRate * nSamps; % częstotliwość próbkowania EbNo = 20; % stosunek energii przypadającej na jeden bit do widmowej % gęstości mocy szumu % Obliczanie SNR (dla funkcji awgn()), 10*log10(log2(M)/nSamps) bo % nadpróbkowywujemy, 10*log10(2) bo N0/2 SNR = EbNo + 10*log10(log2(M)/nSamps) + 10*log10(2); msg = randi([0, 1], SigLen, 1); % Źródło danych % Blok modulacji (pasmo podstawowe). W przykładnie z rozdziału 22.6 % jest on zaimplementowany bez użycia funkcji modulate() hMod = modem.pskmod('M', M, 'SymbolOrder', 'gray', 'InputType', 'bit'); % Koder modulatora TXsig = modulate(hMod, msg); % modulacja %% Przykład 22.2 - #2 Kształtowanie impulsów % Parametry filtra pierwiastek z podniesionego kosinusa FltLength = 8; % rząd filtra RolloffFactor = 0.22; % współczynnik opadania zbocza charakterystyki % częstotl. (rolloff factor) filterSpec = fdesign.pulseshaping(nSamps, 'Square root raised cosine', ... 'Nsym,Beta', FltLength, RolloffFactor); ImpShapeFlt = design(filterSpec); % tworzymy filtr (obiekt) TXsigUpsampled = upsample(TXsig, nSamps); % nadpróbkowanie sygnału % z kodera modulacji TXshaped = filter(ImpShapeFlt, TXsigUpsampled); % filtracja % Widmo Hamming256 = spectrum.welch('Hamming', 256); BasebandSpectrum = figure; psd(Hamming256, TXshaped, 'Fs', Fs, 'SpectrumType', ... 'twosided','CenterDC', true); %% Przykład 22.2 - #3 Konwersja do częstotliwości radiowej z wzoru Eulera t = (0:1/Fs:(SigLen/(sqrt(M)*SymRate))-1/Fs).'; % czas Carrier = sqrt(2)*exp(1i*2*pi*Fc*t); % nośna TXup = real(TXshaped.*Carrier); % konwersja PassbandSpectrum = figure; psd(Hamming256, TXup, 'Fs', Fs, 'SpectrumType','twosided', ... 'CenterDC', true); %% Przykład 22.2 - #4 Kanał AWGN RXup = awgn(TXup, SNR, 'measured'); % Wyświetlanie widma figure(PassbandSpectrum); hold on; psdProbe = psd(Hamming256, RXup, 'Fs', Fs, 'SpectrumType', ... 'twosided', 'CenterDC', true); plot2 = plot(psdProbe); set (plot2, 'Color','r'); legend('Sygnał na wejściu kanału', 'Sygnał na wyjściu kanału', ... 'Location', 'southwest'); hold off; %% Przykład 22.2 - #5 % Odbiornik % Konwerter w dół RXdown = RXup.*conj(Carrier); % Wyświetlanie widma ReceivePlot = figure; psd(Hamming256, RXdown, 'Fs', Fs, 'SpectrumType', 'twosided', ... 'CenterDC', true); %% Przykład 22.2 - #6 % Filtr odbiorczy ReceiveFlt = copy(ImpShapeFlt); RXsym = filter(ReceiveFlt, RXdown); % Wyświetlanie widma hold on; psdProbe = psd(Hamming256, RXsym, 'Fs', Fs, 'SpectrumType', 'twosided',... 'CenterDC', true); plot3 = plot(psdProbe); set (plot3, 'Color','r'); legend('Sygnał przed filtracją',... 'Sygnał po filtracji', 'Location', 'southwest') hold off; %% Przykład 22.2 - #7 % Detekcja % Odrzucamy pierwsze FltLength symbole (opóźnienie filtra) FltDelay = FltLength * nSamps; RXdown = downsample(RXsym(FltDelay+1:end), nSamps); % decymacja hDemod = modem.pskdemod(hMod); % demodulator (obiekt demod) RXmsg = demodulate(hDemod, RXdown); % detekcja liczba_bledow = biterr(msg(1:end-FltLength*log2(M)), RXmsg); % liczba błędów
Przykład 22.3
W przykładzie 22.3 (plik przyklad_22_3.m) przedstawiono implementację w języku MATLAB modelu transmisji sygnału w pasmie podstawowym w kanale AWGN.%% Przykład 22.3 -- Transmisja radiowa w paśmie podstawowym w kanale AWGN %% Parametry poczatkowe siglen = 100000; % dlugość sekwencji EbNomin = 0; EbNomax = 10; % Zakres EbNo EbNovec = EbNomin:2:EbNomax; % Wektor EbNo numEbNos = length(EbNovec); % Liczba punktów EbNo % Modulatory QPSKmod = modem.pskmod('M', 4, 'SymbolOrder', 'gray'); % Modulator QPSK QPSKdemod = modem.pskdemod(QPSKmod); % Demodulator numerrminQPSK = 20; % Minimalna liczba błędów aby skończyć symulacje berQPSK = zeros(1,numEbNos); % BERy serQPSK = zeros(1,numEbNos); % SERy intv4B = cell(1,numEbNos); % przedziały ufności QPSK QAM16mod = modem.qammod('M', 16, 'SymbolOrder', 'gray'); % Modulator 16QAM QAM16demod = modem.qamdemod(QAM16mod); % Demodulator 16QAM numerrmin16QAM = 20; % Minimalna liczba błędów aby skończyć symulacje ber16QAM = zeros(1,numEbNos); % BERy ser16QAM = zeros(1,numEbNos); % SERy intv16B = cell(1,numEbNos); % przedziały ufności 16QAM % Symulacje puszczamy w pętli, każda iteracja dla danej wartości EbN0. %% QPSK for jj = 1:numEbNos EbNo = EbNovec(jj); snr = EbNo + 10*log10(log2(4)); ntrialsQPSK = 0; % Liczba iteracji petli numerrQPSK = 0; % Liczba błędow, dla danej wartoęci EbN0 (bity) numSymerrQPSK = 0; % Symbole % Symuluj tak długo, aż nie wygeneruje się określona liczba błędów. while (numerrQPSK < numerrminQPSK) msg = randi([0, 3], siglen, 1); % Generacja danych txsig = modulate(QPSKmod, msg); % Modulacja rxsig = awgn(txsig, snr, 'measured'); % Dodanie szumu białego (kanał awgn) decodmsg = demodulate(QPSKdemod, rxsig); % Demodulacja newerrsQPSK = biterr(msg, decodmsg); % Liczba błędów w tej iteracji: bity, newSymerrsQPSK = symerr(msg, decodmsg); % symbole numerrQPSK = numerrQPSK + newerrsQPSK; % całkowita liczba błędów numSymerrQPSK = numSymerrQPSK + newSymerrsQPSK; ntrialsQPSK = ntrialsQPSK + 1; % Aktualizacja liczby iteracji pętli. end % Obliczanie BER [berQPSK(jj), intv4B{jj}] = berconfint(numerrQPSK,(ntrialsQPSK * siglen * log2(4)),.95); [serQPSK(jj), intv4S] = berconfint(newSymerrsQPSK,(ntrialsQPSK * siglen),.95); disp(['QPSK: EbNo = ' num2str(EbNo) ' dB, ' num2str(numerrQPSK) ... ' błędów, BER = ' num2str(berQPSK(jj)) ', SER = ' num2str(serQPSK(jj))]) end %% 16QAM for jj = 1:numEbNos EbNo = EbNovec(jj); snr = EbNo + 10*log10(log2(16)); ntrials16QAM = 0; numerr16QAM = 0; numSymerr16QAM = 0; while (numerr16QAM < numerrmin16QAM) msg = randi([0, 15], siglen, 1); txsig = modulate(QAM16mod, msg); rxsig = awgn(txsig, snr, 'measured'); decodmsg = demodulate(QAM16demod, rxsig); newerrs16QAM = biterr(msg, decodmsg); newSymerrs16QAM = symerr(msg, decodmsg); numerr16QAM = numerr16QAM + newerrs16QAM; numSymerr16QAM = numSymerr16QAM + newSymerrs16QAM; ntrials16QAM = ntrials16QAM + 1; end % Obliczanie BER [ber16QAM(jj), intv16B{jj}] = berconfint(numerr16QAM,(ntrials16QAM * siglen * log2(16)),.95); [ser16QAM(jj), intv16S] = berconfint(numSymerr16QAM,(ntrials16QAM * siglen),.95); disp(['16QAM: EbNo = ' num2str(EbNo) ' dB, ' num2str(numerr16QAM) ... ' błędów, BER = ' num2str(ber16QAM(jj)) ', SER = ' num2str(ser16QAM(jj))]) end %% Wykres % QPSK plotQPSK = semilogy(EbNovec(:), berQPSK); set(get(gca,'Xlabel'),'FontSize',10,'FontName','times'); set(get(gca,'Ylabel'),'FontSize',10,'FontName','times'); set(get(gca,'Title'),'FontSize',12,'FontName','times'); set(plotQPSK,'LineWidth',1,'LineStyle','-', 'Color','b'); set(plotQPSK, 'Marker','x', 'MarkerSize',8, 'MarkerEdgeColor', 'b'); grid on; % 16QAM hold on plot16QAM = semilogy(EbNovec(:), ber16QAM); set(plot16QAM,'LineWidth',1,'LineStyle','-.', 'Color','r'); set(plot16QAM, 'Marker','o', 'MarkerSize',8, 'MarkerEdgeColor', 'r'); hold off % Narysuj przedziały ufności hold on; for jj=1:numEbNos semilogy([EbNovec(jj) EbNovec(jj)],intv4B{jj},'g-+'); semilogy([EbNovec(jj) EbNovec(jj)],intv16B{jj},'g-+'); end hold off; xlabel('Eb/N0 [dB]'); ylabel('Prawdopodobieństwo błędu'); legend('QPSK','16QAM', 'Location', 'southwest');
Przykład 22.4
W przykładzie 22.4 (plik przyklad_22_4.m) przedstawiono implementację w języku MATLAB modelu matematycznego systemu radiowego pasma podstawowego wykorzystującego kanał FNFC z zanikiem płaskim.%% Przykład 22.4 Transmisja radiowa. Model kanału FNFC z zanikiem % płaskim i addytywnym szumem białym %% Parametry poczatkowe siglen = 1000; % długość sekwencji trainlen = 200; % długość ciagu uczacego M = 4; % wartościowość modulacji hMod = modem.pskmod('M', M, 'SymbolOrder', 'gray', 'InputType', 'bit'); hDemod = modem.pskdemod(hMod); % Demodulator EbNomin = 0; EbNomax = 16; % Zakres EbNo numerrmin = 10000; % Minimalna liczba błędów aby skończyć symulacje EbNovec = EbNomin:2:EbNomax; % Wektor EbNo numEbNos = length(EbNovec); % Liczba punktów EbNo ber = zeros(1,numEbNos); % BERy intv = cell(1,numEbNos); % przedziały ufności %% Kanał Ts = 1e-7; % czas trwania próbki (symbolu) Fd = 14; % maksymalna częstotliwość Dopplera (Hz) flat_ch = rayleighchan(Ts,Fd); flat_ch.StoreHistory = 1; %% Korektor eqlms = lineareq(1,lms(0.03)); %% Symulacje puszczamy w petli, każda iteracja dla danej wartości EbN0. for jj = 1:numEbNos EbNo = EbNovec(jj); snr = EbNo + 10*log10(log2(M)); ntrials = 0; numerr = 0; % Symuluj tak długo, aż nie wygeneruje się określona liczba błędów. while (numerr < numerrmin) msg = randi([0, 1], siglen, 1); % Generacja danych. txsig = modulate(hMod, msg); % Modulacja. % Przejście sygnału przez kanał FNFC z zanikiem płaskim i efektem Dopplera rxsig = awgn(filter(flat_ch,txsig), snr); % Korekcja eqsig = equalize(eqlms,rxsig,txsig(1:trainlen)); decodmsg = demodulate(hDemod, eqsig); newerrs = biterr(msg(1:trainlen), decodmsg(1:trainlen), log2(M)); numerr = numerr + newerrs; ntrials = ntrials + 1; end [ber(jj), intv1] = berconfint(numerr,(ntrials * siglen),.95); disp(['EbNo = ' num2str(EbNo) ' dB, ' num2str(numerr) ... ' błędów, BER = ' num2str(ber(jj))]) end %% Wykres plotBER = semilogy(EbNovec(:), ber); set(plotBER,'LineWidth',1,'LineStyle','-'); set(plotBER, 'Marker','x'); set(plotBER,'MarkerSize',12, 'MarkerEdgeColor', 'k') set(plotBER, 'Color','k'); grid on; % title('BER vs EbN0') xlabel('SNR [dB]'); ylabel('Prawdopodobieństwo błędu');
Przykład 22.5
W przykładzie 22.5 (plik przyklad_22_5.m) przedstawiono implementację w języku MATLAB modelu matematycznego systemu radiowego pasma podstawowego wykorzystującego kanał FSFC z zanikiem selektywnym.%% Przykład 22.5 Transmisja radiowa. Model kanału FSFC z zanikiem selektywnym % i addytywnym szumem białym %% Parametry poczatkowe siglen = 1000; % długość sekwencji trainlen = 200; % długość ciagu uczacego M = 4; % wartościowość modulacji hMod = modem.pskmod('M', M, 'SymbolOrder', 'gray', 'InputType', 'bit'); hDemod = modem.pskdemod(hMod); EbNomin = 3; EbNomax = 18; % Zakres EbNo numerrmin = 30000; % Minimalna liczba błędów aby skończyć symulacje EbNovec = EbNomin:3:EbNomax; % Wektor EbNo numEbNos = length(EbNovec); % Liczba punktow EbNo ber = zeros(1,numEbNos); % BERy intv = cell(1,numEbNos); % Komórka na przedzialy ufnosci Tber = zeros(1,numEbNos); % Teoretyczne BERy %% Kanal Ts = 2.6e-7; % czas trwania próbki Fd = 10; % maksymalna częstotliwość Dopplera (Hz) sel_ch = stdchan(Ts, Fd, '3gppTUx'); % obiekt kanału sel_ch.NormalizePathGains = 0; ch_delay = sel_ch.ChannelFilterDelay; sel_ch.ResetBeforeFiltering = 0; %% Korektor o rzędzie większym niż 1 nWeights = 30; % rząd korektora (liczba współczynników wagowych) eqrls = lineareq(nWeights, rls(0.98,0.1)); % stworzenie obiektu korektora eqrls.SigConst = hMod.Constellation; % ustawienie konstelacji sygnału eqrls.ResetBeforeFiltering = 0; eqrls.RefTap = floor(nWeights/2); eq_delay = (eqrls.RefTap -1)/eqrls.nSampPerSym; %% Symulacje puszczamy w petli, kazda iteracja dla danej wartości EbN0. for jj = 1:numEbNos EbNo = EbNovec(jj); Tber(jj) = berfading(EbNo, 'psk', M, 10); snr = EbNo + 10*log10(log2(M)); ntrials = 0; numerr = 0; % Symuluj tak długo, aż nie wygeneruje sie określona liczba błędów. while (numerr < numerrmin) msg = randi([0, 1], siglen, 1); % Generacja danych. txsig = modulate(hMod, msg); % Modulacja. % Przejście sygnału przez kanał z zanikiem płaskim i efektem Dopplera rxsig = awgn(filter(sel_ch,txsig), snr, 'measured'); % Add noise. % kompensacja opóźnienia kanału (selektywnego częstotliwościowo) msg_trunc = msg(1:end-2*ch_delay); % opuść ostatnie ch_delay symbole wiadomości txsig_trunc = txsig(1:end-ch_delay); % oraz sygnalu nadanego rxsig_trunc = rxsig(ch_delay+1:end); % opuść pierwsze ch_delay symbole sygnału odebranego % Korekcja eqsig = equalize(eqrls, rxsig,txsig(1:trainlen)); % kompensacja opoznienia korektora (tez jest filtrem pamieciowym) RXsig = eqsig(eq_delay+1:end); % opuść pierwsze eq_delay symbole odebranego sygnału TXmsg = msg_trunc(1:end - 2*eq_delay); % opuść ostatnie eq_delay % symbole nadanego sygnału msglen = length(TXmsg); decodmsg = demodulate(hDemod, RXsig); % Demodulacja. newerrs = biterr(msg(1:trainlen), decodmsg(1:trainlen), log2(M)); numerr = numerr + newerrs; ntrials = ntrials + 1; nBits = ntrials * msglen; end % Obliczanie liczby błędów oraz BER [ber(jj), intv1] = berconfint(numerr, nBits,.95); disp(['EbNo = ' num2str(EbNo) ' dB, ' num2str(numerr) ... ' błędów, BER = ' num2str(ber(jj))]) end %% Wykres plotBER = semilogy(EbNovec(:), ber); set(plotBER,'LineWidth',1,'LineStyle','-'); set(plotBER, 'Marker','+'); set(plotBER,'MarkerSize',12, 'MarkerEdgeColor', 'k') set(plotBER, 'Color','k'); grid on; % title('BER vs EbN0') xlabel('Eb/N0 [dB]'); ylabel('Prawdopodobieństwo błędu');
Przykład 22.6
Przykład 22.6 (plik przyklad_22_06.m) przedstawia najważniejsze operacje przetwarzania sygnałów, wykonywane podczas transmisji radiowej z wykorzystaniem modulacji QPSK (4QAM) – wysyła się w nim konkretne bity w nadajniku i dekoduje je w odbiorniku. Po drodze w kolejnych krokach: 1) przechodzi się z bitów na liczby (fazory) zespolone; 2) wstawia się zera pomiędzy te liczby i wygładza sygnał otrzymany w ten sposób, używając filtra pierwiastka z podniesionego kosinusa (funkcje firrcos() i upfirdn()); 3) moduluje się sygnał; 4) symuluje się prosty kanał AWGN, tłumiący i opóźniający; 5) demoduluje się sygnał i eliminuje wpływ kanału; 6) ponownie filtruje się sygnał filtrem pierwiastka z podniesionego kosinusa; 7) przeprowadza się synchronizację za pomocą sygnału pilota; 8) dekoduje się bity i porównuje z bitami nadanymi. Nadawany sygnał składa się ramek. Każda z nich zawiera preambułę synchronizacyjną oraz właściwą informację.% Przykład 22.6 % Autorzy: Sebastian LIS, Jacek MAJERCZYKI (wyrazili zgodę na publikację), % Tomasz ZIELIŃSKI (tzielin@agh.edu.pl) clear all; close all; % Parametry Nsym = 100; % liczba próbek na symbol Nmod = 10; % liczna próbek na nośną fsym = 1; % liczba symboli na sekundę Kramek = 3; % liczba wysłanych ramek/bloków symboli Npsf = 1001; % liczba współczynników filtra kształtującego impuls; maks 1601 snr = 160; % stosunek sygnału do szumu fpr = Nsym*fsym; % częstotliwość próbkowania wzm = 0.1; % wzmocnienie kanału faza = pi/3; % przesunięcie fazowe kanału kanal = 1; % zniekształcenie wprowadzane przez kanał: 0/1 NIE/TAK korektor = 1; % korektor kanału: 0/1 NIE/TAK dane = [ 0 1 0 2 3 0 3 1 1 2 1 0 2 2 0 1 3 3 0 2 1 1 0 3 0 2 1 1 3 1 0 2 ]; synch = [ 3 0 0 1 2 1 3 0 3 2 2 1 3 0 0 1 2 1 3] ; % wzorzec synchro typu STS % KODER: generowanie zespolnonych symboli QPSK % nr symbolu = bity: 0=11 1=01 2=00 3=10 % odpowadające fazie: pi/4 3pi/4 7pi/4 5pi/4 % odpowiadające complex: 1+j -1+j -1-j 1-j % koder = (1/sqrt(2))* [ 1+j, -1+j, -1-j, 1-j ]; koder = [ exp( j*pi/4 ) exp( j*3*pi/4 ) exp( j*7*pi/4 ) exp( j*5*pi/4 ) ]; psf = firrcos( Npsf-1, fsym/2, 0.35, fpr,'rollof', 'sqrt'); % filtr kształtujący psf1 = sqrt(2)*(fpr/fsym)*psf; psf2 = 2*psf; % pulse shaping filter plot(psf1'); xlabel('n'); title('psf[n]'); grid; pause % NADAJNIK ######################################################################### ramka = [ synch dane ]; % pojedynczna wysłana ramka symboli wyslane = [ 0 ramka ramka ramka ]; % wysłana sekwencja numerów stanów Ksym = length(ramka); % liczba symboli w jednej ramce Nramka = Ksym*Nsym; % liczba próbek sygnału na jedną ramkę symboli IQwyslane = koder( wyslane+1 ); % numery symboli --> stany konstelacji sygnal = upfirdn(IQwyslane,psf1,Nsym,1); % nadpróbkowanie Nsym razy z użyciem psf Nsygnal = length(sygnal); % Rysunki L = 10000; % ile próbek sygnału pokazać figure % wykres fazorowy: imag=funkcja(real) plot(real(sygnal(1:L)),imag(sygnal(1:L)),'b-'); title('Q=f(I)'); xlabel('I[n]'); ylabel('Q[n]'); pause figure % real, imag subplot(311); plot(real(sygnal(1:L))); title('I[n]'); subplot(312); plot(imag(sygnal(1:L))); title('Q[n]'); subplot(313); plot( real(sygnal(1:L)).^2 + imag(sygnal(1:L)).^2 ); title('abs(IQ)'); pause % Modulacja - przejście na wyższą częstotliwość n = 0:Nsygnal-1; sygnal = real(sygnal).*cos(2*pi/Nmod*n) - imag(sygnal).*sin(2*pi/Nmod*n); % KANAŁ ############################################################################ if(kanal==1) sygnal = sygnal*wzm*exp(-j*faza); end % tłumienie i opóźnienie sygnal = awgn( sygnal, snr ); % dodanie szumu % ODBIORNIK ######################################################################## % Demodulacja - powrót na niską częstotliwość, eliminacja wpływu kanału sreal = cos(2*pi/Nmod*n) .* sygnal; simag = -sin(2*pi/Nmod*n) .* sygnal; sygnal = sreal + j*simag; % Korektor FEQ if(kanal==1 & korektor==1) sygnal = sygnal*(1/wzm)*exp(j*faza); end % Generacja sygnału do synchronizacji IQsynch = koder( synch+1 ); % numery symboli --> stany konstelacji sync = upfirdn( IQsynch, psf1, Nsym, 1 ); % nadpróbkowanie Nsym razy z użyciem psf Nsync = length(sync); % Splot z filtrem kształtującym Nstart = (Npsf+1)/2; sygnal= conv(sygnal,psf2); Nsygnal = length(sygnal); sync = conv(sync,psf2); Nsync = length(sync); Nstart = Npsf; % aktualizacja przesunięcia analizy % Rysunki figure % real, imag subplot(211); plot(real(sygnal(1:L))); title('I[n]'); subplot(212); plot(imag(sygnal(1:L))); title('Q[n]'); pause figure % wyres fazorowy: imag=f(real) plot(sygnal(1:L),'b-'); title('Q=f(I) demod'); xlabel('I[n]'); ylabel('Q[n]'); pause % Synchronizacja (przykład) korel = abs( conv( fliplr(conj(sync)),sygnal) ); % korelacja sygnału i synchro. [xmax, imax] = max( korel( 1:round(Nramka) ) ); % znalezienie pierwszego maksimum korel = korel / max( korel ); % normalizacja iwork = Nstart+round(Nsym); iback = (Nsync+round(Nsym))-iwork; nfirst = imax-iback-1; % próbka środka pierwszego symbolu figure n = nfirst + (0 : Ksym*Kramek-1)*Nsym; plot( real(sygnal), imag(sygnal),'b-', real(sygnal(n)), imag(sygnal(n)),'ro'); title('Q=f(I)'); xlabel('I[n]'); ylabel('Q[n]'); pause % Detekcja for k = 0 : Kramek-1 k detekt = []; num = nfirst + k*Nramka + round((0:Ksym-1)*Nsym); % położenia symboli I = real(sygnal(num)); Q = imag(sygnal(num)); for m=1:length(num) if( I(m)>0 & Q(m)>0 ) detekt = [detekt 0]; end if( I(m)<0 & Q(m)>0 ) detekt = [detekt 1]; end if( I(m)>0 & Q(m)<0 ) detekt = [detekt 2]; end if( I(m)<0 & Q(m)<0 ) detekt = [detekt 3]; end if( (I(m)==0) | (Q(m)==0) ) disp('ZERO'); pause; end end ramka, detekt, if( sum( abs( ramka - detekt ) ) == 0 ) disp('TO SAMO !!!'); pause; else disp('BLĄD !!!'); pause; end end
Przykład 22.7
Przykład 22.7 (plik przyklad_22_07.m) to program w języku MATLAB, w którym są przedstawione podstawy cyfrowego kodowania i dekodowania audycji radia FM wraz z bitami RDS (po ich odpowiedniej interpretacji na wyświetlaczu odbiornika pojawia się wysłany tekst). Program nie jest optymalny i ma wyłącznie charakter demonstracyjny. Został on napisany na podstawie normy IEC 62106. Umożliwia tworzenie sumarycznego sygnału łącznego (kanały lewy i prawy oraz dane cyfrowe) w paśmie podstawowym (BB), który jest następnie konwertowany na wyższe częstotliwości (IF). Program daje możliwość wczytywania rzeczywistych, wąskopasmowych danych IQ z istniejących odbiorników radia SDR (np. danych z programu SDR# nagranych z częstotliwością próbkowania 250 kHz – 250 kilopróbek na sekundę) oraz ich dekodowania łącznie z bitami RDS.% Przykład 22.7. % Przykład cyfrowego przetwarzania sygnałów w radiu FM % Radio FM - koder i dekoder razem % Autor: Tomasz ZIELIŃSKI, tzielin@agh.edu.pl clear all; close all; % ######################################################## % INICJOWANIE WARTOŚCI PARAMETRÓW, ZAPROJEKTOWANIE FILTRÓW % Program fm_param.m fs = 250000; % częstotliwość próbkowania sygnału szerokopasmowego FM fpilot = 19000; % częstotliwość pilota [Hz] fsymb = fpilot/16; % częstotliwość próbkowania symboli RDS, 1187.5 Hz fstereo = 2*fpilot; % częstotliwość nośnej sygnału L-R, 38000 Hz frds = 3*fpilot; % częstotliwość nośnej danych RDS, 57000 Hz Abw = 25000; % założona szerokość pasma sygnału audio L = 500; % długość zastosowanych filtrów nierekursywnych dt = 1/fs; % okres próbkowania % Filtr pre-fazy i de-emfazy f1 = 2120; tau1 = 1/(2*pi*f1); w1 = tan(1/(2*Abw*tau1)); b_de = [w1/(1+w1), w1/(1+w1)]; a_de = [1, (w1-1)/(w1+1)]; b_pre = a_de; a_pre = b_de; % Filtr kształtowania impulsów (PSF - pulse shaping filter) Tsymb = 1/fsymb; % czas trwania symbolu RDS Nsymb = fs/fsymb; % liczba próbek na symbol RDS (210.5263158) Nsymb4 = floor(4*Nsymb); % liczba próbek 4 symboli df = fs/Nsymb4; f = 0 : df : 2/Tsymb; Nf=length(f); % widmo z normy H = zeros(1, Nsymb4); H(1:Nf) = cos(pi*f*Tsymb/4); H(end:-1:end-(Nf-2))=H(2:Nf); hpsf = fftshift(ifft(H)); hpsf=hpsf/max(hpsf); % odp. impulsowa hpsf2 = firrcos( Nsymb4, fsymb, 1.0, fs,'rollof','sqrt'); % odp. impuls #2 hpsf2 = hpsf2/max(hpsf2); hpsf2 = hpsf2(1:end-1); n=1:length(hpsf); n2=1:length(hpsf2); plot(n,hpsf,'ro-',n2,hpsf2,'bx-'); grid; pause phasePSF = angle( exp(-j*2*pi*fsymb/fs*[0:Nsymb4-1]) * hpsf' ); % przes. fazowe % Filtr dolnoprzepustowy LowPass do odzyskania sygnału L+R hLPaudio = fir1(L,(Abw/2)/(fs/2),kaiser(L+1,7)); % Filtr wąskopasmowy BandPass do odzyskania sygnału pilota (wokół 19 kHz) fcentr = fpilot; df1 = 1000; df2 = 2000; ff = [ 0 fcentr-df2 fcentr-df1 fcentr+df1 fcentr+df2 fs/2 ]/(fs/2); fa = [ 0 0.01 1 1 0.01 0 ]; hBP19 = firpm(L,ff,fa); % Filtr szerokopasmowy BandPass do odzyskania sygnału L-R (wokół 38 kHz) fcentr = fstereo; df1 = 10000; df2 = 12500; ff = [ 0 fcentr-df2 fcentr-df1 fcentr+df1 fcentr+df2 fs/2 ]/(fs/2); fa = [ 0 0.01 1 1 0.01 0 ]; hBP38 = firpm(L,ff,fa); % Filtr wąskopasmowy BandPass do odzyskania sygnału RDS (wokół 57 kHz) fcentr = frds; df1 = 2500; df2 = 5000; ff = [ 0 fcentr-df2 fcentr-df1 fcentr+df1 fcentr+df2 fs/2 ]/(fs/2); fa = [ 0 0.01 1 1 0.01 0 ]; hBP57 = firpm(L,ff,fa); % ################################# % KODER SYGNAŁU RADIA FM - przykład % Program fm_koder_stereo_RDS.m % Wczytaj dwa monofoniczne sygnały audio [x1, fx1, Nbits ] = wavread('mowa44100'); x1=x1.'; % plot(x1); [x2, fx2, Nbits ] = wavread('bach44100'); x2=x2.'; % soundsc(x1,fx1); % Pre-emfaza, ch-ka płaska do 2.1 kHz, potem narastanie 20 dB na dekadę x1 = filter(b_pre,a_pre,x1); x2 = filter(b_pre,a_pre,x2); % Nadpróbkowanie do częstotliwości fs [N1,D1] = rat(fs/fx1,1e-4); x1 = resample(x1,N1,D1); [N2,D2] = rat(fs/fx2,1e-4); x2 = resample(x2,N2,D2); Nx = min( length(x1),length(x2) ); n=1:Nx; x1=x1(n); x2=x2(n); % x1 = zeros(1,Nx); % celach testowych % Bity RDS do zakodowania Nrds = ceil(Nx/(fs/fsymb)); rds = []; for k=1:ceil(Nrds/10), rds = [ rds 1 1 1 1 0 0 0 1 1 0 ]; end % rds = round(rand(1,Nrds)); % w celach testowych % Kodowanie różnicowe bitów RDS Nrds = length(rds); r = 0; for k=2:Nrds, r(k)=abs(rds(k)-r(k-1)); end Nr = ceil(fs/fsymb *length(r)); % Przejście na impulsy bi-fazowe bip = [-1 1; 1 -1 ]; brds = bip( r+1,: ); brds=brds'; brds=brds(:); % Nadpróbkowanie - wstawienie zer i wygładzenie RDS filtrem kształtującym uprds = zeros(1,Nr); t = dt*(0:Nr-1); clk = abs(diff(sign(sin(2*pi/Tsymb*t))))/2; clk = [clk 0]; indx=1; for n=1:Nr if(clk(n)==1) uprds(n)=brds(indx); indx=indx+1; end end prds = conv( uprds, hpsf); prds = prds(1:Nx); % wygładzenie filtrem psf clear t clk r brds uprds; % Złożenie całkowitego sygnału radia FM n=0:Nx-1; alpha = 2*pi*fpilot/fs*n; x =0.9*(x1+x2)+0.1*cos(alpha)+0.9*(x1-x2).*cos(2*alpha)+0.05*prds.*cos(3*alpha); A = max(x); x=x/A; clear prds alpha; % Końcowa modulacja częstotliwościowa fc = 0; % częstotliwość nośna radia FM - u nas wokół DC kf = 75000; % głębokość modulacji częstotliwości x = exp( j*2*pi*( fc/fs*n + kf*cumsum(x)/fs ) ); x=x.'; I = real(x); Q = imag(x); wavwrite([I Q],fs,32,'FM_Radio_IQ_250KS.wav'); % zapisz wynik na dysku % ########################################################### % DEKODER SYGNAŁU RADIA FM (zsyntezowanego lub rzeczywistego) % Dekoder RDS według standardu IEC 62106 % program fm_dekoder_stereo_RDS.m % Określenie danych wejściowych % y = x; clear x; [y,fs,Nbits] = wavread('FM_Radio_IQ_250KS.wav'); % sygnał zsyntezowany % [y,fs,Nbits] = wavread('FM_Radio_Krakow_101600kHz_IQ_250KS.wav',25*fs); % SDR# y = y(:,1) + sqrt(-1)*y(:,2); % IQ --> complex % ODTWORZENIE SYGNAŁU MONO % Obliczenie częstotliwości chwilowej - demodulacja częstotliwościowa dy = (y(2:end).*conj(y(1:end-1))); y = atan2( imag(dy), real(dy) ); clear dy; % Filtracja dolnoprzepustowa sygnału L+R (mono) ym = filter( hLPaudio, 1, y ); % Pozostawienie co fs/Abw-tej próbki ym = ym(1:fs/Abw:end); % Odsłuchanie sygnału L+R (mono) i zapisanie go na dysk soundsc(ym,Abw); w = ym-mean(ym); w=w/max(abs(w)); wavwrite(w,Abw,'FM_Radio_mono.wav' ); clear w; % ODTWORZENIE SYGNAŁU STEREO % Odseparowanie sygnału pilota 19 kHz (filtracja pasmowoprzepustowa) p = filter(hBP19,1,y); % Pętla PLL z filtrem typu IIR do odtworzenia częstotliwości i fazy pilota [7] % i na tej podstawie sygnałów nośnych: symboli c1, stereo c38 i danych RDS c57 freq = 2*pi*fpilot/fs; theta = zeros(1,length(p)+1); alpha = 1e-2; beta = alpha^2/4; for n = 1 : length(p) perr = -p(n)*sin(theta(n)); theta(n+1) = theta(n) + freq + alpha*perr; freq = freq + beta*perr; end c1(:,1) = cos(theta(1:end-1)/16+phasePSF); % nośna 1,1875 kHz c38(:,1) = cos(2*theta(1:end-1)); % nośna 38 kHz c57(:,1) = cos(3*theta(1:end-1)); clear p; clear theta; % nośna 57 kHz % Filtracja pasmowo-przepustowa sygnału L-R wokół 38 kHZ ys = filter(hBP38,1,y); % Przesunięcie sygnału L-R w częstotliwości do DC (38 kHz --> 0 kHz) ys = real(ys .* c38); clear c38; % Filtracja dolno-przepustowa ys = filter( hLPaudio, 1, ys ); % Pozostawienie co fs/Abw-tej próbki ys = ys(1:fs/Abw:end); % Synchronizacja czasowa sygnałów L+R i L-R (uwzględnienie opóźnienia L-R) delay = (L/2)/(fs/Abw); ym = ym(1:end-delay); ys=2*ys(1+delay:end); % 2 od modul clear ymm yss; % Odtworzenie kanałów L i R y1 = 0.5*( ym + ys ); y2 = 0.5*( ym - ys ); clear ym ys; % De-emfaza, ch-ka płaska do 2.1 kHz, potem opadanie 20 dB na dekadę y1 = filter(b_de,a_de,y1); y2 = filter(b_de,a_de,y2); % Odsłuchanie sygnału stereo po de-emfazie soundsc([y1' y2'],Abw); pause % Zapisanie sygnału stereo radia FM na dysk maxi = max( max(abs(y1)),max(abs(y2)) ); wavwrite( [ y1/maxi y2/maxi ], Abw, 'FM_Radio_stereo.wav' ); clear y1 y2; % ZDEKODOWANIE BITÓW SYGNAŁU RDS % Filtracja pasmowo-przepustowa wokół częstotliwości 57 kHz y = filter(hBP57,1,y); % Przesunięcie sygnału RDS w częstotliwości do DC (57 kHz --> 0 kHz) y = y .* c57; clear c57; % Filtracja LowPass dopasowana - filtr kształtujący impulsy RDS y = filter( hpsf, 1, y ); % Synchronizacja symbolowa (timing recovery) n1 = 5000; Nmany = 50*210; for n = 1:2*210-1 synchro(n) = sum( ( y(n1+n-1:n1+n-1+Nmany-1).*c1(n1 : n1+Nmany-1) ) ); end [v, indx] = max(synchro); y = y(indx:end); c1=c1(1:end-indx+1); % zsynchronizowanie sygnału z "zegarem" % Przesunięcie sygnału w częstotliwości do DC (1.1875 kHz --> 0 kHz) y = y .* c1; y = y/max(y); % Proste całkowanie - suma bieżąca ostatnich fs/Tsymb próbek h = ones(1,round(fs/fsymb)); y = filter(h,1,y); y = y/max(y); % Znalezienie ujemnego i dodatniego zbocza "zegara" N = length(c1); M=5; M2=(M-1)/2; maxi1 = []; maxi2 = []; for n = M2+1:N-M2 if( (c1(n-2)>0) & (c1(n-1)>0) & (c1(n+1)<0) & (c1(n+2)<0) ) % ujemne zbocze maxi1 = [ maxi1 n ]; end if( (c1(n-2)<0) & (c1(n-1)<0) & (c1(n+1)>0) & (c1(n+2)>0) ) % dodatnie zbocze maxi2 = [ maxi2 n ]; end end if( std(y(maxi1)) > std(y(maxi2)) ) maxi=maxi1; else maxi=maxi2; end % DD % Zmiana poziomów: {-1, +1} --> {0,1} rdsbits = (-sign( y( maxi ) )+1)/2; clear c1 maxi maxi1 maxi2; % Dekodowanie różnicowe z uwzględnieniem bi-fazowości sygnału rdsbits = abs(rdsbits(2:end) - rdsbits(1:end-1)); rdsbits = rdsbits(2:2:end) % Zapisanie odczytanych bitów na dysk - dla programu rds.m L. Hollevoeta save FM_Radio_RDS.txt rdsbits /ascii