Individální projekty MPOA

Mikroprocesory s architekturou ARM

Uživatelské nástroje

Nástroje pro tento web


2019:audio-resample

Rozdíly

Zde můžete vidět rozdíly mezi vybranou verzí a aktuální verzí dané stránky.

Odkaz na výstup diff

Obě strany předchozí revize Předchozí verze
Následující verze
Předchozí verze
2019:audio-resample [2020/01/19 19:30]
Filip Šterc [Soubory]
2019:audio-resample [2020/01/20 19:41] (aktuální)
Filip Šterc [Schéma zapojení]
Řádek 7: Řádek 7:
  
 ===== Teorie ===== ===== 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 ==== ==== Interpolace ====
Řádek 12: Řádek 14:
 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.\\ ​ 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…\\+x1…x2…x3…x4…x5… ​ ->  x1…0…0…x2…0…0…x3…0…0…x4…0…0…x50…\\
  
 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. 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.
Řádek 50: Řádek 52:
 ===== Schéma zapojení ===== ===== 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.+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.
  
 {{2019:​sch_xsterc02.png?​500}} {{2019:​sch_xsterc02.png?​500}}
  
-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 f<​sub>​mez</​sub>​ = 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. ​¨+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 f<​sub>​mez</​sub>​ = 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 ===== ===== Implementace =====
  
-Pro realizaci kódu jsem použil prostředí ​STM32CubeIDEkteré 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í.\\+Pro realizaci kódu jsem použil prostředí ​EmBitz, společně s nástrojem ​STM32CubeMX pro generování inicializačního kódu procesorů od STMicroelectronics.
  
-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 kHzAby 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 ​íslušnými přerušeními.\\+Systém ​funguje následujícím způsobem. Vstupní signál ​je vzorkován periferií ADC1, kanál 1 (PA1), ​pomocí ​ovladače DMAkterý ukládá data vždy do vrchní poloviny bufferu adc_buffer[]Po naplnění bufferu jsou tyto data přesunuta do spodní poloviny odkud jsou čteny pomocí ​periferie DAC, kanálu 1 (PA4), opět es ovladač DMA. Tento výstup slouží pouze pro srovnání s později evzorkovaným signálem. Oba ovladače DMA jsou řízeny pomocí timeru TIM2 nastaveného na frekvenci 8 kHz. Aby bylo možné data zpracovávat každých 100 ms, je celková délka adc_bufferu nastavena na 2*800 vzorků.\\
  
-Pro zpracování ​dat je použit kruhový buffer adcBuffer[] s délkou 1024 vzorků. Do tohoto bufferu jsou ukládány interpolované data ze vstupuavšak zatím bez rekonstrukce,​ která je prováděna až před ukládáním na výstup. +Při přesunu ​dat mezi polovinami adc_bufferu,​ jsou tyto vzorky zároveň zkopírovány do bufferu upsample_buffer[], společně s 82 starými vzorky ​proloženy dvěma nulami, pro realizaci nadvzorkování 3xDodatečných 82 vzorků z nižší poloviny ​adc_bufferu se zde nachází kvůli FIR filtru, který vyžaduje paměť 244 edchozích vzorků. (Po nadvzorkování je 82*3 = 246).\\ 
-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 ​ebíháníTento offset však zavede do signálu zpoždění,​ které je ale pro člověka nevnímatelné:​\\ t<​sub>​d</​sub>​ = offset/(N<​sub>​dec</​sub>​*f<​sub>​resamp</​sub>​= 21ms.\\ +Přesun dat je realizován funkcí buffer_prepare():​ 
-<code c>  +<code c> 
-static uint32_t adcBuffer[ADC_BUFFER_LEN] = {0}+void buffer_prepare(void){ 
-static uint16_t adc_readptr ​= ADC_BUFFER_LEN/2+    for(uint16_t i = 0; i < (ADC_BUFFER_LEN + 82); i++){ 
-static uint16_t adc_writeptr ​0;+        ​upsample_buffer[i*3] ​adc_buffer[ADC_BUFFER_LEN ​- 82 + i]
 +        if(i >82){ 
 +            adc_buffer[i - 82] = adc_buffer[ADC_BUFFER_LEN - 82 + i]; 
 +        } 
 +    } 
 +}
 </​code>​ </​code>​
  
-Vzhledem k délce bufferu, která ​je mocnina dvojky, lze kruhovost ​bufferu ​realizovat jednoduchým logickým součinem i inkrementaci/​dekrementaci ukazatelů: +Po přesunu dat do upsample_buffer[] jsou tyto data následně interpolována FIR filtrem. Pro snížení náročnosti ​je společně s interpolací okamžitě prováděna decimace zpracováním pouze každého druhého vzorku (liché vzorky by stejně byly zahozeny). Převzorkované data jsou ukládány do posledního ​bufferu ​dac_buffer[]. Aby se zamezila nutnost ​čekání mezi navzorkováním nových dat a jejich ​evzorkováním,​ je použit buffer dvojnásobné délky 2*1200 vzorků, kdy do jedné poloviny jsou ukládány zpracovávané data a z druhé poloviny jsou data čtena do kanálu 2 (PA5), periferie DAC. Čtení je prováděno ovladačem DMA, který je řízen timerem TIM4 s frekvencí 12 kHz.\\ 
-<code c>  +Převzorkování je umístěno ve funkci resample() se vstupním argumentem dac_buff_side,​ který určuje do které poloviny dac_bufferu mají být data ukládána
-adc_writeptr = (adc_writeptr + 1) & (ADC_BUFFER_LEN - 1); +<code c> 
-</​code>​+void resample(uint8_t dac_buff_side)
 +    float sum
 +    ​uint16_t out; 
 +    uint16_t readBuf;
  
-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 interpolace. 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.\\+    for(uint16_t i = 0; i < DAC_BUFFER_LEN*2;​ i+=2){        //​inkrementování read pointeru +2 pro decimaci 2* 
 +        sum = 0; 
 +        out = 0; 
 +        readBuf = i + 246;​  ​   //uložení ukazatele ​pro ctení
  
-<code c>  +        for(uint8_t j = 0; j FIR_LENGTH; j++){            //​rekonstrukce interpolovaného signálu 
-HAL_ADC_Start(&hadc2); +            sum += upsample_buffer[readBuf-j]*fxcoef[j];​ 
-HAL_ADC_PollForConversion(&hadc2, HAL_MAX_DELAY); +        } 
-value HAL_ADC_GetValue(&hadc2); + 
-HAL_ADC_Stop(&hadc2);+        if(sum > 4095){                     //​prevedení na 32 bit hodnotu požadovanou DAC, se saturací 
 +            out = 4095
 +        }else if(sum < 0)
 +            out = 0
 +        ​}else{ 
 +            out = (uint32_t)(sum); 
 +        } 
 +        dac_buffer[dac_buff_side*DAC_BUFFER_LEN + (i>>1)] = out; 
 +    }
  
-HAL_DAC_SetValue(&​hdac,​ DAC_CHANNEL_1,​ DAC_ALIGN_12B_R,​ value); 
-adcBuffer[adc_writeptr] = value; 
-for(uint8_t i = 0; i < 2; i++){                 //​upsampling 
- adc_writeptr = (adc_writeptr + 1) & (ADC_BUFFER_LEN - 1); 
- adcBuffer[adc_writeptr] = 0;   
 } }
 </​code>​ </​code>​
  
-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 istupováno s frekvencí 12kHzZároveň je z této obsluhy volána funkce resample()která realizuje rekonstrukci vzorku předem interpolovaného signálu z pole adcBuffer[]pomocí předem navrženého FIR filtru a následnou saturaci vzorku ​edávaného ​na výstupSaturace ​ak v tomto í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.\\ +===== Video ===== 
-Decimace ​je definována pouze jako vynechávání vzorků a tak je zde realizována pomocí inkrementace ukazatele pro čtení o 2. +Na následujícím videu je ukázána funkčnost tohoto projektu ​i zpracování signálu o frekvenci 1 kHzNa osciloskopu jsou zobrazeny signály od vrchu dolů:\\ CH3 - vstupní signál na pinu PA1,\\ CH1 - nepřevzorkovaný výstupní signál na pinu PA4,\\ CH2 - evzorkovaný výstupní signál ​na pinu PA5.\\ 
-<code c>  +Na nastavení osciloskopu je možné si imnou, že i es to, že se signály zdají být podobné, tak převzorkovaný ​signál ​na CH2 má rozlišení pouze 200mV/div, oproti ostatním s 500mV/div. Tato nižší ​amplituda ​je vlastností interpolace,​ kdy je prováděna rekonstrukce signálu odfiltrováním přebytečných kopií spektra, což způsobí pokles energie signálu (pro interpolaci 3x, pokles energie na 1/3). Pokud by bylo požadavkem zachování amplitudy signálu, bylo by třeba převzorkovaný signál vynásobit třemi, což ale vede i ke zvýšení šumu signálu.
-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 interpolovaného signálu +[[https://www.youtube.com/watch?v=_VB4ujhArGU|Video ukázka]]
- 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; +
-</​code>​+
  
 ===== Soubory ===== ===== Soubory =====
  
-== STM32CubeIDE ​projekt == +== EmBitz ​projekt == 
-{{2019:xsterc02_projekt_MPOA.zip}}+{{2019:xsterc02_projekt_mpoa.zip}}
  
 == Matlab soubory == == Matlab soubory ==
 {{2019:​xsterc02_matlab.zip}} {{2019:​xsterc02_matlab.zip}}
  
2019/audio-resample.1579458653.txt.gz · Poslední úprava: 2020/01/19 19:30 autor: Filip Šterc