Main Site Documentation

Please help with CURRENT SENSOR BASE CLASS!


#1

I am trying to parse the CURRENT SENSOR BASE CLASS with other CURRENT SENSOR code parts provided by MarkH at http://code.tinyclr.com/tag/current/

I am using VSE2010 with FEZ Domino.

VS gives me an error for “SensorMode” class/namespace that is referenced to in these lines:


  private SensorMode sensorReadMode;
        public SensorMode SensorReadMode
        {
            get { return sensorReadMode; }
            set
            {
                if (sensorReadMode == value)
                    return;
 
                sensorReadMode = value;
 
                switch (value)
                {
                    case SensorMode.FastestRead:
                        UseAveraging = false;
                        UseFiltering = false;
                        UseMovingAverage = false;
                        break;
                    case SensorMode.MostAccurate:
                        UseAveraging = true;
                        UseFiltering = true;
                        UseMovingAverage = true;
                        AverageSampleCount = 10;
                        MovingAverageSize = 5;
                        break;
                    case SensorMode.BestTradeoff:
                        UseAveraging = true;
                        UseFiltering = false;
                        UseMovingAverage = false;
                        AverageSampleCount = 5;
                        break;
                    case SensorMode.Custom:
                    default:
                        break;
                }
            }
        }

Thank you in advance!


#2

Ah, i think it’s missing this:


    /// <summary>
    /// Settings for running the sensor
    /// </summary>
    public enum SensorMode
    {
        /// <summary>
        /// Define your own settings using the properties on the class
        /// </summary>
        Custom,
        /// <summary>
        /// Read the sensor value out as fast as possible. No filtering or averaging will be done.
        /// </summary>
        FastestRead,
        /// <summary>
        /// Read the sensor as accurately as possible. All filtering and averaging will be done - if required.
        /// </summary>
        MostAccurate,
        /// <summary>
        /// The the accurately, but also try to do it quickly. This is best for most uses.
        /// </summary>
        BestTradeoff
    }

Sorry about that :slight_smile:


#3

Looks like that enum is missing.

You can defined it yourself it is just an enum.


#4

Thank you Mark,
you better update your code there…


#5

Mark,
I got stuck with the snippet of code for printing out the current reading (I modified the class name for my current sensor model, but all of your code stays the same):


  using (ICurrentSensor sensor = new ACS758KCB_150B((Cpu.Pin)AnalogIn.Pin.Ain15, (CurrentSensorBase.SensorMode)CurrentSensorBase.SensorMode.MostAccurate))
                {

                    while (true)
                    {
                        Debug.Print("Amps: " + sensor.GetCurrent() + "A");
                        Thread.Sleep(1000);
                    }
                }

The VS2010 gives me an error:
“Sensors.ICCurrent.CurrentSensorBase” does not implement the member of interface “Sensors.ICCurrent.ICurrentSensor.GetCurrentInAmps()”

Here is the full code the way I put in all the cutouts you shared in three separate pages at code.tinyclr.com:


public static void CurrentSensor_Thread()
            {
                using (ICurrentSensor sensor = new ACS758KCB_150B((Cpu.Pin)AnalogIn.Pin.Ain15, (CurrentSensorBase.SensorMode)CurrentSensorBase.SensorMode.MostAccurate))
                {

                    while (true)
                    {
                        currentNow = sensor.GetCurrent();
                        Debug.Print("Amps: " + sensor.GetCurrent() + "A");
                        Thread.Sleep(1000);
                    }
                }
            }


//           Ascended International
//
//             Copyright (c) 2010
//
//            All Rights Reserved
// ------------------------------------------------------------------------------
//    * DO NOT REMOVE THIS HEADER. DO NOT MODIFY THIS HEADER *
/**********************************************************************************
 * You may use this class for non-commerical purposes. If you wish to use this    *
 * software for a commercial pupose please contact Ascended International at:     *
 * mark@ ascended.com.au                                                           *
 *                                                                                *
 * When using this free class, no warranty express or implied is offered.         *
 * In no event shall Ascended International, any of it's employees or shareholds  *
 * be held liable for any direct, indirect, special, exemplary, incidental or     *
 * consequential damages however caused.                                          *
 *                                                                                *
 * If you modify this class, please add your name and the date below as a         *
 * contributor, without removing this notice or modifying it in any way, shape    *
 * or form.                                                                       *
 **********************************************************************************/

using System;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.Hardware;
using GHIElectronics.NETMF.System;


namespace Sensors.ICCurrent
{
    public class ACS758KCB_150B : CurrentSensorBase
    {
        /// <summary>
        /// Create a new base instance of the current sensor.
        /// </summary>
        /// <param name="pin">Pin the sensor's vout is connected to.</param>
        public ACS758KCB_150B(Cpu.Pin pin)
            : base(pin)
        {
            MaximumCurrentCapability = 150;
            MinimumCurrentCapability = -150;
        }
        public ACS758KCB_150B(Cpu.Pin pin, SensorMode mode)
            : base(pin, mode)
        {
            MaximumCurrentCapability = 150;
            MinimumCurrentCapability = -150;
        }

        protected override double ReadSensorValue()
        {
            double x = sensor.Read() - 2527;

            return x / 185;
        }
    }

    public interface ICurrentSensor : IDisposable
    {
        double GetCurrentInAmps();

        bool UseMovingAverage { get; set; }
        int MovingAverageSize { get; set; }

        bool UseAveraging { get; set; }
        int AverageSampleCount { get; set; }

        bool UseFiltering { get; set; }

        float MaximumCurrentCapability { get; }
        float MinimumCurrentCapability { get; }

        CurrentSensorBase.SensorMode SensorReadMode { get; set; }
    }

    public abstract class CurrentSensorBase : ICurrentSensor
    {
        protected AnalogIn sensor;

        protected double[] movingValues;
        int movingPos;

        double[] data;
        double[] values;

        /// <summary>
        /// This should not be used as there is no way to set the pin your sensor is on. This is here for inheritance.
        /// </summary>
        public CurrentSensorBase()
        {

        }

        /// <summary>
        /// Create a new base instance of the current sensor.
        /// </summary>
        /// <param name="pin">Pin the sensor's vout is connected to.</param>
        public CurrentSensorBase(Cpu.Pin pin)
        {
            Initialize(pin);

            SetDefaults();
        }

        /// <summary>
        /// Settings for running the sensor
        /// </summary>
        public enum SensorMode
        {
            /// <summary>
            /// Define your own settings using the properties on the class
            /// </summary>
            Custom,
            /// <summary>
            /// Read the sensor value out as fast as possible. No filtering or averaging will be done.
            /// </summary>
            FastestRead,
            /// <summary>
            /// Read the sensor as accurately as possible. All filtering and averaging will be done - if required.
            /// </summary>
            MostAccurate,
            /// <summary>
            /// The the accurately, but also try to do it quickly. This is best for most uses.
            /// </summary>
            BestTradeoff
        }
 
        public CurrentSensorBase(Cpu.Pin pin, SensorMode mode)
        {
            Initialize(pin);

            SensorReadMode = mode;
            if (mode == SensorMode.Custom)
            {
                SetDefaults();
            }
        }

        internal void SetDefaults()
        {
            UseMovingAverage = false;
            MovingAverageSize = 5;

            UseAveraging = true;
            AverageSampleCount = 10;

            movingValues = new double[MovingAverageSize];
            FillMovingAverageValues();
        }

        internal void Initialize(Cpu.Pin pin)
        {
            sensor = new AnalogIn((AnalogIn.Pin)pin);
            sensor.SetLinearScale(0, 3300);
        }

        /// <summary>
        /// Returns the current in amps and will apply any filtering or averaging before returning the value.
        /// </summary>
        /// <returns>The current the sensor is reading in Amps.</returns>
        public double GetCurrent()
        {
            double amps = 0;

            if (UseAveraging)
            {
                data = new double[AverageSampleCount];

                double min = Double.MaxValue;
                double max = Double.MinValue;

                for (int i = 0; i < AverageSampleCount; i++)
                {
                    double val = ReadSensorValue();
                    data[i] = val;
                    amps += val;

                    if (UseFiltering)
                    {
                        if (min > val)
                            min = val;

                        if (max < val)
                            max = val;
                    }
                }

                amps = amps / AverageSampleCount; // faster than /=

                if (UseFiltering)
                {
                    // do we need to do cleanup through deviation?
                    if (!(max == min || max - min < 1))
                    {
                        // trim down the data
                        double stdDev = StandardDeviation(data, amps);

                        // Standard Dev is too high for our liking!
                        if (stdDev > 0.5)
                        {
                            int candidates = 0;

                            values = new double[AverageSampleCount];

                            for (int i = 0; i < AverageSampleCount; i++)
                            {
                                double dat = data[i];
                                if (dat < amps + stdDev && dat > amps - stdDev)
                                    values[candidates++] = dat;
                            }

                            amps = Average(values, candidates - 1);
                        }
                    }
                }
            }
            else
            {
                amps = ReadSensorValue();
            }

            if (UseMovingAverage)
            {
                AddMovingAverage(amps);
                return Average(movingValues);
            }

            return amps;
        }

        protected abstract double ReadSensorValue();

        static double StandardDeviation(double[] data, double avg)
        {
            //double avg = 0;
            double totalVariance = 0;
            int max = data.Length;

            if (max == 0)
                return 0;

            // get variance
            for (int i = 0; i < max; i++)
            {
                double variance = data[i] - avg;
                totalVariance = totalVariance + (variance * variance);
            }

            return MathEx.Sqrt(totalVariance / max);
        }

        static double Average(double[] data)
        {
            return Average(data, data.Length);
        }

        static double Average(double[] data, int count)
        {
            double avg = 0;

            for (int i = 0; i < count; i++)
                avg += data[i];

            if (avg == 0 || count == 0)
                return 0;

            return avg / count;
        }

        void AddMovingAverage(double nextValue)
        {
            movingValues[movingPos++] = nextValue;

            if (movingPos >= movingValues.Length)
                movingPos = 0;
        }

        protected void FillMovingAverageValues()
        {
            for (int i = 0; i < movingAverageSize; i++)
            {
                AddMovingAverage(ReadSensorValue());
            }
        }

        private SensorMode sensorReadMode;
        public SensorMode SensorReadMode
        {
            get { return sensorReadMode; }
            set
            {
                if (sensorReadMode == value)
                    return;

                sensorReadMode = value;

                switch (value)
                {
                    case SensorMode.FastestRead:
                        UseAveraging = false;
                        UseFiltering = false;
                        UseMovingAverage = false;
                        break;
                    case SensorMode.MostAccurate:
                        UseAveraging = true;
                        UseFiltering = true;
                        UseMovingAverage = true;
                        AverageSampleCount = 10;
                        MovingAverageSize = 5;
                        break;
                    case SensorMode.BestTradeoff:
                        UseAveraging = true;
                        UseFiltering = false;
                        UseMovingAverage = false;
                        AverageSampleCount = 5;
                        break;
                    case SensorMode.Custom:
                    default:
                        break;
                }
            }
        }

        bool useMovingAverage;
        /// <summary>
        /// Controls whether the system uses moving averages to smooth out values.
        /// This should be True if you have a high speed update, or are movement is slow.
        /// This should be False if you are moving fast or have a slow update rate.
        /// Moving averages introduce some lag into the system, therefore it's only useful with high update speeds or slow movements.
        /// The moving average can take out spikes and other crazy phenomenon efficiently.
        /// </summary>
        public bool UseMovingAverage
        {
            get { return useMovingAverage; }
            set
            {
                if (useMovingAverage == value)
                    return;

                useMovingAverage = value;

                if (useMovingAverage == true)
                {
                    movingValues = new double[movingAverageSize];
                    movingPos = 0;

                    FillMovingAverageValues();
                }
            }
        }

        int movingAverageSize;
        /// <summary>
        /// Gets/Sets the size of the moving average set. If the set is too large, there will be considerable lag. If the set is too small, it will be inefficient.
        /// </summary>
        public int MovingAverageSize
        {
            get { return movingAverageSize; }
            set
            {
                if (movingAverageSize == value)
                    return;

                movingAverageSize = value;

                movingValues = new double[movingAverageSize];
                movingPos = 0;

                FillMovingAverageValues();
            }
        }

        private bool useFiltering;
        /// <summary>
        /// Gets/Sets whether standard deviation filtering should be used. This only works with UseAveraging turned on. 
        /// If values read have too wide of a range, anything beyond one standard deviation will be culled and ignored.
        /// If you have high speed movement, this will get a good workout and may not be of any benefit.
        /// If you have slow movement with a lot of 'noise' this will clean it up considerably.
        /// </summary>
        public bool UseFiltering
        {
            get { return useFiltering; }
            set
            {
                if (value && !UseAveraging)
                    throw new NotSupportedException("You cannot use filtering without averaging!");

                useFiltering = value;
            }
        }

        /// <summary>
        /// When using averaging, the sensor will take <c>AverageSampleCount</c> samples and then average them to remove some fluctuations.
        /// This works very well at all times and should be left on, vary the sample count based on the speed of code you require, and the speed you move at.
        /// </summary>
        public bool UseAveraging { get; set; }
        /// <summary>
        /// Gets/sets the number of samples to take for averaging.
        /// </summary>
        public int AverageSampleCount { get; set; }

        #region IDisposable Members

        public void Dispose()
        {
            sensor.Dispose();
        }

        #endregion

        /// <summary>
        /// The maximum Current (in amps) that the senor can sense.
        /// </summary>
        public float MaximumCurrentCapability { get; protected set; }

        /// <summary>
        /// The minimum current (in amps) that the sensor can sense.
        /// </summary>
        public float MinimumCurrentCapability { get; protected set; }
    }

   
}



#6

Add this to the CurrentSensorBase class:


        public double GetCurrentInAmps()
        {
                // implementation goes here or throw a NotImplementedException
        }

I suggest you try using Resharper plugin to Visual Studio. It will make your life a lot easier :slight_smile:

http://www.jetbrains.com/resharper/


#7

I am completely lost there. Where do you want me to insert the

 public double GetCurrentInAmps()
        {
                // implementation goes here or throw a NotImplementedException
        }

#8

Add it to your:


public abstract class CurrentSensorBase : ICurrentSensor
{
    ...
    public double GetCurrentInAmps()
    {
                // implementation goes here or throw a NotImplementedException
    }
    ...    
}


#9

What goes in there then? I feel really stupid these days.

 // implementation goes here or throw a NotImplementedException
  

#10

Nothing. Unless you want to use that method. You are putting a stub to “complete” the interface.


#11

MarkH,
can you please revise your code and repost it? It does not work the way you presented it.