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()

Take into account the two output diagrams of the codes and write an analytical result derived from the diagrams.