Forum Home › Forums › Development and Integration › Precision Loss Due 64-bit data
- This topic has 12 replies, 3 voices, and was last updated 1 month ago by Mikhail.
-
AuthorPosts
-
September 10, 2024 at 3:50 am #15353showmustgoonParticipant
I’ve encountered a precision loss issue when sending some 64-bit data.
During my tests with data exchange between CodeSys and RapidSCADA, I noticed the following problem. In CodeSys, I wrote the following values:LINT1 := 9223372036854775807; ULINT1 := 18446744073709551615; LWORD1 := 18446744073709551615;
However, in RapidSCADA, the values were received as:
9223372036854775808 18446744073709551616 18446744073709551616
After tracing the code, it appears that the precision loss occurs because all data in the Scada system is converted to double during processing. The specific code is as follows:
/// <summary> /// Sets the value and status of the tag, updates the tag data type and format according to the value type. /// </summary> public void Set(DeviceTag deviceTag, object val, int stat) { if (deviceTag == null) throw new ArgumentNullException(nameof(deviceTag)); if (val is string strVal) { deviceTag.DataType = TagDataType.Unicode; deviceTag.Format = TagFormat.String; SetUnicode(deviceTag.Index, strVal, stat); } else if (val is DateTime dtVal) { deviceTag.DataType = TagDataType.Double; deviceTag.Format = TagFormat.DateTime; SetDateTime(deviceTag.Index, dtVal, stat); } else { deviceTag.DataType = TagDataType.Double; deviceTag.Format = TagFormat.FloatNumber; Set(deviceTag.Index, Convert.ToDouble(val), stat); } }
I believe the precision is lost during this conversion. One simple solution I can think of is to modify the val field in CnlData to use the decimal type instead of double. Do you think this approach would work?
- This topic was modified 1 month ago by showmustgoon.
September 10, 2024 at 5:38 am #15355manjey73ParticipantPerhaps this will help you when using LReal (long). Well, look at other methods of working with long, ulong in BitConverter
That is, first convert your string to long using TryParse and only then add it to the channel via BitConverter. At the same time specifying the Integer data type for example
September 10, 2024 at 8:34 am #15361showmustgoonParticipantThat’s a good idea. I believe the parsing logic needs to be modified accordingly as well. this might affect some built-in functionalities of the system (such as statistics). I’ll try to resolve the issue in this direction.
September 10, 2024 at 9:55 am #15367MikhailModeratorHow do you transfer data between CodeSys and RapidSCADA?
By default, channel values uses Double type. If you change a channel to use Int64 type, it can help. However, it may depends on a transfer method.September 10, 2024 at 10:40 am #15369showmustgoonParticipantI’m using OPC UA right now to collect data and send commands between SCADA and CodeSys.
The main issue we’ve noticed is that large 64-bit integers lose precision when being collected and uploaded.
I’m not sure yet if this is a big enough concern to address and are still deciding whether to make adjustments or just limit operations to avoid the issue.September 11, 2024 at 9:10 am #15390MikhailModeratorI’ve checked the source code of the driver. It converts numbers to Double.
Do you have any ideas on how to get around this?September 11, 2024 at 10:35 am #15394showmustgoonParticipantSome other SCADA products I know of require configuring both the original data type and the converted data type to ensure the expected data conversion. For this purpose, the optional original types can be a very complex list, covering thousands of types across dozens of protocols.
In RapidSCADA, the type conversion is done automatically internally, converting to double for subsequent calculations, statistics, and other logic.
I believe data of this length is not a common requirement. If such a situation does arise, I might consider adding an additional type attribute when configuring the data point, performing extra processing during conversion, and potentially abandoning the calculation and statistical functionalities.
Additionally, I’m not sure if replacing double with decimal is a good idea. I only know that decimal offers more precision but am not familiar with the underlying logic.
September 11, 2024 at 11:02 am #15395manjey73ParticipantYou can check the data type of the channel – integer or double (or null by default) and perform different transformations depending on this.
Something like this. where cnl.Values is my Cnl dictionary
if (cnl.Value.DataTypeID == 0 || cnl.Value.DataTypeID == null) // channel data type Double { ServerContext.WriteCurrentData(cnl.Value.CnlNum, new CnlData(valDouble, 1)); } else if (cnl.Value.DataTypeID == 1) // channel data type Int64 { long val = Convert.ToInt64(fieldObj); ServerContext.WriteCurrentData(cnl.Value.CnlNum, new CnlData(BitConverter.Int64BitsToDouble(val), 1)); }
- This reply was modified 1 month ago by manjey73.
September 12, 2024 at 1:23 am #15399showmustgoonParticipantYou can check the data type of the channel – integer or double (or null by default) and perform different transformations depending on this.
Your solution is great, I am planning to additionally extend the INT64 and UINT64 types in the channel table.
- This reply was modified 1 month ago by showmustgoon.
September 12, 2024 at 5:30 am #15406manjey73ParticipantYou can assign the channel data type directly in the driver. Including in the View, you also generate code that allows you to use the Channel Creation Wizard based on your driver’s code. That is, the user does not need to think about what type of channel needs to be set for the signal, the channel creation wizard will do everything necessary.
I don’t remember if it is possible to check channel types from the driver code, since it is configured even before you create channels, but it can definitely help create channels and even specify the required formulas. For example, look at the Modbus code when setting up the bitmask.
September 12, 2024 at 5:54 am #15410showmustgoonParticipantMy consideration is that when writing data to a channel via a command, it is still necessary to know the channel type in order to process the data entered by the user with special handling, rather than simply converting it directly to a double. Of course, this step can be automatically adapted by the driver.
September 12, 2024 at 7:10 am #15415manjey73ParticipantI did not try to check the channel type from the driver immediately before recording, for example, if I created an integer channel directly by the driver, and the user then changed it to double.
If there is such an opportunity, then it is very good.
September 12, 2024 at 9:45 am #15429MikhailModeratorIt’s possible that received values are rounded by the driver. I’m sure sure. You should get channel data as a byte array and play with it.
-
AuthorPosts
- You must be logged in to reply to this topic.