Shop OBEX P1 Docs P2 Docs Learn Events
double data types, floating point math, and the Propeller — Parallax Forums

double data types, floating point math, and the Propeller

idbruceidbruce Posts: 6,197
edited 2012-10-17 14:27 in Propeller 1
Hello Everyone

I have two files of source code that I would like to modify to work with the Propeller chip, however these files include double data types and floating point math. I am wondering if my goal is attainable, before doing a vast amount of research to find out that it cannot be done. I have included the source code of one file that I want to modify.

Bruce
//           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:     *
 * [EMAIL="mark@ascended.com.au"]mark@ascended.com.au[/EMAIL]                                                           *
 *                                                                                *
 * 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.                                                                       *
 **********************************************************************************/
/*
 Contributors:
 * 16 Sep 2010, Mark Harris - Initial code, maths and development [ [EMAIL="markh@rris.com.au"]markh@rris.com.au[/EMAIL] ]
 * 17 Sep 2010, Mark Harris - increased accuracy of 4th order poly by 6 decimal places
 * 26 Sep 2010, Mark Harris - Rewrote poly functions to get accuracty within 1mm
 */
using System;
using Microsoft.SPOT;
using GHIElectronics.NETMF.Hardware;
using GHIElectronics.NETMF.System;
using Microsoft.SPOT.Hardware;
namespace Ascended.SPOT.Sensors.Distance
{
    /// <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
    }
    
    /// <summary>
    /// Driver for Sharp 2D120X (Infrared Proximity Sensor Short Range - Sharp GP2D120XJ00F).
    /// Sparkfun SKU: sku: SEN-08959
    /// TinyCLR SKU: GP2D120
    /// 
    /// Class written by Mark Harris, [email]mark@ascended.com.au/markh@rris.com.au[/email]
    /// </summary>
    public class Sharp2D120X
    {
        protected AnalogIn sensor;
        protected double[] movingValues;
        int movingPos;
        double[] data;
        double[] values;
        /// <summary>
        /// Create a new instance of Sharp2D120X. You should sleep for *at least* 50ms after instantiating this class.
        /// The sensor does not produce accurate results for at least this time.
        /// </summary>
        /// <param name="pin">Pin the sensor's vout is connected to.</param>
        public Sharp2D120X(Cpu.Pin pin)
        {
            Initialise(pin);
            SetDefaults();
            MinimumDistanceCapability = 4.75f;
            MaximumDistanceCapability = 26;
        }
        /// <summary>
        /// Create a new instance of Sharp2D120X. You should sleep for *at least* 50ms after instantiating this class.
        /// The sensor does not produce accurate results for at least this time.
        /// </summary>
        /// <param name="pin">Pin the sensor's vout is connected to.</param>
        /// <param name="mode">Set the sensor read mode defaults</param>
        public Sharp2D120X(Cpu.Pin pin, SensorMode mode)
        {
            // initialise the senor
            Initialise(pin);
            SensorReadMode = mode;
            if (mode == SensorMode.Custom)
            {
                SetDefaults();
            }
            MinimumDistanceCapability = 4.75f;
            MaximumDistanceCapability = 26;
        }
        internal void SetDefaults()
        {
            UseMovingAverage = false;
            MovingAverageSize = 5;
            UseAveraging = true;
            AverageSampleCount = 10;
            movingValues = new double[MovingAverageSize];
            FillMovingAverageValues();
        }
        internal void Initialise(Cpu.Pin pin)
        {
            sensor = new AnalogIn((AnalogIn.Pin)pin);
            sensor.SetLinearScale(0, 3300);
        }
        /// <summary>
        /// Returns the distance in centimetres and will apply any filtering or averaging before returning the value.
        /// </summary>
        /// <returns>The distance the sensor is reading in CM.</returns>
        public double GetDistanceInCM()
        {
            double distance = 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;
                    distance += val;
                    if (UseFiltering)
                    {
                        if (min > val)
                            min = val;
                        if (max < val)
                            max = val;
                    }
                }
                distance = distance / 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, distance);
                        // 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 < distance + stdDev && dat > distance - stdDev)
                                    values[candidates++] = dat;
                            }
                            distance = Average(values, candidates - 1);
                        }
                    }
                }
            }
            else
            {
                distance = ReadSensorValue();
            }
            if (UseMovingAverage)
            {
                AddMovingAverage(distance);
                return Average(movingValues);
            }
            return distance;
        }
        protected double ReadSensorValue()
        {
            int x = sensor.Read();
            // please do not change this unless you *really* know what you are doing. This took many hours to get right.
            if (x > 670)
            {
                // handles 5cm ~23cm very accurately
                return -0.00000000000000814807570435057 * MathEx.Pow(x, 5) +
                    0.0000000000677479681464555 * MathEx.Pow(x, 4) -
                    0.000000223468684525594 * MathEx.Pow(x, 3) +
                    0.000369147142846821 * MathEx.Pow(x, 2) -
                    0.313961024650693 * x +
                    121.96816964022;
            }
            else
            {
                // actually accurate from 17cm ~ 36cm however the above function is more accurate
                return 0.00000000000000814807570435057 * MathEx.Pow(x, 5) +
                    0.0000000000677479681464555 * MathEx.Pow(x, 4) -
                    0.000000223468684525594 * MathEx.Pow(x, 3) +
                    0.000369147142846821 * MathEx.Pow(x, 2) -
                    0.313961024650693 * x +
                    121.96816964022;
            }
            
        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 distance (in centimetres) that the senor can be used.
        /// </summary>
        public float MaximumDistanceCapability { get; protected set; }
        /// <summary>
        /// The minimum distance (in centimetres) that the sensor can be used.
        /// </summary>
        public float MinimumDistanceCapability { get; protected set; }

        public double GetDistanceInInches()
        {
            return GetDistanceInCM() / 2.54;
        }
        public double GetDistanceInMM()
        {
            return GetDistanceInCM() * 10;
        }
        public double GetDistanceInFeet()
        {
            return GetDistanceInCM() * 0.032808399;
        }
        }
    }
}

«1

Comments

  • ersmithersmith Posts: 6,054
    edited 2012-10-06 12:10
    idbruce wrote: »
    I have two files of source code that I would like to modify to work with the Propeller chip, however these files include double data types and floating point math. I am wondering if my goal is attainable, before doing a vast amount of research to find out that it cannot be done. I have included the source code of one file that I want to modify.

    PropGCC supports 64 bit doubles out of the box. I'm not sure if there are any Spin objects that do 64 bit floating point, but there certainly are some 32 bit floating point objects. I've written a 64 bit co-processor (using an additional COG) for GCC called fpucog.c. It's quite a bit faster than PropGCC's built-in 64 bit math, and could probably be adapted for use with Spin with a bit of work.

    Depending on how much accuracy you need you might be able to get away with 32 bit floating point. As I mentioned, there are some Spin objects for this (F32 is the fastest). Catalina C supports 32 bit floating point (its doubles are also 32 bit), and I think that PropForth may support 32 bit floats too, but I'm not certain of that.

    Eric
  • idbruceidbruce Posts: 6,197
    edited 2012-10-06 12:29
    @Eric
    PropGCC supports 64 bit doubles out of the box.

    Then perhaps it would be a good time to get my feet wet with PropGCC. I have looked into it a few times, but I really have not had the necessity or projects that required learning it. I am not sure, but I believe the native code that I want to translate was written in C#, and I believe the doubles are 64 bit.

    Thanks for your input Eric.

    Bruce
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-10-06 12:44
    Bruce,

    What does the code do and why does it need to be so accurate?

    As Eric suggests, if 32-bit precision is good enough then F32 should be able to handle the math portion of the code.

    There's also the option of using a 64-bit floating point coprocessor (if you don't want to use GCC).
  • idbruceidbruce Posts: 6,197
    edited 2012-10-06 12:56
    @Duane

    The code is used with the Sharp IR distance sensors. Supposedly this code will provide measurement accuracies within a couple millimeters. The author has written several objects for several different Sharp IR distance sensors.

    The reason for using doubles is to keep the translation down to a minimum, because the math definitely appears to be a little complicated for translation purpores.
  • Martin_HMartin_H Posts: 4,051
    edited 2012-10-06 13:02
    Bruce, give Propgcc a try, it and the SimpleIDE are quite usable. Large memory model programming feels just like Spin, but you can have some modules in cog memory model too.
  • Dave HeinDave Hein Posts: 6,347
    edited 2012-10-06 14:03
    Try running the code with double precision to see if it is fast enough. If you need more speed you can use the "32bit Double" option under SimpleIDE to force 32-bit floating point instead of 64-bit.
  • Heater.Heater. Posts: 21,230
    edited 2012-10-06 14:46
    I find it really hard to belive that any code using an Sharp IR sensor really neeeds double precision arithmetic. Could be wrong but that is my gut feeling. When measuring real world quantities 52 bits of accuracy seems optimistic given that your sensor input is probably only good for a max of 16 bits usually a lot less.
  • jmgjmg Posts: 15,173
    edited 2012-10-06 14:46
    idbruce wrote: »
    The code is used with the Sharp IR distance sensors. Supposedly this code will provide measurement accuracies within a couple millimeters. The author has written several objects for several different Sharp IR distance sensors.

    Can you try the original code with float instead of double ?

    Float gives you 23-24bits of precision, so is well below 1ppm, an IR sensor will be WAY above that precision floor.

    It seems to me double is chosen simply 'because they could'; on a PC it is a zero cost choice..
  • Heater.Heater. Posts: 21,230
    edited 2012-10-06 14:53
    Yep, I would just impliment it in C using floats, do it in Spin of you really want to torture yourself. I'm sure it will work fine.

    Back in the day I spent some time working on software for a three dimensional, phased array, radar (http://www.radartutorial.eu/19.kartei/karte113.en.html) that could give you bearing, distance and altitude of aircraft 250 miles away. We had no floating point support, it was all done with fixed point arithmetic on a 16 bit machine.

    My boss on that project used to say "If you think you need floating point to solve the problem then you do not understand the problem".

    Anyway that IT sensor sounds like a dinky radar, so what's the problem?
  • Mike GMike G Posts: 2,702
    edited 2012-10-06 23:11
    I'm not sure a double float for millimeter accuracy is needed. You can get 1cm (darn near 0.5cm) accuracy with a BS2 and an 8-bit ADC. Some math is involved outside BS2 processing to come up with a constant to linearize the IR voltage output. Once the constant is calculated the math is simple. I always thought the biggest headache was filtering out bad readings.

    Here's an NV article.
    http://www.parallax.com/Portals/0/Downloads/docs/cols/nv/vol5/col/nv114.pdf

    Another good related read.
    http://www.acroname.com/robotics/info/articles/irlinear/irlinear.html
  • idbruceidbruce Posts: 6,197
    edited 2012-10-06 23:11
    During all my years of programming, I have never really done anything that really involved a lot of serious math, and it was mostly GUI kind of stuff. So I never really messed with or took the time to learn about doubles and such.

    So when I look at something like the following:
                int x = sensor.Read();
                // please do not change this unless you *really* know what you are doing. This took many hours to get right.
                if (x > 670)
                {
                    // handles 5cm ~23cm very accurately
                    return -0.00000000000000814807570435057 * MathEx.Pow(x, 5) +
                        0.0000000000677479681464555 * MathEx.Pow(x, 4) -
                        0.000000223468684525594 * MathEx.Pow(x, 3) +
                        0.000369147142846821 * MathEx.Pow(x, 2) -
                        0.313961024650693 * x +
                        121.96816964022;
                }
                else
                {
                    // actually accurate from 17cm ~ 36cm however the above function is more accurate
                    return 0.00000000000000814807570435057 * MathEx.Pow(x, 5) +
                        0.0000000000677479681464555 * MathEx.Pow(x, 4) -
                        0.000000223468684525594 * MathEx.Pow(x, 3) +
                        0.000369147142846821 * MathEx.Pow(x, 2) -
                        0.313961024650693 * x +
                        121.96816964022;
                }      
    

    It scares the bejeezers out of me. :) It looks simple enough mathematically, but the determining the necessary data type for programming would be quite fuzzy for me.

    My viewpoint is that since the author used 64 bit doubles, why should I be the guy to rock the boat :) Especially if PropGCC supports 64 bit doubles and it would just be a simple translation. However, if the proceeding math can be calculated without doubles, I am open to all suggestions.
  • idbruceidbruce Posts: 6,197
    edited 2012-10-06 23:15
    Mike G

    I have already looked at those documents. I am looking for something that is HIGHLY accurate. I could simply setup the sensor, take some test readings, and create a few tables. However, there are a several people across the internet (robot enthuiasts) that attest to the accuracy of this software.
  • idbruceidbruce Posts: 6,197
    edited 2012-10-06 23:19
    Here is an excerpt from another thread of mine:
    I just ordered a Sharp IR sensor and cable from Parallax. There is a software, electronics, and uC developer in Ausralia that claims these sensors can provide accurate measurements within a few millimeters, and he provides source code for several different Sharp IR sensors. Of course the software will have to be reversed for the SPIN cycle, but I intend to give it a try.

    Here is a couple of links to videos he has presented of testing and using some Sharp IR distance sensors:

    http://www.youtube.com/watch?v=Uw9Os4-Tewk&feature=plcp
    http://vimeo.com/15162561

    EDIT: In addition to the Sharp GP2Y0A21YK0F IR distance sensor that I ordered from Parallax, I am also ordering the Sharp GP2D120XJ00F IR distance sensor from another source. Since making this post, I have found a lot more information pertaining to Mark Harris's IR distance sensor reading software. This link will take you to a wide variety of software for reading various Sharp IR distance sensors. Of course the software will need reverse engineering to enable the software to run on the Propeller chip, but it is a start toward accurate distance reading with Sharp IR distance sensors.

  • jmgjmg Posts: 15,173
    edited 2012-10-07 02:36
    idbruce wrote: »
    However, if the proceeding math can be calculated without doubles, I am open to all suggestions.

    That is simply enough to code both ways and call both on a PC, and simply plot the errors you get, for the same input range, of float vs double.
    I would expect maybe ~20um of difference ?
  • Heater.Heater. Posts: 21,230
    edited 2012-10-07 03:11
    That code snippet above is taking a value from the sensor, x, and pushing it into one of two polynomials. Presumably in an effort to linearize things.
    I can't help thinking that doing that in 64 bit floating point is going to take a lot of code space in the Prop and the same task could be done with a look up table and some linear interpolation, perhaps in less space.
  • Heater.Heater. Posts: 21,230
    edited 2012-10-07 03:22
    jmg,
    code both ways and call both on a PC

    I was just doing that as you speak. Attached is my effort in C which has float and double versions of that polynomial routine and exercises them for inputs from 0 to 1000. (What range should we expect as raw sensor input?)

    The differences between float and double are down at the +-0.000002 level. like so:
    Input           Output Double  Output Float   Error
    0.000000  121.968170  121.968170 -0.000001
    10.000000  118.865251  118.865250 0.000002
    20.000000  115.834831  115.834831 -0.000000
    30.000000  112.875593  112.875595 -0.000002
    40.000000  109.986236  109.986237 -0.000000
    50.000000  107.165479  107.165482 -0.000003
    60.000000  104.412053  104.412056 -0.000003
    70.000000  101.724709  101.724709 0.000001
    80.000000  99.102215  99.102219 -0.000004
    90.000000  96.543354  96.543350 0.000003
    100.000000  94.046926  94.046928 -0.000002
    110.000000  91.611751  91.611748 0.000003
    120.000000  89.236663  89.236664 -0.000001
    130.000000  86.920514  86.920517 -0.000002
    140.000000  84.662176  84.662178 -0.000002
    150.000000  82.460536  82.460533 0.000003
    160.000000  80.314499  80.314499 -0.000000
    170.000000  78.222987  78.222984 0.000003
    180.000000  76.184942  76.184944 -0.000002
    190.000000  74.199322  74.199326 -0.000003
    200.000000  72.265105  72.265106 -0.000001
    210.000000  70.381285  70.381287 -0.000002
    220.000000  68.546874  68.546875 -0.000001
    230.000000  66.760905  66.760902 0.000003
    240.000000  65.022428  65.022430 -0.000003
    250.000000  63.330509  63.330509 0.000000
    260.000000  61.684237  61.684238 -0.000001
    270.000000  60.082718  60.082718 -0.000000
    280.000000  58.525074  58.525074 0.000000
    290.000000  57.010451  57.010452 -0.000002
    300.000000  55.538009  55.538010 -0.000001
    310.000000  54.106931  54.106930 0.000001
    320.000000  52.716417  52.716415 0.000001
    330.000000  51.365686  51.365688 -0.000002
    340.000000  50.053979  50.053978 0.000001
    350.000000  48.780554  48.780556 -0.000001
    360.000000  47.544690  47.544689 0.000000
    370.000000  46.345683  46.345684 -0.000001
    380.000000  45.182853  45.182854 -0.000001
    390.000000  44.055536  44.055534 0.000002
    400.000000  42.963091  42.963093 -0.000002
    410.000000  41.904895  41.904896 -0.000001
    420.000000  40.880346  40.880348 -0.000002
    430.000000  39.888863  39.888863 0.000000
    440.000000  38.929883  38.929882 0.000001
    450.000000  38.002866  38.002865 0.000001
    460.000000  37.107292  37.107292 -0.000001
    470.000000  36.242659  36.242661 -0.000001
    480.000000  35.408491  35.408489 0.000002
    490.000000  34.604328  34.604328 -0.000000
    500.000000  33.829733  33.829731 0.000002
    510.000000  33.084290  33.084290 0.000000
    520.000000  32.367604  32.367603 0.000001
    530.000000  31.679301  31.679300 0.000001
    540.000000  31.019029  31.019030 -0.000001
    550.000000  30.386457  30.386457 -0.000001
    560.000000  29.781275  29.781275 0.000000
    570.000000  29.203196  29.203196 0.000000
    580.000000  28.651953  28.651953 0.000000
    590.000000  28.127302  28.127302 -0.000000
    600.000000  27.629021  27.629021 0.000001
    610.000000  27.156910  27.156910 0.000000
    620.000000  26.710791  26.710791 0.000000
    630.000000  26.290507  26.290506 0.000000
    640.000000  25.895925  25.895926 -0.000001
    650.000000  25.526933  25.526934 -0.000000
    660.000000  25.183444  25.183445 -0.000001
    670.000000  24.865391  24.865391 0.000000
    680.000000  22.203378  22.203379 -0.000001
    690.000000  21.756673  21.756672 0.000001
    700.000000  21.324634  21.324635 -0.000001
    710.000000  20.906814  20.906815 -0.000000
    720.000000  20.502777  20.502777 -0.000000
    730.000000  20.112094  20.112093 0.000001
    740.000000  19.734345  19.734344 0.000001
    750.000000  19.369122  19.369122 0.000000
    760.000000  19.016022  19.016022 0.000001
    770.000000  18.674655  18.674656 -0.000000
    780.000000  18.344638  18.344637 0.000001
    790.000000  18.025595  18.025595 0.000000
    800.000000  17.717161  17.717161 -0.000000
    810.000000  17.418979  17.418980 -0.000000
    820.000000  17.130701  17.130701 -0.000000
    830.000000  16.851985  16.851986 -0.000001
    840.000000  16.582500  16.582500 -0.000000
    850.000000  16.321922  16.321922 -0.000000
    860.000000  16.069934  16.069935 -0.000001
    870.000000  15.826229  15.826229 -0.000000
    880.000000  15.590507  15.590507 -0.000000
    890.000000  15.362474  15.362474 -0.000000
    900.000000  15.141847  15.141847 0.000000
    910.000000  14.928348  14.928348 0.000000
    920.000000  14.721707  14.721707 -0.000000
    930.000000  14.521662  14.521662 0.000000
    940.000000  14.327958  14.327958 0.000000
    950.000000  14.140347  14.140347 -0.000000
    960.000000  13.958588  13.958588 0.000000
    970.000000  13.782447  13.782447 0.000000
    980.000000  13.611697  13.611697 -0.000000
    990.000000  13.446118  13.446117 0.000000
    
  • Mark_TMark_T Posts: 1,981
    edited 2012-10-07 03:48
    Duane Degn wrote: »
    Bruce,

    What does the code do and why does it need to be so accurate?

    As Eric suggests, if 32-bit precision is good enough then F32 should be able to handle the math portion of the code.

    There's also the option of using a 64-bit floating point coprocessor (if you don't want to use GCC).

    Double is probably used because its the default for the architecture, not because the accuracy is required.

    On high-end processors double is often faster than float because everything is at least 64 bit internal, and converting double->float is non-trivial (test for over/underflow, which may have to generate an exception, which requires flushing the instruction pipeline).
  • ersmithersmith Posts: 6,054
    edited 2012-10-07 05:24
    Dave Hein wrote: »
    Try running the code with double precision to see if it is fast enough. If you need more speed you can use the "32bit Double" option under SimpleIDE to force 32-bit floating point instead of 64-bit.

    I think Dave's nailed it here. If 64 bits is fast enough, why sweat about reducing the precision? And conversely, switching from 64 to 32 is pretty trivial in PropGCC, since it's just a command line (or SimpleIDE) option, so it can always be done later.

    Efficiency is important, but so is programmer effort required :-).

    Eric
  • prof_brainoprof_braino Posts: 4,313
    edited 2012-10-07 07:03
    ersmith wrote: »
    ... and I think that PropForth may support 32 bit floats too

    Propforth has modules for double and float. It is optimized and can probably be optimized further, but since its software it will only ever be "not fast". This applies to PASM and C equally. There is also support for the external math co-processor, in forth and other languages, but talking to the external chip is slow and ends up being almost the same as just doing it in software, due to the overhead for transfer etc.

    So the question become how much processing and how often? IF YOU REALLY WANT TO BE CRUNCHING ON NUMBERS, the smart money says use something like a linux workstation , for example Raspberry Pi or better, running a language design for crunching for example GO LANG or better, and use a high speed comm protocol, CSP channels or better. Then collect the data on the prop as fast as you can, dump it to the Linux box as fast as you can, crunch it on the linux at your leisure, and send but your adjustments as fast as you need. Propforth v5.3 and the accompanying GO Lang modules are (going to be) pre configured for this out of the box, we don't have the box yet. Considering the cost of the prop and a Pi, this may be a nice bang for the buck option.

    Smarter folks probably already have this set up in propgcc etc, but forth is likely going to be the fun option.

    Side note: options like SPIN+Python might do the same thing, but would be a bit slower, which is ok if it does what you want.
  • idbruceidbruce Posts: 6,197
    edited 2012-10-07 07:08
    I must say that this thread has become quite interesting. Thanks for all the input.

    @Heater
    That code snippet above is taking a value from the sensor, x, and pushing it into one of two polynomials. Presumably in an effort to linearize things.
    I can't help thinking that doing that in 64 bit floating point is going to take a lot of code space in the Prop and the same task could be done with a look up table and some linear interpolation, perhaps in less space.

    WOW... Thanks for the comparison. Definitely an eye opener.
    (What range should we expect as raw sensor input?)

    Actually, according to Mark Harris's documentation, I will be pushing the Sharp GP2Y0A21YK0F beyond it's accurate measurement capabilities. To pick up the slack for this sensor, I am contemplating also using the Sharp GP2D120XJ00F. Basically, two sensors side by side, or an over/under configuration. However, each of these will be using different polynomial routines. As for the specific values I should expect to see, I have no idea except for the comparisons that he uses.

    The Sharp GP2Y0A21YK0F uses the following comparisons:
    • if (x > 970) // less than 28cm
    • else if (x > 680) // less than ~44cm
    • else
    And the Sharp GP2D120XJ00F uses the following comparisons
    • if (x > 670)
    • else
    @Mark_T
    Double is probably used because its the default for the architecture, not because the accuracy is required.

    On high-end processors double is often faster than float because everything is at least 64 bit internal, and converting double->float is non-trivial (test for over/underflow, which may have to generate an exception, which requires flushing the instruction pipeline).

    Makes perfect sense to me.
  • idbruceidbruce Posts: 6,197
    edited 2012-10-07 07:21
    @prof_braino

    Well, I did not like your whole concept, but I definitely found a golden nugget of useful information.
    Then collect the data on the prop as fast as you can, dump it

    Now that is a VERY useful suggestion. Considering that the readings will eventually be turned into useful data, and transferred to the PC, I could simply switch it around and let the PC do the work. By doing so, I could port this software to Visual C++ very, very quickly, basically a no brainer. However, that would eliminate my current need to get my feet wet with PropGCC :(

    Thanks Prof, I really like that idea!!!!!!!!!!
  • idbruceidbruce Posts: 6,197
    edited 2012-10-07 07:48
    Of course this will all be contingent upon the terms of the author pertaining to commercial use.
  • John AbshierJohn Abshier Posts: 1,116
    edited 2012-10-07 11:03
    Sharp sensors produce an analog output. I am guessing you won't read to output to more than 12 bits. Therefore double precision seems a bit much. How much noise does the Sharp Sensor have. I am on the road. If I were home I would hook up a sharp sensor and just make a lot of reading at a fixed distance to see how much variation it has.

    John Abshier
  • Mike GMike G Posts: 2,702
    edited 2012-10-07 11:36
    Sharp sensors produce an analog output. I am guessing you won't read to output to more than 12 bits. Therefore double precision seems a bit much. How much noise does the Sharp Sensor have. I am on the road. If I were home I would hook up a sharp sensor and just make a lot of reading at a fixed distance to see how much variation it has.
    I completely agree. I tried to explain this in post 11 but idbruce has already researched this solution and found it inadequate for his needs.

    I usually average at least 3 readings. With an 8-bit A/D you can get very close to 0.5cm accuracy with a 8-80cm Sharp IR sensor.
  • Heater.Heater. Posts: 21,230
    edited 2012-10-07 12:10
    Mike G,

    You did say in post #11 "constant to linearize the IR voltage output." and then talk about +/- 0.5cm.

    Given the non-linearity of the thing I am prepared to belive that a polynomial with suitable coefficents can give you accuracy down to milimeters rather than using a single constant for a straight line fit.

    So there is nothing wrong with the idea. It's just that I'm sure the same can be achieved with single precision floats, or even lesser precision fixed point arithmetic. A look up table and linear interpolation would be fine.

    Ultimately the accuracy is determined by physical reality, the ADC resolution, the noise and so on. No point in going overboard on the arithmetic precision.
  • idbruceidbruce Posts: 6,197
    edited 2012-10-07 12:38
    As previously stated, considering that I want to use Mark Harris's code in a commercial application, the choice of whether to use his code or not, will ultimately depend upon what he wants for use of his code. If necessary, to avoid copyright infringement or paying unreasonable fees, I will simply create some serious tables and do my figuring from there.

    As per the copyright notice, I have sent him an email to listed address, and informed him that I would like to use his code in a commercial application.

    However, I still think it might be beneficial to translate this code for use with the Propeller chip in non-commercial applications.

    Bruce
  • Heater.Heater. Posts: 21,230
    edited 2012-10-07 12:50
    It's not worth worrying about. Just write your own.

    If you want to use a fifth order polynomial or a look up table and interpolation just calibrate a sensor. Record output vs distance, find a ploynomial curve fitting program, there are many online like this one http://www.efunda.com/webM/numerical/curvefitpoly.cfm
    and implement the resulting equation or put the equations values into a precomputed table.
  • jmgjmg Posts: 15,173
    edited 2012-10-07 15:30
    idbruce wrote: »
    Actually, according to Mark Harris's documentation, I will be pushing the Sharp GP2Y0A21YK0F beyond it's accurate measurement capabilities.

    If you are pushing any sensor, especially in a constrained-condition case like here, you are probably best calibrating each sensor.

    Next step would be to add a Temperature compensation as well

    ie setup an Auto-record system, such that you can easily capture and then Linear-fit, or compress however you like, the value.
    Given the low speed, and small size here, you could just do a simple EEPROM table.
  • Heater.Heater. Posts: 21,230
    edited 2012-10-07 20:27
    bruce,

    Just had a quick look at a data sheet for thhe device. They make no mention of expected accuracy. They do indicate that all sorts of things can detract from it's accuracy, like:
    a) Ambient lighting.
    b) Differnet colours of target.
    c) Patterns of contrasting colour on the target.
    d) Dirt and dust.

    No doubt temperature may have an effect.

    For sure to get maximum accuracy you are goint to need to operate the thing in carefully controlled conditions. And calibrate individual sensors. Question might then be what are you goint to calibrate against and what accuracy will that have.

    Given all of this it seems having that software work down to dozen decimal places is just silly.
  • Heater.Heater. Posts: 21,230
    edited 2012-10-07 20:39
    Bruce,

    Do read this paper to see what you are up against.

    http://www.gecad.isep.ipp.pt/iscies09/Papers/19November/iscies09_sharp_model.pdf
Sign In or Register to comment.