I have the following codes:
First code
import simpy
import random
import matplotlib.pyplot as plt
import numpy as np

# Parameters
num_edge_nodes = 1
num_cloud_nodes = 1
edge_buffer_size = 10
cloud_buffer_size = 15

# service times
cloud_server_time = 10
A_edge_service_time = 4
A_cloud_service_time = 2
B_edge_sevice_time = 2
B_cloud_service_partialprocess = 4
B_cloud_service_fullprocess = 5
propagation_delay = 1

arrival_rate = 0.8

edge_costs = [1, 2, 3]
cloud_costs = [2, 4, 6]

# Measurements
class Measure:
def init(self, N_arr_a, N_arr_b, drop, total_queuing_delay, edge_cost, cloud_cost):
self.N_arr_A = N_arr_a
self.N_arr_B = N_arr_b
self.drop = drop
self.total_queuing_delay = total_queuing_delay
self.edge_cost = edge_cost
self.cloud_cost = cloud_cost

measurements = Measure(0, 0, 0, 0, 0, 0)

def packet_arrivals(env, micro_data_center, cloud_data_center, data, edge_buffer, cloud_buffer, f_value):
packet_type_options = [‘A’, ‘B’]
packet_id = 1

while True:
packet_type = random.choices(packet_type_options, weights=(1 - f_value, f_value))[0]

if packet_type == ‘A’:
data.N_arr_A += 1
else:
data.N_arr_B += 1

arrival_time = env.now # Adding current time stamp for calculating delay
if len(micro_data_center.items) < edge_buffer:
if packet_type == ‘A’:
micro_data_center.put((packet_id, packet_type, A_edge_service_time, arrival_time))
elif packet_type == ‘B’:
micro_data_center.put((packet_id, packet_type, B_edge_sevice_time, arrival_time))
else:
if len(cloud_data_center.items) < cloud_buffer:
if packet_type == ‘A’:
cloud_data_center.put((packet_id, packet_type, A_cloud_service_time + propagation_delay))
elif packet_type == ‘B’:
cloud_data_center.put((packet_id, packet_type, B_cloud_service_fullprocess + propagation_delay))
else:
data.drop += 1

yield env.timeout(random.expovariate(arrival_rate))
packet_id += 1

def edge_node(env, micro_data_center, cloud_data_center, node_id, data, edge_cost):
while True:
packet_id, packet_type, packet_processing_time, arrival_time = yield micro_data_center.get()

queuing_delay = env.now - arrival_time
data.total_queuing_delay += queuing_delay
data.edge_cost += edge_cost * packet_processing_time
print(f"Edge Node {node_id} processed packet {packet_id} of type {packet_type} at time {env.now}“)

yield env.timeout(packet_processing_time)
if packet_type == ‘B’:
yield cloud_data_center.put((packet_id, packet_type, B_cloud_service_partialprocess + propagation_delay))

def cloud_node(env, cloud_data_center, node_id, data, cloud_cost):
while True:
packet_id, packet_type, packet_processing_time = yield cloud_data_center.get()

yield env.timeout(packet_processing_time)
data.cloud_cost += cloud_cost * packet_processing_time
print(f"Cloud Node {node_id} processed {packet_type} packet {packet_id} (including propagation delay) at time {env.now}”)

# Simulation setup
simtime = 1000000
average_queuing_delays = []
f_list = np.linspace(0, 1, 10)

# Run the simulation
for f in f_list:
env = simpy.Environment()
micro_data_center = simpy.Store(env)
cloud_data_center = simpy.Store(env)
measurements = Measure(0, 0, 0, 0, 0, 0)
env.process(packet_arrivals(env, micro_data_center, cloud_data_center, measurements, edge_buffer_size, cloud_buffer_size, f))

for node_id in range(num_edge_nodes):
env.process(edge_node(env, micro_data_center, cloud_data_center, node_id + 1, measurements, edge_costs[node_id % len(edge_costs)]))

for node_id in range(num_cloud_nodes):
env.process(cloud_node(env, cloud_data_center, node_id + 1, measurements, cloud_costs[node_id % len(cloud_costs)]))

env.run(until=simtime)
average_queuing_delays.append(measurements.total_queuing_delay / (measurements.N_arr_A + measurements.N_arr_B))

# Plot packet loss rate over time
plt.plot(f_list, average_queuing_delays)
plt.xlabel(‘Different f’)
plt.ylabel(‘Average Queueing delay’)
plt.title(‘Average Queueing delay over Different f’)
plt.show()

and the second code :
import simpy
import random
import matplotlib.pyplot as plt
import numpy as np

# Parameters
num_edge_nodes = 2
num_cloud_nodes = 2
edge_buffer_size = 10
cloud_buffer_size = 15

# service times
cloud_server_time = 10
A_edge_service_time = 4
A_cloud_service_time = 2
B_edge_sevice_time = 2
B_cloud_service_partialprocess = 4
B_cloud_service_fullprocess = 5
propagation_delay = 1

arrival_rate = 0.8

edge_costs = [1, 2, 3]
cloud_costs = [2, 4, 6]

# Measurements
class Measure:
def init(self, N_arr_a, N_arr_b, drop, total_queuing_delay, edge_cost, cloud_cost):
self.N_arr_A = N_arr_a
self.N_arr_B = N_arr_b
self.drop = drop
self.total_queuing_delay = total_queuing_delay
self.edge_cost = edge_cost
self.cloud_cost = cloud_cost

measurements = Measure(0, 0, 0, 0, 0, 0)

def packet_arrivals(env, micro_data_center, cloud_data_center, data, edge_buffer, cloud_buffer, f_value):
packet_type_options = [‘A’, ‘B’]
packet_id = 1

while True:
packet_type = random.choices(packet_type_options, weights=(1 - f_value, f_value))[0]

if packet_type == ‘A’:
data.N_arr_A += 1
else:
data.N_arr_B += 1

arrival_time = env.now # Adding current time stamp for calculating delay
if len(micro_data_center.items) < edge_buffer:
if packet_type == ‘A’:
micro_data_center.put((packet_id, packet_type, A_edge_service_time, arrival_time))
elif packet_type == ‘B’:
micro_data_center.put((packet_id, packet_type, B_edge_sevice_time, arrival_time))
else:
if len(cloud_data_center.items) < cloud_buffer:
if packet_type == ‘A’:
cloud_data_center.put((packet_id, packet_type, A_cloud_service_time + propagation_delay))
elif packet_type == ‘B’:
cloud_data_center.put((packet_id, packet_type, B_cloud_service_fullprocess + propagation_delay))
else:
data.drop += 1

yield env.timeout(random.expovariate(arrival_rate))
packet_id += 1

def edge_node(env, micro_data_center, cloud_data_center, node_id, data, edge_cost):
while True:
packet_id, packet_type, packet_processing_time, arrival_time = yield micro_data_center.get()

queuing_delay = env.now - arrival_time
data.total_queuing_delay += queuing_delay
data.edge_cost += edge_cost * packet_processing_time
print(f"Edge Node {node_id} processed packet {packet_id} of type {packet_type} at time {env.now}“)

yield env.timeout(packet_processing_time)
if packet_type == ‘B’:
yield cloud_data_center.put((packet_id, packet_type, B_cloud_service_partialprocess + propagation_delay))

def cloud_node(env, cloud_data_center, node_id, data, cloud_cost):
while True:
packet_id, packet_type, packet_processing_time = yield cloud_data_center.get()

yield env.timeout(packet_processing_time)
data.cloud_cost += cloud_cost * packet_processing_time
print(f"Cloud Node {node_id} processed {packet_type} packet {packet_id} (including propagation delay) at time {env.now}”)

# Simulation setup
simtime = 100000
packet_loss_rates = []
f_list = np.linspace(0, 1, 20)

# Run the simulation
for f in f_list:
env = simpy.Environment()
micro_data_center = simpy.Store(env)
cloud_data_center = simpy.Store(env)
measurements = Measure(0, 0, 0, 0, 0, 0)
env.process(packet_arrivals(env, micro_data_center, cloud_data_center, measurements, edge_buffer_size, cloud_buffer_size, f))

for node_id in range(num_edge_nodes):
env.process(edge_node(env, micro_data_center, cloud_data_center, node_id + 1, measurements, edge_costs[node_id % len(edge_costs)]))

for node_id in range(num_cloud_nodes):
env.process(cloud_node(env, cloud_data_center, node_id + 1, measurements, cloud_costs[node_id % len(cloud_costs)]))

env.run(until=simtime)
packet_loss_rate = measurements.drop / (measurements.N_arr_A + measurements.N_arr_B)
packet_loss_rates.append(packet_loss_rate)

# Plot packet loss rate over time
plt.plot(f_list, packet_loss_rates)
plt.xlabel(‘Different f’)
plt.ylabel(‘Packet Loss Rate’)
plt.title(‘Packet Loss Rate over Different f’)
plt.show()

Also consider this description which is the scenario of packet arrivals:
Description of packet arrivals:
On the one hand, Type A packets are processed locally at the micro data center with a service time of 4 units. If a free server or an available local buffer exists, they are handled there. Otherwise, they are forwarded (with a delay of 1 unit) to the cloud data center for processing, which takes 2 units of service time. If there are no free cloud servers and the cloud buffer is full, the packet is dropped, and the dropped packet counter is incremented. on the other hand, Type B packets undergo pre-processing locally at the micro data center with a service time of 2 units. Subsequently, they are forwarded (with a delay of 1 unit) to the cloud data center for complete processing, which takes 4 units of service time. If there are no free local servers and the local buffer is full, the packets skip local preprocessing and are directly forwarded (with a delay of 1 unit) to the cloud data center. In such cases, the cloud data center handles their processing entirely, requiring 5 units of service time. If there are no free cloud servers and the cloud buffer is full, the packet is dropped, and the dropped packet counter is incremented. Fraction of the packet of type B (from the total packets of A and B) is represented by f and is modifiable.


The output of the codes depict two diagrams: the first diagram is a falling diagram and the second digaram is a rising (up to f=0.6) and then falling diagram. 

Now I want you take into account the information I provided and write an analytical result for each of the diagrams I mentioned. ( Take into account the service times I used in my description of packet arrivals)