
在仿真建模中,为模拟对象(如订单、任务等)动态分配属性是常见的需求。特别是在作业车间或生产线模型中,订单的截止日期(due date)往往需要根据特定规则生成。当需要从一组预定义的、离散的时间点中均匀随机选择截止日期时,需要采用特定的随机数生成方法结合时间处理机制。
固定截止日期的初始设置(示例)
在许多情况下,我们可能首先会尝试设置一个固定的截止日期。例如,将所有订单的截止日期设置为当日的18:00:00 PM。以下是一个常见的实现方式,它使用Java的Calendar类来构建时间对象:
Order order = new Order(); // 创建一个新的订单对象 Calendar cal1 = Calendar.getInstance(); // 获取当前日历实例 cal1.set(Calendar.HOUR_OF_DAY, 18); // 设置小时为18 cal1.set(Calendar.MINUTE, 0); // 设置分钟为0 cal1.set(Calendar.SECOND, 0); // 设置秒为0 cal1.set(Calendar.MILLISECOND, 0); // 设置毫秒为0 order.atrDueDate1 = cal1.getTime(); // 将设置好的时间赋值给订单的截止日期属性 order.atrID = 10; // 设置订单ID order.markParametersAreSet(); // 标记参数已设置(AnyLogic特定方法) // enter.take(order); // 将订单送入流程(AnyLogic特定方法)
这种方法虽然能成功设置固定截止日期,但无法满足从多个时间点随机选择的需求。
实现均匀随机选择的截止日期
要实现从一组固定时间点(例如18:00、19:00、20:00、21:00)中均匀随机选择截止日期,关键在于利用离散均匀分布的随机数生成器来决定小时数。
核心思路
- 确定随机范围: 明确需要随机选择的小时数范围,本例中是18到21。
- 生成离散随机数: 使用一个能生成指定范围内整数的离散均匀分布函数。
- 更新时间对象: 将生成的小时数应用到Calendar对象中。
示例代码
假设我们正在使用AnyLogic仿真软件,它提供了内置的uniform_discr(min, max)函数,可以生成min和max(包含)之间的整数,且每个整数出现的概率相同。
Order order = new Order(); // 创建一个新的订单对象 Calendar cal1 = Calendar.getInstance(); // 获取当前日历实例 // 关键步骤:使用 uniform_discr 函数随机选择小时数 // uniform_discr(18, 21) 将会以相同的概率返回 18, 19, 20 或 21 cal1.set(Calendar.HOUR_OF_DAY, uniform_discr(18, 21)); cal1.set(Calendar.MINUTE, 0); // 设置分钟为0 cal1.set(Calendar.SECOND, 0); // 设置秒为0 cal1.set(Calendar.MILLISECOND, 0); // 设置毫秒为0 order.atrDueDate1 = cal1.getTime(); // 将设置好的时间赋值给订单的截止日期属性 order.atrID = 10; // 设置订单ID order.markParametersAreSet(); // 标记参数已设置 // 最佳实践:创建并启动代理 order.createAndStart(main); // 将新创建的订单代理添加到主模型中并启动
代码解释:
- uniform_discr(18, 21):这是AnyLogic特有的函数,它会从整数集合 {18, 19, 20, 21} 中均匀随机地选择一个数。
- cal1.set(Calendar.HOUR_OF_DAY, ...):将随机生成的小时数设置到Calendar对象中。这样,每次生成的订单都将拥有一个在18:00到21:00之间均匀随机分布的截止日期。
通用Java实现(无AnyLogic环境)
如果不在AnyLogic环境中使用,而是纯Java环境,可以使用java.util.Random类来实现离散均匀分布:
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
public class OrderGenerator {
// 假设 Order 类和 atrDueDate1 属性已定义
static class Order {
Date atrDueDate1;
int atrID;
// 模拟 AnyLogic 的方法,实际Java应用中可能不同
void markParametersAreSet() { /* ... */ }
void createAndStart(Object main) { /* ... */ }
}
public static void main(String[] args) {
Random random = new Random();
int minHour = 18;
int maxHour = 21; // 包含21
for (int i = 0; i < 5; i++) { // 生成5个订单作为示例
Order order = new Order();
Calendar cal1 = Calendar.getInstance();
// 生成 minHour 到 maxHour 之间的随机整数(包含maxHour)
int randomHour = random.nextInt(maxHour - minHour + 1) + minHour;
cal1.set(Calendar.HOUR_OF_DAY, randomHour);
cal1.set(Calendar.MINUTE, 0);
cal1.set(Calendar.SECOND, 0);
cal1.set(Calendar.MILLISECOND, 0);
order.atrDueDate1 = cal1.getTime();
order.atrID = 100 + i;
order.markParametersAreSet();
// order.createAndStart(null); // 在纯Java环境中可能需要不同的处理方式
System.out.println("Order ID: " + order.atrID + ", Due Date: " + order.atrDueDate1);
}
}
}代理创建的最佳实践
在AnyLogic等基于代理的仿真环境中,创建新的代理(Agent)并将其正确地集成到模型中是至关重要的。仅仅实例化一个对象(new Order())是不够的,还需要调用特定的方法来将其添加到模型运行时并启动其行为逻辑。
order.createAndStart(main); 这行代码就是实现这一点的关键。它确保:
- 代理初始化: 代理的生命周期方法(如onStartup)被调用。
- 模型集成: 代理被添加到模型的代理集合中,使其能够参与到仿真事件和交互中。
- 避免问题: 不正确地创建代理可能导致空指针异常、代理无法执行其逻辑、或者模型状态不一致等问题。
始终遵循仿真框架提供的代理创建和启动机制是保证模型正确性和健壮性的最佳实践。
注意事项与总结
- 日期部分: Calendar.set(Calendar.HOUR_OF_DAY, ...) 仅修改了小时、分钟、秒和毫秒部分。日历的年、月、日部分会保留当前系统的日期或仿真模型中的当前日期。如果需要将截止日期设置到未来的特定日期,还需要额外设置Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH等字段。
- 随机性来源: 确保使用的随机数生成器是真正均匀分布的。对于更复杂的随机需求(如非均匀分布),需要使用相应的统计分布函数。
- 代码可读性: 在实际项目中,可以将生成随机截止日期的逻辑封装成一个单独的函数,提高代码的模块化和可读性。
- 框架特定性: uniform_discr和createAndStart是AnyLogic的特定函数和方法。在其他仿真框架或纯Java项目中,需要使用对应的API。
通过上述方法,您可以有效地在模拟环境中为订单生成均匀随机分布于一组固定时间点的截止日期,同时遵循代理创建的最佳实践,确保模型的正确运行和数据的一致性。










