Jump to content

How to 'inverse sign' a float ?


Jakes Daddy
 Share

Recommended Posts

I'm having a problem with a variable of type float which I hope someone can help with.

Basically I have a pot which is my pitch fader. It sends MIDI values 0-127. The centre point of the pot is 0% pitch, and sends a MIDI value of 63. My pitch range is +-6.5%

I am trying to write a C function which will calculate the pitch and display it on the LCD.

My formula for working out the pitch is:

  • Work out the equivilant pitch value for each pot step or movement:
    eachIncrementValue = totalPitch / totalPossibleValues
    eachIncrementValue = (6.5 X 2)/ 127
    eachIncrementValue = 0.10236220472440944881889763779528
  • Then work out the pitch:
    pitch = 0.0 + ( eachIncrementValue * (pin_value - zeroPosition) )
    pitch = 0.0 + ( 0.10236220472440944881889763779528 * (pin_value - 63) )
    pitch is obviously dependant on pin_value, but if it were 12 pitch = -5.22..... If pin_value were 79, pitch = 1.63.....

So far so good. Now, I want to display the value on the LCD, and this is where I'm getting a bit stuck. I want to only display the value to 1 decimal place (eg. 1.6323534 should be displayed as 1.6; and 1.0 should be displayed as 1.0), and I want to display the + or - sign. As I don't know C very well, like how to round down a float, or how the MIOS_LCD_Print* routines would handle a float and the polarity sign I decided to do it myself:

    unsigned char totalPitch = 13;
    unsigned char totalPossibleValues = 127;
    unsigned char zeroPosition = 63;
    float eachIncrementValue;
    float pitch;
    unsigned char wholeNum;
    float remainder;

    eachIncrementValue = (float)totalPitch / totalPossibleValues;
    pitch = 0.0 + ( eachIncrementValue * (pin_value - zeroPosition) );

    // position the cursor on the correct display
    if (pin==0) {
        MIOS_LCD_CursorSet(0x46);
    } else {    
        MIOS_LCD_CursorSet(0xc6);
    }

    // if the pitch is negative then we need to display the minus sign, then multiply the value by -1 so we get the positive value
    if (pitch < 0.0) {
        MIOS_LCD_PrintChar('-');
        pitch = pitch * -1;
    } else 
    if (pitch == 0.0) {
        MIOS_LCD_PrintChar(' ');
    } else {
        MIOS_LCD_PrintChar('+');
    }

    wholeNum = pitch;    // this will explicitally truncate the fractional portion of the pitch - so we are left with the whole number
    MIOS_LCD_PrintBCD1((unsigned char)wholeNum);
    MIOS_LCD_PrintChar('.');
    remainder = (pitch - wholeNum) * 10;
    MIOS_LCD_PrintBCD1((unsigned char)remainder);
It all works with the exception of the line that attempts to convert a negative value to a positive:
    // if the pitch is negative then we need to display the minus sign, then multiply the value by -1 so we get the positive value
    if (pitch < 0.0) {
        MIOS_LCD_PrintChar('-');
        pitch = pitch * -1;
    } else 
The code goes into the if block correctly, and the - sign is correctly displayed. However, the pitch = pitch * -1; appears to corrupt the value, and what I get printed on screen is -F.F for any negative value !! I have tried
    pitch = pitch * -1;
    pitch = pitch * (-1);
    pitch = pitch - pitch - pitch;

None of these work; and so all I can assume is there is something odd about a C float ??

Any ideas anyone ?

Cheers

JD

Link to comment
Share on other sites

Hi JD,

I'm always using triple subtraction to avoid multiplications and therefore the implementation of the SDCC lib which blows up the codesize (although in your case it wouldn't help, 'cause floats also need the lib):

(+2) - (+2) - (+2) = (-2)

(-5) - (-5) - (-5) = (+5)

I quite sure it does not work for you, 'cause you'll need a [tt]signed[/tt] type somewhere. I think, SDCC interprets [tt]int[/tt] as [tt]unsigned int[/tt] by default. I haven't seen no [tt]signed float[/tt] in your code snippets.

Then there are some helping functions for displaying numbers on the display.

Not sure how/if it works with floats, but you can increase the float by multiplying it with ten and then display the result via (BCD = Binary Coded Digital with x chars):

MIOS_LCD_PrintBCD1()

MIOS_LCD_PrintBCD2()

MIOS_LCD_PrintBCD3()

12 as BCD3 would be printed as '012'.

11 as BCD1 would be printed as '1'.

see the function reference listing on ucApps.

Hope this helps,

best regards,

Michael

Link to comment
Share on other sites

Hi JD,

Have you tried with the following?

 pitch = pitch * -1.0f;
Note that the following that you tried should work too:
    pitch = pitch - pitch - pitch;

Stupid question but have you included the float library? I guess so otherwise you should have errors/warnings of undefined stuff.

And is the memory model of the library matching the memory model of your program? I don't remember if it's applicable in this context of SDCC, I used it too long ago...

Maybe you can look at what the compiler is generating in terms of assembly code from your code to check how this code is interpreted.

Best regards,

Lall

Link to comment
Share on other sites

Note that the following that you tried should work too:

Code:

    pitch = pitch - pitch - pitch;

As I already wrote, I believe it does not work, cause pitch is declared just as "float" and it should be "signed float". I'm using this and it works for me.

@stryd: good to know. maybe I should give this one a try (although it was an unbelieveable hassle to get SDCC running last time)...

Regards,

Michael

Link to comment
Share on other sites

As I already wrote, I believe it does not work, cause pitch is declared just as "float" and it should be "signed float". I'm using this and it works for me.

The SDCC doc talks about IEEE float support and to me IEEE float is signed by default but I may be wrong.

I've actually never seen an unsigned float anywhere and on the bunch of platform I've used float is always signed float.

But anyway I would say it's worth a try, it cost only very little time to do it and who knows about the oddities of a compiler or another  ;)

Best regards,

Lall

Link to comment
Share on other sites

Thanks for all the replies gents. You'll be pleased to hear that I have sorted it now  ;D. The problem was one of those very subtle ones ......

My original code was as I originally posted, and in particular the problem was here:

void UpdatePitchValues(unsigned char pin, unsigned int pin_value) __wparam {

    unsigned char totalPitch = 13;

    unsigned char totalPossibleValues = 128;

   unsigned char zeroPosition = 63;

    float eachIncrementValue;

    float pitch;

    unsigned char wholeNum;

    float remainder;

    eachIncrementValue = (float)totalPitch / totalPossibleValues;

    pitch = 0.0 + ( eachIncrementValue * (pin_value - zeroPosition) );

pin_value and zeroPosition are both unsigned, and the subtraction in brackets in the pitch=..... line would have resulted in an unsigned int.

If pin_value was over 63 (the zeroPosition), the subtraction would have been correct, and the result would be a positive integer.

If pin_value was below 63, the subtraction would have been incorrect, and the result would have been a very very large positive integer.

So, my solution is to do the subtraction into a separate signed int as follows:

void UpdatePitchValues(unsigned char pin, unsigned int pin_value) __wparam {

    unsigned char totalPitch = 13;

    unsigned char totalPossibleValues = 128;

    unsigned char zeroPosition = 63;

    signed int multiplier;

    float eachIncrementValue;

    float pitch;

    unsigned char wholeNum;

    float remainder;

    eachIncrementValue = (float)totalPitch / totalPossibleValues;

    multiplier = pin_value - zeroPosition;

    pitch = 0.0 + ( eachIncrementValue * multiplier );

So, as I said, a very subtle problem, but I'm glad its sorted now !  ;D

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

×
×
  • Create New...