Hallo, ich habe ein IIR Filter. Dieser wurde in C umgesetzt. Es würde mich interessieren, wie ich mein Programm von einem Sättigungs-Überlauf schützen kann. Bei mir werden double Werte aufaddiert. Und es stehen 16bit zur Verfügung. Ich habe mir es so vorgestellt, das im Falle eines Überlaufs, keine Fehlermeldung ausgegeben wird, sonder das der Wert bei dem höchsten bzw. niedrigsten Wert weiter fährt und nicht in den niedrigsten bzw. höchsten Bereich überspringt. Ich würde mich über jeden Vorschlag freuen. Danke! Alex
Hallo Alex, einen Überlauf kannst du effektiv nur feststellen wenn du mit floating-point arbeitest (oder aber du hast bei integer entsprechend reserve-bits übriggelassen). Ich habe es bei meinem Filter (software-synthesizre) so gemacht das ich den überlauf ignoriere, da der signalweg komplett in floating-point gerechnet wird und erst bei der umsetzung von fp nach integer habe ich lediglich eine begrenzung des wertes auf -1 bzw. +1 gemacht und dann umgerechnet. bei reiner integer-arithmetik sollte man so vorgehen genug reserve einzurechnen (z.b. 8bit bei 24 bit audio, da kommt man auf einen schönen 32-bit-wert). nach dem aufaddieren sollte man den wert clippen ( auf deine audio-breite) und dann erst in den rückkoppelzweig reinschieben. macht man keine begrenzung steht u.u. müll bzw. ungültige werte in deinen audiodaten und das bringt den rückkoppelzweig u.u. zum schwingen (hab das bei einer implementierung eines iir filters in einem fpga gehabt) hoffe ich konnte dir damit helfen gruß rene
Hallo, ich habe mir folgendes Überlegt: #define isnan(x) ((x) !=(x)) ... ... if (isnan(sum)) { if ( sum < 0) sum=DBL_MAX; if (sum > 0) sum=DBL_MIN; } Was haltet Ihr von dieser Version??
Nix, das geht so nicht. Dein define ist ja immer false. Integer Overflow entweder wie Rene sagt mit nem Extrabit oder so: Addition mit ner Zahl > 0 muß die Summe größer machen und umgekehrt. Falls nicht: Overflow, ist aber aufwendig und langsam. Aber wieso überhaupt sowas machen : 16Bit float macht doch keinen Overflow !? Das ganze ist ne Frage der Dynamik: Dein Filter machte Verstärkung <256, also 8 Bit, bei 16Bit Rechnung solltest du höchstens mit 8 Bit Werten (<256) reingehen. Falls du mit größeren Werten reingehst kriegst Du mit Integerrechnung Overflow und die 16Bit float-Rechnung skaliert Dir Genauigkeit weg, da kanns dann auch schöne Effekte geben. Cheers Detlef
Hallo Detlef, Das ganze muss auch für andere Filter (mit höheren Verstärkung) geeignet sein. So das man nur die Koeffizienten austauscht und sonst nichts. Habe ich es richtig Verstanden? ... ... sum=a+b; ... if(a>0 && b>0 && sum<0) sum=DBL_max; elsif(a<0 && b<0 && sum>0) sum=DBL_min; else sum=sum; ... ... Wie würde die Version mit nem extra Bit aussehen? Gruss, Alex
Hi, float und double Typen laufen nicht über, die sind durch Mantisse/Exponent Darstellung skaliert. Wenn Du auf nen großes double ein kleines aufaddierst, bleibt der Wert einfach gleich. Folgende Routine läuft bei mir bis dr ~ 9*10^15. double dr=1.0; while(dr != (dr+1.0) ){ dr *= 2.0; printf("%e \n",dr); } return 0; double/float sind für digitale Filter, auch IIR, ok und bequem, float Rechnung dauert halt immer länger. IIR mit integer verlangt große Sorgfalt. Erstens muß man die Rückkoppelkoeffizienten mit einer Potenz von 2 skalieren, also beispielsweise ne Multiplikation mit 0.641 erstzen durch 10503/16384, das bringt Fehler rein, die das Verhalten des Filters stark ändern können. Zweitens kann die Integerrechnung an sich zum Schwingen des Filters führen. Drittens maß man sehr genau auf Overflows und die Dynamik achten, am bestens mit dem Extrabit: bei ner Integer-Zweierkomplementdarstellung muß das oberste Bit und das zweitoberste übereinstimmen, sonst wirds als Overflow gewertet. Man verliert ein Bit Dynamik aber das Testen auf Overflow ist einfach. Aber wenn man Zeit hat ist integer Mist, lieber double. Cheers Detlef
Hallo, es hat sich bei mir was geändert, der Rückgabe Wert (diesen habe ich zuvor als Sum bezeichnet) ist von Type Integer. Hier ist main aktuelles Programm: int gefiltert=0; double* A_K = o_dig_filt->A_K; double* B_K = o_dig_filt->B_K; double z1 = o_dig_filt->gefilterte_W[wert].z1; double z2 = o_dig_filt->gefilterte_W[wert].z2; double help_a=0; help_a=z1*A_K[1]+z2*A_K[2]; gefiltert=(int)((ungefiltert-help_a)*B_K[0]+z1*B_K[1]+z2*B_K[2]); o_dig_filt->gefilterte_W[wert].z2=z1; o_dig_filt->gefilterte_W[wert].z1=(ungefiltert-help_a); return gefiltert; Wie kann ich es am besten gegen Überlau absichern, auch wenn es zu einem Überauf nicht kommen kann? Gruss, Alex
bißchen ergänzen double help_b=0.0; help_b=((ungefiltert-help_a)*B_K[0]+z1*B_K[1]+z2*B_K[2]); if(help_b > MAXINT) help_b=MAXINT; if(help_b < MININT) help_b=MININT; gefiltert =(int)help_b; >Wie kann ich es am besten gegen Überlau absichern, auch wenn es zu >einem Überauf nicht kommen kann? Double macht keinen Overflow, integer schon Cheers Detlef
Hallo Detlef, mir ist hier was Aufgefallen: >bißchen ergänzen >double help_b=0.0; >help_b=((ungefiltert-help_a)*B_K[0]+z1*B_K[1]+z2*B_K[2]); >if(help_b > MAXINT) help_b=MAXINT; >if(help_b < MININT) help_b=MININT; >gefiltert =(int)help_b; wenn help_b in den Überlauf geht, dann bekommt dieser Wert ein negatives Vorzeichen. So würde die nächste Abfrage gar nicht stimmen. Da help_b dann kleiner als MAXINT ist. Ist das richtig, oder habe ich da was übersehen? Gruss, Alex
Hallo Alex,
help_b kann nicht in Überlauf gehen, das isnn double.
> bekommt dieser Wert ein negatives Vorzeichen.
welcher Wert ?
Du rechnest komplett in double, da läuft wie gesagt nix über. Bevor Du
nach integer zurückwandelst, prüfts Du ab, ob der double in den integer
Zahlenbreich paßt und schneidest dementsprechend ab. MAXINT/MININT sind
maschinenabhängig, wie groß sind denn deine integers??!
Detlef
Hallo Detlef, INT_MAX ist bei mir 2147483647 INT_MIN ist (-2147483647-1) Warum kann double nicht überlaufen? Double-Type besitz doch auch Grenzen. Gruss, Alex
>Warum kann double nicht überlaufen? Double-Type besitz doch auch >Grenzen habe ich versucht in meinem post vom 24.1. zu erklären. Du hast 32 Bit integers. Detlef
Hallo Detlef, ich habe im Internet nachgeforscht, und habe hier zu dem Thema was gefunden. UNI-Bremen: "Bei einem Überlauf wird Double.POSITIVE_INFINITY oder Double.NEGATIVE_INFINITY" Microsoft: "Gleitkommaoperationen zeigen durch die Rückgabe von PositiveInfinity einen Überlauf an." Das würde bedeuten, das bei einem "Überlauf" von double, würde dem help_b +unendlich bzw. -unendlich zugewiesen. Anschgließend vergleicht man mit "if(help_b > MAXINT) help_b=MAXINT;" ob z.B. +unendlich > MAXINT ist. Falls das der Fall ist, so würde help_b auf MAXINT gesetzt. Habe ich es richtig verstanden? Gruss, Alex
>Du hast 32 Bit integers.
da habe ich was durcheinander gebracht. Softwaremässig stehen mir 32bit
zur Verfügung, Hardwaremässig aber nur 16Bit.
Das hat aber keine Auswirkungen auf das Programm.
Hallo, ja, habe mich mißverständlich und ungenau geäußert. Der Wertebereich der Integer ist irgendwas mit 2^32 ~ 10^9. Der Wertebereich der doubles ist irgendwas mit +/- 10^308 bei 8 Byte, also wesentlich größer. Darauf bezog sich meine Aussage, daß bei 'doublerechnung nix überläuft'. Wenn bei nem double-gerechneten IIR Filter die doubles überlaufen, ist das Filter instabil, das schwingt auf. Poste mal die Koeffizienten o_dig_filt->A_K, daran ist das zu berechnen. Mein Post vom 24.1. bezog sich auf die Dynamik der doubles, mein C-Programm konnte ne Eins von einer 10^15 unterscheiden, das ist aber was anderes als der Wertebereich. Zerknirscht Detlef
Hallo Detlef, das hier sind meine Koeffizienten: double B_Koef[3] = {0.0011858, 0.0023716, 0.0011858}; double A_Koef[3] = {1, -1.9001381, 0.9048735}; Gruss, Alex
ja, das Filter ist stabil, z^2-1.9001381z+0.9048735 hat Nullstellen mit Beträgen <1, das ist die Impulsantwort: 1.185800e-003 4.624784e-003 8.900529e-003 1.272739e-002 1.612995e-002 1.913245e-002 2.175873e-002 2.403215e-002 2.597550e-002 2.761099e-002 Dein C-Code ist ok. Haste z1,z2 initialisiert? Bei dem Ding läuft nix über! Cheers Detlef
Hallo Detlef, ja, z1 und z2 sind initialisiert. das Problem ist aber, dass mein C-Code flexibel bleiben soll, d.h. es soll auch dann funkltionieren, falls die Koeffiozienten gändert werden. Gruss, Alex
Hi, ja, kein Problem, das wird schon auch mit anderen Koeffizienten arbeiten. Draufkucken muß Du aber: Dieser Tiefpaß macht für Gleichspannung Verstärkung 1, also z.B. steckst Du immer '100' rein und nach dem Einschwingen kommen '100' raus. Wenn Du Deine b-Koeffizienten allerdings z.B. Faktor 1000 hochdrehst, macht das Filter eine Verstärkung von 1000, dann kommen für die reingesteckten 100 die Werte 100*1000 raus, da muß Du kucken, ob das in Dein Integer paßt, in die doubles paßt das allemal. Vorsicht auch bei schmalen Bandpässen, da kommt es dann an der Frequenz, die der Bandpaß gut verstärkt, eventuell zum Überlauf. Cheers Detlef
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.