Esempio n. 1
0
//
// this fucntion is called often or very often to process battery data
// can be used equally well for live battery data in real time or to process recorded battery data
//
        public bool bValuateBatteryData(strctBattMonData stRecentBattData, int ciIterationNo)
        {
            bool bRes = false;
            stDischrgChrgCycle stdschrgNewCycle = default(stDischrgChrgCycle);           // neends init such as in DateTime dteSrc = default(DateTime),
            TimeSpan           tmspnStarterMotorRun;

//			Debug.WriteLine("++bValuateBatteryData("+ciIterationNo+")");

// compute average current and keep it to eliminate noise in current sensor line
            if (m_iCurrentAvrgIdx < m_ciCurrAvrgCount)
            {
                m_dblTempCurrent  += stRecentBattData.dblBatAmperes;
                m_iCurrentAvrgIdx += 1;
            }
            else
            {
                m_dblAvrgCurrent100Smpls = m_dblTempCurrent / (double)m_ciCurrAvrgCount;
                m_iCurrentAvrgIdx        = 0;
                m_dblTempCurrent         = 0.0;
            };

// on the very first iteration save this as beginning of recording
            if (0 == ciIterationNo)
            {
                stbtdtmTempFirstRecord = stRecentBattData;
                if (null == m_arriTimesBetwItersHistogr)
                {
                    m_arriTimesBetwItersHistogr = new int [ciMaxHistoSize];
                }
                ;
// erase histogram as well
                Array.Clear(m_arriTimesBetwItersHistogr, 0, ciMaxHistoSize);
            }
            else
            {
// next we check for Microcontroller errors.
                TimeSpan tmspnBetwnIters = stRecentBattData.dtBattDateTime - stcBattPrevData.dtBattDateTime;
// Timer tick may be reported by microcontroller as inaccurate time, including jumping backawards
                if (tmspnBetwnIters.TotalSeconds < 0.0)

// ignore very first inetration, since previous date-time is invalid
//				if(tmspnBetwnIters.Days < 0)
                {
                    Debug.WriteLine("bValuateBatteryData(ERROR) time jumped backwards! Previous=" + stcBattPrevData.dtBattDateTime.ToString("HH:mm:ss.fff") + " > New=" + stRecentBattData.dtBattDateTime.ToString("HH:mm:ss.fff"));
// fix up error - use last known good date-time
                    stRecentBattData.dtBattDateTime = stcBattPrevData.dtBattDateTime;
                }
                else
                {
// for good iteration, save data to histogram
//					Debug.WriteLine("bValuateBatteryData() Curr-Prev duration " + tmspnBetwnIters.Days.ToString() + "."+ tmspnBetwnIters.Hours.ToString("0#") +":"+ tmspnBetwnIters.Minutes.ToString("0#")+":"+tmspnBetwnIters.Seconds.ToString("0#.")+"."+tmspnBetwnIters.Milliseconds.ToString("000"));
                    int iIntervBetwIters = (int)tmspnBetwnIters.TotalMilliseconds;
                    if (iIntervBetwIters < ciMaxHistoSize)
                    {
                        m_arriTimesBetwItersHistogr[iIntervBetwIters] += 1;
                    }
                    ;
// for every 1000 iterations, print a histoghram
                    if (0 == ciIterationNo % 999)
                    {
                        for (int j = 0; j < ciMaxHistoSize; j++)
                        {
                            Debug.WriteLine("[" + j.ToString() + "] : " + m_arriTimesBetwItersHistogr[j].ToString());
                        }
                        ;
                    }
                    ;
                };         // end IF tmspnBetwnIters.TotalSeconds >0
            };             // end IF check for Microcontroller errors.

// here we observe a few parameters including min and max of voltage and current
// as well as watch for engine starting pattern : starter mtr OFF, ON, OFF sequence

// criteria - low discharge current for several seconds - key on ignition on
//  then high discharge current for a second or two - starter on
// then dischanrge current changes to charge current
// then battery gets strong charging which should quckly deacrease within 15 seconds if battery is healthy

//======================================================================
//        -80A       -40A       -2A  -0.1A     0A    +0.1A   +2A  +100A
// str mtr |         discharging      |    no load    |    charging
//                                { --->-------->-------->----}   current crosses zero amperes line
//======================================================================

//-------------------------------------------------------------------------------------------
// BATTERY STRONG DISCHARGE. batt current <-80A
//--------------------------------------------------------------------------------------------
            if (stRecentBattData.dblBatAmperes < -80.0)          // starter surely draws more than that
            {
//check if microcontroller correctly specified battery state
                if (stRecentBattData.chBattState != 'D')
                {
                    Debug.WriteLine("bValuateBatteryData() ERR battery state mismatch - D");
                }
                ;

// watch for maximum current starter draws - in-rush starter motor current
                if (stRecentBattData.dblBatAmperes < m_sdblMaxBattDischrgCurrent)
                {
                    m_sdblMaxBattDischrgCurrent = stRecentBattData.dblBatAmperes;
                }
                else
                {
//					Debug.WriteLine("bValuateBatteryData() Max discharging current=" + sdblMaxBattDischrgCurrent.ToString("+#.#;-#.#;0"));
                };

                if (true == m_bStarterMotorIsOn)
                {
// starter motor keeps running...
                    Debug.WriteLine("bValuateBatteryData() starter mtr is RUNNING");
                }
                else
                {
// starter motor just started
                    Debug.WriteLine("bValuateBatteryData() starter mtr is now ON !");
                    m_bStarterMotorIsOn  = true;
                    stcBattDatStarterOn  = stRecentBattData;
                    stcBattDatStarterOff = stcBattPrevData;
// create new discharge-charge cycle
                    stdschrgNewCycle.bIsCycleComplete     = false;
                    stdschrgNewCycle.bIsFullyRecharged    = false;
                    stdschrgNewCycle.dblMaxChrgCurrent    = -99.0;
                    stdschrgNewCycle.dblMaxDischrgCurrent = m_sdblMaxBattDischrgCurrent;
                    stdschrgNewCycle.stbtdtmStarterOn     = stRecentBattData;
                    stdschrgNewCycle.stbtdtmFirstRecord   = stbtdtmTempFirstRecord;

                    if (null != m_mapDischrgChrgCyles)
                    {
// you can use .Add function to ass new starter motor event data
                        try
                        {
                            m_mapDischrgChrgCyles.Add(stdschrgNewCycle.stbtdtmStarterOn.dtBattDateTime, stdschrgNewCycle);
                        }
                        catch (ArgumentException aexc)
                        {
                            Debug.WriteLine("bValuateBatteryData() battery already has this dis-chrg cycle on record, skip." + aexc.ToString());
                        };
// also can use array notation
//						m_mapDischrgChrgCyles[stdschrgNewCycle.stbtdtmStarterOn.dtBattDateTime]=stdschrgNewCycle;
                    }
                    ;              // end IF m_mapDischrgChrgCyles is not Null
                };                 // end IF true==m_bStarterMotorIsOn
            }
// strong discharge case
//-------------------------------------------------------------------------------------------
// BATTERY DISCHARGE -80A < batt current < -2A
//--------------------------------------------------------------------------------------------
            else if (stRecentBattData.dblBatAmperes >= -80.0 && stRecentBattData.dblBatAmperes < -2.0)
            {
//				Debug.WriteLine("bValuateBatteryData() battery discharging");
//check if microcontroller correctly specified battery state
                if (stRecentBattData.chBattState != 'D')
                {
                    Debug.WriteLine("bValuateBatteryData() ERR battery state mismatch - D");
                }
                ;
// when discharge current is not that big, i.e. not a starter mtr case
// battery discharging case
//-------------------------------------------------------------------------------------------
// BATTERY DISCHARGE -40A < batt current <-0.2A
//--------------------------------------------------------------------------------------------
                if (true == m_bStarterMotorIsOn && stRecentBattData.dblBatAmperes > -40.0 && stRecentBattData.dblBatAmperes < -0.2)
                {
                    Debug.WriteLine("bValuateBatteryData() starter mtr now OFF.");
// starter motor not running now
                    m_bStarterMotorIsOn         = false;
                    stcBattDatStarterOffAfterOn = stRecentBattData;
                    stcBattDatCurrentCrossZero  = stRecentBattData;
                    tmspnStarterMotorRun        = stcBattDatStarterOffAfterOn.dtBattDateTime - stcBattDatStarterOn.dtBattDateTime;
// uncommenting line below causes exception in line reader
                    Debug.WriteLine("bValuateBatteryData() starter mtr duration=" + tmspnStarterMotorRun.Seconds.ToString() + "." + tmspnStarterMotorRun.Milliseconds.ToString("000") + " sec");

// compute charge released for engine starting
                    double dblTempmQ = (stcBattDatStarterOffAfterOn.liQOut - stcBattDatStarterOn.liQOut);

                    Debug.WriteLine("bValuateBatteryData() Battery released " + (dblTempmQ / 1000).ToString() + " Q to start engine");

                    if ((stcBattDatStarterOff.dblBatAmperes - stcBattDatStarterOn.dblBatAmperes) != 0.0)
                    {
// compute battery internal resistance and related parameters
                        m_dblBatteryResistance = (stcBattDatStarterOff.dblBatVolts - stcBattDatStarterOn.dblBatVolts) /
                                                 (stcBattDatStarterOff.dblBatAmperes - stcBattDatStarterOn.dblBatAmperes);
                        Debug.WriteLine("bValuateBatteryData() batt R=" + m_dblBatteryResistance.ToString("0.#000") + " Ohm");
// estimate cranking amperes based on voltage-current

// Hot cranking amperes (HCA) is the amount of current a battery can provide at 80°F (26.7°C).
//	The rating is defined as the current a lead-acid battery at that temperature can deliver for 30 seconds and maintain at least 1.2 V/cell (7.2 volts for a 12-volt battery).
// Cranking amperes (CA), also sometimes referred to as marine cranking amperes (MCA), is the amount of current a battery can provide at 32°F (0°C).
//	The rating is defined as the number of amperes a lead-acid battery at that temperature can deliver for 30 seconds and maintain at least 1.2 V/cell (7.2 volts for a 12 volt battery).
// Cold cranking amperes (CCA) is the amount of current a battery can provide at 0°F (−18°C).
//	The rating is defined as the current a lead-acid battery at that temperature can deliver for 30 seconds and maintain at least 1.2 volts per cell (7.2 volts for a 12-volt battery)

                        if (m_dblBatteryResistance != 0.0)
                        {
// example
// key on 12.1V,-6.4A; starter on 10.7V, -104A; R=(12.1-10.7)/(104-6)=1.4V/97.6A=0.014 Ohm
// knowing R predict CA by computation CA=(12.1-7.2)/R
                            m_dblCA = (stcBattDatStarterOff.dblBatVolts - 7.2) / m_dblBatteryResistance;
                            Debug.WriteLine("bValuateBatteryData() batt CA=" + m_dblCA.ToString("0000") + " Amperes");
                        }
                        ;
//
// determine whether it was actual engine starting cyle or maybe just a momentary drop in battry current
//
// decision made is based on high discharge currnet value and duration of it
// Must draw high discharge current for at least 0.5 sec to qualify as engine starting event
// AND battery should be discharging : state=D and voltage should be < 12.6 Volts
                        if (tmspnStarterMotorRun.Seconds >= 1 ||
                            (tmspnStarterMotorRun.Seconds == 0 && tmspnStarterMotorRun.Milliseconds > 500))
                        {
                            m_iEngineStartEvtCnt += 1;
// modify last incomplete discharge-charge cycle and update its data
                            Debug.WriteLine("bValuateBatteryData() valid cycle duration " + tmspnStarterMotorRun.Seconds.ToString() + "." + tmspnStarterMotorRun.Milliseconds.ToString("000") + " sec detected. Completing dischrg-chrg cycle....");
// find our dis-chrg cycle in array and modify it to store starter off data
                            stDischrgChrgCycle stdschrgCycleInWorks = m_mapDischrgChrgCyles[stcBattDatStarterOn.dtBattDateTime];
// if found, modify data in place
//
// we have now stdschrgCycleInWorks.stbtdtmStarterOn part filled only.
// now populate stdschrgCycleInWorks.stbtdtmStarterOffAfterOn and other members
//
                            stdschrgCycleInWorks.bIsCycleComplete     = true;
                            stdschrgCycleInWorks.dblMaxChrgCurrent    = -99.0;
                            stdschrgCycleInWorks.dblBatteryResistance = m_dblBatteryResistance;
                            stdschrgCycleInWorks.dblCA = m_dblCA;
                            stdschrgCycleInWorks.dblMaxDischrgCurrent     = m_sdblMaxBattDischrgCurrent;
                            stdschrgCycleInWorks.stbtdtmStarterOffAfterOn = stRecentBattData;
                            stdschrgCycleInWorks.tmspnStrMotorRunDur      = tmspnStarterMotorRun;
                            stdschrgCycleInWorks.dblCoulmbsToStartEngine  = dblTempmQ / 1000.0;
// save it into array
                            m_mapDischrgChrgCyles[stcBattDatStarterOn.dtBattDateTime] = stdschrgCycleInWorks;
                        }
                        else
                        {
// not a engine starting cycle! Just very short current drop, e.g. downspike
                            Debug.WriteLine("bValuateBatteryData() Cycle duration too short: " + tmspnStarterMotorRun.Seconds.ToString() + "." + tmspnStarterMotorRun.Milliseconds.ToString("000") + " sec.");
                            Debug.WriteLine("bValuateBatteryData() Not a starter mtr cycle. Removing incomplete dischrg-chrg cycle....");
// so we delete previous spurious dischr-chrg cycle from our list
                            m_mapDischrgChrgCyles.Remove(stcBattDatStarterOn.dtBattDateTime);
                        };
                    }
                    ;                      // end IF of (stcBattDatStarterOff.dblBatAmperes-stcBattDatStarterOn.dblBatAmperes) !=0 Amp

// store time of this moment and watch for 15 minutes from it - battery should quckly charge, charge current decrease
                }
                ;                  // end IF of true==m_bStarterMotorIsOn
            }
//
// when battery current current crosses zero Ampreres line
// this includes NO LOAD case as well - see inner check
            else if (stRecentBattData.dblBatAmperes >= -2.0 && stRecentBattData.dblBatAmperes <= +2.0)
            {
//-------------------------------------------------------------------------------------------
// BATTERY NO LOAD -0.1A < batt current <+0.1A
//--------------------------------------------------------------------------------------------
                if (stRecentBattData.dblBatAmperes >= -0.1 && stRecentBattData.dblBatAmperes <= +0.1)
                {
//					Debug.WriteLine("bValuateBatteryData() batt no load");
// may update SoC bars for NL case here
//check if microcontroller correctly specified battery state
                    if (stRecentBattData.chBattState != 'I')
                    {
                        Debug.WriteLine("bValuateBatteryData() ERR battery state mismatch - NL");
                    }
                    ;
                }
                ;
//
// check to determine if we are coming here just after engine starting cycle
// - to find out, we determine if an element is present with date-time of starter motor was switched on
                bool bHasStarterOnElem = m_mapDischrgChrgCyles.ContainsKey(stcBattDatStarterOn.dtBattDateTime);

                if (true == bHasStarterOnElem)
                {
// if we have at least one engine starter cycle, then we count form the last engine starter cycle - error happens here -- !
                    stDischrgChrgCycle stdschrgCycleInWorks = m_mapDischrgChrgCyles[stcBattDatStarterOn.dtBattDateTime];

// and if average battery current is around zero, then we compute battery A*Hrs capacity based on charge accepted
// from the moment charging started (starter off) till now
                    if (m_iEngineStartEvtCnt > 0 && Math.Abs(m_dblAvrgCurrent100Smpls) < 1.2 && false == stdschrgCycleInWorks.bIsFullyRecharged)
                    {
                        long liBatteryChargeAccepted = (stRecentBattData.liQIn - stcBattDatCurrentCrossZero.liQIn) / 1000;
                        Debug.WriteLine("bValuateBatteryData() Battery is fully charged. Q in =" + liBatteryChargeAccepted.ToString() + " Q");
                        Debug.WriteLine("bValuateBatteryData() Battery capacity est. " + ((double)liBatteryChargeAccepted / 3600.0).ToString("#0.0") + " A*Hrs");
//						workerObject.bLogDataToFile("Battery fully charged (based on ~0A average battery current");
                        stdschrgCycleInWorks.bIsFullyRecharged = true;
// save time stamp when battery fully charged
                        stdschrgCycleInWorks.stbtdtmWhenFullyCharged = stRecentBattData;
// find last discharge-charge cycle we used
                        m_mapDischrgChrgCyles[stcBattDatStarterOn.dtBattDateTime] = stdschrgCycleInWorks;
// update last discharge-charge cycle with new data
                    }
                    ;                      // end IF true==bHasStarterOnEle
                }
                else
                {
                    Debug.WriteLine("bValuateBatteryData() Cannot determine if Battery is fully charged, because starter ON event was not found " + stcBattDatStarterOn.dtBattDateTime.ToString("dd.HH:mm:ss.fff"));
                };
            }
// battery is now charging
//-------------------------------------------------------------------------------------------
// BATTERY CHARGING batt current > +0.2A
//--------------------------------------------------------------------------------------------
            else if (stRecentBattData.dblBatAmperes > +0.2)
            {
//				Debug.WriteLine("bValuateBatteryData() battery charging");

                if (stRecentBattData.chBattState != 'C')
                {
                    Debug.WriteLine("bValuateBatteryData() ERR battery state mismatch - C");
                }
                ;
// watch for maximum charging current
                if (stRecentBattData.dblBatAmperes > m_sdblMaxBattChrgCurrent)
                {
                    m_sdblMaxBattChrgCurrent = stRecentBattData.dblBatAmperes;
                    stcBattDatMaxChargCurr   = stRecentBattData;
                }
                else
                {
// once we get here the first time then battery charging current starts to drop,
// so note max charging current
//					Debug.WriteLine("bValuateBatteryData() Max charging current=" + sdblMaxBattChrgCurrent.ToString("+#.#;-#.#;0"));
                };
            }
            else
            {
// tbd
                Debug.WriteLine("bValuateBatteryData() TBD case");
            };
// just store momentary data for the next run
            stcBattPrevData = stRecentBattData;

//			Debug.WriteLine("--bValuateBatteryData()="+bRes.ToString());
            return(bRes);
        } // end of bValuateBatteryData()
Esempio n. 2
0
        //
        // this fucntion is called often or very often to process battery data
        // can be used equally well for live battery data in real time or to process recorded battery data
        //
        public bool bValuateBatteryData(strctBattMonData stRecentBattData, int ciIterationNo)
        {
            bool bRes=false;
            stDischrgChrgCycle stdschrgNewCycle=default(stDischrgChrgCycle); // neends init such as in DateTime dteSrc = default(DateTime),
            TimeSpan tmspnStarterMotorRun;
            //			Debug.WriteLine("++bValuateBatteryData("+ciIterationNo+")");

            // compute average current and keep it to eliminate noise in current sensor line
            if(m_iCurrentAvrgIdx<m_ciCurrAvrgCount)
            {
                m_dblTempCurrent+=stRecentBattData.dblBatAmperes;
                m_iCurrentAvrgIdx+=1;
            }
            else
            {
                m_dblAvrgCurrent100Smpls=m_dblTempCurrent / (double)m_ciCurrAvrgCount;
                m_iCurrentAvrgIdx=0;
                m_dblTempCurrent=0.0;
            };

            // on the very first iteration save this as beginning of recording
            if(0==ciIterationNo)
            {
                stbtdtmTempFirstRecord=stRecentBattData;
                if(null==m_arriTimesBetwItersHistogr)
                {
                    m_arriTimesBetwItersHistogr=new int [ciMaxHistoSize];
                };
            // erase histogram as well
                Array.Clear(m_arriTimesBetwItersHistogr,0,ciMaxHistoSize);
            }
            else
            {
            // next we check for Microcontroller errors.
                TimeSpan tmspnBetwnIters=stRecentBattData.dtBattDateTime - stcBattPrevData.dtBattDateTime;
            // Timer tick may be reported by microcontroller as inaccurate time, including jumping backawards
                if(tmspnBetwnIters.TotalSeconds < 0.0)

            // ignore very first inetration, since previous date-time is invalid
            //				if(tmspnBetwnIters.Days < 0)
                {
                    Debug.WriteLine("bValuateBatteryData(ERROR) time jumped backwards! Previous=" + stcBattPrevData.dtBattDateTime.ToString("HH:mm:ss.fff") + " > New=" + stRecentBattData.dtBattDateTime.ToString("HH:mm:ss.fff"));
            // fix up error - use last known good date-time
                    stRecentBattData.dtBattDateTime=stcBattPrevData.dtBattDateTime;
                }
                else
                {
            // for good iteration, save data to histogram
            //					Debug.WriteLine("bValuateBatteryData() Curr-Prev duration " + tmspnBetwnIters.Days.ToString() + "."+ tmspnBetwnIters.Hours.ToString("0#") +":"+ tmspnBetwnIters.Minutes.ToString("0#")+":"+tmspnBetwnIters.Seconds.ToString("0#.")+"."+tmspnBetwnIters.Milliseconds.ToString("000"));
                    int iIntervBetwIters=(int)tmspnBetwnIters.TotalMilliseconds;
                    if(iIntervBetwIters < ciMaxHistoSize)
                    {
                        m_arriTimesBetwItersHistogr[iIntervBetwIters]+=1;
                    };
            // for every 1000 iterations, print a histoghram
                    if(0==ciIterationNo%999)
                    {
                        for(int j=0; j<ciMaxHistoSize; j++)
                        {
                            Debug.WriteLine("["+j.ToString()+"] : " + m_arriTimesBetwItersHistogr[j].ToString());
                        };
                    };
                }; // end IF tmspnBetwnIters.TotalSeconds >0
            }; // end IF check for Microcontroller errors.

            // here we observe a few parameters including min and max of voltage and current
            // as well as watch for engine starting pattern : starter mtr OFF, ON, OFF sequence

            // criteria - low discharge current for several seconds - key on ignition on
            // 	then high discharge current for a second or two - starter on
            // then dischanrge current changes to charge current
            // then battery gets strong charging which should quckly deacrease within 15 seconds if battery is healthy

            //======================================================================
            //        -80A       -40A       -2A  -0.1A     0A    +0.1A   +2A  +100A
            // str mtr |         discharging      |    no load    |    charging
            //                                { --->-------->-------->----}   current crosses zero amperes line
            //======================================================================

            //-------------------------------------------------------------------------------------------
            // BATTERY STRONG DISCHARGE. batt current <-80A
            //--------------------------------------------------------------------------------------------
            if(stRecentBattData.dblBatAmperes<-80.0) // starter surely draws more than that
            {
            //check if microcontroller correctly specified battery state
                if(stRecentBattData.chBattState!='D')
                {
                    Debug.WriteLine("bValuateBatteryData() ERR battery state mismatch - D");
                };

            // watch for maximum current starter draws - in-rush starter motor current
                if(stRecentBattData.dblBatAmperes<m_sdblMaxBattDischrgCurrent)
                {
                    m_sdblMaxBattDischrgCurrent=stRecentBattData.dblBatAmperes;
                }
                else
                {
            //					Debug.WriteLine("bValuateBatteryData() Max discharging current=" + sdblMaxBattDischrgCurrent.ToString("+#.#;-#.#;0"));
                };

                if(true==m_bStarterMotorIsOn)
                {
            // starter motor keeps running...
                    Debug.WriteLine("bValuateBatteryData() starter mtr is RUNNING");
                }
                else
                {
            // starter motor just started
                    Debug.WriteLine("bValuateBatteryData() starter mtr is now ON !");
                    m_bStarterMotorIsOn=true;
                    stcBattDatStarterOn=stRecentBattData;
                    stcBattDatStarterOff=stcBattPrevData;
            // create new discharge-charge cycle
                    stdschrgNewCycle.bIsCycleComplete=false;
                    stdschrgNewCycle.bIsFullyRecharged=false;
                    stdschrgNewCycle.dblMaxChrgCurrent=-99.0;
                    stdschrgNewCycle.dblMaxDischrgCurrent=m_sdblMaxBattDischrgCurrent;
                    stdschrgNewCycle.stbtdtmStarterOn=stRecentBattData;
                    stdschrgNewCycle.stbtdtmFirstRecord=stbtdtmTempFirstRecord;

                    if(null!=m_mapDischrgChrgCyles)
                    {
            // you can use .Add function to ass new starter motor event data
                        try
                        {
                            m_mapDischrgChrgCyles.Add(stdschrgNewCycle.stbtdtmStarterOn.dtBattDateTime, stdschrgNewCycle);
                        }
                        catch (ArgumentException aexc)
                        {
                            Debug.WriteLine("bValuateBatteryData() battery already has this dis-chrg cycle on record, skip." + aexc.ToString());
                        };
            // also can use array notation
            //						m_mapDischrgChrgCyles[stdschrgNewCycle.stbtdtmStarterOn.dtBattDateTime]=stdschrgNewCycle;
                    }; // end IF m_mapDischrgChrgCyles is not Null

                }; // end IF true==m_bStarterMotorIsOn
            }
            // strong discharge case
            //-------------------------------------------------------------------------------------------
            // BATTERY DISCHARGE -80A < batt current < -2A
            //--------------------------------------------------------------------------------------------
            else if(stRecentBattData.dblBatAmperes>=-80.0 && stRecentBattData.dblBatAmperes<-2.0)
            {
            //				Debug.WriteLine("bValuateBatteryData() battery discharging");
            //check if microcontroller correctly specified battery state
                if(stRecentBattData.chBattState!='D')
                {
                    Debug.WriteLine("bValuateBatteryData() ERR battery state mismatch - D");
                };
            // when discharge current is not that big, i.e. not a starter mtr case
            // battery discharging case
            //-------------------------------------------------------------------------------------------
            // BATTERY DISCHARGE -40A < batt current <-0.2A
            //--------------------------------------------------------------------------------------------
                if(true==m_bStarterMotorIsOn && stRecentBattData.dblBatAmperes>-40.0 && stRecentBattData.dblBatAmperes<-0.2)
                {
                    Debug.WriteLine("bValuateBatteryData() starter mtr now OFF.");
            // starter motor not running now
                    m_bStarterMotorIsOn=false;
                    stcBattDatStarterOffAfterOn=stRecentBattData;
                    stcBattDatCurrentCrossZero=stRecentBattData;
                    tmspnStarterMotorRun=stcBattDatStarterOffAfterOn.dtBattDateTime - stcBattDatStarterOn.dtBattDateTime;
            // uncommenting line below causes exception in line reader
                    Debug.WriteLine("bValuateBatteryData() starter mtr duration="+tmspnStarterMotorRun.Seconds.ToString() +"."+tmspnStarterMotorRun.Milliseconds.ToString("000") + " sec");

            // compute charge released for engine starting
                    double dblTempmQ=(stcBattDatStarterOffAfterOn.liQOut-stcBattDatStarterOn.liQOut);

                    Debug.WriteLine("bValuateBatteryData() Battery released " + (dblTempmQ/1000).ToString() +  " Q to start engine");

                    if((stcBattDatStarterOff.dblBatAmperes-stcBattDatStarterOn.dblBatAmperes)!=0.0)
                    {
            // compute battery internal resistance and related parameters
                        m_dblBatteryResistance=(stcBattDatStarterOff.dblBatVolts-stcBattDatStarterOn.dblBatVolts)/
                                    (stcBattDatStarterOff.dblBatAmperes-stcBattDatStarterOn.dblBatAmperes);
                        Debug.WriteLine("bValuateBatteryData() batt R="+m_dblBatteryResistance.ToString("0.#000")+ " Ohm");
            // estimate cranking amperes based on voltage-current

            // Hot cranking amperes (HCA) is the amount of current a battery can provide at 80°F (26.7°C).
            //	The rating is defined as the current a lead-acid battery at that temperature can deliver for 30 seconds and maintain at least 1.2 V/cell (7.2 volts for a 12-volt battery).
            // Cranking amperes (CA), also sometimes referred to as marine cranking amperes (MCA), is the amount of current a battery can provide at 32°F (0°C).
            //	The rating is defined as the number of amperes a lead-acid battery at that temperature can deliver for 30 seconds and maintain at least 1.2 V/cell (7.2 volts for a 12 volt battery).
            // Cold cranking amperes (CCA) is the amount of current a battery can provide at 0°F (−18°C).
            //	The rating is defined as the current a lead-acid battery at that temperature can deliver for 30 seconds and maintain at least 1.2 volts per cell (7.2 volts for a 12-volt battery)

                        if(m_dblBatteryResistance!=0.0)
                        {
            // example
            // key on 12.1V,-6.4A; starter on 10.7V, -104A; R=(12.1-10.7)/(104-6)=1.4V/97.6A=0.014 Ohm
            // knowing R predict CA by computation CA=(12.1-7.2)/R
                            m_dblCA=(stcBattDatStarterOff.dblBatVolts-7.2)/m_dblBatteryResistance;
                            Debug.WriteLine("bValuateBatteryData() batt CA="+m_dblCA.ToString("0000")+" Amperes");
                        };
            //
            // determine whether it was actual engine starting cyle or maybe just a momentary drop in battry current
            //
            // decision made is based on high discharge currnet value and duration of it
            // Must draw high discharge current for at least 0.5 sec to qualify as engine starting event
            // AND battery should be discharging : state=D and voltage should be < 12.6 Volts
                        if(tmspnStarterMotorRun.Seconds>=1 ||
                                (tmspnStarterMotorRun.Seconds==0 && tmspnStarterMotorRun.Milliseconds>500) )
                        {
                            m_iEngineStartEvtCnt+=1;
            // modify last incomplete discharge-charge cycle and update its data
                            Debug.WriteLine("bValuateBatteryData() valid cycle duration " + tmspnStarterMotorRun.Seconds.ToString() +"."+tmspnStarterMotorRun.Milliseconds.ToString("000") + " sec detected. Completing dischrg-chrg cycle....");
            // find our dis-chrg cycle in array and modify it to store starter off data
                            stDischrgChrgCycle stdschrgCycleInWorks=m_mapDischrgChrgCyles[stcBattDatStarterOn.dtBattDateTime];
            // if found, modify data in place
            //
            // we have now stdschrgCycleInWorks.stbtdtmStarterOn part filled only.
            // now populate stdschrgCycleInWorks.stbtdtmStarterOffAfterOn and other members
            //
                            stdschrgCycleInWorks.bIsCycleComplete=true;
                            stdschrgCycleInWorks.dblMaxChrgCurrent=-99.0;
                            stdschrgCycleInWorks.dblBatteryResistance=m_dblBatteryResistance;
                            stdschrgCycleInWorks.dblCA=m_dblCA;
                            stdschrgCycleInWorks.dblMaxDischrgCurrent=m_sdblMaxBattDischrgCurrent;
                            stdschrgCycleInWorks.stbtdtmStarterOffAfterOn=stRecentBattData;
                            stdschrgCycleInWorks.tmspnStrMotorRunDur=tmspnStarterMotorRun;
                            stdschrgCycleInWorks.dblCoulmbsToStartEngine=dblTempmQ/1000.0;
            // save it into array
                            m_mapDischrgChrgCyles[stcBattDatStarterOn.dtBattDateTime]=stdschrgCycleInWorks;
                        }
                        else
                        {
            // not a engine starting cycle! Just very short current drop, e.g. downspike
                            Debug.WriteLine("bValuateBatteryData() Cycle duration too short: " + tmspnStarterMotorRun.Seconds.ToString() +"."+tmspnStarterMotorRun.Milliseconds.ToString("000") + " sec.");
                            Debug.WriteLine("bValuateBatteryData() Not a starter mtr cycle. Removing incomplete dischrg-chrg cycle....");
            // so we delete previous spurious dischr-chrg cycle from our list
                            m_mapDischrgChrgCyles.Remove(stcBattDatStarterOn.dtBattDateTime);
                        };

                    }; // end IF of (stcBattDatStarterOff.dblBatAmperes-stcBattDatStarterOn.dblBatAmperes) !=0 Amp

            // store time of this moment and watch for 15 minutes from it - battery should quckly charge, charge current decrease
                }; // end IF of true==m_bStarterMotorIsOn
            }
            //
            // when battery current current crosses zero Ampreres line
            // this includes NO LOAD case as well - see inner check
            else if(stRecentBattData.dblBatAmperes>=-2.0 && stRecentBattData.dblBatAmperes<=+2.0)
            {
            //-------------------------------------------------------------------------------------------
            // BATTERY NO LOAD -0.1A < batt current <+0.1A
            //--------------------------------------------------------------------------------------------
                if(stRecentBattData.dblBatAmperes>=-0.1 && stRecentBattData.dblBatAmperes<=+0.1)
                {
            //					Debug.WriteLine("bValuateBatteryData() batt no load");
            // may update SoC bars for NL case here
            //check if microcontroller correctly specified battery state
                    if(stRecentBattData.chBattState!='I')
                    {
                        Debug.WriteLine("bValuateBatteryData() ERR battery state mismatch - NL");
                    };
                };
            //
            // check to determine if we are coming here just after engine starting cycle
            // - to find out, we determine if an element is present with date-time of starter motor was switched on
                bool bHasStarterOnElem=m_mapDischrgChrgCyles.ContainsKey(stcBattDatStarterOn.dtBattDateTime);

                if(true==bHasStarterOnElem)
                {
            // if we have at least one engine starter cycle, then we count form the last engine starter cycle - error happens here -- !
                stDischrgChrgCycle stdschrgCycleInWorks=m_mapDischrgChrgCyles[stcBattDatStarterOn.dtBattDateTime];

            // and if average battery current is around zero, then we compute battery A*Hrs capacity based on charge accepted
            // from the moment charging started (starter off) till now
                    if(m_iEngineStartEvtCnt>0 && Math.Abs(m_dblAvrgCurrent100Smpls)<1.2 && false==stdschrgCycleInWorks.bIsFullyRecharged)
                    {
                        long liBatteryChargeAccepted=(stRecentBattData.liQIn-stcBattDatCurrentCrossZero.liQIn)/1000;
                        Debug.WriteLine("bValuateBatteryData() Battery is fully charged. Q in ="+liBatteryChargeAccepted.ToString()+" Q");
                        Debug.WriteLine("bValuateBatteryData() Battery capacity est. "+((double)liBatteryChargeAccepted/3600.0).ToString("#0.0")+" A*Hrs");
            //						workerObject.bLogDataToFile("Battery fully charged (based on ~0A average battery current");
                        stdschrgCycleInWorks.bIsFullyRecharged=true;
            // save time stamp when battery fully charged
                        stdschrgCycleInWorks.stbtdtmWhenFullyCharged=stRecentBattData;
            // find last discharge-charge cycle we used
                        m_mapDischrgChrgCyles[stcBattDatStarterOn.dtBattDateTime]=stdschrgCycleInWorks;
            // update last discharge-charge cycle with new data
                    }; // end IF true==bHasStarterOnEle
                }
                else
                {
                    Debug.WriteLine("bValuateBatteryData() Cannot determine if Battery is fully charged, because starter ON event was not found "+stcBattDatStarterOn.dtBattDateTime.ToString("dd.HH:mm:ss.fff"));
                };
            }
            // battery is now charging
            //-------------------------------------------------------------------------------------------
            // BATTERY CHARGING batt current > +0.2A
            //--------------------------------------------------------------------------------------------
            else if(stRecentBattData.dblBatAmperes>+0.2)
            {
            //				Debug.WriteLine("bValuateBatteryData() battery charging");

                if(stRecentBattData.chBattState!='C')
                {
                    Debug.WriteLine("bValuateBatteryData() ERR battery state mismatch - C");
                };
            // watch for maximum charging current
                if(stRecentBattData.dblBatAmperes>m_sdblMaxBattChrgCurrent)
                {
                    m_sdblMaxBattChrgCurrent=stRecentBattData.dblBatAmperes;
                    stcBattDatMaxChargCurr=stRecentBattData;
                }
                else
                {
            // once we get here the first time then battery charging current starts to drop,
            // so note max charging current
            //					Debug.WriteLine("bValuateBatteryData() Max charging current=" + sdblMaxBattChrgCurrent.ToString("+#.#;-#.#;0"));
                };
            }
            else
            {
            // tbd
                Debug.WriteLine("bValuateBatteryData() TBD case");
            };
            // just store momentary data for the next run
            stcBattPrevData=stRecentBattData;

            //			Debug.WriteLine("--bValuateBatteryData()="+bRes.ToString());
            return bRes;
        }