【问题标题】:Simple Low Pass Filter for Boolean switch用于布尔开关的简单低通滤波器
【发布时间】:2018-08-12 13:23:11
【问题描述】:

在 C# 类中,如果更改之间的间隔太短,则需要过滤掉或忽略 Update 方法中的布尔更改。

本质上我需要所谓的“低通滤波器”

假设我们在 Update 或 FixedUpdate 中有以下内容

if (myBoolean condition){
 myVal  =0;
}else{

 myVal= _rawInput;
}

上面的 myBoolean 条件切换得太快了。我需要“过滤掉”或忽略这些短时间间隔。

我尝试使用此 LowPass Filter 类与移动加速度计输入一起使用,但没有运气,因为它假定被过滤的值是浮点数。 http://devblog.aliasinggames.com/accelerometer-unity/有人可以帮忙吗?

【问题讨论】:

  • 你可以有一个时间跨度类型的静态类变量,如果已经过了足够的时间,则将其设置为当前时间,比较当前时间 - 时间跨度类型的变量,如果与当前时间的差异 - 静态时间跨度变量是不够的忽略做你的更新。我将在下面发布一个答案,解释我的建议。
  • @RyanWilson 我写代码的时间比你写的时间长,但想法相同:)
  • @PatrickArtner 是的。我看到你在实际编码方面打败了我。干得好,我 +1。

标签: c# unity3d boolean lowpass-filter


【解决方案1】:

低通滤波器?

using System;
using System.Linq;

public class Program
{
    public static bool MyValue = false;

    public static DateTime lastChange { get; set; } = DateTime.MinValue;

    public static void ChangeValue(bool b)
    {
        // do nothing if not 2s passed since last trigger AND the value is different
        // dont reset the timer if we would change it to the same value
        if (DateTime.Now - lastChange < TimeSpan.FromSeconds(2) || MyValue == b)
            return;
        // change it and remember change time
        lastChange = DateTime.Now;
        MyValue = b;
        Console.WriteLine($"Bool changed from {!b} to {b}. Time: {lastChange.ToLongTimeString()}");
    }

    public static void Main(string[] args)
    {
        for (int i = 0; i < 10000000; i++)
        {
            ChangeValue(!MyValue);
        }
    }
}

输出:

Bool changed from False to True. Time: 23:29:23
Bool changed from True to False. Time: 23:29:25
Bool changed from False to True. Time: 23:29:27

整个循环运行大约 7 秒 - 大约每秒 115 万次触发器来改变它。

【讨论】:

    【解决方案2】:

    你可以把它变成一个类:

    public class FilteredBool
    {
        private bool _inputValue;
        private bool _outputValue;
        private TimeSpan _minimumTime = TimeSpan.FromSeconds(5);
        private DateTime _lastChangeTime = DateTime.MinValue;
    
        public bool Value
        {
            get
            {
                if (_outputValue != _inputValue)
                {
                    if (_lastChangeTime + _minimumTime < DateTime.Now)
                        _outputValue = _inputValue;
                }
                return _outputValue;
            }
            set
            {
                if (_inputValue != value)
                {
                    _inputValue = value;
                    _lastChangeTime = DateTime.Now;
                }
            }
        }
    
        public TimeSpan MinimumTime
        {
            get { return _minimumTime; }
            set { _minimumTime = value; }
        }
    
        public static implicit operator bool(FilteredBool value)
        {
            return value.Value;
        }
    }
    

    这对bool 有一个隐式运算符,因此您可以替换任何采用bool(或if)的函数调用,而无需调用.Value。没有返回 FilteredBool 的隐式运算符,因为这需要设置过滤时间。如果你愿意,你可以添加这个,我觉得这有点牵强。

    【讨论】:

    • _outputvalue / getter 内部的检查和修改有什么目的?
    • @PatrickArtner 这是我的代码中的一个错字,我修复了它。检查在 getter 中,因为只有在“获取”值时才真正重要。 “_outputValue != _inputValue”确保内部检查只运行一次。你可以把它拿出来,但它应该更高效一点,不必每次都做日期/时间数学。
    • 但是如果我每秒触发你的类设置方法 10000 次,如果仍然会闪烁 - 根据 Q 它不应该做的确切事情是什么?时间结束后它可能会切换或不切换,这取决于我触发它的频率?反过来也很整洁:)
    • @PatrickArtner 它不会“闪烁”,输入必须保持高(或低)5 秒才能改变输出值。您可以通过设置 MinimumTime 属性来设置 OP 要求的“时间间隔”(必须保持的时间)。
    【解决方案3】:

    OP 感谢您提供出色的解决方案。作为布尔低通滤波器的快速破解,我还想知道是否可以简单地使用计数器和模运算,本质上是“减慢”FixedUpdate 方法。布尔值的变化永远不会比模运算(或余数)= 零的间隔更快。没有考虑过实现细节。想法?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 2021-06-12
      • 1970-01-01
      • 2012-12-02
      • 1970-01-01
      • 2014-07-29
      • 2013-06-04
      相关资源
      最近更新 更多