Consider the code:
import simpy
import random
import matplotlib.pyplot as plt

# Parameters
# num_edge_nodes = 1  # we use a list instead
edge_buffer_size = 10
cloud_buffer_size = 15

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

arrival_rate = 0.8


# Measurements
class Measure:
    def __init__(self, N_arr_a, N_arr_b, drop, total_queuing_delay_A, type_a_packets):
        self.N_arr_A = N_arr_a
        self.N_arr_B = N_arr_b
        self.drop = drop
        self.total_queuing_delay_A = total_queuing_delay_A
        self.type_a_packets = type_a_packets


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


# Considering the edge_speed_coefficient for changing the speed of the edge node
def packet_arrivals(env, micro_data_center, cloud_data_center, data, edge_buffer, cloud_buffer, f_value,
                    edge_speed_coefficient):
    packet_type_options = ['A', 'B']
    packet_id = 1

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

        # Updating arrival data
        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 * edge_speed_coefficient,
                                       arrival_time))  # Applying the coefficient for changing the speed of the edge node
                data.type_a_packets += 1
            elif packet_type == 'B':
                micro_data_center.put((packet_id, packet_type, B_edge_sevice_time * edge_speed_coefficient,
                                       arrival_time))  # Applying the coefficient for changing the speed of the edge node
        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))
                    data.type_a_packets += 1
                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):
    while True:
        packet_id, packet_type, packet_processing_time, arrival_time = yield micro_data_center.get()

        if packet_type == 'A':
            queuing_delay = env.now - arrival_time  # Calculating delay
            data.total_queuing_delay_A += queuing_delay

        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_server(env, cloud_data_center):
    while True:
        packet_id, packet_type, packet_processing_time = yield cloud_data_center.get()
        yield env.timeout(packet_processing_time)
        print(
            f"Cloud Server processed {packet_type} packet {packet_id} (including propagation delay) at time {env.now}")


# Simulation setup
simtime = 100000
average_queuing_delays_A = []
edge_node_num_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
f = 0.5  # Fraction type B packets

# Run the simulation
for num_edge_nodes in edge_node_num_list:
    env = simpy.Environment()
    micro_data_center = simpy.Store(env)
    cloud_data_center = simpy.Store(env)
    env.process(packet_arrivals(
        env, micro_data_center, cloud_data_center, measurements, edge_buffer_size, cloud_buffer_size, f,
        edge_speed_coefficient=1))

    for node_id in range(num_edge_nodes):
        env.process(edge_node(env, micro_data_center, cloud_data_center, node_id + 1, measurements))

    env.process(cloud_server(env, cloud_data_center))
    env.run(until=simtime)
    average_queuing_delays_A.append(measurements.total_queuing_delay_A / measurements.type_a_packets)

plt.plot(edge_node_num_list, average_queuing_delays_A)
plt.xlabel('Number of the edge nodes')
plt.ylabel('Average queueing delay (time unit) ')
plt.title('Average queueing delay for Type A packets over the number of the edge nodes')
plt.show()



I use the above code to perform the task below which is a part of simulating a network system, taking into account the output of the code, write an anlytic result for the task considering the task requirements.
The task:
Now define a desired value for the maximum average queuing time of type A packets,
denoted Tq.
Assuming  a single-server Micro Data Center and a single-server Cloud Data Center, replace the edge node with a progressively faster server. Which is the4
minimum value of the average service rate that is required to reduce the queuing time of type A packets below the threshold Tq?