Proposal: Changing Precision of SoC - from Integer to a decimal type

Hi everyone,

In our large-scale energy storage projects (20 MWh+) we had an SoC related problem: the precision of the SOC channel in Battery/SymmetricEss is too low, as 1% increase/decrease relates to 200kWh. The channel is currently an Integer (0-100), so the keep all near equals power solver starts to oscillate slightly (not critical for 20MWh, but will become more critical with increasing capacities), and external interfaces used for trading don’t work correctly because of the large jumps between the reported integer percentage values.

We have already applied a fix: we introduced a seperate SOC_DECIMAL channel as a decimal type using float, so the general approach is already tested and works well in practice. After further analysis, however, we concluded that double is the better choice, for higher precision and better compatibility with Java streams and the keep all near equals power solver, who both use double.

For this reason we would like to change the channel to a double value in the long run. We are aware that this is a breaking change and cannot be implemented easily in the short term. However, since we depend on this change, we would like to introduce a deprecation period to manage the transition. As a first step, we would add a new channel:

SOC_DECIMAL(Doc.of(OpenemsType.DOUBLE) //
        .unit(Unit.PERCENT) //
        .persistencePriority(PersistencePriority.HIGH)); //

which would initially live in a new interface:

public interface SocDecimalBattery extends OpenemsComponent

Once all Battery/SymmetricEss implementations and controllers have been migrated to the double-based functionality, the SOC_DECIMAL channel would be refactored into the SOC channel and the now-redundant channel would be removed.

For the migration in InfluxDB we can utilize the io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/FieldTypeConflictHandler.java to drive the migration and ensure the same data type is written per shard into InfluxDB.

Of course, there are also a few points where we see room for discussion:

  1. Should the channel be a double or a float? We lean towards double, but are open
    to arguments for float.

  2. How long should the deprecation period be?

    • We felt 6 months would be appropriate, but we are open to suggestions, as we are aware of how significant this transition is.

As mentioned, we know this is a breaking change, so we are of course open to discussion. What do you think of the change in general? Are there alternative proposals, or are the resulting problems too severe?

Hi Tim. We have been thinking about this in the past, and figured that SOC in general should be sufficient for a single battery generally (typically a BMS does not even provide more details); but the problem appears more in a Cluster system as you describe.

To solve what the traders are actually interested in, we recently implemented AvailableChargeEnergy and AvailableDischargeEnergy. This also takes into account if certain batteries/ESS are not available at the moment. We are still in the process of improving this implementation, but maybe it helps already for your use-case.

Hi Stefan!
Thank you for the reply.
The BMS of the Batteries we are working with provide the SOC as a decimal value and we would really like to take advantage of that.
I tried to find the AvailableChargeEnergy and AvailableDischargeEnergy Channels but couldn’t. Are they part of the official Repository? We would need them in the Edge2Edge Ess so I would like to verify if this could help us or not.
However, this does not address our problem in the keep all near equals power solver. Like I said, it is not necessarily a critical problem now, but it will become one in the future. If we are already making a change, this would fix the problem without having to touch the keep all near equals power solver (probably) at all.

I think there is a general question behind it:

What are we doing when a specific channel precision is not sufficient anymore? Do we support migration to different channel types / units and we are building some kind of history database converter? Or are we adding new channels and declare the old channels as Outdated?

There are a few other problematic types / units in the battery implementation. For example:

// Should be MILLIVOLT instead of VOLT. With VOLT, it's not possible to define exact per-cell limits.
CHARGE_MAX_VOLTAGE(Doc.of(OpenemsType.INTEGER)//
				.unit(Unit.VOLT)//
				.persistencePriority(PersistencePriority.HIGH)), //

// Same as CHARGE
DISCHARGE_MIN_VOLTAGE(Doc.of(OpenemsType.INTEGER)//
				.unit(Unit.VOLT)//
				.persistencePriority(PersistencePriority.HIGH)), //

// High voltage batteries need MILLIAMPERE precision. Our precision here means that in case of a 500V battery, we can either display 0W or 500W
CURRENT(Doc.of(OpenemsType.INTEGER)//
				.unit(Unit.AMPERE)//
				.persistencePriority(PersistencePriority.HIGH)), //