Skocz do zawartości

Python vs pure C, różne wyniki obliczeń w visual studio z pythonem a obliczenia przez mikrokontroler STM32 F407


DeadGeneratio

Pomocna odpowiedź

Dobry wieczór, może łatwe, a może trudne pytanie. Dlaczego obliczając wartości w pythonie i w STM32 otrzymuję dwa różne wyniki? Zmienna norm różni się znacząco, przez co wartości a0, a1, a2, b1, b2 wychodzą inne. Kod z pythona i z C poniżej:

def callBiquad(type, Fc, Q, peakGainDB):
  x = Fc/SAMPLE_RATE
    global a0, a1, a2,b1, b2
    V = np.power(10, np.abs(peakGainDB)/20.0)
    K = np.tan(np.pi * x)
    ... // Ine filtry
    elif(type == 'peak'):
        if(peakGainDB >= 0):
            norm = 1 / (1 + 1/Q * K + K * K)
            a0 = (1 + V/Q * K + K * K) * norm
            a1 = 2 * (K * K - 1) * norm
            a2 = (1 - V/Q * K + K * K) * norm
            b1 = a1
            b2 = (1 - 1/Q * K + K * K) * norm
            print("Zmiana wartości dobroci wpływa na szerokość modyfikowanego pasma - zwiększenie tej wartości spowoduje zmniejszenie wpływu filtru na częstotliwości bliskie modyfikowanej")
            print("Zmiana wartości wzmocnienia wpływa na amplitudę modyfikowanej częstotliwości uwzględnionej przez częstotliwość Fc i rozszerzonej przez dobroć Q")
            print()
            print("Obliczono współczynniki a0, a1, a2, b1 oraz b2 dla filtru wzmacniającego konkretną częstotliwość")
            print("Przekazane wartości filtra - częstotliwość odcięcia Fc [Hz] = ", Fc, ", dobroć filtra Q = ", Q, " oraz wzmocnienie [dB] = " , peakGainDB)
            print("Wartość norm = ", norm)
            print("Wartość współczynnika a0 = ", a0)
            print("Wartość współczynnika a1 = ", a1)
            print("Wartość współczynnika a2 = ", a2)
            print("Wartość współczynnika b1 = ", b1)
            print("Wartość współczynnika b2 = ", b2)
        else:
            norm = 1 / (1 + V/Q * K + K * K)
            a0 = (1 + 1/Q * K + K * K) * norm
            a1 = 2 * (K * K - 1) * norm
            a2 = (1 - 1/Q * K + K * K) * norm
            b1 = a1
            b2 = (1 - V/Q * K + K * K) * norm
            print("Zmiana wartości dobroci wpływa na szerokość modyfikowanego pasma - zwiększenie tej wartości spowoduje zmniejszenie wpływu filtru na częstotliwości bliskie modyfikowanej")
            print("Zmiana wartości wzmocnienia wpływa na amplitudę modyfikowanej częstotliwości uwzględnionej przez częstotliwość Fc i rozszerzonej przez dobroć Q")
            print()
            print("Obliczono współczynniki a0, a1, a2, b1 oraz b2 dla filtru tłumiącego konkretną częstotliwość")
            print("Przekazane wartości filtra - częstotliwość odcięcia Fc [Hz] = ", Fc, ", dobroć filtra Q = ", Q, " oraz wzmocnienie [dB] = " , peakGainDB)
            print("Wartość norm = ", norm)
            print("Wartość współczynnika a0 = ", a0)
            print("Wartość współczynnika a1 = ", a1)
            print("Wartość współczynnika a2 = ", a2)
            print("Wartość współczynnika b1 = ", b1)
            print("Wartość współczynnika b2 = ", b2)

Natomiast w C:

// Niskie tony - od 20 do 400 Hz - LT = Low Tones
int8_t peakGainLT = 0;
int8_t previouspeakGainLT = 0;
uint16_t FcLT = 100;
double QLT = 0.7071;
float a0LT, a1LT, a2LT, b1LT, b2LT = 0;
float lin_LT_z1, lin_LT_z2, lout_LT_z1, lout_LT_z2 = 0;
float rin_LT_z1, rin_LT_z2, rout_LT_z1, rout_LT_z2 = 0;
uint8_t updateLT = 1;

if (updateLT == 1 || previouspeakGainLT != peakGainLT) {
		updateLT = 0;
		callBiquad(peakGainLT, QLT, FcLT, &a0LT, &a1LT, &a2LT, &b1LT, &b2LT);
		lin_LT_z1 = lin_LT_z2 = lout_LT_z1 = lout_LT_z2 = rin_LT_z1 =
				rin_LT_z2 = rout_LT_z1 = rout_LT_z2 = 0;
		previouspeakGainLT = peakGainLT;
	}

void callBiquad(int8_t peakGain, double Q, uint16_t Fc, float *a0_ptr,
	float *a1_ptr, float *a2_ptr, float *b1_ptr, float *b2_ptr) {
	float norm = 0;
	float V = pow(10, (peakGain / 20.0));
	float K = tan(M_PI * (Fc / 96000.0));

	if (peakGain >= 0.0) {
		norm = 1.0 / (1.0 + 1.0 / Q * K + K * K);
		*a0_ptr = (1.0 + V / Q * K + K * K) * norm;
		*a1_ptr = 2.0 * (K * K - 1.0) * norm;
		*a2_ptr = (1.0 - V / Q * K + K * K) * norm;
		*b1_ptr = *a1_ptr;
		*b2_ptr = (1.0 - 1 / Q * K + K * K) * norm;
	} else {
		norm = 1.0 / (1.0 + V / Q * K + K * K);
		*a0_ptr = (1.0 + 1.0 / Q * K + K * K) * norm;
		*a1_ptr = 2.0 * (K * K - 1.0) * norm;
		*a2_ptr = (1.0 - 1.0 / Q * K + K * K) * norm;
		*b1_ptr = *a1_ptr;
		*b2_ptr = (1.0 - V / Q * K + K * K) * norm;
	}
}

Wyniki dla wartości peakGain >= 0 są identyczne w obu programach. Natomiast ustawiając poniżej 0 są rozbieżne na niekorzyść C, w pythonie jest dobrze policzone. DLa ujemnej wartości wzmocnienia przykładowo współczynnik a0 powinien być mniejszy niż 1. Wynik tego samego obliczenia w obu językach programowania na różnych platformach:

image.thumb.png.89e8af43b3a4cb4bcaae08dff5a318ef.pngimage.thumb.png.a601ffd0bb13b274b827988ff2c4d302.png

Ktoś pomógłby radą? Chwilowo kończą mi się pomysły, za tydzień pewnie jakbym usiadł z czystym umysłem to od razu znalazłbym oczywisty błąd, ale potrzebuję przyśpieszyć swoją pracę nad inżynierką. Dodatkowo jako bonus tak to nazywając, efekt filtra obliczonego z mikrokontrolera oraz w pythonie na wygenerowany przebieg dla ciekawych:

image.thumb.png.74e201a7b924421fe18f762921c2b2f8.pngimage.png

Efekt powinien być oczywisty - zmniejszamy amplitudę częstotliwości w okolicy 100 Hz, zależne to jest od dobroci filtru - parametr Q. Im większa ta wartość, tym mniejsze pasmo tłumione. Jeśli ktoś potrzebuje mogę wrzucić zarówno plik z kodem pythona jak i STM

 

Edytowano przez DeadGeneratio
Link do komentarza
Share on other sites

(edytowany)

Spróbuję zaraz z ciekawości, nie wiem tylko czy double nie spowolni dodatkowo wszystkich obliczeń - wiem, że mam dostępną jednostkę do obliczeń zmiennoprzecinkowych ale nie wiem czy typu single czy double. Taki kod wykonuje się dla człowieka szybko, ale płytka musi od groma przerwań obsłużyć, dam zaraz znać co się stanie po zamianie typu.

Niestety dalej to samo, zamieniłem tylko float norm na double norm. Wynik ten sam, niepoprawny, natomiast gdybym zamienił dodatkowo zmienne współczynników oraz pamięci poprzednich wartości dźwięku płytka przestałaby wykonywać swoje zadanie - wszystko opieram na float-ach, musiałbym zmienić cały kod.

Edytowano przez DeadGeneratio
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

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • 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.