dbus-serialbattery icon indicating copy to clipboard operation
dbus-serialbattery copied to clipboard

BMS does not respect the limit load current value (CCL)

Open olvelasco opened this issue 2 years ago • 4 comments

Describe the bug When we have ESS activated and activated the feed in to grid of the surplus energy, if it is programmed that the limit of DCL charging current is for example 2 A above a SOC of 85%, this parameter only affects the load from the multiplus but if we have an MPPT, it continues to charge the batteryuntill thee max charge voltage (CVL) is reached The solution would be that the driver, when reaching a certain % of SOC establish that the load voltage (CVL) must be a value of for example 3.35 V per cell ( in my case a CVL value of 3,35*17) so that it does not continue to charge the battery but continues to send the surplus energy from the MPPT to the grid.

Thanks

VenusOS (please complete the following information):

  • Device type: Cerbo
  • Firmware Version 2.80

Battery/BMS (please complete the following information):

  • BMS/Battery type: JKBMS
  • Cells: 17
  • Interface: Ve.Direct

olvelasco avatar Mar 12 '22 11:03 olvelasco

I think this discussion on the Victron Energy community forum is a relevant supporting document. In addition the DVCC reference section 8.2 note is the source of truth.

When 'DC-coupled PV feed-in excess' is enabled with ESS, the DVCC system will not apply the DVCC charge current limit from PV to battery. This is behaviour is necessary to allow the export. Charge voltage limits will still apply.

As olvelasco says, the CVL is the control mechanism for energy coming from the MPPTs.

At the moment Battery.manage_charge_current manages the charge current (and discharge current!) limit. Perhaps this needs to be refactored into an object which manages CVL, CCL and DCL dependent on whether you want old behaviour (fine for systems without DC coupled MPPTs) or the new behaviour.

Interestingly /Info/MaxChargeVoltage is currently set to self.battery.max_battery_voltage in DbusHelper.setup_vedbus, which for jkbms is "MAX_CELL_VOLTAGE * self.cell_count", where MAX_CELL_VOLTAGE is defaulted at 3.45V.

chickenbig avatar May 19 '22 07:05 chickenbig

As per the above, the issue should be renamed to "VenusOS does not respect ... if MPPTs are installed" ;-)

Thanks to Louisvdw and his driver I'm planing an ESS using JK-BMS with second live batteries, thus uneven cells are expected. In my research somehow I came to this issue and had a glance at the respective code.

We don't know how different BMSs determine SoC but it is used to calculate CCL/DCL, thus the values and steps for reducing (dis)charge current seem to be choosen a little bit arbitrary and very careful. My job involves working with the original application of mentioned battries - I've seen a lot of balancing and funny SoCs, especially at the lower end causing "sudden cutoffs"...

With or without MPPTs I think voltage is way more reliable to control the end of charging - the current will automatically adjust by the magic of Ohm's law. ;-)

Lacking first hand expirience with JK-BMS and ESS, I would not rely on the SoC reported by the BMS and suggest to calculate CVL and DCL based on cell voltages instead. Something like this could be more efficient without risking battery health:

Charging: bv: current battery voltage maxcv: MAX_CELL_VOLTAGE mbv: max battery voltage = mcv * cell count lcv: lowest cell voltage hcv: highest cell voltage cvl: charge voltage limit x: voltage difference for top balancing, depending on BMS settings i.e. 0,1V if mcv=3.45V, balancing starts at 3.45V and BMS cutoff at 3.65V

IF hcv <= maxcv 
    cvl = mbv + x           # not there yet, charge with slightly higher voltage to get that current flowing
ENDIF

IF hcv > maxcv 
    IF lcv < maxcv
           cvl = bv + x     # balancing, highest cell can't exceed mcv+x, lower cells can catch up
    ELSE                    # lvc >= maxcv
           cvl = mbv        # all cells at 100% SoC (for given maxcv), balancer has to bleed x from cells above maxcv
    ENDIF
ENDIF

IF hcv > maxcv + x
    cvl = bv   # just in case - balancer could not cope with current, pause charging
ENDIF

This should charge all cells to maxcv as fast as possible without exceeding maxcv+x. With reasonable settings the BMS should never trigger a high voltage cutoff.

Discharging: mincv: MIN_CELL_VOLTAGE lcv: lowest cell voltage dcl: discharge current limit mdc: max discharge current x: voltage difference above mcv to start reducing dicharge current, i.e. 0.1V for mincv=3.1V would reduce current below 3.2V

IF lcv >= mincv + x                                     # sufficient voltage,
    dcl = mdc                                           # full current allowed
ENDIF

IF lcv < mincv + x
    IF lcv > mincv                                      # recuced current area
        dcl = mdc * ((lcv - mincv) / x)                 # current reducing linear with voltage
       # dcl = mdc * (1 - ((mincv + x - lcv) / x)^2 )   # parabolic reduction
    ELSE                                                # at or below mincv
        dcl = 0                                         # stop discharge
ENDIF

This should gently discharge to mincv without triggering low voltage cutoff from BMS. Not sure about oscilations in dcl from recovering cell voltage, maybe a parabolic reduction works better (flat decline at higher voltage, sharp decline closer to mincv: dcl = mdc * (1 - ((mincv + x - lcv) / x)^2 ) results in 75% of mdc in the middle of [mincv , mincv+x]

I can't code in Python but I'd happily write the documentation if this gets implemented after a thorough review.

dropax avatar Jun 08 '22 00:06 dropax

I believe that I understand the motivation behind not wanting to use Coulomb counting (SoC) to determine the CVL; there can be drift over long periods of low current, and when this SoC gets 'reset' is probably BMS specific.

LiFePO4 cells do not have a linear voltage/SoC relationship; charging at 3.45V/cell and get to > 90% SoC. Turning off charging/discharging the cell relaxes to a lower voltage. This suggests that voltage alone is not sufficient to determine the charge voltage (or even whether charge is allowed), and that higher SoC should also feed into the decision. An alternative would be to store some kind of state between runs of the driver, but my guess is that such state would further complicate matters; being a stateless driver (i.e. functional across the information provided by the BMS) would make fault tolerance (e.g. driver restart, VenusOS restart) much easier and reduce the state-space which would need to be tested. Another alternative to this would be to ignore fault tolerance and store the fact that it is charging/floating as a local variable, and if the driver fails mid-float then that's just bad luck.

In this matter it feels as if there is no fully correct approach, so perhaps making it configurable (i.e. turning the CVL/CCL/DCL calculation into an object conforming to a standard interface) would help experimentation and ensure personal taste is easily accommodated. As a bonus it would make unit testing the different approaches much easier (provided the data passed in conforms to a reasonably narrow interface too).

As an aside, Andy from Off Grid Garage has done some experiments around charging LiFePO4 cells; see LiFePO4 charging and discharging curve explained. How far to go? (Qishou EVE LF304 capacity test) , Charging LiFePo4 (LFP) to 3.4V and 3.5V with and without Absorption. What a difference! , Finding 20% and 80% SOC with LiFePO4. Why charging current and charging speed matters! and Busting the 20%-80% SOC myth for LiFePO4 batteries. for a taste of the complexity of the subject. I do wish he's summarise his current system settings in writing somewhere (perhaps with a link to the video/charge curve rationale) ...

chickenbig avatar Jun 08 '22 08:06 chickenbig

I don't understand "This suggests that voltage alone is not sufficient to determine the charge voltage". My assumtion is that we don't have a (reliable) SoC to begin with. For a single cell end of charge usually is defined by current tapering off below 0.02-0.1C at a given charge voltage. We use cells in series, thus I think "cell voltage is very sufficient to control battary charge voltage"

The suggested algorithm is nice for balancing but indeed will hold the battery at "absorption" forever - it is lacking a mechanism for switching into float (and returning back to absorption). An important point! My first idea was to use the control_allow_charge proprty, but that is controled by a different voltage limit an (ironically) SoC. Any ideas?

dropax avatar Jun 08 '22 21:06 dropax

Charging: bv: current battery voltage maxcv: MAX_CELL_VOLTAGE mbv: max battery voltage = mcv * cell count lcv: lowest cell voltage hcv: highest cell voltage cvl: charge voltage limit x: voltage difference for top balancing, depending on BMS settings i.e. 0,1V if mcv=3.45V, balancing starts at 3.45V and BMS cutoff at 3.65V

IF hcv <= maxcv 
    cvl = mbv + x           # not there yet, charge with slightly higher voltage to get that current flowing
ENDIF

IF hcv > maxcv 
    IF lcv < maxcv
           cvl = bv + x     # balancing, highest cell can't exceed mcv+x, lower cells can catch up
    ELSE                    # lvc >= maxcv
           cvl = mbv        # all cells at 100% SoC (for given maxcv), balancer has to bleed x from cells above maxcv
    ENDIF
ENDIF

IF hcv > maxcv + x
    cvl = bv   # just in case - balancer could not cope with current, pause charging
ENDIF

This should charge all cells to maxcv as fast as possible without exceeding maxcv+x. With reasonable settings the BMS should never trigger a high voltage cutoff.

This thinks a nice idea, I think we should test if this really works.

Marvo2011 avatar Nov 09 '22 05:11 Marvo2011

@dropax have I right understand that x should "the max cell difference for balancing start" from the BMS Setting? For my example it is only 0.005V I'd now if the MPPTs can accept this little difference, but I tried to set it in VenusOS with was accepted.

Edit: Max voltage precision for MPPT seams 10mV. So 0.01V as "max cell difference for balancing start" should work.

Marvo2011 avatar Nov 09 '22 07:11 Marvo2011

Hi Marvo2011!

No, x was meant as arbitrary value that you are comfortable to charge above you regular MAX_CELL_VOLTAGE - my (JK)BMS is set to start balancing at a lower voltage. I've implemented the suggested algorithm in Node-Red, with x=0.1 V. I assumed this to be the smallest increment of the CVL setting (like in remote console). It did not work very well - charge current was jumping like crazy and the pack even discharged while trying to balance. Since I don't use MPPTs I gave up on this and adjust charge current/disable charging based on reported max cell voltage.

The D-bus path accepts a float value, the 10mV precision you found may work indeed, I'll try a smaller value (this may take a while, my scedule is rather crammed atm...)

dropax avatar Nov 09 '22 10:11 dropax

@dropax I have created a simple dbus dummy service to test this.

https://github.com/Marvo2011/dbus-optimized-cvl/blob/main/optimized-cvl.py Your logic starts at line 98, with cat /data/etc/dbus-optimized-cvl/optimized-cvl_error.log you can debug the calculated voltage limit. For install unzip it to /data/etc/dbus-optimized-cvl and to run ln -s /data/etc/dbus-optimized-cvl/service /service/optimized-cvl for autostart add this line to /data/rc.local

Marvo2011 avatar Nov 09 '22 11:11 Marvo2011

@dropax I think with MPPTs it works much better than with a MultiPlus (In this first test without feed-in and fixed 5A) Bildschirmfoto 2022-11-17 um 09 35 32

Marvo2011 avatar Nov 17 '22 09:11 Marvo2011

Hi @Marvo2011, great work!

Thanks for the proof of concept and the detailed instructions, I'll try it asap.

Some thoughts, without having this tested:

  • Does your BMS cutoff at 3.5 V or is this the "natural limit" of the interaction between your service and the multi?
  • It looks like the Multi's voltage regulation is much coarser, maybe the CVL is internally rounded to 100 mV resolution and thus the algorithm needs too many iterations to effectively adjust the CVL. Which in turn results in the oscilations. Did you also log the battery current? I'd guess in the dips you see dicharging through the Multi.
  • Balancing took nearly 24 hours - weak balancers against a big, unbalanced pack?
  • Cells are held at 3.45 V for 4 hours: "balancing done detection" is in line 107, from there we should send a signal to stop charging and let the cells come down to their open clamp voltage. I'm not sure if "stop charging" would conflict with feed-in of excess power from the MPPT to the grid. If it does, setting CVL to i.e. 3.4 V/cell (or 3.35 like @olvelasco suggested) until SoC is below a certain level may be a solution.*

*No idea how to do this in a stateless fashion (@chickenbig's concern) but I think it is acceptable to loose a "pack is balanced"-flag due to a reboot. At least we should have a somewhat reliable SoC from here. My BMS calculates SoC way too high (around 1% per day), with Louis' original implementation of CCL a full charge with balancing would take ages...

dropax avatar Nov 17 '22 11:11 dropax

@dropax

  • Seams a "natural limit", my BMS can only disconnect the - pole over a relay, and it does it at 3.65V
  • I have log the battery power, see in the attachment
  • Yes, my integrated balancer in the BMS is very bad (100mA), I have ordered a new one (5A) but the shipment takes some time.
  • Yes, I think that is a good point. But we have to do this over the voltage, "stop charging" disables the MPPTs absolutely. Bildschirmfoto 2022-11-17 um 13 01 36

Marvo2011 avatar Nov 17 '22 12:11 Marvo2011