Main Content

对多个 MDF 文件进行数据分析

以下示例说明如何研究多个驾驶周期间放电模式下的车辆电池电量。用于此分析的数据包含在一组 MDF 格式的车辆日志文件中。对于此示例,我们需要建立一种机制,用于“检测”车辆电池何时处于给定模式。我们真正要做的是建立一个探测器,以确定何时关注的信号(在本例中为电池电量)满足特定条件。当条件得到满足时,我们称之为一个“事件”。每个事件都需要满足一定的时间限制才算是“合格”事件。也就是说,事件至少要持续 5 秒,才算是一个“合格的”事件。这种鉴定步骤有助于限制噪声和消除瞬变。此示例中显示的阈值仅用于举例说明。

设置数据源位置

定义要分析的文件集的位置。

dataDir = '*.dat';

获取文件集信息

将要分析的所有 MDF 文件的名称放入一个元胞数组中。

fileList     = dir(dataDir);
fileName     = {fileList(:).name}';
fileDir      = {fileList(:).folder}';
fullFilePath = fullfile(fileDir, fileName)
fullFilePath = 5x1 cell
    {'/tmp/Bdoc24a_2511836_3070643/tp8879c7f7/vnt-ex86857001/ADAC.dat' }
    {'/tmp/Bdoc24a_2511836_3070643/tp8879c7f7/vnt-ex86857001/ECE.dat'  }
    {'/tmp/Bdoc24a_2511836_3070643/tp8879c7f7/vnt-ex86857001/HWFET.dat'}
    {'/tmp/Bdoc24a_2511836_3070643/tp8879c7f7/vnt-ex86857001/SC03.dat' }
    {'/tmp/Bdoc24a_2511836_3070643/tp8879c7f7/vnt-ex86857001/US06.dat' }

预分配输出数据元胞数组

使用一个元胞数组来捕获一组迷你表,这些表用来表示每个 MDF 文件所关注的事件数据。

numFiles = size(fullFilePath, 1);
eventSet = cell(numFiles, 1)
eventSet=5×1 cell array
    {0x0 double}
    {0x0 double}
    {0x0 double}
    {0x0 double}
    {0x0 double}

定义事件检测和通道信息条件

chName = 'Power';         % Name of the signal of interest in the MDF files
thdValue = [5, 55];       % Threshold in KW
thdDuration = seconds(5); % Threshold for event qualification

循环遍历每个 MDF 文件并应用事件检测器函数

eventSet 是一个元胞数组,其中包含已分析的每个文件的摘要表。您可以将这个由表组成的元胞数组视为一组迷你表,所有这些迷你表都具有相同的格式,但每个迷你表的内容分别对应于不同的 MDF 文件。

在此示例中,事件检测器不仅报告事件的开始和结束时间,还报告有关事件本身的一些描述性统计量。这种聚合和报告可用于发现活动和对活动进行故障排除。要更详细地了解 MDF 文件对接和数据处理,请打开并探查此示例中的 processMDF 函数。

请注意本例的数据处理方式,它以原子方式解析每个 MDF 文件,并将解析结果返回到结果元胞数组中对应的索引位置。这允许处理函数通过 parfor 利用并行计算功能。parfor 和标准 for 在输出方面可以互换,但两者在完成分析所需的处理时间上有所不同。要试验并行计算,只需将下面的 for 调用更改为 parfor 并运行示例即可。

for i = 1:numFiles
    eventSet{i} = processMDF(fullFilePath{i}, chName, thdValue, thdDuration);
end
eventSet{1}
ans=20×8 table
    FileName    EventNumber    EventDuration    EventStart    EventStop     MeanPower_KW    MaxPower_KW    MinPower_KW
    ________    ___________    _____________    __________    __________    ____________    ___________    ___________

    ADAC.dat        2            00:01:22       19.345 sec    101.79 sec       28.456           53.5              5   
    ADAC.dat        3            00:00:08       107.82 sec    116.36 sec       21.295           53.5           5.09   
    ADAC.dat        5            00:00:55        123.8 sec    179.67 sec       28.642           37.2           5.01   
    ADAC.dat        6            00:00:10       189.83 sec    200.36 sec       11.192           54.4            5.1   
    ADAC.dat        8            00:00:40        212.4 sec    252.79 sec       28.539           37.4           5.01   
    ADAC.dat        9            00:00:08       258.76 sec    267.37 sec       21.289           53.7           5.02   
    ADAC.dat        11           00:00:44       274.81 sec    319.79 sec       28.554           37.2           5.08   
    ADAC.dat        12           00:00:08       325.75 sec    334.37 sec       21.279           53.7           5.05   
    ADAC.dat        14           00:00:44       341.81 sec    386.79 sec       28.554           37.2           5.08   
    ADAC.dat        15           00:00:08       392.75 sec    401.37 sec       21.278           53.7           5.04   
    ADAC.dat        17           00:00:44       408.81 sec    453.67 sec       28.579           37.2           5.08   
    ADAC.dat        18           00:00:07       463.77 sec    471.37 sec       11.895         54.676           5.04   
    ADAC.dat        20           00:00:40       483.44 sec    523.79 sec       28.544         37.363         5.0682   
    ADAC.dat        21           00:00:08       529.75 sec    538.37 sec       21.279           53.7           5.05   
    ADAC.dat        23           00:00:44       545.81 sec    590.79 sec       28.553           37.2           5.08   
    ADAC.dat        24           00:00:08       596.75 sec    605.37 sec       21.279           53.7           5.05   
      ⋮

串联结果

将元胞数组 eventSet 的内容合并到一个表中。我们现在可以使用表 eventSummary 进行后续分析。head 函数用于显示表 eventSummary 的前 5 行。

eventSummary = vertcat(eventSet{:});
disp(head(eventSummary, 5))
    FileName    EventNumber    EventDuration    EventStart    EventStop     MeanPower_KW    MaxPower_KW    MinPower_KW
    ________    ___________    _____________    __________    __________    ____________    ___________    ___________

    ADAC.dat         2           00:01:22       19.345 sec    101.79 sec       28.456          53.5              5    
    ADAC.dat         3           00:00:08       107.82 sec    116.36 sec       21.295          53.5           5.09    
    ADAC.dat         5           00:00:55        123.8 sec    179.67 sec       28.642          37.2           5.01    
    ADAC.dat         6           00:00:10       189.83 sec    200.36 sec       11.192          54.4            5.1    
    ADAC.dat         8           00:00:40        212.4 sec    252.79 sec       28.539          37.4           5.01    

可视化摘要结果以确定后续步骤

查看事件持续时间的概览。

histogram(eventSummary.EventDuration)
grid on
title 'Distribution of Event Duration'
xlabel 'Event Duration (minutes)'
ylabel 'Frequency'

Figure contains an axes object. The axes object with title Distribution of Event Duration, xlabel Event Duration (minutes), ylabel Frequency contains an object of type histogram.

现在看看均值电量与事件持续时间。

scatter(eventSummary.MeanPower_KW, minutes(eventSummary.EventDuration))
grid on
xlabel 'MeanPower(KW)'
ylabel 'Event Duration (minutes)'
title 'Mean Power vs. Event Duration'

Figure contains an axes object. The axes object with title Mean Power vs. Event Duration, xlabel MeanPower(KW), ylabel Event Duration (minutes) contains an object of type scatter.

深入分析关注的事件

检查持续时间超过 4 分钟的事件。首先,创建一个封装来查找关注的情形。msk 是逻辑索引,用于显示表 eventSummary 的哪些行满足指定的条件。

msk = eventSummary.EventDuration > minutes(4);

提取表 eventSummary 中满足指定条件的行并显示结果。

eventOfInterest = eventSummary(msk, :);
disp(eventOfInterest)
    FileName     EventNumber    EventDuration    EventStart    EventStop     MeanPower_KW    MaxPower_KW    MinPower_KW
    _________    ___________    _____________    __________    __________    ____________    ___________    ___________

    HWFET.dat        18           00:04:43       297.22 sec    580.37 sec       12.275          30.2          5.0024   

在整个驾驶周期背景中可视化此事件

我们需要完整的文件路径和文件名来从 MDF 文件中读取数据。表 eventOfInterest 具有文件名,因为我们对其进行了跟踪。它没有该文件的完整文件路径。为了获得这些信息,我们会对原始文件名和路径列表进行一些集合处理。首先,找到关注的文件的完整文件路径。

fileMsk = find(ismember(fileName, eventOfInterest.FileName))
fileMsk = 3

使用 mdfRead 从 MDF 文件中读取感兴趣的通道数据。

data = mdfRead(fullFilePath{fileMsk}, Channel=chName)
data = 1x1 cell array
    {79176x1 timetable}

data{1}
ans=79176×1 timetable
        time           Power  
    _____________    _________

    0.0048987 sec            0
    0.0088729 sec            0
    0.01 sec                 0
    0.013223 sec             0
    0.016446 sec             0
    0.019668 sec             0
    0.02 sec                 0
    0.021658 sec      -2.4e-28
    0.023878 sec     -3.42e-15
    0.026098 sec     -1.04e-14
    0.027766 sec      -1.9e-14
    0.029433 sec     -3.14e-14
    0.03 sec         -3.66e-14
    0.031341 sec     -5.14e-14
    0.032681 sec     -6.92e-13
    0.034022 sec     -1.56e-12
      ⋮

使用自定义绘图函数进行可视化

自定义绘图函数可用于封装和重用。在整个驾驶周期背景中可视化事件。要了解可视化的创建方式,请打开并探查此示例中的 eventPlotter 函数。

eventPlotter(data{1}, eventOfInterest)

Figure contains an axes object. The axes object with title HWFET.dat, xlabel Time (min), ylabel Power (KW) contains 2 objects of type line. One or more of the lines displays its values using only markers These objects represent Raw Signal, Event.