Individální projekty MPOA

Mikroprocesory s architekturou ARM

Uživatelské nástroje

Nástroje pro tento web


2019:audio-resample

Toto je starší verze dokumentu!


Převzorkování zvukového signálu

Autor: Filip Šterc

Zadání

Realizujte algoritmus pro převzorkování audio signálu s vhodným poměrem, např. z 8kHz na 12kHz. Maximálně optimalizujte použitý kód, příp. vhodně využijte matematické knihovny a DSP rozšíření. Vstup a výstup signálu z vývojové desky realizujte přes DMA pomocí periferií ADC a DAC.

Teorie

V této části se budeme zabývat teorií kolem převzorkování signálu z jednoho kmitočtu na druhý pomocí celočíselného poměru vzorkovacích frekvencí. V tomto projektu je konkrétně použit poměr 2:3 s frekvencemi 8 kHz a 12 kHz. Avšak tento algoritmus s poměrem 2:3 lze bez jakýcholiv změn použít i pro další frekvence vzorkování v tomto poměru.

Interpolace

Pro převzorkování signálu na jiný kmitočet je nutné kmitočet nejdříve interpolovat na nejbližší společný celočíselný násobek kmitočtů (vstupního a výstupního), v tomto případě se jedná o kmitočet 24kHz. Toto je provedeno přidáním nulových vzorků mezi každý vzorek vstupního signálu. Pro interpolaci na N*fvz kmitočet je třeba přidat N-1 nul mezi každý vzorek.

x1…x2…x3…x4…x5… → x1…0…0…x2…0…0…x3…0…0…x4…0…0…x5…0…

Toto sice způsobí přesun vzorkovacího kmitočtu na N násobek původního kmitočtu, ale spektra přítomna na nižších násobcích vzorkovací frekvence zůstanou stále přítomna a zároveň způsobují nulovou úroveň nově přidaných vzorků. Proto je pro rekonstrukci signálu potřeba tyto spektra odfiltrovat pomocí vhodného FIR filtru.

Decimace

Po interpolaci je potřeba signál decimovat a tím snížit vzorkovací frekvenci na požadovanou úroveň. Decimaci na vzorkovací kmitočet fvz/N, je možné provést pomocí vybrání pouze každého Ntého vzorku. V tomto případě je potřeba decimace 2x, to znamená vybrání každého druhého vzorku.

y1…y2…y3…y4…y5…y6…y7… → y1…y3…y5…y7…

Ve spektru, takováto decimace, způsobí nakopírování spektra z původní frekvence na frekvenci novou. Aby nedošlo k aliasingu, je třeba zajistit, aby bylo spektrum signálu před decimací prázdné na frekvencích vyšších jak polovina nového vzorkovacího kmitočtu.

Převzorkování

Během převzorkování je, dle teorie, třeba signál filtrovat pomocí 2 různých FIR filtrů. Jeden pro rekonstrukci signálu po interpolaci a druhý pro předejití aliasingu před decimací. Tyto filtry jsou však kaskádně zařazeny hned za s sebou a proto je v praxi možné je nahradit pomocí jediného filtru s nejmenším potřebným mezním kmitočtem.

Pro interpolaci je třeba filtrovat veškerý signál od poloviny vzorkovacího kmitočtu vstupního signálu.
V tomto případě: fvz1/2 = 8 kHz/2 = 4 kHz.

Pro decimaci je třeba filtrovat veškerý signál od poloviny vzorkovacího kmitočtu výstupního signálu.
V tomto případě: fvz2/2 = 12 kHz/2 = 6 kHz.

Nižší kmitočet je 4 kHz, proto bude v tomto projektu použit FIR filtr s pásmem nepropusti od této frekvence.

V přechozí kapitole bylo řečeno, že pro převzorkování bude třeba filtr s pásmem nepropustnosti od frekvence 4 kHz. Pro využití co největšího pásma spektra je vhodné volit mezní kmitočet taktéž blízko tohoto kmitočtu. Avšak příliš krátká přechodová oblast mezi těmito kmitočty zase znamená velký počet koeficientů FIR filtru, proto je třeba tento kmitočet volit rozumně. Pro tento případ byl zvolen mezní kmitočet fmez = 3,75 kHz. V kombinaci s definovanou úrovní potlačení -80 dB je řád filtru n = 243. Samotný FIR filtr je navržen pomocí programu Matlab v rozšíření Filter Designer s následujícími parametry:

Koeficienty navrženého filtru byly uloženy do souboru „FIR_mat.mat“, a poté převedeny na hlavičkový soubor jazyka C „fir_coef.h“ pomocí matlabovského skriptu „FIR_test.m“.

Schéma zapojení

signál ze zvukové karty počítače je v napěťovém rozmezí (-1 - 1) V. Použitý procesor však zvládá zpracovávat pouze kladná napětí, proto je třeba úroveň signálu nejdříve zvednout nad zem. Toto lze snadno vyřešit pomocí sériového kondenzátoru a napěťového děliče, který úroveň signálu posune na úroveň poloviny napájecího napětí 3V.

Při výběru hodnot kondenzátoru, je třeba brát ohled na frekvenci signálu. Pro signál se toto zapojení jeví jako filtr horní propusti s odpory zapojenými paralelně, proto pro vybrané hodnoty je mezní frekvence fmez = 1/(2*pi*0,5R*C) = 28,9 Hz. Pro člověka je slyšitelný pouze zvuk v rozmezí 16 Hz - 20 kHz, tudíž kromě malé krajní oblasti mezi (16 - 29) Hz, slyšitelný signál může projít beze změny. ¨

Implementace

Pro realizaci kódu jsem použil prostředí STM32CubeIDE, které kombinuje IDE založené na Eclipse společně s prostředím STM32CubeMX pro generování inicializačního kódu jednotlivých periferií. Bohužel se mi při pokusu o realizaci nepovedlo zprovoznit ovladače DMA, které byly součástí zadání. A to ani při sledování nejrůznějších návodů, či pokusu importovat dříve fungující projekt do tohoto prostředí. Z tohoto důvodu je finální realizace vytvořena pomocí přímého čtení hodnot z periferií.

Systém je časován pomocí přerušení dvou časovačů. Tyto časovače jsou nastaveny na časy čtení a zápisu vstupu a výstupů, tudíž 8 a 12 kHz. Aby nedocházelo k blokování jádra přerušením, je obsluha přesunuta do hlavní smyčky a přistupuje se k ní pomocí příznaků v podobně globálních funkcí, které jsou nastavovány příslušnými přerušeními.

Pro zpracování dat je použit kruhový buffer adcBuffer[] s délkou 1024 vzorků. Do tohoto bufferu jsou ukládány nadvzorkované data ze vstupu, avšak zatím bez rekonstrukce, která je prováděna až před ukládáním na výstup. Pro pohyb v tomto bufferu jsou použity 2 ukazatele/indexy: adc_readptr a adc_writeptr. Tyto ukazatele jsou incializovány s offsetem poloviny délky bufferu aby nedocházelo k dočasnému vzájemnému přebíhání. Tento offset však zavede do signálu zpoždění, které je ale pro člověka nevnímatelné:
td = offset/(Ndec*fresamp) = 21ms.

static uint32_t adcBuffer[ADC_BUFFER_LEN] = {0};
static uint16_t adc_readptr = ADC_BUFFER_LEN/2;
static uint16_t adc_writeptr = 0;

Vzhledem k délce bufferu, která je mocnina dvojky, lze kruhovost bufferu realizovat jednoduchým logickým součinem při inkrementaci/dekrementaci ukazatelů:

adc_writeptr = (adc_writeptr + 1) & (ADC_BUFFER_LEN - 1);

Vstup je realizován pomocí periferie ADC2, kanálu 1 (pin PA1). Analogová hodnota na tomto pinu je čtena s frekvencí 8 kHz a okamžitě zapisována do pole adcBuffer[], následována dvěma nulovýma hodnotama pro okamžitou realizaci nadvzorkování. Současně je tato hodnota i poslána na kanál 1 (pin PA4) periferie DAC pro možnost porovnání nepřevzorkovaného signálu s převzorkovaným.

HAL_ADC_Start(&hadc2);
HAL_ADC_PollForConversion(&hadc2, HAL_MAX_DELAY);
value = HAL_ADC_GetValue(&hadc2);
HAL_ADC_Stop(&hadc2);
 
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, value);
adcBuffer[adc_writeptr] = value;
for(uint8_t i = 0; i < 2; i++){                 //nadvzorkování
	adc_writeptr = (adc_writeptr + 1) & (ADC_BUFFER_LEN - 1);
	adcBuffer[adc_writeptr] = 0;  	
}

Převzorkovaný výstup je realizovaný pomocí kanálu 2 (pin PA5) periferie DAC. Obsluha je opět v hlavní smyčce a je na ni přistupováno s frekvencí 12kHz. Zároveň je z této obsluhy volána funkce resample(), která realizuje rekonstrukci vzorku předem nadvzorkovanéhosignálu z pole adcBuffer[], pomocí předem navrženého FIR filtru a následnou saturaci vzorku předávaného na výstup. Saturace však v tomto případě není nezbytná, protože vzhledem k poklesu energie signálu vlivem interpolace by výstupní signál měl mít vždy nižší amplitudu než vstupní signál.
Decimace je definována pouze jako vynechávání vzorků a tak je zde realizována pomocí inkrementace ukazatele pro čtení o 2.

float sum = 0;
uint32_t out;
uint16_t readBufTmp = adc_readptr;			//uložení ukazatele pro čtení
 
for(uint8_t i = 0; i < FIR_LENGTH; i++){		//rekonstrukce signálu pro interpolaci
	sum += adcBuffer[readBufTmp]*fxcoef[i];
	readBufTmp = (readBufTmp - 1) & (ADC_BUFFER_LEN - 1);
}
 
adc_readptr = (adc_readptr + 2) & (ADC_BUFFER_LEN - 1);	//inkrementování read pointeru +2 pro decimaci 2*
 
if(sum > 4095){			//převedení na 32 bit hodnotu požadovanou DAC, se saturací
	out = 4095;
}else if(sum < 0){
	out = 0;
}else{
	out = (uint32_t)(sum);
}
return out;

Soubory

STM32CubeIDE projekt
Matlab soubory
2019/audio-resample.1579535716.txt.gz · Poslední úprava: 2020/01/20 16:55 autor: Filip Šterc