예제 #1
0
// don't give out entire dictionary - it is protected element
        public stDischrgChrgCycle dctGetBatChrgCycl(DateTime dtmFindBy)
        {
            stDischrgChrgCycle stdsccrgTempCycle = default(stDischrgChrgCycle);
            bool bKeyFound = false;

            Debug.WriteLine("++dctGetBatChrgCycl(key=)");

            try
            {
                bKeyFound = m_mapDischrgChrgCyles.ContainsKey(dtmFindBy);

                if (true == bKeyFound)
                {
// dictionary has this key, so retrieve entire element
                    stdsccrgTempCycle = m_mapDischrgChrgCyles[dtmFindBy];
                }
                ;
            }
            catch (ArgumentNullException excnotIn)
            {
                Debug.WriteLine("dctGetBatChrgCycl() key not found! " + excnotIn.ToString());
            };

            Debug.WriteLine("--dctGetBatChrgCycl(key=)");
            return(stdsccrgTempCycle);
        }
예제 #2
0
        public stDischrgChrgCycle dctGetBatChrgCyclByIdx(int Index)
        {
            stDischrgChrgCycle stdsccrgTempCycle = default(stDischrgChrgCycle);

            if (Index < m_mapDischrgChrgCyles.Count)
            {
                stdsccrgTempCycle = m_mapDischrgChrgCyles.ElementAt(Index).Value;
            }
            ;
            return(stdsccrgTempCycle);
        }
예제 #3
0
        public static AutomotiveBattery bDeserBattCls()
        {
            AutomotiveBattery abtClassFromStorage = null;

            Debug.WriteLine("++bDeserBattCls()");

            IFormatter formatter = new BinaryFormatter();

            try
            {
                Stream streamFrom = new FileStream(AutomotiveBattery.cstrMyBattClassFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
                abtClassFromStorage = (AutomotiveBattery)formatter.Deserialize(streamFrom);
                streamFrom.Close();
                int jcnt = abtClassFromStorage.m_mapDischrgChrgCyles.Count;
                Debug.WriteLine("bSerBattCls() Also restored " + jcnt.ToString() + " discharge-charge cycles");
                for (int k = 0; k < jcnt; k++)
                {
// element at retrievs a pair, not just an element
                    stDischrgChrgCycle stdchrgclTemp = abtClassFromStorage.m_mapDischrgChrgCyles.ElementAt(k).Value;
                    Debug.WriteLine("bSerBattCls() [" + k.ToString() + "] " + stdchrgclTemp.stbtdtmStarterOn.dtBattDateTime.ToString() +
                                    " CA=" + stdchrgclTemp.dblCA.ToString("000") + " A, R=" + stdchrgclTemp.dblBatteryResistance.ToString("0.0000") + " Ohm at " + stdchrgclTemp.stbtdtmStarterOn.dblBattTemp.ToString("+00.0") + "°C");
                }
                ;
            }
            catch (SerializationException serexp)
            {
                Debug.WriteLine("Form1() ctor: Failed to find saved instance of myAutoBattery." + serexp.ToString());
            }
            catch (IOException ioexp)
            {
                Debug.WriteLine("Form1() ctor: Failed to find saved instance of myAutoBattery." + ioexp.ToString());
            };

            Debug.WriteLine("--bDeserBattCls()=" + ((null == abtClassFromStorage)?"null":abtClassFromStorage.ToString()));
            return(abtClassFromStorage);
        }
예제 #4
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()