NiDA 1.0.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package NiDA --version 1.0.1
                    
NuGet\Install-Package NiDA -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NiDA" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NiDA" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="NiDA" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NiDA --version 1.0.1
                    
#r "nuget: NiDA, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NiDA@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NiDA&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=NiDA&version=1.0.1
                    
Install as a Cake Tool

NiDA 使用说明文档

目录

  1. 概述
  2. 功能特性
  3. 系统要求
  4. 快速开始
  5. API 参考
  6. 配置指南
  7. 事件处理
  8. 错误处理
  9. 数据平滑
  10. 数据映射
  11. 最佳实践

概述

NiDA(National Instruments Data Acquisition)是一个基于 .NET 8.0 的 NI-DAQmx 驱动封装库,专注于简化和规范 NI 数据采集设备的使用流程。

该库提供了设备连接、数据采集、模拟输出、数据平滑、数据映射等核心功能,适用于工业自动化、实验室测量、传感器数据采集等应用场景。


功能特性

  • 设备管理:自动发现可用 NI 设备,获取设备信息
  • 模拟输入:支持单次采样和连续采集模式
  • 模拟输出:支持单点输出和波形输出
  • 数据缓存:线程安全的环形数据缓存区
  • 数据平滑:支持移动平均、中值滤波、高斯滤波三种算法
  • 数据映射:支持电压值到物理量(温度、压力等)的线性映射
  • 事件驱动:提供数据采集、状态变化、错误发生等事件通知
  • 配置管理:支持配置的序列化保存和加载
  • 日志记录:自动记录错误日志到文件

系统要求

  • 操作系统:Windows 10/11
  • .NET 版本:.NET 8.0 或更高版本
  • 驱动要求:NI-DAQmx 驱动已安装
  • 硬件:支持 NI-DAQmx 的 NI 设备(如 USB-6001/6002/6003 等)

快速开始

1. 基本使用流程

using NiDA.Config;
using NiDA.Core;

// 步骤1:创建设备配置
DeviceConfig config = new DeviceConfig
{
    DeviceName = "Dev1",
    InputChannel = "ai0",
    OutputChannel = "ao0",
    SampleRate = 1000,
    SampleCount = 100
};

// 步骤2:使用配置初始化设备
NiDevice device = new NiDevice(config);

// 步骤3:初始化设备
if (device.Initialize())
{
    // 步骤4:开始数据采集
    device.StartAcquisition();

    // 步骤5:处理数据(通过事件或缓存)
    // ...

    // 步骤6:停止采集
    device.StopAcquisition();
}

// 步骤7:释放资源
device.Dispose();

2. 使用事件处理数据

// 订阅数据采集事件
device.DataCollected += (sender, e) =>
{
    double[] rawData = e.RawData;      // 原始电压数据
    double[] mappedData = e.MappedData; // 映射后的物理量数据
    DateTime timestamp = e.Timestamp;    // 采集时间戳
};

// 订阅状态变化事件
device.StatusChanged += (sender, e) =>
{
    Console.WriteLine($"状态变化: {e.OldStatus} -> {e.NewStatus}");
    Console.WriteLine($"消息: {e.Message}");
};

// 订阅错误事件
device.ErrorOccurred += (sender, e) =>
{
    Console.WriteLine($"错误: {e.Message}");
    Console.WriteLine($"错误码: {e.ErrorCode}");
    Console.WriteLine($"建议: {e.RecoverySuggestion}");
};

API 参考

NiDevice 类

设备操作核心类,提供所有设备交互功能。

构造函数
构造函数 说明
NiDevice() 使用默认配置创建设备实例
NiDevice(DeviceConfig config) 使用指定配置创建设备实例
属性
属性 类型 说明
Status DeviceStatus 当前设备状态
Config DeviceConfig 当前设备配置
DataMapper IDataMapper 数据映射器
DataSmoother ISmoother 数据平滑器
DataCache ConcurrentQueue<double> 数据缓存队列
CacheCount int 缓存中的数据数量
方法
方法 说明
Initialize() 初始化设备,建立连接
StartAcquisition() 开始连续数据采集
StopAcquisition() 停止数据采集
ReadSingleSample() 同步采集一次数据
ReadSingleSampleAsync() 异步采集一次数据
WriteAnalogOutput(value, useMappedValue) 写入单点模拟输出
WriteAnalogOutputAsync(value, useMappedValue) 异步写入单点模拟输出
WriteAnalogOutputWaveform(values, useMappedValue) 写入模拟输出波形
WriteAnalogOutputWaveformAsync(values, useMappedValue) 异步写入模拟输出波形
GetCachedData() 获取所有缓存数据
ClearCache() 清空数据缓存
UpdateConfig(config) 更新设备配置
Dispose() 释放设备资源
事件
事件 说明
DataCollected 数据采集完成时触发
StatusChanged 设备状态变化时触发
ErrorOccurred 发生错误时触发

配置指南

DeviceConfig 配置项

配置项 类型 默认值 说明
DeviceName string "Dev1" 设备名称
InputChannel string "ai0" 模拟输入通道
OutputChannel string "ao0" 模拟输出通道
SampleRate double 1000 采样率(Hz)
SampleCount int 100 每次采集的样本数
InputMinVoltage double -10.0 输入电压范围最小值(V)
InputMaxVoltage double 10.0 输入电压范围最大值(V)
OutputMinVoltage double -10.0 输出电压范围最小值(V)
OutputMaxVoltage double 10.0 输出电压范围最大值(V)
TerminalConfiguration string "Rse" 终端配置(Rse/Diff/Nrse/PseudoDiff)
CacheSize int 10000 数据缓存大小
EnableMapping bool false 是否启用数据映射
MappingSlope double 1.0 映射斜率
MappingIntercept double 0.0 映射截距
MappingUnit string "" 映射单位(如 "°C")
EnableSmoothing bool false 是否启用数据平滑
SmoothingAlgorithm enum MovingAverage 平滑算法类型
SmoothingWindowSize int 5 平滑窗口大小
SmoothingSigma double 1.0 高斯滤波标准差

配置保存和加载

using NiDA.Config;

// 保存配置到文件
DeviceConfig config = new DeviceConfig { DeviceName = "Dev1" };
ConfigManager.SaveConfig(config, "my_config.json");

// 从文件加载配置
DeviceConfig loadedConfig = ConfigManager.LoadConfig("my_config.json");

// 检查配置文件是否存在
bool exists = ConfigManager.ConfigExists("my_config.json");

// 验证配置文件有效性
bool isValid = ConfigManager.ValidateConfigFile("my_config.json");

// 重置为默认配置
DeviceConfig defaultConfig = ConfigManager.ResetToDefault();

// 克隆配置
DeviceConfig clonedConfig = ConfigManager.CloneConfig(config);

预设配置

// 获取默认配置
DeviceConfig defaultConfig = DeviceConfig.CreateDefault();

// 创建高精度配置(高采样率场景)
DeviceConfig highPrecisionConfig = DeviceConfig.CreateHighPrecision();
// SampleRate = 10000, SampleCount = 1000, CacheSize = 100000

// 创建低功耗配置(低采样率场景)
DeviceConfig lowPowerConfig = DeviceConfig.CreateLowPower();
// SampleRate = 100, SampleCount = 10, CacheSize = 1000

事件处理

DataCollectedEventArgs

采集到新数据时触发的事件参数。

public class DataCollectedEventArgs : EventArgs
{
    public double[] RawData { get; }      // 原始电压数据
    public double[] MappedData { get; }   // 映射后的数据(如果有)
    public DateTime Timestamp { get; }    // 采集时间戳
    public bool HasMappedData { get; }    // 是否有映射数据
}

StatusChangedEventArgs

设备状态变化时触发的事件参数。

public class StatusChangedEventArgs : EventArgs
{
    public DeviceStatus NewStatus { get; }  // 新状态
    public DeviceStatus OldStatus { get; }  // 旧状态
    public string Message { get; }           // 状态消息
}

ErrorOccurredEventArgs

发生错误时触发的事件参数。

public class ErrorOccurredEventArgs : EventArgs
{
    public string Message { get; }              // 错误消息
    public ErrorType ErrorType { get; }          // 错误类型
    public int ErrorCode { get; }                // 错误码
    public string RecoverySuggestion { get; }   // 恢复建议
}

设备状态枚举

public enum DeviceStatus
{
    Uninitialized,  // 未初始化
    Initialized,    // 已初始化
    Connected,      // 已连接
    Acquiring,      // 正在采集
    Stopped,        // 已停止
    Error           // 错误状态
}

错误处理

异常类型

异常类型 说明
AcquisitionException 数据采集相关异常
ConfigurationException 配置相关异常
ConnectionException 设备连接相关异常
DeviceException 设备操作基类异常
MappingException 数据映射相关异常

异常处理示例

try
{
    DeviceConfig config = ConfigManager.LoadConfig();
    NiDevice device = new NiDevice(config);

    if (!device.Initialize())
    {
        Console.WriteLine("设备初始化失败");
        return;
    }

    device.StartAcquisition();
}
catch (AcquisitionException ex)
{
    Console.WriteLine($"采集异常: {ex.Message}");
    ErrorLogger.LogException(ex);
}
catch (ConnectionException ex)
{
    Console.WriteLine($"连接异常: {ex.Message}");
    ErrorLogger.LogException(ex);
}
catch (ConfigurationException ex)
{
    Console.WriteLine($"配置异常: {ex.Message}");
    ErrorLogger.LogException(ex);
}
catch (Exception ex)
{
    Console.WriteLine($"未知异常: {ex.Message}");
    ErrorLogger.LogException(ex);
}

日志文件

错误日志自动记录到 Logs/NiDataAcquisition_YYYYMMDD.log 文件。

// 手动记录错误
ErrorLogger.LogError(ErrorLogger.ErrorType.Connection, "连接失败", ex);

// 手动记录信息
ErrorLogger.LogInfo("设备初始化成功");

// 获取当前日志文件路径
string logPath = ErrorLogger.GetLogFilePath();

数据平滑

支持的平滑算法

算法 枚举值 说明
移动平均 MovingAverage 计算窗口内数据的平均值
中值滤波 Median 取窗口内数据的中值
高斯滤波 Gaussian 高斯权重加权平均

使用数据平滑

// 方法1:通过配置启用平滑
DeviceConfig config = new DeviceConfig
{
    EnableSmoothing = true,
    SmoothingAlgorithm = SmoothingAlgorithm.MovingAverage,
    SmoothingWindowSize = 5
};
NiDevice device = new NiDevice(config);

// 方法2:直接设置平滑器
device.DataSmoother = new MovingAverageSmoother { WindowSize = 5 };
// 或
device.DataSmoother = new MedianSmoother { WindowSize = 5 };
// 或
device.DataSmoother = new GaussianSmoother { WindowSize = 5, Sigma = 1.0 };

ISmoother 接口

public interface ISmoother
{
    int WindowSize { get; set; }      // 平滑窗口大小
    double Smooth(double[] data);      // 平滑单个值(重载版本)
    double[] SmoothArray(double[] data); // 平滑数组
}

数据映射

数据映射功能将原始电压值转换为物理量值。

映射公式

物理量 = 电压 × 斜率 + 截距
电压 = (物理量 - 截距) / 斜率

使用数据映射

// 方法1:通过配置启用映射
DeviceConfig config = new DeviceConfig
{
    EnableMapping = true,
    MappingSlope = 100.0,      // 例如:电压到温度的斜率
    MappingIntercept = -273.15, // 例如:转换为摄氏度
    MappingUnit = "°C"         // 单位
};
NiDevice device = new NiDevice(config);

// 方法2:直接设置映射器
device.DataMapper = new LinearDataMapper(
    slope: 100.0,
    intercept: -273.15,
    unit: "°C",
    isEnabled: true
);

// 手动映射
double voltage = 2.73;  // 输入电压
double temperature = device.DataMapper.Map(voltage);  // 转换为温度

// 反向映射(物理量转电压)
double outputVoltage = device.DataMapper.ReverseMap(25.0);  // 25°C 转电压

IDataMapper 接口

public interface IDataMapper
{
    bool IsEnabled { get; set; }           // 是否启用映射
    string Unit { get; set; }              // 物理量单位
    double Map(double rawValue);           // 单值映射
    double ReverseMap(double mappedValue); // 单值反向映射
    double[] MapArray(double[] rawValues); // 批量映射
    double[] ReverseMapArray(double[] mappedValues); // 批量反向映射
}

自定义映射器

// 实现 IDataMapper 接口
public class CustomDataMapper : IDataMapper
{
    public bool IsEnabled { get; set; } = true;
    public string Unit { get; set; } = "";

    public double Map(double rawValue)
    {
        // 自定义映射逻辑
        return Math.Pow(rawValue, 2) * 10;
    }

    public double ReverseMap(double mappedValue)
    {
        // 自定义反向映射逻辑
        return Math.Sqrt(mappedValue / 10);
    }

    public double[] MapArray(double[] rawValues)
    {
        return rawValues.Select(Map).ToArray();
    }

    public double[] ReverseMapArray(double[] mappedValues)
    {
        return mappedValues.Select(ReverseMap).ToArray();
    }
}

// 使用自定义映射器
device.DataMapper = new CustomDataMapper { IsEnabled = true, Unit = "custom" };

最佳实践

1. 资源管理

// 使用 using 语句确保资源正确释放
using (NiDevice device = new NiDevice(config))
{
    device.Initialize();
    device.StartAcquisition();

    // 处理数据...
}
// 设备资源在这里自动释放

2. 线程安全

// DataCache 是线程安全的 ConcurrentQueue
device.DataCollected += (sender, e) =>
{
    // 可以安全地从多个线程访问
    double[] data = device.GetCachedData();
};

// 使用缓存数据时建议复制
device.DataCollected += (sender, e) =>
{
    double[] dataCopy = device.GetCachedData().ToArray();
    // 处理副本...
};

3. 配置验证

// 保存配置前验证
if (config.IsValid())
{
    ConfigManager.SaveConfig(config);
}
else
{
    Console.WriteLine("配置无效,请检查参数");
}

4. 异步操作

// 使用异步方法避免阻塞 UI 线程
private async Task StartAcquisitionAsync()
{
    await Task.Run(() =>
    {
        device.StartAcquisition();
    });

    // 或使用异步单次采集
    double[] data = await device.ReadSingleSampleAsync();
}

5. 错误恢复

device.ErrorOccurred += (sender, e) =>
{
    if (e.RecoverySuggestion != null)
    {
        Console.WriteLine($"建议: {e.RecoverySuggestion}");
    }

    // 根据错误类型执行恢复
    switch (e.ErrorType)
    {
        case ErrorType.Connection:
            // 尝试重新连接
            break;
        case ErrorType.Acquisition:
            // 尝试重启采集
            break;
    }
};

完整示例

完整数据采集示例

using NiDA.Config;
using NiDA.Core;
using NiDA.Events;
using System.Collections.Concurrent;

class DataAcquisitionExample
{
    private static ConcurrentQueue<double> dataBuffer = new();

    public static void Run()
    {
        // 1. 创建并配置设备
        DeviceConfig config = new DeviceConfig
        {
            DeviceName = "Dev1",
            InputChannel = "ai0",
            OutputChannel = "ao0",
            SampleRate = 1000,
            SampleCount = 100,
            EnableMapping = true,
            MappingSlope = 100.0,
            MappingIntercept = 0,
            MappingUnit = "mV",
            EnableSmoothing = true,
            SmoothingAlgorithm = SmoothingAlgorithm.MovingAverage,
            SmoothingWindowSize = 5
        };

        // 2. 创建设备实例
        using (NiDevice device = new NiDevice(config))
        {
            // 3. 订阅事件
            device.DataCollected += OnDataCollected;
            device.StatusChanged += OnStatusChanged;
            device.ErrorOccurred += OnErrorOccurred;

            // 4. 初始化设备
            if (!device.Initialize())
            {
                Console.WriteLine("设备初始化失败");
                return;
            }

            // 5. 开始采集
            Console.WriteLine("开始数据采集...");
            device.StartAcquisition();

            // 6. 等待采集数据
            Thread.Sleep(5000);

            // 7. 停止采集
            device.StopAcquisition();

            // 8. 获取并处理缓存数据
            double[] cachedData = device.GetCachedData();
            Console.WriteLine($"缓存数据点数: {cachedData.Length}");
        }
        // 9. 设备资源自动释放
    }

    private static void OnDataCollected(object sender, DataCollectedEventArgs e)
    {
        foreach (double value in e.RawData)
        {
            dataBuffer.Enqueue(value);
        }

        if (e.HasMappedData)
        {
            double avgMapped = e.MappedData.Average();
            Console.WriteLine($"平均映射值: {avgMapped:F2} {e.MappedData.Length}");
        }
    }

    private static void OnStatusChanged(object sender, StatusChangedEventArgs e)
    {
        Console.WriteLine($"状态: {e.OldStatus} -> {e.NewStatus}");
    }

    private static void OnErrorOccurred(object sender, ErrorOccurredEventArgs e)
    {
        Console.WriteLine($"错误 [{e.ErrorCode}]: {e.Message}");
        if (e.RecoverySuggestion != null)
        {
            Console.WriteLine($"建议: {e.RecoverySuggestion}");
        }
    }
}

模拟输出示例

public static void AnalogOutputExample()
{
    DeviceConfig config = new DeviceConfig
    {
        DeviceName = "Dev1",
        OutputChannel = "ao0",
        OutputMinVoltage = -10.0,
        OutputMaxVoltage = 10.0
    };

    using (NiDevice device = new NiDevice(config))
    {
        device.Initialize();

        // 单点输出(直接电压值)
        device.WriteAnalogOutput(2.5);  // 输出 2.5V

        // 单点输出(使用映射值)
        device.WriteAnalogOutput(25.0, useMappedValue: true);  // 假设映射系数为 0.1,输出 2.5V

        // 波形输出
        double[] waveform = Enumerable.Range(0, 100)
            .Select(i => 5.0 * Math.Sin(2 * Math.PI * i / 100))
            .ToArray();
        device.WriteAnalogOutputWaveform(waveform);

        device.Dispose();
    }
}

版本信息

  • 版本: 1.0.0
  • 框架: .NET 8.0
  • 依赖: NationalInstruments.DAQmx
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.6 110 6/6/2026
1.0.5 97 6/6/2026
1.0.4 105 6/6/2026
1.0.3 110 5/11/2026
1.0.2 110 5/10/2026
1.0.1 98 5/10/2026
1.0.0 100 5/10/2026