系统仿真(三)


一、题目

设计实现一个电梯系统,检验不同场景下学生到达一楼的时间开销,该系统应满足的条件
有:

– 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

在时间轴推进部分进行读取和插入,推到仿真时间轴。

三、流程图

image-20210428210251693

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结果:

image-20210429003239703

2、多种楼层场景下的学生耗时:

image-20210429003055980

image-20210429092259548

image-20210429004413054

3、楼层数N=9,student_num=180情形的demo结果:

N9_start_1

N9_start_2

N9_leave1

N9_leave2

N9_cyc200

image-20210426002803669

image-20210426002816661

N9_cyc200_mean_time_hist

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


文章作者: Liuss
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Liuss !
评论
  目录