(三)运动学片段提取 2019年研究生数学建模D题《汽车行驶工况构建》

数据预处理阶段,我们成功对每个文件的异常数据做出了异常处理,下面我们开始对各个文件做运动学片段提取。

在这里首先插一句,其实预处理阶段,我们对数据的异常处理大部分都是以剔除的方式处理的,这种方式有利有弊!利处自然是简单省事,并且一般来说,产生的异常数据都是无效的,留着也没用,反而会影响片段时长的占比。但是弊处也有,那就是很有一部分的有用数据也被处理了。因为可能某段数据只是那么几个时间点异常,导致了整个片段不连续,直接不可以最为被挑选的对象,这样样本容量会减少,从而影响最终的工况曲线的表征能力。

可是,比赛时间有限呀!当时为了节省时间,我还是毫不犹豫地提出了上述情况地异常数据。一共提取到运动学片段 830 + 613 + 547 = 1990 个,这个数量还算比较合理。因为我们总共有 496464 条采集数据,在我们查到的文献里,采集数据量和我们差不多的也只有将近 2000 个运动学片段。

好的,下面开始讲片段提取方法。

运动学片段提取方法

运动学片段示意图(点击查看大图)

首先,得看懂这个图。简单的来说,一个运动学片段可以看作一个具有周期性的运动学速度-时间曲线图。运动学片段由怠速段和运动段组成,其中怠速段指的是速度一直保持为0的那一段曲线;运动段,顾名思义,在运动,那就是速度始终大于0的那一段曲线。整个合在一起叫一个运动学片段。你会发现,片段的起点速度为0,终点速度也是0。

此外,因为怠速段时长不允许超过180s,因为一旦超过180s就视为异常,所以当提取怠速段的时候,并不是两个运动段之间的所有速度为0的片段叫做怠速段。真正的怠速段定义应是,在运动段之前的180s以内的一段持续为0的片段,超过的部分直接忽略掉,而运动段后面是没有怠速段(速度为0)的。那是下一个运动学片段的,或者是多余的。


建模编程

由上面的分析,我们开始定义运动段的模型化的定义。

  • 首先,对于一段速度-时间曲线图,我们找到其中连续不为0的片段;

  • 然后,找到片段的前一个时间点速度为0且片段的后一个时间点速度也为0的这样的片段,这样的片段很有可能是运动段;

  • 接着,找出持续时间大于10s的片段,因为这样的片段才是比较合理的运动段;
  • 紧接着,从前一个时间点开始,逐点向前查找,速度是否持续大于0,一直到遇到速度不为0的时刻点,此时怠速段找到,这里有必要提一下毛刺处理,如果没有这个处理,将会因为毛刺,而提前终止怠速段的前向查找,导致怠速段时长变短,最终影响工况曲线构建,所以考虑毛刺的异常处理非常关键。此外,一直等于0也是不可以的,因为超过180s就属于异常,因此一旦长度到了180s就要从那里断开了;
  • 最后,把怠速段到运动段这短时间存起来,就得到一个运动学片段了。

为了更直观感受,给一个流程图:

运动学片段提取流程图(点击查看大图)

完整代码

下面给出完整代码:

  • 运动学片段提取代码
function kinepart = kinePartDetect(data)
datanew = data;
% 提取速度
data_temp = cell2mat(datanew(2:end,2));
fprintf('正在查找运动学片段...\n')
% 找出速度大于0的数据
v_index = find(data_temp(:,1)>0);
% 找出连续的片段
deal_index1 = is_continue(v_index);
% 统计连续片段长度
for i = 1:length(deal_index1)
    index1_length(i) = length(deal_index1{i});
end
% 找出超过10s的数据段
deal_index2 = deal_index1(index1_length > 10,1);
% 找出前后都为0的,符合要求的运动片段
is_part = zeros(length(deal_index2),1);
for i = 1:length(deal_index2)
    part_start = deal_index2{i,1}(1)-1;
    part_end = deal_index2{i,1}(end)+1;
    if (data_temp(part_start)==0) && (data_temp(part_end)==0)
        is_part(i) = 1;
    end
end
deal_index3 = deal_index2(is_part==1,1);
kinepart = cell(length(deal_index3),1);
% 找出前面180s范围内为0的那一段
for j = 1:length(deal_index3)
    for k = 1:180
        if deal_index3{j,1}(1)-k > 1  %不可以超出索引
            if data_temp(deal_index3{j,1}(1)-k) ~= 0 
                break;
            end
        else
            break;
        end
    end
    now_index = (deal_index3{j,1}(1)-k+1:deal_index3{j,1}(end)+1);
    kinepart{j,1} = datanew([1,now_index+1],:);
end
fprintf('一共找到%d个运动学片段!\n',length(deal_index3));
end

按照前面分析的去提取运动学片段


  • 判断片段连续
function data_slice = is_continue(data)
m = length(data);
k = 1;
data_slice = cell(m,1);
data_slice{1,1} = data(1);
for i = 2:m
    if data(i) - data(i-1) == 1
       data_slice{k,1} = [ data_slice{k,1},data(i)];
    else
        k = k+1;
        data_slice{k,1} = data(i);
    end
end
% 多余空行删除
data_slice(all(cellfun(@(x) isempty(x),data_slice),2),:)=[];
end

这个函数在第一问也用到了,十分关键的一个函数,用它可以将一组数,按连续性,分割成不同的片段。


  • 处理每个文件
function dealFile(filename)
% 载入数据
fprintf('正在导入%s...\n',filename);
load([filename,'数据预处理后'],'datanew');
data = datanew;
fprintf('导入成功!一共导入%d条数据\n',length(data)-1);
% 选取运动学片段
kinepart = kinePartDetect(data);
% 保存运动学片段
save([filename,'运动学片段'],'kinepart');
end

  • 画运动段图像
function drawKinepartpic(filename)
set(gcf,'outerposition',get(0,'screensize'))
fprintf('正在导入%s运动学片段...\n',filename);
load([filename,'运动学片段'],'kinepart');
for i = 1:4
    subplot(2,2,i)
    data = kinepart{i}; % 读取运动学片段
    plotdata = cell2mat(data(2:end,2));
    plot(plotdata,'r-','linewidth',2)
    grid on
    set(gca,'fontsize',24)
    xlabel('时间(s)'),ylabel('车速(km/h)');
    set(gca,'GridLineStyle','--','GridColor','k','GridAlpha',1)
    text = sprintf('%s - %s',data{2,1},data{end,1}); % 片段起止时间
    axis tight
    title(text) 
end
print(gcf,'-djpeg','-r300',[filename,'前4个运动学片段']);
fprintf('%s前4个运动学片段绘制完成!\n',filename)
end

为了展示最后提取到的运动学片段,我们将每个文件提取到的运动学片段中的前四个展示到一起。


  • 主程序
%% 准备存储空间
clc,clear,close all

filename = {'文件1','文件2','文件3'};
tic
for i = 1:length(filename)
    dealFile(filename{i});
    figure(i)
    drawKinepartpic(filename{i});
    fprintf('----------------------\n');
end
fprintf('所有文件运动学片段提取完成!\n');
toc

运行结果展示

运行时的画面是这样的:

运行界面图(点击查看大图)

运行时,先将上一问的数据复制过来,以备调用;运行主程序即可,完成后,将会生成每个文件的运动学片段,以元胞来存储,并且内容和原始数据一样,统一包括那些字段,只不过数据变少了。整个运算耗时 104.098016 秒。

输出文字如下

正在导入文件1...
导入成功!一共导入518137条数据
正在查找运动学片段...
一共找到830个运动学片段!
正在导入文件1运动学片段...
文件1前4个运动学片段绘制完成!
----------------------
正在导入文件2...
导入成功!一共导入518279条数据
正在查找运动学片段...
一共找到613个运动学片段!
正在导入文件2运动学片段...
文件2前4个运动学片段绘制完成!
----------------------
正在导入文件3...
导入成功!一共导入431784条数据
正在查找运动学片段...
一共找到547个运动学片段!
正在导入文件3运动学片段...
文件3前4个运动学片段绘制完成!
----------------------
所有文件运动学片段提取完成!
时间已过 104.098016 秒。
>> 

得到的三幅运动学片段图如下:


文件1前4个运动学片段展示图

文件2前4个运动学片段展示图

文件3前4个运动学片段展示图

猜你喜欢

转载自www.cnblogs.com/gshang/p/11587366.html