(三)运动学片段提取
在数据预处理阶段,我们成功对每个文件的异常数据做出了异常处理,下面我们开始对各个文件做运动学片段提取。
在这里首先插一句,其实预处理阶段,我们对数据的异常处理大部分都是以剔除的方式处理的,这种方式有利有弊!利处自然是简单省事,并且一般来说,产生的异常数据都是无效的,留着也没用,反而会影响片段时长的占比。但是弊处也有,那就是很有一部分的有用数据也被处理了。因为可能某段数据只是那么几个时间点异常,导致了整个片段不连续,直接不可以最为被挑选的对象,这样样本容量会减少,从而影响最终的工况曲线的表征能力。
可是,比赛时间有限呀!当时为了节省时间,我还是毫不犹豫地提出了上述情况地异常数据。一共提取到运动学片段 830 + 613 + 547 = 1990 个,这个数量还算比较合理。因为我们总共有 496464 条采集数据,在我们查到的文献里,采集数据量和我们差不多的也只有将近 2000 个运动学片段。
好的,下面开始讲片段提取方法。
运动学片段提取方法
此外,因为怠速段时长不允许超过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
运行结果展示
运行时的画面是这样的:
输出文字如下
正在导入文件1...
导入成功!一共导入518137条数据
正在查找运动学片段...
一共找到830个运动学片段!
正在导入文件1运动学片段...
文件1前4个运动学片段绘制完成!
----------------------
正在导入文件2...
导入成功!一共导入518279条数据
正在查找运动学片段...
一共找到613个运动学片段!
正在导入文件2运动学片段...
文件2前4个运动学片段绘制完成!
----------------------
正在导入文件3...
导入成功!一共导入431784条数据
正在查找运动学片段...
一共找到547个运动学片段!
正在导入文件3运动学片段...
文件3前4个运动学片段绘制完成!
----------------------
所有文件运动学片段提取完成!
时间已过 104.098016 秒。
>>
得到的三幅运动学片段图如下:
下一阶段任务
完成第三问,点击查看