📄 get_packet_timing.m
字号:
%
% NN: number of users
% NPKTS: number of packets to simulate
% lambda: queue arrival rate (packets per second)l
% ack_gap:
% WARMUP: number of warmup packets to pass transient phase
% NSYNC:
% NSFD:
% TC:
% L:
% G:
% PACKET_LENGTH:
% SYMBOL_LENGTH:
% code_len:
% PLOT_DEBUG:
%
% This function returns the struct stat
%
% stat.startTimes: same but only for the time when we are not
% in warmup
% stat.stopTimes: dito
% stat.UOIPktsSimulated: the number of UOI packets simulated so far
% stat.packets: packet starting times plus node numbers
%
function [stat] = ...
get_packet_timing(NN,NPKTS,lambda,ack_gap,WARMUP,NSYNC,NSFD,TC,L,G,...
PACKET_LENGTH,SYMBOL_LENGTH,code_len,PLOT_DEBUG)
%lambda = 500; %queue arrival rate (packets per second)
preamble_len = (NSYNC + NSFD)*code_len*L*TC;
packet_len = preamble_len + (PACKET_LENGTH*SYMBOL_LENGTH*TC); %packet length in seconds
payload_len = packet_len - preamble_len;
templ_len = G * code_len * L * TC; %length of sync template
% They might be required later
stat.preamble_len = preamble_len;
stat.packet_len = packet_len;
stat.payload_len = payload_len;
%repeat lambda if size 1
if(length(lambda)==1)
lambda = lambda * ones(1,2);
end
%max lambda that can be sustained
lambda_max = floor(1/(packet_len+ack_gap));
fprintf('Maximum Lambda = %.2f\n',lambda_max);
if(sum(lambda > lambda_max)) %one of the lambdas is bigger
warning('lambda > lambda_max = %d',lambda_max);
lambda(lambda > lambda_max) = lambda_max;
end
%ack_gap = 0; %seconds
sec_per_symbol = SYMBOL_LENGTH * TC;
%from 802.15.4-2006 standard
macMinBE = 8;%3; %min backoff exponent
aUnitBackoffPeriod = 20; %symbols per backoff period
%we adapt the number of warmup packets here so that it is the number of
%packets of the UOI we will see when the user with highest lambda has sent
%WARMUP packets on the channel
WARMUP = WARMUP/max(lambda) * lambda(1);
%WARMUP = 300; %number of warmup packets to pass transient phase
%NPKTS = 20; %number of packets to simulate
UOI = 1; %node number of UOI (typically 1)
%define events
QARR = 1; %packet arrives at queue
CHARR = 2; %packet leaves queue, arrives at channel
CHDEP = 3; %packet leaves channel
%define states
IDLE = 0; %channel is idle, no packets whatsoever
SEEK = 1; %an interferer packet was seen on channel, if this overlaps with
%a later packet of the UOI we have to take it into account. Note this is
%also possible over several stages (ie, interferer packet overlapping with
%other interferer packets that finally overlap with the UOI packet)
RX = 3; %a UOI packet is being received
%initialize event Scheduler
evSched.currentTime = -1; %current time
evSched.firingTime = 0; %time of the event in process
evSched.evList = []; % This is the event list, note that it is a [n x 3] vector.
% The first column corresponds to the firing time
% The second column is the event type
% 1 arrival of packet in the queue
% 2 departure of packet of queue / arrival on the channel
% 3 departure from the channel
% The third column indicates the node number, 1 = UOI
evSched.evListLength = 0; % And a variable corresponding to the event list size (i.e number of rows)
%simulation state variables
sim.UOIPktsSent = 0; %number of UOI packets seen on the channel
sim.start = false; %flag to indicate whether we are still in warmup or started sim already
sim.forced_start = false; %force start if there are no gaps due to constantly utilized channel
sim.state = IDLE; %state of the sim;
sim.tentStart = 0; %tentative start time, start time induced by interfering packet
%will become a real start time if a UOI packet arrives before all
%interfering packets left the channel
sim.activeIFs = 0; %the number of interfering packets currently on the channel
sim.packets_since_tent = []; %store packets since last tentative start
sim.packetQueue = zeros(1,NN); %current length of the queue for each node
sim.firstLeave = zeros(1,NN); %first possible leave time for new packet
sim.allStartTimes = []; %starting times of simulations WARMUP + SIM
sim.allStopTimes = []; %corresponding ending times WARMUP + SIM
stat.startTimes = []; %same but only for the time when we are not in warmup
stat.stopTimes = []; %dito
debug.UOIstartTimes = []; %the times when an UOI packet arrives on the channel once WARMUP is over
stat.UOIPktsSimulated = 0; %the number of UOI packets simulated so far
stat.packets = []; %packet starting times plus node numbers
%schedule arrival of first packet for every node
for i=1:NN
evSched = addEvent(getNextArrival(lambda(min(i,2))),QARR,i,evSched);
end
%run the simulation
while(true)
%get next event
evSched.firingTime = evSched.evList(1,1);
evType = evSched.evList(1,2);
node = evSched.evList(1,3);
% Remove it from the event list
evSched = delEvent(evSched);
switch evType
case QARR,
%schedule the departure, arrival on channel of the packet
if(sim.packetQueue(node) == 0)
sim.firstLeave(node) = ...
max(evSched.firingTime,sim.firstLeave(node));
end
%calculate random backoff
bo_s = getBackoff(macMinBE,aUnitBackoffPeriod,sec_per_symbol);
%schedule the arrival of the packet on the channel
evSched = addEvent(sim.firstLeave(node)+bo_s,CHARR,node,evSched);
%when is the earliest possible, next packet can be sent
sim.firstLeave(node) = ...
sim.firstLeave(node)+bo_s+packet_len+ack_gap;
%increment size of queue
sim.packetQueue(node) = sim.packetQueue(node) + 1;
%schedule next arrival
evSched = ...
addEvent(evSched.firingTime+getNextArrival(lambda(min(node,2))), ...
QARR,node,evSched);
case CHARR,
%delete it from the packet queue
sim.packetQueue(node) = sim.packetQueue(node) - 1;
%schedule it's departure from the channel
evSched = addEvent(evSched.firingTime+packet_len,CHDEP,node,evSched);
if(node == UOI)%check whether WARMUP over
if(sim.UOIPktsSent > WARMUP)
sim.start = true;
end
sim.UOIPktsSent = sim.UOIPktsSent + 1;
%fprintf('tarr=%.5f, tdep=%.5f, q=%d\n',evSched.firingTime,evSched.firingTime+packet_len,sim.packetQueue(node));
end
%register the packet
stat.packets = [stat.packets; evSched.firingTime,node];
% $$$ %start registering packets
% $$$ if(sim.start)
% $$$ if(isempty(stat.packets))%fill in the packets since the last
% $$$ %tentative start wich now will become the start of our overall sim
% $$$ stat.packets = [stat.packets; sim.packets_since_tent];
% $$$ end
% $$$ stat.packets = [stat.packets; evSched.firingTime, node];
% $$$ end
%act depending on current state
switch sim.state
case IDLE,
if(node == UOI)%IDLE + UOI arrival -> start sim, go to RX
sim.allStartTimes = [sim.allStartTimes evSched.firingTime];
if(sim.start) %if warmup over we need to keep track of how many UOI
%packets we simulated, plus fill the
%start/stopTimes arrays
stat.UOIPktsSimulated = stat.UOIPktsSimulated + 1;
debug.UOIstartTimes = [debug.UOIstartTimes evSched.firingTime];
stat.startTimes = [stat.startTimes evSched.firingTime];
end
sim.state = RX;
else%IDLE + IF arrival -> might have to start here, go to SEEK
sim.tentStart = evSched.firingTime;
sim.activeIFs = sim.activeIFs + 1;
sim.state = SEEK;
sim.packets_since_tent = [evSched.firingTime, node];
end
case SEEK,
if(node == UOI)%SEEK + UOI arrival -> start sim (unless already running), go to RX
if(~isempty(sim.allStopTimes) && sim.allStopTimes(end) == sim.tentStart)
sim.allStopTimes = sim.allStopTimes(1:end-1);
if((sim.start && stat.UOIPktsSimulated > 0) || ...
(sim.forced_start &&stat.UOIPktsSimulated == 0))
%if warmup over we need to keep track of how many UOI
%packets we simulated, plus fill the
%start/stopTimes arrays
stat.UOIPktsSimulated = stat.UOIPktsSimulated + 1;
debug.UOIstartTimes = [debug.UOIstartTimes evSched.firingTime];
if(stat.UOIPktsSimulated ~= 0)
stat.stopTimes = stat.stopTimes(1:end-1);
end
end
%make sure we dont look for a gap forever (in the case
%we have constantly something on the channel)
if(sim.UOIPktsSent > 2*WARMUP)
sim.forced_start = true; %force start at the end of this packet
end
else
sim.allStartTimes = [sim.allStartTimes sim.tentStart];
if(sim.start)
%if warmup over we need to keep track of how many UOI
%packets we simulated, plus fill the
%start/stopTimes arrays
stat.UOIPktsSimulated = stat.UOIPktsSimulated + 1;
debug.UOIstartTimes = [debug.UOIstartTimes evSched.firingTime];
stat.startTimes = [stat.startTimes sim.tentStart];
end
end
sim.state = RX;
else%SEEK/RX + IF arrival -> active IFs ++
sim.activeIFs = sim.activeIFs + 1;
sim.packets_since_tent = [sim.packets_since_tent; evSched.firingTime, node];
end
case RX,%
if(node == UOI)
fprintf('Bug: arrival while receiving!\n');
else%SEEK/RX + IF arrival -> active IFs ++
sim.activeIFs = sim.activeIFs + 1;
end
otherwise
fprintf('Bug: this type of state does not exist!\n');
end
case CHDEP,
%act depeding on current state
switch sim.state
case IDLE,
fprintf('Bug: departure while idle!\n');
case SEEK,
if(node == UOI)
fprintf('Bug: UOI departure while seeking!\n');
else%SEEK + IF departure -> active IFs --, go to idle if no more IFs active
sim.activeIFs = sim.activeIFs - 1;
if(sim.activeIFs == 0)
sim.state = IDLE;
end
end
case RX,
if(node == UOI)%RX + UOI departure -> register stop time, 0 active IFs, goto IDLE
if(sim.activeIFs == 0)
sim.state = IDLE;
else%otherwise it could be that we have to go on simulating
sim.tentStart = evSched.firingTime;
sim.state = SEEK;
end
sim.allStopTimes = [sim.allStopTimes evSched.firingTime];
if(sim.start && stat.UOIPktsSimulated)
%if warmup over we need to keep track of how many UOI
%packets we simulated, plus fill the
%start/stopTimes arrays
stat.stopTimes = [stat.stopTimes evSched.firingTime];
end
if(stat.UOIPktsSimulated == NPKTS)%check whether we are done
break;
end
if(sim.forced_start && stat.UOIPktsSimulated == 0)
stat.startTimes = [stat.startTimes evSched.firingTime];
end
else%RX + IF departure -> decrease active IFs
sim.activeIFs = sim.activeIFs - 1;
end
otherwise
fprintf('Bug: this type of state does not exist!\n');
end
otherwise
fprintf('Bug: this type of event does not exist!\n');
end
end
%only keep the packets that are useful ie, that fall into a start-stop
%period
%ind_useful_pkts = [];
%first get those who started within one packet length from first start
temp = stat.packets(:,1)';
if(sim.forced_start)
temp(temp<=stat.startTimes(1)-packet_len)=0;
else
temp(temp<=stat.startTimes(1)-packet_len-templ_len)=0;
end
temp(temp>=stat.startTimes(1))=0;
ind_useful_pkts = find(temp);
for i=1:length(stat.startTimes)
temp = stat.packets(:,1)';
temp(temp<stat.startTimes(i)-templ_len)=0;
temp(temp>stat.stopTimes(i))=0;
% find(temp)
ind_useful_pkts = [ind_useful_pkts find(temp)];
end
ind_useful_pkts = unique(sort(ind_useful_pkts));
stat.packets = stat.packets(ind_useful_pkts,:);
if(sim.forced_start)
stat.startTimes(1) = stat.startTimes(1) + templ_len;
end
stat.startTimes = stat.startTimes - templ_len;
if(PLOT_DEBUG)
figure
stem(stat.startTimes,ones(1,length(stat.startTimes)),'r')
hold on
stem(stat.stopTimes,ones(1,length(stat.stopTimes)),'b')
stem(debug.UOIstartTimes,ones(1,length(debug.UOIstartTimes)),'gx')
stem(stat.packets(:,1),min(1,stat.packets(:,2)/2),'k.')
end
%effective packets per seconds
sim_time = stat.stopTimes(end)-stat.startTimes(1);
eff_pkts_per_second = NPKTS/sim_time;
theoretical_rate_Mbps = lambda(1)*PACKET_LENGTH/1e06;
eff_rate_Mbps = NPKTS*PACKET_LENGTH/sim_time/1e06;
fprintf('Duration of the simulation = %.4f [s]\n',sim_time);
fprintf('Packets/sec = %.2f, theo. rate = %.2f [Mbps]\n', ...
eff_pkts_per_second,theoretical_rate_Mbps);
fprintf('Eff. rate = %.2f [Mbps]\n',eff_rate_Mbps);
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -