Analiza i obróbka sygnału(FFT)

0

Witam,

Od jakiegoś czasu "bawię" się w analizowanie sygnału. Nie mogę uporać się z jedną sprawą; Przekonwertowałem plik z muzyką na format raw(bez nagłówków, próbkowanie 44,100kHz 16bit signed), następnie przesyłam dane strumieniowo do mojego programu a ten przesyła do programu aplay.

/* ... */
#define N 1024

int main(int argc, char * argv[]){
	double x[N];
	double y[N];
	short buf[N];
	int i;
	int len;
	do{
		len = fread(buf, 2, N, stdin); /* odczyt muzyki */
		for(i=0; i<N; i++){
			x[i] = buf[i];
			y[i] = 0;
		}
		FFT(1, log2_(N), x, y); /* zamiana na widmo */
		
		for(i=N/2; i<N; i++){ /* wyzerowanie ujemnych częstotliwości(A) */
			x[i] = y[i] = 0;
		}

		for(i=100; i<N; i++){ /* "idealny" filtr dolnoprzepustowy(B) */
		  x[i] = y[i] = 0;
		}

		FFT(0, log2_(N), x, y); /* zamiana na dźwięk */

		for(i=0; i<N; i++){ /* C */
			buf[i] = x[i];
		}

		fwrite(buf, 2, N, stdout);
	}while(len);

	return 0;
}
// cat muzyka.raw | ./moj_program | aplay -r 44100 -f S16_LE

Zamieniając sygnał na widmo, powstaje odbicie lustrzane sygnału wejściowego względem środka - te częstotliwości "wyżej" nazwałem ujemnymi - wprowadzając sygnał zespolony(z przemiany czestotliwości), druga część wykresu właśnie pokazywała mi częstotliwości ujemne. Nie wiem jak zabardzo to interpretować w tym przypadku.
Częstotliwości ujemne zeruje w punkcie A, oczywiście głośność końcowa dźwięku będzie mniejsza, ale nie zniekształca sygnału. Problem pojawia się w punkcie C, tutaj chcę przepuścić dalej tylko niskie częstotliwości; działać działa, tylko słychać charakterystyczne przeskoki pomiędzy następną analizą(44100/1024 razy na sekundę występują te pyknięcia). Teoretycznie nie byłoby problemu jakbym zamienił cały sygnał na widmo i go obrobił, ale właśnie jak musi się różnić obróbka sygnału który jest podzielony na paczki(1024 próbek) jak w tym przypadku?
Nie mogę znaleźć na internecie jakiegoś opisu dotyczącego filtracji oraz przesuwaniu częstotliwości. Ma ktoś z was jakieś materiały na ten temat?

0

A nie lepiej użyć filtrów w dziedzinie czasu zamiast kombinować ze spektogramem? Na pewno wydajniejszy sposób.

2

łączysz dwa różne sygnały, na styku musi trzaskać.
robi się to "na zakładkę", furieruje się nachodzące na siebie odcinki czasu, następnie robi cudawianki z widmem, wraca w dziedzinę czasu
i teraz, masz dwa nachodzące w czasie na siebie sygnały,
na odcinki gdzie nachodzą na siebie jeden płynne się gasi a drugi wzmacnia

0

Xitami możesz przybliżyć co zrobić z tymi próbkami? Nie mogę nic sensownego się doszukać. Widzę że jesteś z Gliwic i chyba z tego co wywnioskowałem z elektrody to studiujesz? Siedzę w elektronie, mieszkasz gdzieś w pobliżu?

0

kiedyś zacząłem studia, ale dostałem w łapki komputer i przestałem mieć czas na pierdoły :-) a było to dawno, oj dawno.
nieuk hobbysta jestem i tyle.
Siedzisz w elektronie? To takie malutkie cóś, co to niektórzy sądzą że jest tylko jedno strasznie rozbiegane po wszechświecie? To bardzo maluśki musi być z Ciebie kwadracik. :-) Mieszkam na kur... tamie, ale co z tego?
A wracając do naszych baranów. Nadachowski (bez kulki) przetłumaczył bardzo fajną książkę o DSP, oryginał udostępniony przez autora znajdziesz w sieci
www.dspguide.com
doskonała rzecz dla inżyniera, bez onieśmielającej matematyki. Choć narwaniec może poczytać i o Laplace'u i o Z.

0

wracając w dziedzinę czasu można chyba robić krótsze FFT, sygnał i tak walnięty a nasze uszy i tak nie wrażliwe na fazę (jeśli nie mierzą odległości).
odwracało by się widmo rzeczywiste (nie urojone), a to można zrobić licząc odwrotne FFT ale o połowę krótsze
wracając w dziedzinę czasu chcemy uzyskać sygnał rzeczywisty ( :) a może część rzeczywistą na prawo a urojoną na lewo :) ) aby tak było widmo musi być parzyste (jak cos, nie jak sin)
to jest wskazówka co zrobić z "ujemnymi" częstotliwościami.

1

Wczoraj nasiedziałem się nad zeszytem i porysowałem sobie różne łączenia próbek, wymyśliłem żeby robić to kosinusoidalnie; wtedy przypomniało mi się że coś podobnego widziałem na internecie - a dokładnie o ile dobrze pamiętam, poprawa widma poprzez okienkowanie.
Udało mi się coś takiego splecić:

//gcc -o main main.c fft.c -lm && cat wakeup.raw | ./main | aplay -r 44100 -f S16_LE

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

#define FREQ 44100
#define N   (4096)

int log2_(int l){
  int r = 0;
  while(l>>=1) r++;
  return r;
}


typedef double window[N*2];
typedef double sample[N];

int sample_read(sample samp){
	short buf[N];
	int i;
	int len = fread(buf, 2, N, stdin);
	for(i=0; i<N; i++) samp[i] = buf[i];
	return len;
}

void sample_write(sample samp){
	short buf[N];
	int i;
	for(i=0; i<N; i++) buf[i] = samp[i];
	fwrite(buf, 2, N, stdout);
}

void window_copy(window dst, window src){
	memcpy(dst, src, sizeof(window));
}

void window_next(window win, sample samp){
	static sample s[3];
	memcpy(s[0], s[1], sizeof(sample)*2);
	memcpy(s[2], samp, sizeof(sample));
	memcpy(win, s[0] + N/2, sizeof(window));
}

void window_hann(window win){
	int i;
	for(i=0; i<N*2; i++){
		win[i] *= 0.5 - 0.5*cos(2*M_PI*i/(N*2));
	}
}

void window2complex(double * re, double * im, window win){
	int i;
	for(i=0; i<N*2; i++){
		re[i] = win[i];
		im[i] = 0;
	}
}

void complex2window(window win, double * re, double * im){
	int i;
	for(i=0; i<N*2; i++){
		win[i] = re[i];
	}
}

void windows2sample(sample samp, window wprv, window wcur){
	int i;
	sample samp1;
	sample samp2;
	memcpy(samp1, wprv+N, sizeof(sample));
	memcpy(samp2, wcur, sizeof(sample));
	for(i=0; i<N; i++){
		samp[i] = samp1[i] + samp2[i];
	}
}

int main(int argc, char * argv[]){
	int i;
	double x[N*2], y[N*2];
	sample samp;
	window wcur, wprv;

	while(sample_read(samp)){
		
		window_copy(wprv, wcur);	/* wprv <- wcur */
		window_next(wcur, samp);	/* worg <- samp */
		window_hann(wcur);			/* hann window  */

/* FFT */
		window2complex(x, y, wcur);
		FFT(1, log2_(N*2), x, y);

		for(i=200; i<N*2; i++){	/* TEST */
		  	y[i] = x[i] = 0; 
		}
		
		FFT(0, log2_(N*2), x, y);
		complex2window(wcur, x, y);
/* END */

		windows2sample(samp, wprv, wcur);
		sample_write(samp);
	}

	return 0;
}

Dźwięk jest bardzo ładny, wycięte są wysokie częstotliwości.
sample składa się z 4096 próbek a window(okno) z 2048 + 4096 + 2048 próbek, inaczej 0.5 + 1 + 0.5 "sample". Tutaj dodatkowo uzyskałem 2x dłuższe dane do obróbki na FFT, więc o ile się nie mylę mam większą rozdzielczość ;)
A do czego mi to wszytko? robię radio sdr i właśnie została mi do zrobienia porządna obróbka cyfrowa sygnału, bo taka na szybko nie dawała dobrych efektów.
Dzięki wielkie za pomoc!

0

a mam jeszcze pomysła.
a jeżeli poprzestawiać prążki widma, byle jak, byle parzyście i w sposób odwracalny
nadałoby się do szyfrowania np. mowy w analogowym kanale?
ważne czy dałoby się odwrócić po zaszumieniu i jakimś przefiltrowaniu.

0

Myślę że by się dało. Teraz moje wypociny optymalizuje i zrobię z tego biblioteczkę, gdzie się będzie wpuszczać strumieniowo dane, podawać wskaźnik do funkcji obrabiającej widmo i z tego wszystkiego będzie zwracany strumieniowo sygnał po obróbce. Jak to posklejam to jeszcze dziś spróbuję zrobić tego typu szyfrowanie.

0

bardzom ciekaw wyników, fajnie gdyby po drodze znalazł się głośnik i mikrofon, może puścić jeszcze nie za głośno jakąś muzyczkę albo świsty z niedostrojonego radia.

0

Radio wygląda mniej więcej tak(jeszcze przed założeniem tematu):
Pokazane jest widmo sygnału, oraz drugi program który przesuwa wstęgę boczną na pasmo dźwiękowe(trochę jest rozjechane stąd ten "dziwny" dźwięk).
Zrobiłem klasę DFP, dzięki której można obrabiać już dźwięk jak się chce ;)

/* filtr dolnoprzepustowy - TEST */
void spectrum_process(tsamp * re, tsamp * im, int len){
	int i;
	for(i=100; i<len; i++){
		  	re[i] = im[i] = 0; 
	}
}

int main(){
	short * stream;
	DFP * dfp = new DFP(STREAM_SIZE, spectrum_process);

	while(stream = sample_read()){
		dfp->process(stream, 0/* imaginary */);
		sample_write(stream); 
	}
	return 0;
}
0

Zamieniając sygnał na widmo, powstaje odbicie lustrzane sygnału wejściowego względem środka - te częstotliwości "wyżej" nazwałem ujemnymi

Sygnał o próbkowaniu 44100 Hz niesie informację o częstotliwościach max 22050 Hz. widmo częstotliwości wyższych będzie wyglądało właśnie jak lustrzane odbicie częstotliwości niższych — ale to bzdura, nie ma sensu powyżej połowy częstotliwości próbkowania nawet widma liczyć.

słychać charakterystyczne przeskoki pomiędzy następną analizą
poczytaj o oknowaniu (windowing)

0
Azarien napisał(a)

ale to bzdura, nie ma sensu powyżej połowy częstotliwości próbkowania nawet widma liczyć.

Nie wiem czy uważnie przeczytałeś, testowałem na dźwięku; wprowadzając sygnał z przemiany częstotliwości, nie mam już odbicia lustrzanego, tylko dodatkowo częstotliwości ujemne(poza tym FFT nie policzy mi wybranych prążków, czy połowy widma)
Od lewej strony do środka; częstotliwości dodatnie, Od prawej strony do środka; ujemne częstotliwości.
Np. Sygnał wejściowy 100kHz i 300kHz, jeśli je przemnożę przez 200kHz(oraz dla przesuniętego o 90 stopni - jako re i im), powstaną mi częstotliwości:
100kHz - 200kHz = -100kHz
-100kHz - 200kHz = -300kHz
300kHz - 200kHz = 100kHz
-300kHz - 200kHz = -500kHz
Powstałe częstotliwości faktycznie są rozmieszczone tak jak wcześniej napisałem. Jeśli interpretowałbym częstotliwości jako wartości dodatnie, 2 sygnały -100kHz i 100kHz nałożyłyby mi się czego chcę uniknąć.

Azarien napisał(a)

poczytaj o oknowaniu (windowing)

Naszukałem się i nic sensownego nie znalazłem.
Sam windowing jest tylko do poprawy widma.
Problem już na pierwszej stronie został rozwiązany dzięki Xitami, bardzo naprowadziło mnie: "odcinki gdzie nachodzą na siebie jeden płynne się gasi a drugi wzmacnia".

1 użytkowników online, w tym zalogowanych: 0, gości: 1