通过去抖动机制或延迟确认,解决交流接触器时间差导致的状态波动问题

从你的描述和代码来看,需求如下:

  1. Read 方法持续读取硬件状态:

    • Read 方法通过循环不断读取 AUXRealTimeState1.TestPowerStatus,并在状态为 true 时设置 GlobalCache.TestPowerReadStatus = true。

    • 每次循环有 100ms 的延迟(Thread.Sleep(100)),表示这是一个轮询机制,用于监控硬件状态。

  2. PSRead 依赖状态:

    • 只有当 GlobalCache.TestPowerReadStatus 为 true 时,才允许调用 MingShengInterop.LabVIEWExports.PSRead。

  3. 设置 false 立即停止:

    • 一旦 AUXRealTimeState1.TestPowerStatus 被设置为 false,需要立即将 GlobalCache.TestPowerReadStatus 设置为 false,从而停止 PSRead 调用。

  4. 交流接触器时间差:

    • 由于交流接触器闭合存在时间差,硬件状态可能会有短暂波动(例如短暂为 true),需要确保逻辑稳定,避免误读。

问题:

  • 当前代码中,AUXSET 和 Read 方法都只在 TestPowerStatus 为 true 时设置 GlobalCache.TestPowerReadStatus = true,但没有处理 TestPowerStatus 为 false 的情况。这导致一旦 TestPowerReadStatus 被置为 true,即使硬件状态变为 false,也无法及时停止 PSRead。

  • Read 方法的轮询可能导致性能问题,尤其是在高频调用或多线程环境中。

  • 交流接触器的时间差可能导致状态短暂波动,需要更稳定的状态管理机制。

优化目标

  1. 状态同步:

    • 确保 GlobalCache.TestPowerReadStatus 实时反映 AUXRealTimeState1.TestPowerStatus 的状态,true 时允许 PSRead,false 时立即停止。

  2. 处理时间差:

    • 通过去抖动机制或延迟确认,解决交流接触器时间差导致的状态波动问题。

  3. 性能优化:

    • 优化 Read 方法的轮询机制,减少不必要的资源消耗。

  4. 线程安全:

    • 如果代码运行在多线程环境中,确保状态访问和修改是线程安全的。

  5. 可维护性:

    • 代码逻辑清晰,添加日志便于调试。

优化后的代码

以下是优化后的代码,解决了状态同步、时间差和性能问题:

csharp

// 全局变量,用于去抖动
private bool _lastTestPowerStatus = false;
private int _falseCount = 0;
private const int FalseThreshold = 3; // 连续检测到 false 的次数阈值,防止短暂波动

public void AUXSET()
{
    lock (_lock) // 线程安全
    {
        var TestPowerStatus = AUXRealTimeState1.TestPowerStatus;
        UpdatePowerReadStatus(TestPowerStatus);
    }
}

public void Read()
{
    while (!m_Dis)
    {
        lock (_lock) // 线程安全
        {
            var TestPowerStatus = AUXRealTimeState1.TestPowerStatus;
            UpdatePowerReadStatus(TestPowerStatus);
        }
        Thread.Sleep(100); // 保留原有 100ms 轮询间隔
    }
}

// 提取状态更新逻辑,统一管理
private readonly object _lock = new object();
private void UpdatePowerReadStatus(bool TestPowerStatus)
{
    if (TestPowerStatus)
    {
        _lastTestPowerStatus = true;
        _falseCount = 0; // 重置计数器
        GlobalCache.TestPowerReadStatus = true;
    }
    else
    {
        if (_lastTestPowerStatus)
        {
            _falseCount++;
            if (_falseCount >= FalseThreshold)
            {
                GlobalCache.TestPowerReadStatus = false; // 连续多次 false 才停止
                _lastTestPowerStatus = false;
            }
        }
        else
        {
            GlobalCache.TestPowerReadStatus = false; // 已经为 false,直接保持
        }
    }
    // 日志记录状态变化
    Console.WriteLine($"UpdatePowerReadStatus: TestPowerStatus={TestPowerStatus}, TestPowerReadStatus={GlobalCache.TestPowerReadStatus}, FalseCount={_falseCount}");
}

// PSRead 调用逻辑
if (GlobalCache.TestPowerReadStatus)
{
    lock (_lock) // 线程安全
    {
        MingShengInterop.LabVIEWExports.PSRead(HWSelect,
                                               out pSRealV,
                                               out pSRealI,
                                               out PSStatus,
                                               out Error,
                                               out dutRealV);
        Console.WriteLine("PSRead executed");
    }
}
else
{
    Console.WriteLine("PSRead skipped due to TestPowerReadStatus=false");
}

优化点说明

  1. 状态同步:

    • 在 AUXSET 和 Read 方法中,通过统一的 UpdatePowerReadStatus 方法管理 GlobalCache.TestPowerReadStatus。

    • 当 TestPowerStatus 为 true 时,立即设置 GlobalCache.TestPowerReadStatus = true,允许 PSRead。

    • 当 TestPowerStatus 为 false 时,结合去抖动机制(见下文),确保状态稳定后才停止 PSRead。

  2. 去抖动机制:

    • 使用 _falseCount 和 FalseThreshold(默认设为 3 次,约 300ms)来处理交流接触器的时间差。

    • 只有连续多次(例如 3 次,每次 100ms)检测到 TestPowerStatus = false,才将 GlobalCache.TestPowerReadStatus 设置为 false,避免短暂波动导致误停止。

    • 如果状态已经稳定为 false(_lastTestPowerStatus = false),直接保持 TestPowerReadStatus = false。

  3. 线程安全:

    • 使用 lock (_lock) 保护 GlobalCache.TestPowerReadStatus 的读写操作,确保多线程环境下状态一致。

    • PSRead 调用也加锁,防止并发访问问题。

  4. 性能优化:

    • 保留了原有的 Thread.Sleep(100),以保持 100ms 的轮询间隔,符合硬件读取需求。

    • 通过提取 UpdatePowerReadStatus 方法,减少重复代码,提升可维护性。

    • 日志记录帮助快速定位状态问题,减少调试成本。

  5. 时间差处理:

    • 去抖动机制(FalseThreshold)确保交流接触器闭合时间差不会导致 TestPowerReadStatus 频繁切换。

    • 可根据实际时间差调整 FalseThreshold(例如,若时间差为 200ms,可设为 2 或 3)。

进一步优化建议

  1. 调整去抖动阈值:

    • 如果已知交流接触器的闭合时间差(例如 200ms),可以调整 FalseThreshold 为 200 / 100 = 2,以更精确匹配硬件特性。

    • 示例:将 FalseThreshold 设为 2,表示连续 2 次(200ms)检测到 false 才停止。

  2. 异步轮询:

    • 如果 Read 方法的阻塞式轮询影响性能,可以改用异步方式,释放线程资源。

    • 示例:

      csharp

      public async Task Read()
      {
          while (!m_Dis)
          {
              lock (_lock)
              {
                  var TestPowerStatus = AUXRealTimeState1.TestPowerStatus;
                  UpdatePowerReadStatus(TestPowerStatus);
              }
              await Task.Delay(100); // 异步延迟
          }
      }
    • 注意:调用方需支持异步(await Read())。

  3. 事件驱动替代轮询:

    • 如果硬件支持状态变更通知(例如事件或回调),可以替换 Read 方法的轮询机制,改为事件驱动,减少 CPU 占用。

    • 示例(假设硬件提供 TestPowerStatusChanged 事件):

      csharp

      public void Initialize()
      {
          AUXRealTimeState1.TestPowerStatusChanged += (sender, newStatus) =>
          {
              lock (_lock)
              {
                  UpdatePowerReadStatus(newStatus);
              }
          };
      }
  4. 状态机:

    • 如果系统复杂,考虑使用状态机明确管理硬件状态(如“开启”、“关闭”、“过渡”),提高代码可维护性。

  5. 性能监控:

    • 增加性能计数器,记录 PSRead 调用频率和状态切换次数,优化轮询间隔或去抖动阈值。

总结

优化后的代码通过统一的 UpdatePowerReadStatus 方法管理状态,结合去抖动机制处理交流接触器的时间差,确保 TestPowerStatus 为 true 时允许 PSRead,而一旦稳定为 false 就立即停止。线程安全机制和日志记录提升了可靠性和可调试性。如果能提供具体的时间差时长或硬件特性,我可以进一步调整 FalseThreshold 或提出更精确的方案!

你可能感兴趣的:(C#实战教程,前端,数据库,c#)