一、题目
设计实现一个电梯系统,检验不同场景下学生到达一楼的时间开销,该系统应满足的条件
有:
– N层楼场景, 每层楼住宿学生数n个
– 每楼层学生到达电梯时间由第一次作业起床时间分布和洗漱时间分布决定。
– 每宿舍楼男女生不混住, 假设只考虑男生宿舍楼场景
– 所有学生目的地均为一楼
– 电梯运行速度假设为2.1361s/每层
– 电梯按先呼叫先服务+运行方向楼层排序策略运行
– 每层停留时间( 学生进电梯) 符合[10,60]秒的均匀分布
– 电梯最大载荷为10人, 超载则直接移动至最近目的地
– 电梯空闲时停留在最后服务楼层
• 检验不同场景下学生到达一楼的时间开销性能
• 建议场景组如下:
二、设计思路
1、定义实体student类,并加入对应的属性;
2、因为要基于事件调度推进仿真时间钟,封装pop_Event_queue_new函数用于取出事件,insert_Event_queue_new用于插入事件;
3、由于需要在各楼层进行排队,设置’queue’矩阵用于排队,矩阵的每一行代表各个楼层,矩阵第一列表示当前楼层的排队人数,其他列用于排队学生的id。为方便调用队列queue的取出操作,封装为函数pop_queue;
4、然后事件主要定义为三种:
type == -1 %elevator close the door
type == 0 %elevator change the loc
type == 1 % arrival event
在时间轴推进部分进行读取和插入,推到仿真时间轴。
三、流程图
1、type=1:arrive event
2、type=0:change location event
3、type=-1:close the door event
四、代码实现
1、构造学生类
定义学生类的相关属性值,根据先前调研的起床和洗漱时间,确定学生进入电梯系统的时间,以开始时间、学生id插入type=1的到达事件到事件列表中;
classdef student
properties
id
StartTime
floor
left_elevator
end
end
2、事件描述
2.1、pop_queue函数
function [ queue, pop_id ] = pop_queue( queue, index ,num_to_pop )
pop_id = [];
num_pop = 0;
if queue(index,1) <= num_to_pop %想取出的学生数少于当前层排队人数
num_pop = queue(index,1); %排队的人都取出
for i = 2:(num_pop+1)
pop_id = [pop_id queue(index,i)];
if queue(index,i) == 0
bb = 1;
end
end
queue(index,:) = 0;
else %想取出的学生数多于当前层排队人数
num_pop = num_to_pop;
queue(index,1) = queue(index,1) - num_pop;
for i = 2:(num_pop +1)
pop_id = [pop_id queue(index,i)];
if queue(index,i) == 0
bb = 1;
end
queue(index,i) = 0; %将被取出的学生 位置处 置0
end
for i = 2:(queue(index,1)+1)
queue(index,i) = queue(index,i+num_pop); %将后面没被取出的同学 排队前移
queue(index,i+num_pop) = 0; %被前移的学生位置处 置0
end
end
end
2.2、pop_Event_queue事件
function [time, type, id, event_queue]=pop_Event_queue(event_queue)
time= event_queue(1,1);% move the timer
type = event_queue(2,1);
id = event_queue(3,1);
s = size(event_queue);
if s == [3 1]% only one event existed
event_queue = [];
else %more than one event existed
%push the fisrt event out.
event_queue=event_queue(:,2:s(2));
end
2.3、 insert_Event_queue事件
function event_queue=insert_Event_queue(event_queue,time, type,id)
if isempty(event_queue)
event_queue = [time type id]';
else
s = size(event_queue);
%check the start and end
if event_queue(1,1) >= time
%add to the start
event_queue = [[time type id]' event_queue(:,1:s(2))];
elseif event_queue(1,s(2)) <= time
%add to the end
event_queue = [event_queue(:,1:s(2)) [time type id]'];
else
for n = 1:s(2) %go through the event queue and find the right place to insert
if event_queue(1,n)<time
%insert the time and type
event_queue = [event_queue(:,1:n) [time type id]' event_queue(:,n+1:s(2))];
break;
end
end
end
end
3、初始化
3.1、初始化楼层和电梯参数
首先数值初始化,这里按照先前调研的电梯速度2.1361s/层;
%set the format of event queue, 1st :time 2nd:event type(1,arrival, 2 service end)
Event_queue= [];
N=9; %5 6 7 8 9
%queue was used for customer waiting
%queue= [(0),(0),(0),(0),(0),(0),(0),(0)];
queue = zeros(N,40);
%set the status of elevator
elevator_loc = 1;
elevator_num_threshold = 10;
num_in_elevator = 0;
time_every_floor = 0.0356017; %2.1361/60s
elevator_dst = 0;
queue_in_elevator = [];
elevator_door = 0;
3.2、 初始化学生对象
由前几次作业内容得,学生起床时间点wakeup_time=normrnd(71.1321,23.0661,1,student_num);
起床耗时wakeup_cost_time=lognrnd(1.1611,0.6013,1,student_num);
洗漱耗时:wash_time=lognrnd(2.59928,0.604217,1,student_num);
进入电梯排队系统的时间t=wakeup_time+wakeup_cost_time+wash_time;
%set the student number
student_num = 20*N; %20
cyc_num=200; %sometimes it work badly.
wakeup_time=normrnd(71.1321,23.0661,1,student_num);
wakeup_cost_time=lognrnd(1.1611,0.6013,1,student_num);
wash_time=lognrnd(2.59928,0.604217,1,student_num);
t=wakeup_time+wakeup_cost_time+wash_time;
time=sort(t);
fprintf('Case: floor_number:N= %d\n',N);
for cyc_i=1:cyc_num
for t=1:student_num
s(t)=student;
s(t).id = t;
s(t).StartTime = time(t);
s(t).floor = unidrnd(N); %floor=1 2 3 4 5 6 7 8 9
s(t).left_elevator = 0;
if s(t).floor == 1
s(t).left_elevator = s(t).StartTime;
else
Event_queue = insert_Event_queue(Event_queue, s(t).StartTime, 1,s(t).id);
end
% Event_queue = insert_Event_queue(Event_queue, s(t).StartTime, 1,s(t).id);
end
%% Print some infomation
t_floor = []; %打印生成同学对应的楼层
for i = 1:student_num
t_floor = [t_floor s(i).floor];
end
% t_floor
t_start=[]; %打印生成同学进入电梯系统对应的开始时间
for i =1:student_num
t_start = [t_start s(i).StartTime];
end
4、电梯队列事件驱动
然基于事件的时间轴推进,依次从事件表中取出第一个事件,然后到对应的type索引中,进行对应的事件处理;
然后计算出学生在离开电梯系统t_left,以及在电梯系统中花费的时间t_cost;
并进行结果可视化。
代码见第六节
五、测试结果
1、楼层数N=8,student_num=20情形下的demo结果:
2、多种楼层场景下的学生耗时:
3、楼层数N=9,student_num=180情形的demo结果:
4、others
Floor_number:N | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|
Average time( min) | 1.392610 | 1.483222 | 1.528963 | 2.055363 | 2.495391 |
迟到人数 | 2 | 4 | 6 | 7 | 7 |
六、主函数代码
clc,clear all
close all
%set the format of event queue, 1st :time 2nd:event type(1,arrival, 2 service end)
Event_queue= [];
N=8; %5 6 7 8 9
%queue was used for customer waiting
%queue= [(0),(0),(0),(0),(0),(0),(0),(0)];
queue = zeros(N,20);
%set the status of elevator
elevator_loc = 1;
elevator_num_threshold = 10;
num_in_elevator = 0;
time_every_floor = 0.0356017; %2.1361/60s
elevator_dst = 0;
queue_in_elevator = [];
elevator_door = 0;
%% init student with randomlized decision graph
%set the student number
student_num = 20; %20
wakeup_time=normrnd(71.1321,23.0661,1,student_num);
wakeup_cost_time=lognrnd(1.1611,0.6013,1,student_num);
wash_time=lognrnd(2.59928,0.604217,1,student_num);
t=wakeup_time+wakeup_cost_time+wash_time;
time=sort(t);
for t=1:student_num
s(t)=student;
s(t).id = t;
s(t).StartTime = time(t);
s(t).floor = unidrnd(N); %floor=1 2 3 4 5 6 7 8 9
s(t).left_elevator = 0;
if s(t).floor == 1
s(t).left_elevator = s(t).StartTime;
else
Event_queue = insert_Event_queue(Event_queue, s(t).StartTime, 1,s(t).id);
end
% Event_queue = insert_Event_queue(Event_queue, s(t).StartTime, 1,s(t).id);
end
%% Print some infomation
t_floor = []; %打印生成同学对应的楼层
for i = 1:student_num
t_floor = [t_floor s(i).floor];
end
t_floor
t_start=[]; %打印生成同学进入电梯系统对应的开始时间
for i =1:student_num
t_start = [t_start s(i).StartTime];
end
t_start
%% now start the time series
t=0;
while(~isempty(Event_queue))%keep moving as long as t less than end_time
[t,type,id,Event_queue]=pop_Event_queue(Event_queue);
if type == -1 %elevator close the door
elevator_door = 0;
if elevator_loc == 1
for i = N:-1:1
if queue(i,1) ~= 0
elevator_dst = i;
break;
end
end
if i == 1
elevator_dst = 0;
else
Event_queue = insert_Event_queue(Event_queue,t+time_every_floor*(elevator_dst-1), 0, elevator_dst);
end
else
if num_in_elevator < elevator_num_threshold
if queue(elevator_loc,1) ~= 0
[queue, pop_id] = pop_queue(queue,elevator_loc,elevator_num_threshold-num_in_elevator);
while(~isempty(pop_id))
temp_id = pop_id(1);
queue_in_elevator = [queue_in_elevator temp_id];
num_in_elevator = num_in_elevator + 1;
pop_id = pop_id(2:length(pop_id));
end
end
time_arrive_next_floor = t + time_every_floor;
Event_queue = insert_Event_queue(Event_queue,time_arrive_next_floor, 0, elevator_loc-1);%insert change event
else
time_arrive_next_floor = t + time_every_floor;
Event_queue = insert_Event_queue(Event_queue,time_arrive_next_floor, 0, elevator_loc-1);%insert change event
end
end
elseif type == 0 %elevator change the loc
elevator_loc = id;
elevator_door = 1;
if elevator_loc == 1
while(num_in_elevator ~= 0)
temp_id = queue_in_elevator(1);
s(temp_id).left_elevator = t;
queue_in_elevator = queue_in_elevator(2:length(queue_in_elevator));
num_in_elevator = num_in_elevator - 1;
end
% queue_in_elevator = [];
elevator_dst = 0;
time_elevator_close = t + (10 + 50 * rand())/60;
Event_queue = insert_Event_queue(Event_queue,time_elevator_close, -1, elevator_loc);%insert close event
elseif elevator_loc == elevator_dst
elevator_dst = 1;
time_elevator_close = t + (10 + 50 * rand())/60;
Event_queue = insert_Event_queue(Event_queue,time_elevator_close, -1, elevator_loc);%insert close event
if queue(elevator_loc,1) ~= 0
[queue, pop_id] = pop_queue(queue,elevator_loc,elevator_num_threshold-num_in_elevator);
while(~isempty(pop_id))
temp_id = pop_id(1);
queue_in_elevator = [queue_in_elevator temp_id];
num_in_elevator = num_in_elevator + 1;
pop_id = pop_id(2:length(pop_id));
end
end
elseif elevator_dst == 1
if queue(elevator_loc,1) ~= 0 && num_in_elevator < elevator_num_threshold
[queue, pop_id] = pop_queue(queue,elevator_loc,elevator_num_threshold-num_in_elevator);
while(~isempty(pop_id))
temp_id = pop_id(1);
queue_in_elevator = [queue_in_elevator temp_id];
num_in_elevator = num_in_elevator + 1;
pop_id = pop_id(2:length(pop_id));
end
time_elevator_close = t + (10 + 50 * rand())/60;
Event_queue = insert_Event_queue(Event_queue,time_elevator_close, -1, elevator_loc);%insert close event
else
Event_queue = insert_Event_queue(Event_queue,t+time_every_floor, 0, elevator_loc-1);%insert change event
end
end
%check the event type
elseif type == 1% arrival event
if elevator_loc == s(id).floor && elevator_door == 1
if num_in_elevator < elevator_num_threshold
queue_in_elevator = [queue_in_elevator id];
num_in_elevator = num_in_elevator + 1;
else %排队
temp_num_in_queue = queue(s(id).floor,1); %读取楼层排队现有人数
queue(s(id).floor,temp_num_in_queue+2) = id; %把当前id加入排队队列对应的位置
queue(s(id).floor,1) = queue(s(id).floor,1) + 1; %更新当前楼层排队人数
end
elseif queue(s(id).floor,1) == 0 %学生不在电梯所在楼层,当前楼层无人排队
temp_num_in_queue = queue(s(id).floor,1);
queue(s(id).floor,temp_num_in_queue+2) = id;
queue(s(id).floor,1) = queue(s(id).floor,1) + 1;
if elevator_loc == 1 && elevator_dst == 0
for i = N:-1:1
if queue(i,1) ~= 0
elevator_dst = i;
break;
end
end
Event_queue = insert_Event_queue(Event_queue,t+time_every_floor*(elevator_dst-1), 0, elevator_dst);
end
else %else, join the queue
temp_num_in_queue = queue(s(id).floor,1);
queue(s(id).floor,temp_num_in_queue+2) = id;
queue(s(id).floor,1) = queue(s(id).floor,1) + 1;
end
end
end
%% 结果图形可视化
t_cost=[];
t_left=[];
for i =1:student_num
t_cost = [t_cost s(i).left_elevator-s(i).StartTime];
end
for i =1:student_num
t_left = [t_left s(i).left_elevator];
end
t_left
x=(1:student_num);
figure
plot(x,t_cost,'LineWidth',1.5);
xlabel('Student ID');
ylabel('Elevator time cost(min)');
grid on;
figure
title('N=8 Student=20 demo');
sz = linspace(10,180,student_num);
c = linspace(1,10,length(t_floor));
scatter(t_floor,t_cost,sz,c,'LineWidth',1.5);
xlabel('Floor ID');
ylabel('Elevator time cost(min)');
%% 结果值输出
fprintf('Case: floor_number:N= %d\n',N);
fprintf('Average time spent by students in the elevator= %f min\n',mean(t_cost));
fprintf('-----------------------------------------------------------\n')
t_start_int=floor(t_start);
t_start_decimal=t_start-floor(t_start);
start_clock_s=t_start_decimal*60;
for k=1:student_num
if t_start_int(k)<50
start_clock_h(k)=6;
start_clock_m(k)=t_start_int(k);
fprintf('The %dth student from the %dth floor start at %d:%d %fs,\n',s(k).id,s(k).floor,start_clock_h(k),start_clock_m(k),start_clock_s(k));
elseif t_start_int(k)>=50 && t_start_int(k)<110
start_clock_h(k)=7;
start_clock_m(k)=t_start_int(k)-50;
fprintf('The %dth student from the %dth floor start at %d:%d %fs\n',s(k).id,s(k).floor,start_clock_h(k),start_clock_m(k),start_clock_s(k));
elseif t_start_int(k)>=110 && t_start_int(k)<140
start_clock_h(k)=8;
start_clock_m(k)=t_start_int(k)-110;
fprintf('The %dth student from the %dth floor start at %d:%d %fs\n',s(k).id,s(k).floor,start_clock_h(k),start_clock_m(k),start_clock_s(k));
else
fprintf('The %dth student didn’t start until 8:30\n',s(k).id);
end
end
fprintf('-----------------------------------------------------------\n')
t_left_int=floor(t_left);
t_left_decimal=t_left-floor(t_left);
left_clock_s=t_left_decimal*60;
for k=1:student_num
if t_left_int(k)<50
left_clock_h(k)=6;
left_clock_m(k)=t_left_int(k);
fprintf('The %dth student from the %dth floor leave at %d:%d %fs,\n',s(k).id,s(k).floor,left_clock_h(k),left_clock_m(k),left_clock_s(k));
elseif t_left_int(k)>=50 && t_left_int(k)<110
left_clock_h(k)=7;
left_clock_m(k)=t_left_int(k)-50;
fprintf('The %dth student from the %dth floor leave at %d:%d %fs\n',s(k).id,s(k).floor,left_clock_h(k),left_clock_m(k),left_clock_s(k));
elseif t_left_int(k)>=110 && t_left_int(k)<140
left_clock_h(k)=8;
left_clock_m(k)=t_left_int(k)-110;
fprintf('The %dth student from the %dth floor leave at %d:%d %fs\n',s(k).id,s(k).floor,left_clock_h(k),left_clock_m(k),left_clock_s(k));
else
fprintf('The %dth student didn’t leave until 8:30\n',s(k).id);
end
end