float nach unsigned int

Gast #2779321
Hallo,
ich programmiere gerade einen Regelalgorithmus welcher mit 32 Bit Floats 
rechnet (--> soll so sein!).
Der Algorithmus gibt eine Float Zahl zurück. Für die Ansteuerung der PWM 
benötige ich allerdings eine 16 Bit Unsigned Int.
Ich steh gerade echt auf dem Schlauch was die Typkonvertierung anbelangt 
kann mir jemand weiterhelfen?
(Achja ich benutze den C30 Compiler von Micrchip falls das von Bedeutung 
ist).

Viele Grüße,
Sebastian
Sebastian schrieb:

> Ich steh gerade echt auf dem Schlauch was die Typkonvertierung anbelangt
> kann mir jemand weiterhelfen?

Einfach den float benutzen? Wenn der Empfänger einen unsigned int 
benötigt, dann fügt der Compiler schon eine entsprechende Konvertierung 
ein.


Ein bischen Komfort kann man von einem Compiler schon erwarten. Sonst 
hätte man ja Hochsprachen nicht erfinden müssen, wenn man sich dann 
sowieso um jeden Kleinscheiss erst recht wieder selber kümmern muss.
Gast
Das dachte ich auch zuerst allerdings funktioniert weder der cast noch 
die direkte Zuweisung (andersherum allerdings schon). Kann es sein, dass 
das Problem an der Konvertierung 32 Bit --> 16 Bit liegt?
Gast
Sebastian schrieb:
> Das dachte ich auch zuerst allerdings funktioniert weder der cast noch
> die direkte Zuweisung (andersherum allerdings schon). Kann es sein, dass
> das Problem an der Konvertierung 32 Bit --> 16 Bit liegt?

das kommt auf die werte an. In einem float können auch zahlen > 
MAX_INT32 sein und dann steht unsinn drin.
Gast
Natürlich wird der Nachkommateil des Floats abgeschnitten. Ein 
Interger-Typ beinhaltet nunmal nur Ganzzahlen.

Sebastian schrieb:
> Das dachte ich auch zuerst allerdings funktioniert weder der cast noch
> die direkte Zuweisung (andersherum allerdings schon).

Ohne konkrete Fehlermeldung des Compilers bzw. einer Beschreibung des 
Fehlverhaltens können wir nicht ermitteln wo das Problem liegt.

Gruß lowlevel
Gast
Der Compiler gibt keine Fehlermeldung oder Warning raus.
Folgender Code soll das Problem verdeutlichen:

float regelStellWert; //32 Bit float!

unsigned int pwm; //16 Bit unsigned int!


pwm = regelStellWert; //Es steht nur Käse in PWM

pwm = (unsigned int) regelStellWert; //Auch so steht nur Käse in PWM

Gibts da vielleicht irgend ne spezielle Funktion etc.?
Sebastian schrieb:

> float regelStellWert; //32 Bit float!
>
> unsigned int pwm; //16 Bit unsigned int!
>
>
> pwm = regelStellWert; //Es steht nur Käse in PWM

Dann schau dir doch mal den originalen Wert in regelStellWert an.

Wie schon gesagt: ein unsigned int hat nach oben eine Grenze. Mehr geht 
nun mal mit den verfügbaren Bits nicht. Ist dein regelStellWert größer 
als diese Grenze, dann geht das nicht.

> Gibts da vielleicht irgend ne spezielle Funktion etc.?
Dein Problem liegt höchst wahrscheinlich in den Wertebereichen. Also 
musst du dir erst mal einen Überblick verschaffen über welche 
Wertebereich (hier: beim float) überhaupt geredet wird.
Gast
Wie Karl Heinz andeutete, prüfe mal was bei deinen Berechnung so 
herausgekommt, denn bevor Du eine typecast durchführst solltest Du 
sicher sein, dass der Wert in die zu "castenden" Variable passt. Casts 
sind erlaubt wenn nötig, aber verpönnt:-)
Gast
Habs gerade mal im Debugger nachgeschaut (beide Zahlen in hex)

regelStellWert = 0x4293 6E24

pwm = 0x6E24


Es wird also letzlich nur die hinteren 16 Bit übernommen, was natürlich 
Quatsch ist.
Gibt es da irgend ne Konvertierungsfunktion um eine float korrekt in 
eine unsigned int zu wandeln?
Gast
Kann es sein, daß du nicth mit float/double sondern mit fixed point
rechnest. Sieht nach Q16 aus, auch wenn PID usw in Q15 gerechnet wird.

Zur Info: Q15=16bit fixed point im 1.15 Format und Q16=16.16 Format.
Persönliche Seite
John_der_Seemann schrieb:
> @Peter II:
>
> "Schneidet" der Compiler bei deiner Methode ebenfalls die
> Nachkommastellen einfach weg?

Das ist "Implementation Defined" laut Standard.

Es gibt folgende Möglichkeiten, wie die Implementierung das erlegigt; je 
nach Compiler auch einstellbar per Kommandozeile:

• Round to Zero
• Round to Nearest
• Round down (towards -oo)
• Round up (towards +oo)
Gast
C30 ist GCC. Wenn wie hier Beschrieben:
Sebastian schrieb:
> regelStellWert = 0x4293 6E24
>
> pwm = 0x6E24

dann heisst das, regelStellWert ist irgendein Int, deutet stark auf
fixed point float hin und hat nichts mit float zu tun.
Um diese Zahlen umzuwandeln zu konvertieren gibt es entsprechende
Funktionen. viele DSP Libs von Microchip verwenden fixed point float,
jedoch wird generell Q15 genommen, vielleicht wurde auch das gemischt.
Sebastian schrieb:
> Habs gerade mal im Debugger nachgeschaut (beide Zahlen in hex)
>
> regelStellWert = 0x4293 6E24
>
> pwm = 0x6E24
>
>
> Es wird also letzlich nur die hinteren 16 Bit übernommen, was natürlich
> Quatsch ist.
> Gibt es da irgend ne Konvertierungsfunktion um eine float korrekt in
> eine unsigned int zu wandeln?

Zeig doch mal deinen Code.

die Variable regelStellWert ist vom Datentyp 'float'? Das steht da 
explizit so im Code?
die Variale pwm ist vom Datentyp unsigned int (oder int)? Auch das steht 
da so explizit im Code?

Deine Zuweisung sieht so und nicht anders aus?
     pwm = regelStellWert;

Da sind nirgends Pointer involviert?
Gast
Hier die Originalstelle im Code:
1
float stellWert = 0;
2
unsigned int pwmui = 0;
3

4
PidDataType pidReglerDaten;
5
PidInit(1,0,0,100.0,-100.0, & pidReglerDaten);
6
  
7
PWMInit(70);
8
PWMStart();
9

10
        while(1)
11
  {
12
            sollWert = 100;
13
            vTaskDelayUntil (& lastWakeTime, period);
14
            adValue = GetADVal(I2CADDRESS, I2CCONFBYTESTART);
15
            messWert = GetTemperature(adValue);
16
            stellWert =  PidController(sollWert, messWert, pidReglerDaten);
17
            pwmui = stellWert;
18
            PWMChangeDuty(pwmui);
19
            
20
  }

Sobald stellWert an pwmui "übergeben" wird, passiert das obere Problem. 
Werden die Werte Dezimal betrachtet ist der Wert von stellWert richtig 
der Wert von pwmui ist Quatsch.
Gast
Das sind doch alles Q15 Werte, !!!
Mal das Handbuch zur Lib lesen, ist sehr gut beschrieben.

Ansonsten für Dummys:
float varfloat;

   varfloat = Fract2Float(pidReglerDaten.measuredOutput);
   varfloat = Fract2Float(pidReglerDaten.controlReference);
   varfloat = Fract2Float(pidReglerDaten.controlOutput);
Gast
Die Programmausführung steht dann bei der Funktion PWMChangeDuty.

Kann mich mal jemand aufklären was Q15 Werte sind - hab das noch nie 
gehört und denke doch einiges an Erfahrung zu haben?
Sebastian schrieb:
> Die Programmausführung steht dann bei der Funktion PWMChangeDuty.
>
> Kann mich mal jemand aufklären was Q15 Werte sind - hab das noch nie
> gehört und denke doch einiges an Erfahrung zu haben?

Ist doch ganz einfach.
Was sagt die Doku zur Funktion PidController?

Da stehts drinnen.
Du musst dir angewöhnen, die Doku zu benutzen und weniger zu raten.
Dafür gibt es Doku. Wenn du keine hast, dann musst du dir eben eine Doku 
online suchen.
Moderator (Firma: Titel) Persönliche Seite
pic schrieb:
> Das sind doch alles Q15 Werte, !!!
Sebastian schrieb:
> Kann mich mal jemand aufklären was Q15 Werte sind
Google nach q15 und pic...
1
The I/Q Fixed Point Math Library provides a set of speed optimized functions 
2
for the most common digital signal processing applications. This library 
3
provides significant performance savings over equivalent functions coded in 
4
C and allows developers to dramatically shorten their development time. The 
5
I/Q math library provides mathematical functions useful in a variety of 
6
applications ranging from motor control, digital power control, digital 
7
signal processing and general purpose real-time control using fractional 
8
data types. The function formats provided in the library are in Q15 (1.15) 
9
and Q16 (15.16) representations.
Kurz: du verwendest die falsche Lib.
Gast
1
float     PidController (float sollwert, float messwert, PidDataType *pid)
2
{
3
    float   regelAbw;
4
    float   soll;
5
    float   mess;
6
    float   pAnteil;
7
    float   iAnteil;
8
    float   dAnteil;
9
    float   stellwert;
10
    
11
    soll = sollwert;
12
    mess = messwert;
13

14
    regelAbw = soll - mess;
15

16
    //Berechnung des P-Anteils
17
    pAnteil = pid->integralSum * regelAbw;
18

19
    //Berechnung des I-Anteils mit Begrenzung der Integralsumme (Anti-Windup)
20
    iAnteil = pid->integralSum + regelAbw;
21
...
22
..
23
.

Der Regler beeinhaltet spezielle Routinen die ich nicht öffentlich 
machen darf, aber ich habe den Regler selber geschrieben.
Der Regler ist gestestet und funktioniert. Ich habe einfach nur dieses 
"lästige" Problem mit der Konvertierung float nach int oder IEEE nach 
Decimal ...
Vermutlich ist bei diesem speziellen Compiler der float-Typ mit anderen 
Formaten überlagert und daher funktionieren die standard Konventionen 
nicht mehr.
Sowas ist sehr ungünstig, da wäre ein neuer Typ besser gewesen.

Es läßt sich bestimmt auch irgendwo einstellen, ob float wirklich als 
float oder als was anderes verwendet wird.


Peter
Gast
float wird im IEEE 754 Format gespeichert. Ich müsste also eine Routine 
geben um von diesem in das integer Format zu konvertieren.
Ich weiß leider nicht mehr weiter. Hätte nicht gedacht, dass durch 
solche "Kleinigkeiten" ein Projekt nicht mehr weiter geht.
Gast
Naja wenns gar nicht anders geht, so funktionierts (meine Werte liegen 
nur zwischen null und hundert):
1
float temp;
2
unsigned int i;            
3

4
            if (stellWert < 0)
5
            {
6
                pwmui = 0;
7
            }
8
            if (stellWert > 100)
9
            {
10
                pwmui = 100;
11
            }
12
            else
13
            {
14
                temp = 0;
15
                for (i=0; i<100; i++)
16
                {
17
                    if (stellWert >= temp && !(stellWert <(temp +1)))
18
                    {
19
                        pwmui=i;
20
                    }
21
                    temp++;
22
                }
23
            }
24

25
            PWMChangeDuty(pwmui);

Mich würde trotzdem interessieren ob und wo es da irgendwelche 
Einstellungen gibt, ich hab keine gefunden!
A. K. schrieb:
> Sebastian schrieb:
>> float wird im IEEE 754 Format gespeichert.
>
> Sicher? Gibt bei PICs m.W. auch Exotisches als float. Sowas wie 24-Bit
> Format.

Selbst dann müsste der Compiler die Umwandlung machen.
Das ergibt keinen Sinn, wenn er zwar die Umwandlung von int->float drauf 
hat, aber die Umkehrung nicht.

Da ist was anderes faul.
Und ich denke mal, das hat was mit den 0x0 zu tun. An dieser Adresse 
steht im Flash/ROM die Bytefolge 6E 24 42 93
Und bei einer Anzeige im Debugger, die auf 4 Bytes rausläuft (wie zb 
float), wird eben alles angezeigt, während bei einem int eben nur die 
ersten beiden Bytes angezeigt werden.

Was kommt eigentlich raus, wenn du dir diese Bytefolge als float (also 
nicht in Hex-Form sondern richtig mit Dezimalpunkt und allem Drum und 
Drann) anzeigen lässt?
Gast
Geh mal in die "Build Options" Deines Projektes, dann im Reiter "MPLAB 
LINK30" die Category "Libraries" auswählen.

Was steht da?
Ist "Fast floating-point math" ausgewählt?
Ändert sich das Programmverhalten, wenn Du da etwas änderst?
Gast
Könnte es eventuell sein, daß du die Funktion nicht declarierst und
der Compiler dann einen Int annimmt, und die int->float und float->int
einfach wegoptimiert und gleich den int Wert zuweist.

Ansonsten die Float value müsste 172 sein, auch das wäre ausserhalb 
deines
Bereiches von 0-100. Sind das reale Werte oder nur eine buggy 
Simulation.

Dein Code oben dürfte nur die Werte entweder 0, 100, 101 annehmen.
und auch die Vergleiche sind falsch codiert.
Gast
Bronco schrieb:
> Geh mal in die "Build Options" Deines Projektes, dann im Reiter "MPLAB
> LINK30" die Category "Libraries" auswählen.
>
> Was steht da?
> Ist "Fast floating-point math" ausgewählt?
> Ändert sich das Programmverhalten, wenn Du da etwas änderst?

Das war des Rätsels Lösung!!

Vielen herzlichen Dank an Bronco und all die Anderen hilfsbereiten hier 
im Forum - Ihr habt mir den Tag gerettet!

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 14 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.