Приложение Data Analytics со многими MDF-файлами

В этом примере показано, как исследовать степень батареи транспортного средства в режиме разряда в различных циклах привода. Данные для этого анализа содержатся в наборе файлов журнала транспортных средств в формате MDF. В данном примере нам нужно создать механизм, который может «обнаружить», когда батарея транспортного средства находится в заданном режиме. Что мы действительно делаем, так это строим детектор, чтобы определить, когда интересующий сигнал (батарея степени в этом случае) соответствует конкретным критериям. Когда критерии будут удовлетворены, мы назовем это «событием». Каждое событие будет впоследствии «квалифицировано» путем установления временных границ. То есть событие «квалифицировано», если оно сохраняется не менее 5 секунд (такой шаг проверки может помочь ограничить шум и удалить переходные процессы). Пороги, показанные в этом примере, являются только иллюстративными.

Установка местоположения источника данных

Определите местоположение набора файлов для анализа.

dataDir = '*.dat';

Получение информации о наборе файлов

Получите имена всех MDF-файлов для анализа в один массив ячеек.

fileList = dir(dataDir);
fileName = {fileList(:).name}';
fileDir  = {fileList(:).folder}';
fullFilePath = fullfile(fileDir, fileName)
fullFilePath = 5x1 cell
    {'/tmp/BR2021ad_1655202_62692/mlx_to_docbook1/tp4da62608/vnt-ex86857001/ADAC.dat' }
    {'/tmp/BR2021ad_1655202_62692/mlx_to_docbook1/tp4da62608/vnt-ex86857001/ECE.dat'  }
    {'/tmp/BR2021ad_1655202_62692/mlx_to_docbook1/tp4da62608/vnt-ex86857001/HWFET.dat'}
    {'/tmp/BR2021ad_1655202_62692/mlx_to_docbook1/tp4da62608/vnt-ex86857001/SC03.dat' }
    {'/tmp/BR2021ad_1655202_62692/mlx_to_docbook1/tp4da62608/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 для последующего анализа. The head функция используется для отображения первых 5 строк таблицы eventSummary.

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. The axes with title Distribution of Event Duration contains an object of type histogram.

Теперь посмотрите на Mean Степени vs. Event Длительности.

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. The axes with title Mean Power vs. Event Duration 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

Создайте объект MDF, чтобы считать данные из MDF-файла.

mdfObj = mdf(fullFilePath{fileMsk})
mdfObj = 
  MDF with properties:

   File Details
                 Name: 'HWFET.dat'
                 Path: '/tmp/BR2021ad_1655202_62692/mlx_to_docbook1/tp4da62608/vnt-ex86857001/HWFET.dat'
               Author: ''
           Department: ''
              Project: ''
              Subject: ''
              Comment: ''
              Version: '3.00'
             DataSize: 3167040
     InitialTimestamp: 2017-08-09 12:20:03.000000000

   Creator Details
    ProgramIdentifier: 'MDA v7.1'
              Creator: [1x1 struct]

   File Contents
           Attachment: [0x1 struct]
         ChannelNames: {{5x1 cell}}
         ChannelGroup: [1x1 struct]

   Options
           Conversion: Numeric

Идентифицируйте канал с channelList и считайте все данные из этого файла.

chInfo = channelList(mdfObj, chName)
chInfo=1×9 table
    ChannelName    ChannelGroupNumber    ChannelGroupNumSamples    ChannelGroupAcquisitionName    ChannelGroupComment    ChannelDisplayName    ChannelUnit    ChannelComment    ChannelDescription
    ___________    __________________    ______________________    ___________________________    ___________________    __________________    ___________    ______________    __________________

      "Power"              1                     79176                     <undefined>                cg comment                 ""            <undefined>     <undefined>              ""        

data = read(mdfObj, chInfo)
data = 1x1 cell array
    {79176x1 timetable}

Обратите внимание, что чтение с выходом channelList возвращает массив ячеек результатов.

data{1}(1:10,:)
ans=10×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

Визуализация с помощью пользовательской функции построения графика

Пользовательские функции построения графика полезны для инкапсуляции и повторного использования. Визуализируйте событие в контексте всего цикла дисков. Чтобы понять, как была создана визуализация, откройте и исследуйте eventPlotter функция из этого примера.

eventPlotter(data{1}, eventOfInterest)

Figure contains an axes. The axes with title HWFET.dat contains 2 objects of type line. These objects represent Raw Signal, Event.

Закройте файл

Закройте доступ к MDF-файлу путем удаления его переменной из рабочей области.

clear mdfObj