Skocz do zawartości

Bufor cykliczy - nadpisywanie 1 elementu, odczyt całości


radek04

Pomocna odpowiedź

Cześć, 

problem mam chyba dość prosty, ale przy moich umiejetnościach robi się trudny 🙂

Potrzebuję bufor cykliczny, który będę zapełniał odczytami z czujnika w równych odstępach czasu. W trakcie działania programu chcę najstarszą wartość nadpisać nową, a nastepnie odczytać i przetworzyć cały bufor. 

Np. dla 8 elementów (indeksy od 0 do 7) i kolejnej iteracji pętli, pod indeks nr 4 zapisuję nowe dane, a następnie odczytuję cały bufor w kolejnosci: 5,6,7,0,1,2,3,4.

O ile odczytanie pojedynczej komórki z takiego bufora jest problemem często poruszanym, o tyle mam kłopot ze złożeniem w chronologiczną tablicę całego bufora. Czy za każdym razem muszę podawać adres każdej z 8 komórek bufora, czy da radę odczytać wszystkie 8 (w odpowiedniej kolejności) jednym poleceniem?

Link do komentarza
Share on other sites

Nie podałeś na jakiej platformie pracujesz i w jakim języku piszesz.

A odczytać i przetworzyć dane możesz np następująco:
 

#define		BUF_SIZE	8
uint8_t 	index;
uint32_t	buf[BUF_SIZE];

// Gdy odbierzesz dane to zapisujesz je w buforze pod adresem index, oraz zwiększasz zmienną index o jeden
buf[index] = Nowe dane;
index++;
index %= BUF_SIZE; // Ograniczasz index do 8 elementów

// Gdy przetwarzasz dane z bufora to odczytujesz je chronologicznie w pętli
for (uint8_t i = 0; i < BUF_SIZE; i++) {
  Przetwarzaj_dane(buf[(index + i) % BUF_SIZE]);    // operator % oznacza modulo (poczytaj o tym operatorze)
}

 

Edytowano przez MR1979
  • Lubię! 1
  • Pomogłeś! 1
Link do komentarza
Share on other sites

Korzystam z STM32 i piszę w C.

No tak, modulo powinno wystarczyć. Myślałem o tym, by od razu odczytać wiele komórek bez jorzystania z petli, ale z pętlą for też powinno być dobrze.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

(edytowany)

Kurczę, chyba nie będzie to tak proste, jak mi się wydawało. Ale może znów coś doradzicie.
Chodzi o to, że w jednym momencie owo "przetwarzanie danych" to nie trywialna operacja matematyczna, a szybka transformata Fouriera (FFT). Korzystam z gotowej funkcji i mam pewne wątpliwości, w które miejsca dokładnie dodawać operację modulo z użyciem indeksu, a w które nie. Zastanawiam się, czy przed wywołaniem funkcji FFT o nazwie dittt() można użyć tej sztuczki z modulo, czy jednak trzeba ingerować w samą funkcję dittt().

Żeby nie zmieniać oznaczeń w kodzie, podaję moje odpowiedniki wcześniej wymienionych zmiennych:

BUF_SIZE - TRSIZ
index - iteration_TRSIZ

Program wykonuje kilka operacji po drodze, ale w najważniejszym momencie mój bufor (tak naprawdę mam 24 podobne bufory, ale będę pisał o jednym) jest rozszerzany dwukrotnie i w co drugie miejsce wpisywane są zera (wartości urojone - wymagania użytej funkcji FFT).

for (int i = TRSIZ-1; i >= 0; i--)
{
	adcc_AaX[2*i] = AaX[i];	//parzyste indeksy - real
	adcc_AaX[2*i+1] = 0;	//nieparzyste indeksy - imagine
  	//tutaj pozostałe bufory
}

(Wiele lat temu pierwszy raz korzystałem z tej funkcji FFT i w sumie dziś już nie wiem, dlaczego indeks w pętli jest dekrementowany, a nie inkrementowany. Ale zdaje się, że nie ma to znaczenia)

Następnie ten rozszerzony bufor poddawany jest przetwarzaniu FFT:

for (int i = 0; i < liczba_sensorow; i++)
{
	if (i==0) dittt(adcc_AaX);
  	//tutaj pozostałe bufory
}

Poniżej gwóźdź programu, czyli realizacja FFT:

void dittt(float data1[2*TRSIZ])		//oblicza FFT
{
	skok = fs / TRSIZ;
	float wtemp, wr, wpr, wpi, wi, theta;
	float tempr, tempi;
	int N = TRSIZ;
	int i = 0, j = 0, n = 0, k = 0, m = 0, isign = -1, istep, mmax;
	float *data;
  	data = &data1[0] - 1;
	//data = &data1[(0+iteration_TRSIZ)%TRSIZ] - 1; //Tutaj moja zmiana - czy dobrze? Czy raczej musi być już 2*TRSIZ zamiast TRSIZ?
	n = N * 2;
	j = 1;
	//do the bit-reversal
	for (i = 1; i < n; i += 2)
	{
		if (j > i)
		{
			SWAP(data[j], data[i]); 			//czy tutaj modulo?
			SWAP(data[j + 1], data[i + 1]);		//czy tutaj modulo?
		}
		m = n >> 1;
		while (m >= 2 && j > m)
		{
			j -= m;
			m >>= 1;
		}
		j += m;
	}
	//calculate the FFT
	mmax = 2;
	while (n > mmax)
	{
		istep = mmax << 1;
		theta = isign * (6.28318530717959 / mmax);
		wtemp = sin(0.5 * theta);
		wpr = -2.0 * wtemp * wtemp;
		wpi = sin(theta);
		wr = 1.0;
		wi = 0.0;
		for (m = 1; m < mmax; m += 2)
		{
			for (i = m; i <= n; i += istep)
			{
				j = i + mmax;
				tempr = wr * data[j] - wi * data[j + 1];	//czy tutaj modulo?
				tempi = wr * data[j + 1] + wi * data[j];	//czy tutaj modulo?
				data[j] = data[i] - tempr;					//czy tutaj modulo?
				data[j + 1] = data[i + 1] - tempi;			//czy tutaj modulo?
				data[i] = data[i] + tempr;					//czy tutaj modulo?
				data[i + 1] = data[i + 1] + tempi;			//czy tutaj modulo?
			}
			wtemp = wr;
			wr += wtemp * wpr - wi * wpi;
			wi += wtemp * wpi + wi * wpr;
		}
		mmax = istep;
	}
	for (k = 0; k < N; k += 2)
	{
		m = k / 2;
		if (k == 0)
		{
			fx[m] = 0.0;
			amplituda[m] = 0;
		} //zerowanie w indeksie [0]
		else
		{
			modul = sqrt(pow(data[k + 1], 2) + pow(data[k + 2], 2));	//czy tutaj modulo?
			fx[m] = fx[m - 1] + skok;
			amplituda[m] = modul * 2 / TRSIZ;
		}
		featuresSTM[wykonania_dittt*TRSIZ/2+m] = amplituda[m];
	}
wykonania_dittt++;
}

W komentarzach zaznaczyłem miejsca, gdzie wg mnie powinny być zmiany. Proszę o sprawdzenie mojego pomysłu. I rozumiem, że w tej funkcji korzystać muszę już z rozmiaru bufora równego 2*TRSIZ, prawda? Mimo że rzeczywiste (niezerowe) wartości występują tylko w liczbie TRSIZ.

Chyba że zaproponujecie jakiś lepszy sposób użycia bufora cyklicznego bez ingerencji w funkcję dittt(), która nie jest mojego autorstwa (coś tam bardzo delikatnie dorobiłem na swoje potrzeby). Może da radę w miejscu, gdzie rozszerzam bufor, poukładać dane w odpowiedniej kolejności?

Edytowano przez radek04
Link do komentarza
Share on other sites

36 minut temu, radek04 napisał:

lepszy sposób użycia bufora cyklicznego bez ingerencji w funkcję dittt()

Coś mi tu pachnie błędem w założeniach.

Jakie rozszerzanie bufora i po co? 

Zarówno owo "rozszerzenie" jak i samo wywołanie funkcji dittt zmieni zawartość bufora czyniąc go bezużytecznym. Nie lepiej stworzyć sobie jakąś tablicę roboczą? Coś w stylu:

float robocza[2*TRSIZ];
for (i=0; i<TRSIZ;i++) {
    robocza[2*i] = twój_bufor[(i+iteration_TRSIZ] % TRSIZ);
    robocza[2*i+1] = 0;
}
dittt(robocza);

Wynik masz w tablicy roboczej, a funkcja dittt pozostaje taka jaka jest.

 

  • Pomogłeś! 1
Link do komentarza
Share on other sites

41 minut temu, ethanak napisał:

Jakie rozszerzanie bufora i po co?

Funkcja dittt() to uogólniona postać szybkiej transformacji Fouriera. Jako dane wejściowe przyjmuje liczby zespolone: indeks parzysty - część rzeczywista, indeks nieparzysty - część urojona. W moim przypadku są tylko liczby rzeczywiste, dlatego "ręcznie" muszę dodać część urojoną, stąd rozszerzony 2x bufor.

43 minuty temu, ethanak napisał:

Zarówno owo "rozszerzenie" jak i samo wywołanie funkcji dittt zmieni zawartość bufora czyniąc go bezużytecznym. Nie lepiej stworzyć sobie jakąś tablicę roboczą?

Masz rację. Dlatego - dopiero po napisaniu mojego posta - pomyślałem o tym, by ta główna tablica AaX o rozmiarze TRSIZ była buforem cyklicznym, natomiast wartości w tablicy adcc_AaX o rozmiarze 2*TRSIZ "układać" w taki sposób, by pod indeksem nr 0 znalazł się zawsze odpowiedni w danym momencie element z bufora AaX.

47 minut temu, ethanak napisał:
float robocza[2*TRSIZ];
for (i=0; i<TRSIZ;i++) {
    robocza[2*i] = twój_bufor[(i+iteration_TRSIZ] % TRSIZ);
    robocza[2*i+1] = 0;
}
dittt(robocza);

I chyba właśnie coś takiego zaproponowałeś.
Zdaje się, że właśnie o to mi chodziło. Dzięki.

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.