Kompresja sygnałów fonicznych
Autorzy: Maciej Bartkowiak
Pliki: rozdzial_15.zip
Przykład 15.1
Jest to uproszczona implementacja modelu kodeka (plik przyklad_15_1.m), która dokonuje dekompozycji sygnału na wskazaną liczbę podpasm. Wartości próbek każdego podpasma są skalowane i kwantowane z określoną rozdzielczością bitową. Liczba bitów potrzebnych do zakodowania skwantowanych próbek naturalnym kodem binarnym jest szacowana na podstawie zakresu dynamicznego w każdym paśmie. Następnie sygnał jest rekonstruowany przez odwrócenie procesu. Program kodowanie_podpasmowe znajduje się w pliku plik kodowanie_podpasmowe.m.% przykład 15.1: Demonstracja kodowania podpasmowego clc; clear; close all [x,Fs] = wavread('harpsichord.wav'); % Wczytanie sygnału z pliku wav soundsc(x,Fs) % odsłuchanie figure(1) specgram(x,2048,Fs,2000) % demonstracja spektrogramu title('Sygnał oryginalny') % Zakodowanie koderem podpasmowym z użyciem 8 podpasm i 6 bitów na próbkę % UWAGA: przed skwantowaniem każde pasmo jest normalizowane do zakresu –1..1 [y2,bps] = kodowanie_podpasmowe(x,8,6); soundsc(y2,Fs) figure(2) specgram(y2,2048,Fs,2000) title(sprintf('Liczba bitów na próbkę: %1.2f\n',bps)) % Zakodowanie koderem podpasmowym z użyciem 32 podpasm i 8 bitów na próbkę [y3,bps] = kodowanie_podpasmowe(x,32,5); soundsc(y3,Fs) figure(3) specgram(y3,2048,Fs,2000) title(sprintf('Liczba bitów na próbkę: %1.2f\n',bps)) % Zakodowanie koderem podpasmowym z użyciem 16 podpasm i zmiennej liczby bitów na próbkę [y4,bps] = kodowanie_podpasmowe(x,16,[6 5 4 4 3 3 3 3 3 3 3 3]); soundsc(y4,Fs) figure(4) specgram(y4,2048,Fs,2000) title(sprintf('Liczba bitów na próbkę: %1.2f\n',bps))
Przykład 15.2
Szybka implementacja przekształcenia DCT-4 w formie mnożenia macierzy. Kod przykładu jest zapisany w pliku dct4.m.function y = dct4(x) % Szybkie obliczenie transformaty DCT-4 z bloku próbek % y = dct4(x) % x - pionowy wektor próbek % y - pionowy wektor współczynników x = x(:); N = length(x); if mod(N, 2) error('Rząd transformacji musi być parzysty'); end N = length(x); [n,k] = meshgrid(0:(N-1),0:(N/2-1)); C = cos(pi*(2*n+1+N/2).*(2*k+1)/(2*N)); y = C*x;
Przykład 15.3
Szybka implementacja odwrotnego przekształcenia DCT-4 w formie mnożenia macierzy. Kod przykładu jest zapisany w pliku idct4.m.function y = idct4(x) % Szybkie obliczenie odwrotnej transformaty DCT-4 z bloku współczynników % % y = idct4(x) % x - pionowy wektor współczynników % y - pionowy wektor próbek x = x(:); N = 2*length(x); [k,n] = meshgrid(0:(N/2-1),0:(N-1)); C = cos(pi*(2*n+1+N/2).*(2*k+1)/(2*N)); y = 4*C*x/N;
Przykład 15.4
Demonstracja (plik przyklad_15_4.m), jak wygląda zrekonstruowany blok próbek sygnału po wykonaniu DCT-4 i odwrotnej DCT-4. Na wspólnym wykresie wyświetlimy sygnał oryginalny (niebieski), składniki aliasowe (zielone) oraz ich złożenie, czyli sygnał zrekonstruowany w 1 bloku (na czerwono).% przykład 15.4 % Przygotowanie wektora kolumnowego próbek funkcji liniowo rosnącej x = (1:100)'; % Obliczenie transformaty i odwrotnej transformaty F = dct4(x); y = idct4(F); % Wykresy figure(1) plot([x [-x(end/2:-1:1); x(end:-1:end/2+1)] y]) legend('Oryginalny','Nakładki','Wynik transformaty odwrotnej') disp('Proszę nacisnąć dowolny klawisz'); pause % Przygotowanie wektora próbek przykładowego sygnału t = (1:1e3)'; x = exp(-3*t/1e3).*cos(2*pi*t.^2/1e5); % Obliczenie transformaty i odwrotnej transformaty F = dct4(x); y = idct4(F); % Wykresy plot([x [-x(end/2:-1:1); x(end:-1:end/2+1)] y]) legend('Oryginalny','Nakładki','Wynik transformaty odwrotnej') disp('Proszę nacisnąć dowolny klawisz'); pause % Przygotowanie wektora próbek przykładowego sygnału t = linspace(-5,5,1e4)'; x = sinc(t); % Obliczenie transformaty i odwrotnej transformaty F = dct4(x); y = idct4(F); % Wykresy plot([x [-x(end/2:-1:1); x(end:-1:end/2+1)] y]) legend('Oryginalny','Nakładki','Wynik transformaty odwrotnej')
Przykład 15.5
Uproszczona implementacja kodera transformatowego, który dokonuje podziału sygnału x na bloki o długości N, z zakładką N/2 i oblicza transformatę MDCT. Współczynniki transformaty Fk są skalowane i kwantowane zgodnie z podanymi współczynnikami skalującymi Q, którymi można regulować stopień kompresji (jeden wspólny współczynnik lub wektor indywidualnych współczynników osobno dla każdego indeksu częstotliwości). Wyjściowa tablica symboli sym to całkowitoliczbowa reprezentacja skwantowanych współczynników transformaty. Wypadkowa wielkość zakodowanego strumienia (średnia liczba bitów na próbkę, bps) jest szacowana na podstawie zakresu dynamicznego symboli (osobno dla każdego indeksu częstotliwości). Implementacja kodera jest zapisana w pliku kodtr.m.function [sym,bps] = kodtr(x,N,Q) % Koder transformatowy % % [sym,bps] = kodtr(x, N, Q) % x – sygnał wejściowy % % N – długość bloku próbek dla transformaty MDCT % Q – współczynniki skalujące (jeden wspólny lub wektor indywidualnych współczynników) % sym – tablica zakodowanych symboli % bps – średnia liczba bitów zakodowanych danych na próbkę sygnału wejściowego H = N/2; % przesunięcia kolejnych bloków M = floor((length(x)-H)/H); % liczba bloków sym = zeros(H,M); % tablica symboli danych zakodowanych win = sin(pi*((0:(N-1))+0.5)/N)'; % okienko do transformaty MDCT h_wbar = waitbar(0,'Przetwarzanie ramek', 'Name', 'Kodowanie transformatowe'); for m = 0:M-1 waitbar(m/M,h_wbar); n0 = m*H + 1; % początek bloku x0 = x(n0:n0+N-1); % pobieranie bloku próbek x0 = x0.*win; % okienkowanie Fk = dct4(x0); % obliczenie transformaty Fkq = fix(Fk.*Q); % kwantowanie współczynników sym(:,m+1) = Fkq; % zapisanie do tablicy symboli end close(h_wbar); % Oszacowanie wielkości strumienia danych zakr = (max(sym')-min(sym'))'; % zakresy zmienności symboli koszt = max(0,ceil(log2(zakr))); % szacunkowy koszt zakodowania symboli bps = mean(koszt); % średnia liczba bitów na próbkę
Przykład 15.6
Implementacja dekodera transformatowego zgodna z koderem z przykładu 15.5. Dekoder rekonstruuje sygnał y poprzez odwrócenie skalowania zastosowanego do współczynników transformaty przed kwantyzacją, zastosowanie odwrotnego przekształcenia MDCT i zsumowania odtworzonych bloków próbek z zakładką 50%. Implementacja funkcji dekodera znajduje się w pliku dektr.m.function y = dektr(sym,N,Q) % Dekoder transformatowy % y = dektr(sym, N, Q) % % sym – tablica zakodowanych symboli % N – długość bloku próbek dla transformaty MDCT % Q – współczynniki skalujące (jeden wspólny lub wektor indywidualnych współczynników) % y – sygnał odtworzony H = N/2; % przesunięcia kolejnych bloków M = size(sym,2); % liczba bloków L = H * (M+1); % szacowana długość sygnału zdekodowanego y = zeros(L,1); % miejsce na próbki sygnału win = sin(pi*((0:(N-1))+0.5)/N)'; % okienko do transformaty MDCT h_wbar = waitbar(0,'Dekodowanie ramek', 'Name', 'Kodowanie transformatowe'); for m = 0:M-1 waitbar(m/M,h_wbar); Fkq = sym(:,m+1); % odczytanie kolejnego wektora symboli Fkr = Fkq./Q; % odtworzenie współczynników transformaty y0 = idct4(Fkr); % obliczenie odwrotnej transformaty y0 = y0.*win; % ponowne okienkowanie n0 = m*H + 1; % początek bloku y(n0:n0+N-1) = y(n0:n0+N-1)+y0; % składanie bloków na zakładkę end close(h_wbar);
Przykład 15.7
Uproszczona implementacja bloku operacji TNS w koderze. Operacja jest powtarzana dla pojedynczych bloków współczynników transformaty kosinusowej, które odpowiadają blokom próbek, w których wykryto impuls (transient). Zmodyfikowane współczynniki zastępują oryginalne współczynniki w tym bloku. Kod funkcji znajduje się w pliku tns_pre.m.function [Fk,R] = tns_pre(Fk,Pmax,Gmin) % Fk = tns_pre(Fk,Pmax,Gmin) % % Fk - wektor współczynników transformaty MDCT % Pmax - maksymalny rząd predykcji % Gmin - minimalny zysk predykcji % R - współczynniki PARCOR predyktora Rmin = 0.05; % wyznaczamy współczynniki predyktora a = lpc(Fk,Pmax); % przekształcamy do postaci PARCOR R = poly2rc(a); % znajdujemy małe wartości współczynników z = find(abs(R)>=Rmin,1,'last'); if ~isempty(z) % odrzucamy końcowe małe współczynniki zmniejszając rząd predyktora R(z+1:end)=[]; a = rc2poly(R); % przeliczenie z PARCOR na LPC end % filtr analizy ("wybielanie" w czasie, % czyli wyrównywanie amplitudy sygnału) X = filter(a,1,Fk); % obliczanie zysku predykcji Gp = rms(Fk)/rms(X); if Gp >= Gmin % warunek aktywności narzędzia TNS % zastąpienie wybranych współczynników MDCT wartościami błędu predykcji Fk = X; else R = []; end
Przykład 15.8
Uproszczona implementacja bloku operacji TNS w dekoderze. Operacja jest wykonywana dla tych samych pojedynczych bloków współczynników transformaty kosinusowej, które zostały zmodyfikowane po stronie kodera (informacja o włączeniu TNS wynika z niezerowego bloku współczynników predyktora powiązanego z danym blokiem transformaty). Rezultatem operacji jest odtworzenie właściwych współczynników, które reprezentują zakodowany sygnał. Kod funkcji jest zapisany w pliku tns_post.m.function Fk = tns_post(Fk,R) % Fk = tns_post(Fk,A) % % Fk - wektor współczynników transformaty MDCT % R - współczynniki predyktora % przeliczenie współczynników do postaci LP a = rc2poly(R); % filtr syntezy (odtwarzanie przebiegu) Fk = filter(1,a,Fk);