用于过滤器优化的数据分组算法

时间:2018-08-09 15:28:29

标签: c# algorithm filter can-bus

我正在使用MCP2515(CAN收发器)进行项目开发,该芯片的功能之一是可以通过应用规则(掩码)仅允许特定范围的数据通过过滤器来过滤ID。我最多可以有6个不同的过滤器。在我正在编码的应用程序中,我解析一个DBC文件以选择我想要接收的信号。如果我有6个或更少的信号,我可以为这些信号中的每一个制定一个“通过规则”,但是如果我有6个以上的信号,则需要创建包含所有所需ID的规则。理想情况下,每个组将合并尽可能小的数据范围。我希望可以自动计算出它,因此我需要创建一种算法来重新组合我的ID。

例如,如果我选择了以下ID: 32、154、157、160、354、363、680、682、841、845、871、932、936、940

我的数据组将是[32],[154、157、160],[354、363],[680、682],[841、845、871],[932、936、940]。

这是我现在拥有的代码,但是在处理范围的两端时遇到麻烦(在上述情况下:32和940)。

private void getMasks()
    {
        List<List<uint>> fields = new List<List<uint>>();

        uint spectrum = 0;
        uint chunkSize = 0;
        IDs.Sort();
        spectrum = IDs.Last() - IDs.First();

        //Gets the sixth of my whole data range for a first grouping
        chunkSize = (uint)Math.Ceiling(((double)spectrum / 6));

        //Regroups data in the 6 ranges
        for(int i = 0; i < 6; i++)
        {
            fields.Add(new List<uint>());
            foreach (uint id in IDs)
            {
                if (id >= ((i * chunkSize) + IDs.First()) && id < (((i + 1) * chunkSize) - 1) + IDs.First())
                    fields[i].Add(id);                    
            }                
        }

        //If a range doesn't have data, removes it
        for (int j = 0; j < fields.Count; j++)
            if (fields[j].Count == 0)
            {
                fields.RemoveAt(j);
                j--;
            }

        //Reorganize the data in fields to have the smallest range possible in the subgroups
        for(int k = 0; k < fields.Count - 1; k++)
        {
            //MY PROBLEM IS IN THE NEXT TWO LOOPS

            //If the last data in a group is closer from the first data of the next group than from the second last of its own group, moves it to the next group
            while(fields[k].Count >= 2 && fields[k+1].Count > 0 && ((fields[k][fields[k].Count -1] - fields[k][fields[k].Count - 2]) > (fields[k+1][fields[k+1].Count -1] - fields[k][fields[k].Count - 1])))
            {
                fields[k + 1].Add(fields[k].Last());
                fields[k].RemoveAt(fields[k].Count - 1);
            }

            //If the first data in a group is closer to the last data of the last group than to the second data of its own group, moves it to the last group.
            while (fields[k].Count > 0 && fields[k + 1].Count >= 2 && ((fields[k+1][1] - fields[k+1][0]) > (fields[k].Last() - fields[k+1][0])))
            {
                fields[k].Add(fields[k+1][0]);
                fields[k+1].RemoveAt(0);
            }
        } 
        //Some other code to find the masks to apply            
    }

有人可以给我一些提示或示例,说明如何在尽可能小的范围内重新组合数据吗?

谢谢

阿尔弗雷德

2 个答案:

答案 0 :(得分:1)

这是您的列表,其中包含到下一项的计算出的“距离”:

32(122), 154(3), 157(3), 160(194), 354(9), 363(317), 680(2), 682(159), 841(4), 845(26), 871(61), 932(4), 936(4), 940()

此处同一列表按“距离”降序排列:

363(317), 160(194), 682(159), 32(122), 871(61), 845(26), 354(9), 841(4), 932(4), 936(4), 154(3), 157(3), 680(2), 940() 

您需要什么-服用前5项:

363(317), 160(194), 682(159), 32(122), 871(61)

并在这些项目之后“拆分”原始列表:

32(122)                  // split 4
154(3), 157(3), 160(194) // split 2
354(9), 363(317)         // split 1
680(2), 682(159)         // split 3
841(4), 845(26), 871(61) // split 5
932(4), 936(4), 940()

它将给您6个小组(您最多削减了5个空格)

答案 1 :(得分:0)

在代码中:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {

        static void Main(string[] args)
        {
            List<int> signals = new List<int>() { 680, 841, 154, 940, 160, 157, 936, 354, 363,  682, 871, 932, 845, 32};

            signals.Sort();

            List<GapData> gapsData = new List<GapData>();

            for(int i = 0; i < signals.Count - 1; i++)
            {
                GapData newGap = new GapData() { Index = i, Span = signals[i + 1] - signals[i] };
                gapsData.Add(newGap);
            }

            gapsData.Sort();

            gapsData = gapsData.Take(5).ToList(); //Keep 5 biggest gaps

            gapsData = gapsData.OrderBy(i => i.Index).ToList(); //sort on index

            List<List<int>> groupedList = new List<List<int>>();

            int index = 0;

            List<int> currentGroup = new List<int>();
            groupedList.Add(currentGroup);

            for(int i = 0; i < signals.Count; i++)
            {
                if (index < 5 && gapsData[index].Index < i)
                {
                    currentGroup = new List<int>();
                    groupedList.Add(currentGroup);
                    index++;
                }
                currentGroup.Add(signals[i]);
            }
        }


        public class GapData:IComparable<GapData>
        {
            public GapData()
            {
            }
            public int Index { get; set; }

            public int CompareTo(GapData other)
            {
                return - Span.CompareTo(other.Span);
            }


            public int Span { get; set; }
        }
    }

}