Test and Measurement Forum

C# General Software Down-sampling Code

Post your .Net discussions here

C# General Software Down-sampling Code

Postby Sanjay » Tue Jul 05, 2016 2:11 pm

The Picoscope already has hardware down-sampling, this is the code I have used in my spare time for Software down-sampling whilst using the SDK.
Tested on the PS5000A, should work for any version.

Method used: Largest Triangle Three Buckets
Information: 4.2 Page 21 http://skemman.is/stream/get/1946/15343/37285/3/SS_MSthesis.pdf

Method (Where threshold is the amount of samples that will be left after the downsample):
Code: Select all
public static IEnumerable<Tuple<double, double>> downsample(List<Tuple<double, double>> data, int threshold)
        {
            int dataLength = data.Count;
            if (threshold >= dataLength || threshold == 0)
                return data; // Nothing to do

            List<Tuple<double, double>> sampled = new List<Tuple<double, double>>(threshold);

            // Bucket size. Leave room for start and end data points
            double every = (double)(dataLength - 2) / (threshold - 2);

            int a = 0;
            Tuple<double, double> maxAreaPoint = new Tuple<double, double>(0, 0);
            int nextA = 0;

            sampled.Add(data[a]); // Always add the first point

            for (int i = 0; i < threshold - 2; i++)
            {
                // Calculate point average for next bucket (containing c)
                double avgX = 0;
                double avgY = 0;
                int avgRangeStart = (int)(Math.Floor((i + 1) * every) + 1);
                int avgRangeEnd = (int)(Math.Floor((i + 2) * every) + 1);
                avgRangeEnd = avgRangeEnd < dataLength ? avgRangeEnd : dataLength;

                int avgRangeLength = avgRangeEnd - avgRangeStart;

                for (; avgRangeStart < avgRangeEnd; avgRangeStart++)
                {
                    avgX += data[avgRangeStart].Item1; // * 1 enforces Number (value may be Date)
                    avgY += data[avgRangeStart].Item2;
                }
                avgX /= avgRangeLength;

                avgY /= avgRangeLength;

                // Get the range for this bucket
                int rangeOffs = (int)(Math.Floor((i + 0) * every) + 1);
                int rangeTo = (int)(Math.Floor((i + 1) * every) + 1);

                // Point a
                double pointAx = data[a].Item1; // enforce Number (value may be Date)
                double pointAy = data[a].Item2;

                double maxArea = -1;

                for (; rangeOffs < rangeTo; rangeOffs++)
                {
                    // Calculate triangle area over three buckets
                    double area = Math.Abs((pointAx - avgX) * (data[rangeOffs].Item2 - pointAy) -
                                           (pointAx - data[rangeOffs].Item1) * (avgY - pointAy)
                                      ) * 0.5;
                    if (area > maxArea)
                    {
                        maxArea = area;
                        maxAreaPoint = data[rangeOffs];
                        nextA = rangeOffs; // Next a is this b
                    }
                }

                sampled.Add(maxAreaPoint); // Pick this point from the bucket
                a = nextA; // This a is the next a (chosen b)
            }

            sampled.Add(data[dataLength - 1]); // Always add last

            return sampled;
        }


Usage (Only after results have been collected):
Code: Select all
                        //Create new list with tuples
                                 List<Tuple<double, double>> list = new List<Tuple<double, double>>();
                                 //Iterate through results after runblock
                                 for (int i = 0; i < maxBuffers[channel].Length; i++)
                                 {
                                    //Populate tuple list
                                    list.Add(new Tuple<double, double>(i * timeInterval, maxBuffers[channel][i]));
                                 }

                                IEnumerable<Tuple<double, double>> downsampledData = GraphModel.downsample(list, App.downsampleSize); //Sampled down data to process


Example:
Signal Generated:
Image

All 100K Samples:
http://i.imgur.com/CLYGazk.png

100K Samples down-sampled to 5K samples:
http://i.imgur.com/96q91p3.png

100K Samples down-sampled to 1K samples:
http://i.imgur.com/aYC61j4.png
Sanjay
Active User
Active User
 
Posts: 6
Joined: Mon Jun 20, 2016 1:08 pm

Return to .Net Languages (C#, VB.Net, .)

Who is online

Users browsing this forum: No registered users and 3 guests