Dokumen ini membahas analisis sistem antrian pada sebuah copy shop kecil yang memiliki satu mesin fotokopi self-service dan kapasitas ruang tunggu terbatas untuk empat orang. Kondisi ini sering menyebabkan pelanggan harus menunggu di luar toko. Untuk mengurangi masalah tersebut, pemilik mempertimbangkan penambahan satu mesin fotokopi tambahan.
 Melalui pendekatan teori antrian dan pemodelan sederhana, dokumen ini menilai dampak penambahan mesin terhadap waktu tunggu pelanggan, panjang antrian, dan peluang terjadinya penumpukan di luar toko. Hasil analisis diharapkan dapat membantu memberikan gambaran kuantitatif yang jelas mengenai manfaat penambahan mesin bagi kelancaran pelayanan.
Copy shop mempunyai self-service copier dengan kondisi berikut:
Apakah penambahan satu mesin fotokopi dapat meminimalisir jumlah pelanggan tidak bisa langsung masuk dan harus menunggu di luar?
Sistem antrian yang benar untuk masalah ini adalah: \[ M/M/c \]
Model ini mengasumsikan kapasitas antrian tak terbatas. Angka
K=4 dalam kasus ini bukanlah batas sistem, melainkan
ambang batas yang menentukan kapan seorang pelanggan
harus menunggu di luar.
Syarat utama agar sistem stabil adalah \(\rho < 1\).
Probabilitas sistem dalam keadaan kosong (\(P_0\)) \[ P_0 = \left[ \left(\sum_{n=0}^{c-1} \frac{a^n}{n!}\right) + \frac{a^c}{c!(1-\rho)} \right]^{-1} \]
Probabilitas kondisi \(n\) pelanggan (\(P_n\)) \[ P_n = \begin{cases} \dfrac{a^n}{n!} P_0, & 0 \le n < c \\ \\ \dfrac{a^c \rho^{n-c}}{c!} P_0, & n \ge c \end{cases} \]
Panjang antrian rata-rata (\(L_q\)) \[ L_q = \frac{P_0 \, a^c \, \rho}{c! \, (1-\rho)^2} \]
Waktu tunggu rata-rata dalam antrian (\(W_q\)) \[ W_q = \frac{L_q}{\lambda} \]
Waktu rata-rata dalam sistem (\(W\)) \[ W = W_q + \frac{1}{\mu} \]
Jumlah rata-rata pelanggan dalam sistem (\(L\)) \[ L = \lambda W = L_q + a \]
lambda_rc <- 24
mu_rc <- 30
K_rc <- 4
compute_mmc <- function(lambda, mu, c, K) {
rho <- lambda / (c * mu)
if (rho >= 1) {
return(list(rho = rho, stable = FALSE, Lq = Inf, Wq = Inf, P_wait_outside = 1, Lq_outside = Inf, Wq_outside = Inf, Lq_inside = Inf, P_wait_queue = 1, P0 = 0, Pk = 1))
}
a <- lambda / mu
sum_part <- sum(sapply(0:(c - 1), function(n) a^n / factorial(n)))
p0_inv <- sum_part + (a^c / (factorial(c) * (1 - rho)))
P0 <- 1 / p0_inv
erlang_c <- (a^c / (factorial(c) * (1 - rho))) * P0
Lq <- erlang_c * rho / (1 - rho)
Wq <- Lq / lambda
p_wait_outside <- erlang_c * (rho^(K - c))
# Breakdown of queue metrics
Pk_val <- (a^c / factorial(c)) * rho^(K-c) * P0
Lq_outside <- Pk_val * rho / (1 - rho)^2
lambda_eff_q_outside <- lambda * p_wait_outside
Wq_outside <- if(lambda_eff_q_outside > 0) Lq_outside / lambda_eff_q_outside else 0
Lq_inside <- Lq - Lq_outside
list(
rho = rho,
Lq = Lq,
Wq = Wq,
P_wait_outside = p_wait_outside,
Lq_outside = Lq_outside,
Wq_outside = Wq_outside,
Lq_inside = Lq_inside,
P_wait_queue = erlang_c,
P0 = P0,
Pk = Pk_val
)
}
rough_c1 <- compute_mmc(lambda_rc, mu_rc, 1, K_rc)
rough_c2 <- compute_mmc(lambda_rc, mu_rc, 2, K_rc)Konfigurasi dasar toko dengan satu mesin memiliki utilisasi rata-rata: \[ \rho = \frac{\lambda}{c\mu} = \frac{24}{1 \times 30} = 0.8 \] Artinya, mesin fotokopi akan sibuk 80% dari waktunya. Probabilitas seorang pelanggan datang dan harus menunggu (karena mesin sibuk, \(n \ge 1\)), yang dihitung dengan formula probabilitas antrian (Erlang C) untuk c=1, sama dengan nilai utilisasi: \[ P(n \ge 1) = \frac{a^c}{c!(1-\rho)} P_0 = \rho = 0.8 \] Dari sini, kita dapat menghitung panjang antrian rata-rata total: \[ L_q = P(n \ge 1) \times \frac{\rho}{1-\rho} = 0.8 \times \frac{0.8}{1-0.8} = 3.20 \text{ pelanggan} \] Sehingga, waktu tunggu rata-rata total menjadi: \[ W_q = \frac{L_q}{\lambda} = \frac{3.20}{24} \approx 0.133 \text{ jam, atau } 8.0 \text{ menit} \]
Dengan menambahkan mesin kedua, utilisasi rata-rata per mesin turun secara signifikan: \[ \rho = \frac{\lambda}{c\mu} = \frac{24}{2 \times 30} = 0.4 \] Ini berarti setiap mesin rata-rata hanya sibuk 40% dari waktunya. Karena ada dua mesin (\(c=2\)), kita perlu menghitung probabilitas sistem kosong (\(P_0\)) terlebih dahulu. Dengan \(a = \lambda/\mu = 24/30 = 0.8\): \[ P_0 = \left[ \left(\sum_{n=0}^{1} \frac{0.8^n}{n!}\right) + \frac{0.8^2}{2!(1-0.4)} \right]^{-1} = \left[ (1 + 0.8) + \frac{0.64}{1.2} \right]^{-1} \approx 0.4286 \] Probabilitas seorang pelanggan datang dan harus menunggu (karena kedua mesin sibuk, \(n \ge 2\)) dihitung dengan formula probabilitas antrian (dikenal sebagai formula Erlang C): \[ P(n \ge 2) = \frac{a^c}{c!(1-\rho)} P_0 = \frac{0.8^2}{2! \times (0.6)} \times 0.4286 \approx 22.9% \] Dari sini, kita dapat menghitung panjang antrian rata-rata total: \[ L_q = P(n \ge 2) \times \frac{\rho}{1-\rho} = 0.2286 \times \frac{0.4}{0.6} \approx 0.152 \text{ pelanggan} \] Sehingga, waktu tunggu rata-rata total menjadi sangat singkat: \[ W_q = \frac{L_q}{\lambda} = \frac{0.152}{24} \approx 0.0063 \text{ jam, atau } 22.9 \text{ detik} \]
| Metrik | \(c=1\) | \(c=2\) | Catatan |
|---|---|---|---|
| Utilisasi per mesin (\(\rho\)) | 0.80 | 0.40 | Tingkat kesibukan per mesin |
| \(L_q\) (pelanggan) | 3.20 | 0.152 | Rata-rata total pelanggan mengantri |
| \(W_q\) (menit) | 8.0 | 0.4 | Rata-rata total waktu tunggu |
| \(P(\text{antri di luar})\) | 41.0% | 3.7% | Peluang menunggu di luar |
 Perbandingan antara kedua skenario menunjukkan keunggulan signifikan dari penambahan mesin kedua. Fokus utama dari analisis ini adalah masalah antrian di luar. Dari sisi analitis, kita dapat membandingkan probabilitas seorang pelanggan akan datang dan harus menunggu di luar, atau \(P(\text{antri di luar})\).
 Penambahan mesin kedua menurunkan probabilitas ini secara dramatis, dari 41.0% pada skenario satu mesin, menjadi hanya 3.7% pada skenario dua mesin. Penurunan tajam ini mengimplikasikan bahwa waktu tunggu dan panjang antrian di luar juga akan berkurang secara masif, mendekati nol. Besaran pastinya akan divalidasi melalui simulasi.
Rough-cut analysis menunjukkan penambahan mesin kedua secara dramatis mengurangi total antrian, waktu tunggu, dan yang terpenting, secara efektif mengurangis kemungkinan pelanggan harus antri di luar. Simulasi akan memvalidasi hasil ini.
 Simulasi ini bertujuan untuk memvalidasi analisis rough-cut. Kedua skenario (satu mesin vs dua mesin) beroperasi di bawah asumsi yang sama, yaitu kedatangan Poisson pada \(\lambda = 24\) pelanggan/jam, layanan eksponensial dengan \(\mu = 30\) pelanggan/jam per mesin, disiplin FIFO, dan batas kapasitas empat orang di dalam toko. Pertanyaan yang ingin kami jawab adalah:
Kami mengimplementasikan sebuah Discrete-Event Simulator (DES) dengan dua jenis events:
n_in_system < 4), pelanggan diterima dan masuk. Jika
penuh, mereka menunggu di antrian luar.Simulator secara kontinu memperbarui system-state dan mengumpulkan data berikut:
Setiap skenario dijalankan selama 64 jam, direplikasi 64 kali, dengan seed acak yang tetap untuk reproduktibilitas.
lambda <- 24
mu <- 30
K <- 4
time_horizon <- 64
n_replications <- 64
scenarios <- c("Satu Mesin" = 1, "Dua Mesin" = 2)| Simbol | Deskripsi | Nilai |
|---|---|---|
| \(\lambda\) | Laju kedatangan | 24 pelanggan/jam |
| \(\mu\) | Laju pelayanan per mesin | 30 pelanggan/jam |
| \(K\) | Kapasitas maksimum toko | 4 |
| Horizon | Lama simulasi | 64 jam |
| Reps | Replikasi independen | 64 |
| Scenarios | Skenario mesin | 1 dan 2 |
set.seed(123) # Untuk reproduktibilitas
run_simulation <- function(c, lambda, mu, K, horizon) {
## --- Initialize system states ---
clock <- 0
n_in_system <- 0
n_in_queue_internal <- 0
n_queue_outside <- 0
server_status <- rep(0, c)
queue_internal_arrival_times <- numeric(0)
queue_outside_arrival_times <- numeric(0)
## --- Initialize statistics collectors ---
arrivals_total <- 0
total_customers_served <- 0
had_to_wait_outside <- 0
total_wait_time_internal <- 0
total_wait_time_outside <- 0
total_system_time <- 0
area_under_l <- 0
area_under_q_internal <- 0
area_under_q_outside <- 0
total_server_busy_time <- numeric(c)
customer_data <- list()
## Seed the event list with the first arrival
event_list <- data.frame(
time = rexp(1, lambda),
type = "arrival",
server_id = NA_integer_,
customer_id = 1
)
customer_data[[1]] <- list(arrival_time = event_list$time[1])
next_cust_id <- 2
## --- Main event loop ---
while (clock < horizon) {
if (nrow(event_list) == 0) break
event_list <- event_list[order(event_list$time), ]
next_event <- event_list[1, ]
event_list <- event_list[-1, ]
if (is.na(next_event$time) || next_event$time > horizon) {
break
}
## Advance clock and update area-under-the-curve stats
time_since_last_event <- next_event$time - clock
area_under_l <- area_under_l + n_in_system * time_since_last_event
area_under_q_internal <- area_under_q_internal + n_in_queue_internal * time_since_last_event
area_under_q_outside <- area_under_q_outside + n_queue_outside * time_since_last_event
clock <- next_event$time
## --- Handle Arrival Event ---
if (next_event$type == "arrival") {
arrivals_total <- arrivals_total + 1
next_arrival_time <- clock + rexp(1, lambda)
if (next_arrival_time <= horizon) {
event_list <- rbind(event_list, data.frame(
time = next_arrival_time, type = "arrival", server_id = NA, customer_id = next_cust_id
))
customer_data[[next_cust_id]] <- list(arrival_time = next_arrival_time)
next_cust_id <- next_cust_id + 1
}
if (n_in_system < K) {
n_in_system <- n_in_system + 1
customer_data[[next_event$customer_id]]$shop_entry_time <- clock
idle_servers <- which(server_status == 0)
if (length(idle_servers) > 0) {
server_id <- idle_servers[1]
server_status[server_id] <- 1
service_time <- rexp(1, mu)
departure_time <- clock + service_time
customer_data[[next_event$customer_id]]$service_start_time <- clock
event_list <- rbind(event_list, data.frame(
time = departure_time, type = "departure", server_id = server_id, customer_id = next_event$customer_id
))
total_server_busy_time[server_id] <- total_server_busy_time[server_id] + service_time
} else {
n_in_queue_internal <- n_in_queue_internal + 1
queue_internal_arrival_times <- c(queue_internal_arrival_times, next_event$customer_id)
}
} else {
n_queue_outside <- n_queue_outside + 1
queue_outside_arrival_times <- c(queue_outside_arrival_times, next_event$customer_id)
had_to_wait_outside <- had_to_wait_outside + 1
}
## --- Handle Departure Event ---
} else if (next_event$type == "departure") {
server_id <- next_event$server_id
cust_id <- next_event$customer_id
total_system_time <- total_system_time + (clock - customer_data[[cust_id]]$arrival_time)
if (!is.null(customer_data[[cust_id]]$service_start_time) && !is.null(customer_data[[cust_id]]$shop_entry_time)) {
total_wait_time_internal <- total_wait_time_internal + (customer_data[[cust_id]]$service_start_time - customer_data[[cust_id]]$shop_entry_time)
}
total_customers_served <- total_customers_served + 1
server_status[server_id] <- 0 # Server is now free
if (n_queue_outside > 0) {
# Admit from outside first to fill the departing person's slot
admitted_cust_id <- queue_outside_arrival_times[1]
queue_outside_arrival_times <- queue_outside_arrival_times[-1]
n_queue_outside <- n_queue_outside - 1
customer_data[[admitted_cust_id]]$shop_entry_time <- clock
total_wait_time_outside <- total_wait_time_outside + (clock - customer_data[[admitted_cust_id]]$arrival_time)
n_in_queue_internal <- n_in_queue_internal + 1
queue_internal_arrival_times <- c(queue_internal_arrival_times, admitted_cust_id)
} else {
n_in_system <- n_in_system - 1
}
# Now, serve from internal queue if possible
if (n_in_queue_internal > 0) {
server_status[server_id] <- 1 # Re-occupy server
next_cust_id_internal <- queue_internal_arrival_times[1]
queue_internal_arrival_times <- queue_internal_arrival_times[-1]
n_in_queue_internal <- n_in_queue_internal - 1
customer_data[[next_cust_id_internal]]$service_start_time <- clock
service_time <- rexp(1, mu)
departure_time <- clock + service_time
event_list <- rbind(event_list, data.frame(
time = departure_time, type = "departure", server_id = server_id, customer_id = next_cust_id_internal
))
total_server_busy_time[server_id] <- total_server_busy_time[server_id] + service_time
}
}
}
L <- area_under_l / horizon
Lq_internal <- area_under_q_internal / horizon
Lq_outside <- area_under_q_outside / horizon
W_jam <- if (total_customers_served > 0) total_system_time / total_customers_served else 0
Wq_internal_jam <- if (total_customers_served > 0) total_wait_time_internal / total_customers_served else 0
Wq_outside_jam <- if (had_to_wait_outside > 0) total_wait_time_outside / had_to_wait_outside else 0
P_wait_outside <- if (arrivals_total > 0) had_to_wait_outside / arrivals_total else 0
utilization <- if (horizon > 0) sum(total_server_busy_time) / (c * horizon) else 0
data.frame(
L = L,
Lq_internal = Lq_internal,
Lq_outside = Lq_outside,
W_jam = W_jam,
Wq_internal_jam = Wq_internal_jam,
Wq_outside_jam = Wq_outside_jam,
P_wait_outside = P_wait_outside,
Utilisasi = utilization
)
} Fungsi run_simulation() memelihara state utama sistem,
yaitu jam simulasi, jumlah pelanggan di dalam toko
(n_in_system), antrian dalam
(n_in_queue_internal), antrian luar
(n_queue_outside), status setiap server, dan sebuah
event list. Kedatangan baru akan masuk ke sistem internal jika
ada ruang, atau ditambahkan ke antrian luar jika toko penuh.
Keberangkatan akan memicu penarikan pelanggan dari antrian luar (jika
ada) untuk masuk ke toko, dan server yang kosong akan segera melayani
pelanggan dari antrian dalam. Area di bawah kurva untuk jumlah pelanggan
di setiap state dihitung secara kontinu untuk memperoleh estimasi
steady-state (\(L\), \(L_{q, \text{dalam}}\), \(L_{q, \text{luar}}\)) sepanjang horizon 64
jam.
| Skenario | Metrik | Satuan | Rata-rata | Std. Dev | CI 95% (Bawah) | CI 95% (Atas) |
|---|---|---|---|---|---|---|
| Dua Mesin | L (pelanggan di dalam toko) | pelanggan | 0.922 | 0.050 | 0.910 | 0.934 |
| Satu Mesin | L (pelanggan di dalam toko) | pelanggan | 2.355 | 0.194 | 2.308 | 2.403 |
| Dua Mesin | Lq (antrian dalam) | pelanggan | 0.125 | 0.020 | 0.120 | 0.130 |
| Satu Mesin | Lq (antrian dalam) | pelanggan | 1.556 | 0.168 | 1.515 | 1.597 |
| Dua Mesin | Lq (antrian luar) | pelanggan | 0.024 | 0.013 | 0.021 | 0.027 |
| Satu Mesin | Lq (antrian luar) | pelanggan | 1.638 | 0.790 | 1.444 | 1.831 |
| Dua Mesin | W (total waktu di sistem, jam) | jam | 0.039 | 0.002 | 0.039 | 0.040 |
| Satu Mesin | W (total waktu di sistem, jam) | jam | 0.165 | 0.038 | 0.156 | 0.175 |
| Dua Mesin | Wq (tunggu dalam, jam) | jam | 0.005 | 0.001 | 0.005 | 0.005 |
| Satu Mesin | Wq (tunggu dalam, jam) | jam | 0.065 | 0.006 | 0.063 | 0.066 |
| Dua Mesin | Wq (tunggu luar, jam) | jam | 0.026 | 0.007 | 0.025 | 0.028 |
| Satu Mesin | Wq (tunggu luar, jam) | jam | 0.161 | 0.052 | 0.148 | 0.173 |
| Dua Mesin | P(harus antri luar) | proporsi | 0.036 | 0.012 | 0.033 | 0.039 |
| Satu Mesin | P(harus antri luar) | proporsi | 0.405 | 0.072 | 0.388 | 0.423 |
| Dua Mesin | Utilisasi per mesin | proporsi | 0.399 | 0.016 | 0.395 | 0.403 |
| Satu Mesin | Utilisasi per mesin | proporsi | 0.800 | 0.028 | 0.793 | 0.806 |
Hasil dari simulasi memvalidasi kesimpulan dari rough-cut analysis (model M/M/c)!
 Fokus utama perbandingan adalah metrik probabilitas
pelanggan harus antri di luar (P(antri di luar)),
yang dapat dihitung secara andal oleh kedua metode.
P(antri di luar) sebesar 41.0%, dan hasil
simulasi mengkonfirmasi angka ini dengan nilai 40.5%. Untuk metrik yang lebih spesifik seperti waktu tunggu
rata-rata di luar (Wq,luar), yang tidak dihitung
di bagian analitis karena kompleksitas formulanya, simulasi memberikan
jawaban definitif. Hasil simulasi menunjukkan bahwa pada
skenario satu mesin, waktu tunggu di luar adalah
masalah signifikan dengan rata-rata 9.6 menit. Sementara itu, pada
skenario dua mesin, waktu tunggu di luar turun menjadi
sangat kecil, yaitu hanya 95 detik.
 Kesesuaian yang terbukti pada metrik P(antri di luar)
dan kemampuan simulasi untuk mengukur Wq,luar secara
presisi memberikan keyakinan penuh pada kesimpulan akhir.
 Berdasarkan hasil model analitis dan simulasi yang konsisten dan kini selaras dengan realitas sistem, maka penambahan mesin fotokopi kedua SANGAT DIREKOMENDASIKAN.
 Dengan satu mesin, pelanggan memiliki kemungkinan 40.5% untuk harus menunggu di luar toko, dengan rata-rata waktu tunggu di luar yang signifikan yaitu sekitar 9.6 menit. Penambahan mesin kedua secara virtual mengeliminasi masalah antrian di luar, menurunkan peluangnya menjadi hanya 3.6% dan membuat waktu tunggu di luar menjadi sangat kecil. Ini secara langsung menjawab tujuan pemilik untuk menghindari pelanggan yang berbaris di luar toko, sehingga meningkatkan kepuasan pelanggan dan efisiensi operasional secara keseluruhan.
Tambah mesin copier!