基于R simmer包的DES维修优化模型验证与状态时长计算问询
Hey there! Let's take a look at your simmer model for failure-repair simulation and figure out how to calculate system state durations properly.
First off, your model is structurally correct—it accurately represents a single-component, single-repairman failure-repair system:
- Component failure intervals follow an exponential distribution with rate λ (implemented via the
add_generatortrigger functionrexp(1, lambda)). - Repair times follow an exponential distribution with rate μ (handled by
timeout(function() rexp(1, mu))). - The repairman resource has an infinite queue, which matches the real-world scenario where failures wait for service if the repairman is busy.
This system is a classic M/M/1 queuing model, and we can use its analytical solution to verify your simulation results:
$$\text{Unavailability} = \frac{\lambda}{\lambda + \mu}$$
With your parameters ($\lambda=1/1000$, $\mu=1/10$), the analytical unavailability is ~0.0099 (1/101)—this gives you a benchmark to compare your simulation output against.
You can extract state durations in two straightforward ways:
Method 1: Use Arrival Logs (Simplest)
Simmer automatically logs the lifecycle of each "failure" entity. We can use this data to calculate total downtime directly:
# Extract arrival logs after running your model arrivals <- get_mon_arrivals(env.fr) # Calculate downtime for each failure event (from failure onset to repair completion) arrivals$downtime <- arrivals$end_time - arrivals$start_time # Compute total downtime and unavailability total_downtime <- sum(arrivals$downtime) unavailability <- total_downtime / 10000000 # 10000000 is your simulation end time # Calculate total uptime total_uptime <- 10000000 - total_downtime
With your set seed, the simulation result will be very close to the analytical benchmark.
Method 2: Explicitly Track System State (More Intuitive)
If you want clear visibility into state transitions, add state markers to your trajectory and analyze the attribute logs:
# Modify the trajectory to mark state changes traj <- trajectory() %>% # Mark system as failed (state 1) when a failure occurs set_attribute("system_state", 1) %>% seize("Repairman") %>% timeout(function() rexp(1, mu)) %>% release("Repairman") %>% # Mark system as normal (state 0) when repair finishes set_attribute("system_state", 0) # Re-run the model with the updated trajectory env.fr <- simmer("FailureRepair") %>% add_resource("Repairman", queue_size = Inf) %>% add_generator("failure", traj, function() rexp(1, lambda)) %>% run(until = 10000000) # Extract and clean state logs state_log <- get_mon_attributes(env.fr) %>% arrange(time) # Sort logs by time # Account for initial state: system starts in normal state (0) until first failure initial_uptime <- state_log$time[1] # Calculate duration of each state interval state_log <- state_log %>% mutate( next_time = c(time[-1], 10000000), duration = next_time - time ) # Sum total uptime and downtime total_uptime <- initial_uptime + sum(state_log$duration[state_log$value == 0]) total_downtime <- sum(state_log$duration[state_log$value == 1]) unavailability <- total_downtime / 10000000
This method lets you visualize exactly when state changes happen, which is useful if you plan to extend the model to more complex systems.
Your choice of simmer is perfect for this type of maintenance optimization problem—its flexible trajectory and resource system scales easily to multi-component, multi-repairman scenarios if you need to expand your model later.
内容的提问来源于stack exchange,提问作者Rel_Ai

