Crimson 3.2 Converting a float16 to a float 3.2

Join Date
Nov 2024
Location
Fort St. John
Posts
5
Hey guys

I am trying to poll a float16 (It's as horrible as it sounds) modbus register from a Prostar MPPT 25 Solar regulator. I am polling the data into a Red Lion DA10 and configuring with Crimson 3.2 Software. It appears that Crimson can only poll 32 or 64 bit floating points. So I need to convert the float 16 into a float 32 using the programing function within the software. I have been unsuccessful writing a script using the Crimson syntax, as it differs from C or C++ in an infuriating way. Just wondering if anyone on here has come across this before. Red Lion tech support is hard to get ahold of.

Thanks
 
Hey guys

I am trying to poll a float16 (It's as horrible as it sounds) modbus register from a Prostar MPPT 25 Solar regulator. I am polling the data into a Red Lion DA10 and configuring with Crimson 3.2 Software. It appears that Crimson can only poll 32 or 64 bit floating points. So I need to convert the float 16 into a float 32 using the programing function within the software. I have been unsuccessful writing a script using the Crimson syntax, as it differs from C or C++ in an infuriating way. Just wondering if anyone on here has come across this before. Red Lion tech support is hard to get ahold of.

Thanks
Is this one float32's bits in two 16-bit INTs (that is very common), or is it actually a the entire float is in one 16-bit INT?

Either way, please post a few examples of known float values with the corresponding 16-bit INT value(s).

The 16-bit INT pair conversion to a 32-bit float is straightforward.

The single 16-bit INT to a 32-bit float is a little busier, but still straightforward. If you have documentation of the encoding of the value into the 16 bits (similar to this: Single-precision floating-point format - Wikipedia), then it will be much easier.
 
I did this with Ignition expressions a while back. I think the RedLion can do this also.

operators:
& = bitwise and
>> shift right
^ power

logic:
input = the value read from the Morningstar as an integer holding register
exponent = (input & 31744) >> 10
fraction = (input & 1023) / 1024.0
output = (fraction + 1.0) * 2.0^(int(exponent) - 15)

IIRC, this will not work with a negative mantissa or exponent but that should not be a valid value from the Morningstar anyway.
 
Last edited:
It's IEEE754 half-precision binary16 according to ProStar MPPT MODBUS Specification. Inside there are examples on how to make it 32 bit float using C and also javascript.


Turns out that there is actually support in modern Intel and AMD CPUs for this datatype and it can be converted into 32 bit with a single instruction.

This is how to do it in C (without CPU support):

C#:
// ProStar MPPT MODBUS Document
// C Float16 Conversion to Float32 example
// Convert a float16 (IEEE754 half-precision binary16) to float32 (IEEE754 Single precision binary32)
#include <stdint.h>
#include <math.h>

float F16ConvertToF32(uint16_t f16) {
    float f32 = 0;
  
    unsigned sign = (f16 & 0x8000) >> 15; //extract out the sign
    unsigned exponent = ((f16 & 0x7C00) >> 10); //extract out the exponent
    float fraction = (f16 & 0x03ff) / 1024.0; //extract out the fraction
  
    //check for inf & NaN, 0x7F800000 = +inf 0xFF800000 = -inf
    if (exponent == 0x1f) {
        if (fraction == 0) {
            int positveInf = 0x7f800000;
            int negativeInf = 0xff800000;
            return (sign == 0) ? *(float*)&positveInf : *(float*)&negativeInf;
        }
        else {
            return 0.0 / 0.0; //use 0.0 to generate NaN
        }
    }
  
    //check for 0 or subnormal
    if (exponent == 0 ) {
        if (fraction == 0 ) { // if it is 0
            if(sign == 1 )
                return -0.0;
            return 0.0; // use 0.0 to return a zero in float
        }
        else {
            f32 = fraction * pow(2.0, -14.0);
            if (sign == 1)
                f32 *= -1.0;
            return f32;
        }
    }
    //the number is not a NaN or 0 or subnormal
    f32 = (fraction + 1.0) * pow(2.0, ((int)exponent - 15));
    if (sign == 1)
        f32 *= -1.0;
    return f32;
}
 
Last edited:
I did this with Ignition expressions a while back. I think the RedLion can do this also.

operators:
& = bitwise and
>> shift right
^ power

logic:
input = the value read from the Morningstar as an integer holding register
exponent = (input & 31744) >> 10
fraction = (input & 1023) / 1024.0
output = (fraction + 1.0) * 2.0^(int(exponent) - 15)

IIRC, this will not work with a negative mantissa or exponent but that should not be a valid value from the Morningstar anyway.
When I try to Input this logic into the Crimson software, I get a few different error messages depending on how I structure it.

for example:
If I use "fraction = (input & 1023) / 1024.0" I get the error "The operands of operator '=' must be of the same type". It is because of the decimal place in 1024.0, the tag "fraction" is set as an integer tag, and if I set it to a floating point type it gives me an error saying I cannot use bitwise AND in a floating point tag.

The "output = (fraction + 1.0) * 2.0^(int(exponent) - 15)" has the same problem with the decimals, and if i change the tag to a floating point type it does not let me use ^. It also doesn't like the bracket placement after 2.0^

I'll admit I'm pretty new to writing C code, perhaps it's just a simple syntax errors. But when I write this code as you have posted, or like the example shown in the Morningstar modbus manual, Crimson software gets very upset. At this point I'm pretty sure I can hear it whispering vicious ad-hominem attacks about my lack of intellect.
 
When I try to Input this logic into the Crimson software, I get a few different error messages depending on how I structure it.

for example:
If I use "fraction = (input & 1023) / 1024.0" I get the error "The operands of operator '=' must be of the same type". It is because of the decimal place in 1024.0, the tag "fraction" is set as an integer tag, and if I set it to a floating point type it gives me an error saying I cannot use bitwise AND in a floating point tag.

The "output = (fraction + 1.0) * 2.0^(int(exponent) - 15)" has the same problem with the decimals, and if i change the tag to a floating point type it does not let me use ^. It also doesn't like the bracket placement after 2.0^

I'll admit I'm pretty new to writing C code, perhaps it's just a simple syntax errors. But when I write this code as you have posted, or like the example shown in the Morningstar modbus manual, Crimson software gets very upset. At this point I'm pretty sure I can hear it whispering vicious ad-hominem attacks about my lack of intellect.
the tag "fraction" and "output" should both be floats. I assume those "=" assignments are actually ":=" assignments.

if I [declare] it [fraction?] to a floating point type it gives me an error saying I cannot use bitwise AND in a floating point tag.
Did you perhaps declare input as a floating point tag as well as fraction for that test? input must be a 16-bit integer, although apparently internally Crimson does everything in 32-bit integers.

Code:
exponent_INT := (input_INT & 0x7C00) / 0x0400;                   // or ... := (input_INT >> 10) & 0x001F;

fraction_FLOAT := float(input_INT & 0x03FF) / 1024.0;            // Note the cast to float

if (fraction_FLOAT > 0) {

    fraction_FLOAT := fraction_FLOAT + 1.0;

}

output_FLOAT := fraction_FLOAT * (2.0^(exponent_INT - 15));      // Note the extra level of parens; I rarely trust operator precedence

if( (input_INT & 0x8000) != 0) {

    output_FLOAT := -output_FLOAT;

}
 
Last edited:
Heh.
Code:
int r64_INT[2];    // or however arrays are declared
int input_INT;
float input_FLOAT;

r64_INT[0] := 0;                           // or possibly r64_INT[1] := 0;

r64_INT[1] := (input_INT & 0x7FFF) << 10;  // or possibly r64_INT[0] := ...

if((input_INT & 0x4000) != 0) {
    r64_INT[1] := r64_INT[1] | 0x7E000000;
}

if((input_INT & 0x8000) != 0) {
    r64_INT[1] := r64_INT[1] | 0x80000000;
}

input_FLOAT := R64ToReal(r64_INT[0])
 
You should look into explicit type casting in crimson software.

Also possibly do bit manipulation first and then save that into another unsigned integer variable. Then use that variable to do float calculations on.
 
the tag "fraction" and "output" should both be floats. I assume those "=" assignments are actually ":=" assignments.


Did you perhaps declare input as a floating point tag as well as fraction for that test? input must be a 16-bit integer, although apparently internally Crimson does everything in 32-bit integers.

Code:
exponent_INT := (input_INT & 0x7C00) / 0x0400;                   // or ... := (input_INT >> 10) & 0x001F;

fraction_FLOAT := float(input_INT & 0x03FF) / 1024.0;            // Note the cast to float

if (fraction_FLOAT > 0) {

    fraction_FLOAT := fraction_FLOAT + 1.0;

}

output_FLOAT := fraction_FLOAT * (2.0^(exponent_INT - 15));      // Note the extra level of parens; I rarely trust operator precedence

if( (input_INT & 0x8000) != 0) {

    output_FLOAT := -output_FLOAT;

}
 
This code is close, I'm still getting an error for the ^ operator.
Maybe the exponent needs to be float(exponent_INT -15)?

Also,
  • If exponent_INT > 15, it could multiply by float(1 << (exponent_INT -15)),
  • else if exponent_INT < 15, it could divide by float (1 << (15 - exponent_INT))
Then you don't need the 2.0^...
 
This code is close, I'm still getting an error for the ^ operator.
It's because you have 2.0^ instead of 2^ I think.
But then 2^-15 for examble is a float. Only positive numbers become integers. Maybe it doesn't support negative or perhaps even fractional numbers with the ^ operator.

You could also check if exponent_int-15 is positive or negative. If it's negative you can divide instead of multiply. Since x*(2^y) is the same as x/(2^-y)
 
Last edited:
The program I saw above is written in C so ^ is the XOR or toggle operator.
Isn't the power function 2**n? BTW, don't use the pow() or power() function unless the exponent is a fraction.
I have recent code where I use grad*grad instead of grad**2. grad is the gradient.
The problem with many pow() or power() functions is that they use exp() and ln() functions that are very slow.
Since I do a lot of work with polynomials, I see a lot of functions that look like f(t)=a+b*t+c*t**2+d*t**3+e*t**4+f*t**2
I NEVER write it like that in a real program. I use
f(t) = ((((f*t+e)*t+d)*t+c)*t+b)+a
This is much more efficient and minimize adding small numbers to numbers that are much bigger that results in loosing precision.
 
The program I saw above is written in C so ^ is the XOR or toggle operator.
Isn't the power function 2**n?.
:rolleyes:oh dear, LOL, I think @Peter Nachtwey hit the nail on the head: ^ is not exponentiation in Crimson; it think Power(base,power) is the only available option to calculate the relevant factor from the exponent in a single step.

TL;DR

In C, ** would dereference a pointer to a pointer. C does not have an exponentiation operator, but it has pow(base,power) from #include <math.h>.

** is exponentiation in Fortran, Python, IDL (IIRC), and perhaps some others.

This is Crimson, which is C-like, but it is not C. ^ is definitely XOR in Crimson.

I don't see an exponentiation operator in Crimson, so Power(base,exponent) may be the only option to raise a number to a power (other than the bit shift, which would require two choices.

Also, my R64ToReal example is not right; the exponent part needs to be tweaked a bit. I'll fix it later.
 
Last edited:

Similar Topics

I'm using Crimson 3.2 and would like to create a drop-down list. Tag Data type is INT.
Replies
4
Views
52
Hello! I am working on a portion of my program to save job data. I have a button that is labelled "Start Job" and this also starts the data logger...
Replies
10
Views
212
Hello, I am unable to map the string tag on the Text field or Data Box Properties. I am trying to Pop up Alpha Numeric Keypad for Recipe history...
Replies
4
Views
143
Created a widget for a valve with folder binding which displays open/close status. I want to allow operator to click on the valve which should...
Replies
4
Views
204
Hi all, I'm replacing a HMI with a Red Lion HMI with Crimson 3 configuration s/w, anyone who can help with configuring the HMI tags to DB's with...
Replies
6
Views
192
Back
Top Bottom