<div dir="ltr"><div dir="ltr">Ok,<br><div>so I've reviewed my current charge curve and have another idea as to what was happening... which is that the charger itself was dynamically changing the power-available to be used for charging .. and stepping up and down in increments. This makes sense of the difference between the two charge sessions I recorded by hand, and the stepped nature of the curve I recorded.</div><div><br></div><div>The only vehicle code that takes temperature into account is the roadster .. which is definitely not generic... and is doing calculations in miles and degrees Celsius (weird) and is possibly not going to be relevant or easy to leverage. All other code (apart from VWUP) uses: </div><div>* A custom function (no table)</div><div>* a single flat value or </div><div>* a version of the flat stepped code with percent ranges.</div><div><br></div><div>I'll move mine to use a (calculated) gradient between points and lose the dependence on voltage.</div><div><br></div><div>I don't see that your code significantly reduces the number of division operations used (though I totally understand that aim) since it uses it for the first and last soc section only.</div><div><br></div><div>What might actually be better is a temperature efficiency gradient centred around 20 degrees. Either a single one - or in the table. See below.</div><div><br></div><div>//.ichael</div><div><br></div><div>----8<--</div><div><pre id="gmail-vimCodeElement" style="font-size:13px;white-space:pre-wrap;color:rgb(0,0,0)"><span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)"><br class="gmail-Apple-interchange-newline">// Charging profile</span>
<span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">// - Must be from lowest to highest to%.</span>
<span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">// - max watts is at optimal temperature.</span>
<span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">// - MaxWattsUsed = maxChargeWatts * 1-(|battery_temp - tempOptimal| * tempDegrade)</span>
<span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">// 0.0182 means degrades by 40% of original at zero degress</span>
<span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">// - GUESTIMATE ONLY needs data.</span>
charging_step_t ioniq5_chargesteps[] = {
<span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">// to max optimal temp degrade</span>
<span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">// % watts deg C gradient</span>
{ <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">10</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">220000</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">22</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0.0182</span> },
{ <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">25</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">210000</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">22</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0.0182</span> },
{ <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">45</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">200000</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">22</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0.0182</span> },
{ <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">75</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">150000</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">22</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0.0182</span> },
{ <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">80</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">80000</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">22</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0.0182</span> },
{ <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">85</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">60000</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">22</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0.0182</span> },
{ <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">90</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">40000</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">22</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0.0182</span> },
{ <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">95</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">25000</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">22</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0.0182</span> },
{ <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">100</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">7200</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">22</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0.0182</span> },
{ <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0</span>, <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0</span>},
};
<span class="gmail-doxygenComment" style="font-size:1em;color:rgb(255,139,139)">/**</span><span class="gmail-doxygenComment" style="font-size:1em;color:rgb(255,139,139)"> </span><span class="gmail-doxygenBrief" style="font-size:1em;color:rgb(173,216,230);font-weight:bold;font-style:italic">Calculate the remaining minutes to charge.</span>
<span class="gmail-doxygenComment" style="font-size:1em;color:rgb(255,139,139)">*</span><span class="gmail-doxygenBody" style="font-size:1em;color:rgb(0,0,255)"> Works on the premise that the charge curve applies to the MAXIMUM only.</span>
<span class="gmail-doxygenComment" style="font-size:1em;color:rgb(255,139,139)">*</span><span class="gmail-doxygenBody" style="font-size:1em;color:rgb(0,0,255)"> Each section is calculated such that the 'max watts' is effectively the 'end' value at that 'to'.. </span>
<span class="gmail-doxygenComment" style="font-size:1em;color:rgb(255,139,139)">*</span><span class="gmail-doxygenBody" style="font-size:1em;color:rgb(0,0,255)"> and the power use is assumed to be a gradient from the last 'to' value to the end 'to' value.</span>
<span class="gmail-doxygenComment" style="font-size:1em;color:rgb(255,139,139)">*/</span>
<span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">int</span> CalcRemainingChargeMins(<span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">int</span> chargeVolt, <span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">float</span> chargewatts, <span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">float</span> availwatts, <span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">bool</span> adjustTemp, <span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">float</span> tempCelcius, <span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">int</span> fromSoc, <span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">int</span> toSoc, <span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">int</span> batterySizeWh, charging_step_t charge_steps[])
{
<span class="gmail-Statement" style="font-size:1em;color:rgb(165,42,42);font-weight:bold">if</span> (chargewatts <= <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0</span> || fromSoc >= toSoc)
<span class="gmail-Statement" style="font-size:1em;color:rgb(165,42,42);font-weight:bold">return</span> <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0</span>;
<span class="gmail-Statement" style="font-size:1em;color:rgb(165,42,42);font-weight:bold">if</span> (availwatts < chargewatts) <span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">// encompasses '0' case.</span>
availwatts = chargewatts;
<span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">int</span> last_to_soc = fromSoc;
<span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">int</span> last_speed = chargewatts;
<span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">// Track the sum of percent/kw. Reduces floating point operations.</span>
<span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">// The 'batterySizeWh' * 60 / 100 would be used on every sum.. so factored to the end.</span>
<span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">float</span> sumval = <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0</span>;
<span class="gmail-Statement" style="font-size:1em;color:rgb(165,42,42);font-weight:bold">for</span> (<span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">int</span> i = <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0</span>; charge_steps[i].maxChargeWatts > <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0</span>; ++i) {
<span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">const</span> charging_step_t &step = charge_steps[i];
<span class="gmail-Statement" style="font-size:1em;color:rgb(165,42,42);font-weight:bold">if</span> (<span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">/*</span><span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">step.voltage <= chargeVolt &&</span><span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">*/</span> step.toPercent > last_to_soc) {
<span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">int</span> next_to_soc = std::min(toSoc, step.toPercent);
<span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">int</span> percents_In_Step = next_to_soc - last_to_soc;
<span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">float</span> maxCharge = step.maxChargeWatts ;
<span class="gmail-Statement" style="font-size:1em;color:rgb(165,42,42);font-weight:bold">if</span> (adjustTemp && step.tempOptimal > <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0</span>)
maxCharge *= <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">1</span>-(std::abs(tempCelcius - step.tempOptimal) * step.tempDegrade);
<span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">float</span> endSpeed = std::min(availwatts, maxCharge);
<span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">// Keep it as a doubled value here to avoid a /2 which becomes *2 below.</span>
<span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">float</span> curSpeedDbl = last_speed + endSpeed;
<span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">// our one division.</span>
sumval += ( percents_In_Step * <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">2</span>) / curSpeedDbl;
last_to_soc = next_to_soc;
last_speed = endSpeed;
}
}
<span class="gmail-Statement" style="font-size:1em;color:rgb(165,42,42);font-weight:bold">if</span> (last_to_soc < toSoc) {
sumval += (toSoc - last_to_soc) / last_speed;
}
<span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">// convert to minutes (summary value to minutes)</span>
<span class="gmail-Statement" style="font-size:1em;color:rgb(165,42,42);font-weight:bold">return</span> (<span class="gmail-Type" style="font-size:1em;color:rgb(46,139,87);font-weight:bold">int</span>)((batterySizeWh * sumval * <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0.6</span><span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">/*</span><span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)"> 60/100 </span><span class="gmail-Comment" style="font-size:1em;color:rgb(0,0,255)">*/</span>) + <span class="gmail-Constant" style="font-size:1em;color:rgb(255,0,255)">0.5</span>);
}</pre></div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, 30 Dec 2022 at 07:59, Michael Geddes <<a href="mailto:frog@bunyip.wheelycreek.net">frog@bunyip.wheelycreek.net</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr">Firstly, the Voltage architecture (800V, 400V, 240V 3Phase, 240V 1Phase) in use is going to affect the amount of power able to be delivered because the limiting factor will be the current and possibly the potential difference across the individual cell (?)- so it is my _thesis_ that this will matter, especially in the mid section of the charging; I need to get more information on this so I have made a plugin to handle gathering data. I'm quite happy to ditch it if it doesn't bare out.</div><div>Ah, also there are two more metrics that I should log that you have reminded me of: The available power (I think I have that metric) and the temperature (? ave of the batteries perhaps). </div><div dir="ltr"><br></div><div dir="ltr">I'll have to try and get to one of the few 800v chargers available in my state again - finding 50kw chargers is pretty easy.<div><br></div><div>I have mapped by hand the charging 'curve' at an 800V charger (only 150kw or so though - so yes, power also matters), and my experience was that it was quite 'stepped' - ie it seemed to go in stages. Though I can see the advantage of the gradient, the only time it went to more of a curve/gradient is a little bit in the transition areas and above 90% SOC ( which I'm not really fussed with being too precise above 90%).</div><div><br></div><div> I'm still a little uncertain how to handle coming from a low SOC as the lower SOC charges a bit slower, so still need to manage somehow the maximum power available to the charger (which I possibly have as a metric - I should probably include that in the logging and in the calculation, and yes, that might end up being a better input into the algorithm).</div><div><br></div><div>The way I have it working (btw) means that a higher voltage architecture defaults to the lower voltage curve (line) if a higher step isn't there. So where the curves (lines) converge I don't double up on data in the table. The AC Charger seems to be pretty constant right up to 90% for example.</div></div><div><br></div><div>//.ichael</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, 30 Dec 2022 at 02:50, Michael Balzer <<a href="mailto:dexter@expeedo.de" target="_blank">dexter@expeedo.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Michael,<br>
<br>
while it makes sense to add a general standard utility for this, I don't <br>
think the Hyundai/Kia code is a good candidate for this.<br>
<br>
I find it confusing you need to take the voltage into account rather <br>
than the power. Also, the "WattHours" numbers don't seem to make sense <br>
-- why would you have different capacities in the same SOC differences, <br>
and why depending on the voltage? Also, the calculator seems to need / <br>
be based on rectangular steps instead of an actual charge curve?<br>
<br>
A more natural generalized definition would in my opinion be based on <br>
modeling the actual curve, like the one I've implemented for the VW Up, <br>
see `OvmsVehicleVWeUp::CalcChargeTime()`. That takes the charge curve as <br>
direct (SOC → max power) coordinates, just adding the section gradients <br>
as a speed optimization (float divisions are very CPU intense on the ESP32):<br>
<br>
struct {<br>
int soc; float pwr; float grd;<br>
} ccurve[] = {<br>
{ 0, 30.0, (32.5-30.0) / ( 30- 0) },<br>
{ 30, 32.5, (26.5-32.5) / ( 55- 30) },<br>
{ 55, 26.5, (18.5-26.5) / ( 76- 55) },<br>
{ 76, 18.5, (11.0-18.5) / ( 81- 76) },<br>
{ 81, 11.0, ( 6.5-11.0) / ( 91- 81) },<br>
{ 91, 6.5, ( 3.0- 6.5) / (100- 91) },<br>
{ 100, 3.0, 0 },<br>
};<br>
<br>
But maybe some other vehicle already has an even more generalized & easy <br>
to use approach. My function lacks temperature compensation, but <br>
normally delivers sufficiently close results.<br>
<br>
Regards,<br>
Michael<br>
<br>
<br>
Am 29.12.22 um 13:02 schrieb Michael Geddes:<br>
> Hi,<br>
><br>
> There's a remaining charge calculator currently in the hyundai base <br>
> class which I have improved upon. This configuration allows for the <br>
> charge voltage to be part of the equation. This is the example from <br>
> data I collected with the ioniq 5 on 800v charging .. and I've written <br>
> a plugin so I can get more charge profile information at other charge <br>
> voltages.<br>
><br>
> I'm happy to leave it in the Ioniq 5 code, but was wondering if I <br>
> should put the implementation in a common area.. vehicle.h maybe?<br>
><br>
> //.ichael<br>
><br>
> ---8<----------------------<br>
><br>
> // Charging profile<br>
> // - Must be from lowest to highest to%.<br>
> // - Higher voltages must come before lower voltages for the same to%<br>
> charging_step_t ioniq5_chargesteps[] = {<br>
> // voltage, to%, WattHours<br>
> { 750, 10, 100000 },<br>
> { 750, 25, 190000 },<br>
> { 750, 45, 220000 },<br>
> { 750, 75, 120000 },<br>
> { 750, 80, 80000 },<br>
> { 400, 85, 60000 },<br>
> { 400, 90, 40000 },<br>
> { 100, 90, 1100 },<br>
> { 400, 95, 25000 },<br>
> { 100, 95, 7400 },<br>
> { 100, 100, 7200 },<br>
> { 0, 0, 0 },<br>
> };<br>
><br>
> int CalcRemainingChargeMins(int chargeVolt, float chargespeed, int <br>
> fromSoc, int toSoc, int batterySize, charging_step_t charge_steps[])<br>
> {<br>
><br>
> _______________________________________________<br>
> OvmsDev mailing list<br>
> <a href="mailto:OvmsDev@lists.openvehicles.com" target="_blank">OvmsDev@lists.openvehicles.com</a><br>
> <a href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev" rel="noreferrer" target="_blank">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a><br>
<br>
-- <br>
Michael Balzer * Helkenberger Weg 9 * D-58256 Ennepetal<br>
Fon 02333 / 833 5735 * Handy 0176 / 206 989 26<br>
<br>
_______________________________________________<br>
OvmsDev mailing list<br>
<a href="mailto:OvmsDev@lists.openvehicles.com" target="_blank">OvmsDev@lists.openvehicles.com</a><br>
<a href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev" rel="noreferrer" target="_blank">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a><br>
</blockquote></div></div>
</blockquote></div></div>