100本ノック / シミュレーション / シミュレーション100本ノック
製造業シミュレーション入門|Pythonで学ぶ生産能力・在庫・納期リスク
生産能力を「平均」だけで決めないための工場シミュレーション入門
100本ノックの全体像と目的
「製造業シミュレーション100本ノック」は、確率分布、待ち行列、離散イベント、連続系、確率過程、最適化、デジタルツインまでを、製造業の意思決定に結び付けながら段階的に学ぶシリーズです。目的は、手法の暗記ではなく、設備投資・人員配置・在庫・納期といった施策を、現場で試す前に仮想的に比較する力を身に付けることです。
今回は No.001〜No.010「シミュレーション入門」を扱います。架空の組立工場を題材に、モデル、状態、イベント、時間の進め方、確率モデルと決定論モデルの違いを、同じ業務文脈で確認します。
[!NOTE] 本資料は、数理工房 (もしくは代表である和山個人) が過去に企業研修において使用した notebook を企業様の許可を得て再構成・編集のうえ公開しています。
掲載データはすべて架空のものであり、実在する企業・工場・数値とは一切関係ありません。
はじめに:この記事で扱う製造業の実務課題
ある組立工場では「日産100台」という平均能力を根拠に受注を増やす案が出ています。しかし、実際の現場には加工時間のばらつき、突発故障、段取り、需要の揺れがあります。本記事では、増産後も納期と仕掛在庫(WIP)を守れるかを考えます。
現場でよくある状況
- 月平均の生産量は計画内だが、繁忙日に仕掛が急増する
- 平均加工時間だけで能力を計算し、停止やばらつきを過小評価する
- Excelの単一シナリオでは、悪いケースの頻度が分からない
- 設備増強、人員応援、保全強化の効果を同じKPIで比較できない
なぜこの問題は判断が難しいのか
平均値が同じでも、発生順序とばらつきが違えば待ち時間は変わります。また、設備投資は実機での試行が高価で、混雑や故障が重なる条件を再現しにくいものです。シミュレーションは、前提を明示し、複数シナリオを安全に反復するための「意思決定用の実験装置」です。ただし、モデルは現実そのものではなく、目的に必要な範囲へ単純化した表現です。
今回扱うノックの全体像
| No. | テーマ | 製造業での問い |
|---|---|---|
| 001 | シミュレーションとは何か | 施策を実機導入前に比較できるか |
| 002 | なぜ必要なのか | 平均値では見えない納期リスクは何か |
| 003 | システムモデリング | 工場の何を残し、何を捨てるか |
| 004 | 状態変数 | 現時点の工場状態をどう表すか |
| 005 | イベント | 状態を変える出来事は何か |
| 006 | 時間進行方式 | 固定刻みとイベント駆動をどう選ぶか |
| 007 | 離散時間 | 日次の在庫・能力をどう追うか |
| 008 | 連続時間 | タンク水位のような連続量をどう追うか |
| 009 | 確率 | ばらつきを含むリスクをどう測るか |
| 010 | 決定論 | 基準ケースと感度をどう確認するか |
Python 環境の準備
外部データは使用しません。numpy、pandas、matplotlib だけで架空データを生成・分析します。乱数生成器は seed を固定し、再実行しても同じ結果になるようにします。
import sys
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import japanize_matplotlib
SEED = 20260712
rng = np.random.default_rng(SEED)
pd.set_option("display.max_columns", 20)
print(f"Python : {sys.version.split()[0]}")
print(f"numpy : {np.__version__}")
print(f"pandas : {pd.__version__}")
print(f"matplotlib : {matplotlib.__version__}")
print(f"random seed: {SEED}")
Python : 3.13.1
numpy : 2.5.1
pandas : 3.0.3
matplotlib : 3.11.0
random seed: 20260712
架空データの作成
60稼働日の組立ラインを想定します。需要、実効能力、故障時間を生成し、在庫が不足した分は受注残として翌日に繰り越します。ここでの数値は教材用であり、実在工場とは関係ありません。
n_days = 60
days = np.arange(1, n_days + 1)
demand = np.maximum(70, rng.normal(98, 13, n_days).round()).astype(int)
downtime = np.where(rng.random(n_days) < 0.18, rng.gamma(2.0, 1.1, n_days), 0.0)
capacity = np.maximum(65, (108 - 8.0 * downtime + rng.normal(0, 4, n_days)).round()).astype(int)
inventory, backlog = 120, 0
records = []
for day, dem, cap, stop in zip(days, demand, capacity, downtime):
required = dem + backlog
production = min(cap, required)
available = inventory + production
shipped = min(available, required)
inventory = available - shipped
backlog = required - shipped
records.append((day, dem, cap, stop, production, shipped, inventory, backlog))
factory = pd.DataFrame(records, columns=[
"day", "demand", "capacity", "downtime_h", "production", "shipped", "inventory", "backlog"
])
factory.head(10).round(2)
| day | demand | capacity | downtime_h | production | shipped | inventory | backlog | |
|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 108 | 121 | 0.0 | 108 | 108 | 120 | 0 |
| 1 | 2 | 107 | 107 | 0.0 | 107 | 107 | 120 | 0 |
| 2 | 3 | 103 | 96 | 1.1 | 96 | 103 | 113 | 0 |
| 3 | 4 | 103 | 109 | 0.0 | 103 | 103 | 113 | 0 |
| 4 | 5 | 103 | 110 | 0.0 | 103 | 103 | 113 | 0 |
| 5 | 6 | 104 | 105 | 0.0 | 104 | 104 | 113 | 0 |
| 6 | 7 | 95 | 101 | 0.0 | 95 | 95 | 113 | 0 |
| 7 | 8 | 105 | 115 | 0.0 | 105 | 105 | 113 | 0 |
| 8 | 9 | 119 | 105 | 0.0 | 105 | 119 | 99 | 0 |
| 9 | 10 | 108 | 109 | 0.0 | 108 | 108 | 99 | 0 |
No.001:シミュレーションとは何か
実務での意味
シミュレーションは、設備・人・在庫・注文の相互作用を計算機上で再現し、施策別のKPIを比較する方法です。将来を一点で「当てる」ものではなく、前提を置いたときに何が起こり得るかを調べます。
分析・モデル化の考え方
ここでは能力を現状、増員、保全強化の3案で変え、累積需要と累積生産の差から最大受注残を比較します。評価軸は平均生産量だけでなく、サービス水準に直結する最大受注残です。
Pythonで確認する
scenarios = {"現状": 0, "増員(+8台/日)": 8, "保全強化(停止半減)": None}
rows = []
for name, uplift in scenarios.items():
cap = capacity + uplift if uplift is not None else np.maximum(65, (108 - 4.0 * downtime).round()).astype(int)
daily_gap = demand - cap
backlog_path = np.maximum.accumulate(np.r_[0, np.cumsum(daily_gap)])
backlog_path = np.cumsum(daily_gap) - np.minimum.accumulate(np.r_[0, np.cumsum(daily_gap)])[:-1]
rows.append([name, cap.mean(), max(0, backlog_path.max()), (cap >= demand).mean()])
scenario_result = pd.DataFrame(rows, columns=["施策", "平均能力(台/日)", "最大受注残(台)", "日次需要充足率"])
scenario_result.round({"平均能力(台/日)": 1, "日次需要充足率": 3})
| 施策 | 平均能力(台/日) | 最大受注残(台) | 日次需要充足率 | |
|---|---|---|---|---|
| 0 | 現状 | 105.2 | 40 | 0.733 |
| 1 | 増員(+8台/日) | 113.2 | 32 | 0.883 |
| 2 | 保全強化(停止半減) | 106.6 | 28 | 0.817 |
結果の読み取り
能力を一律に増やす案と、停止影響を減らす案では、平均能力が近くても最大受注残と日次需要充足率が異なります。意思決定では「平均能力が何台増えたか」だけでなく、納期リスクが許容範囲へ下がるかを確認します。費用を加えれば、次に費用対効果を比較できます。
No.002:なぜシミュレーションが必要なのか
実務での意味
平均需要が平均能力を下回っていても、繁忙と故障が重なれば受注残は発生します。静的な能力表では、発生順序による滞留を評価できません。
分析・モデル化の考え方
日次の負荷率を とします。平均負荷率に加え、日別負荷率の上側分位点と受注残の時系列を見ることで、通常日と厳しい日を分けて評価します。
Pythonで確認する
factory["load_ratio"] = factory["demand"] / factory["capacity"]
summary_002 = factory[["demand", "capacity", "load_ratio", "backlog"]].agg(["mean", "max"])
display(summary_002.round(2))
fig, ax = plt.subplots(figsize=(9, 4))
ax.plot(factory["day"], factory["demand"], label="需要", alpha=0.8)
ax.plot(factory["day"], factory["capacity"], label="実効能力", alpha=0.8)
ax.fill_between(factory["day"], factory["capacity"], factory["demand"],
where=factory["demand"] > factory["capacity"], color="tomato", alpha=0.25, label="能力不足")
ax.set_title("日次需要と実効生産能力")
ax.set_xlabel("稼働日")
ax.set_ylabel("台/日")
ax.grid(True, alpha=0.3)
ax.legend()
fig.tight_layout()
plt.show()
| demand | capacity | load_ratio | backlog | |
|---|---|---|---|---|
| mean | 99.38 | 105.22 | 0.95 | 1.82 |
| max | 126.00 | 121.00 | 1.47 | 40.00 |

結果の読み取り
全期間平均だけなら余力があるように見えても、赤い領域では当日の能力が需要を下回ります。こうした不足が連続すると、後日の余力で取り戻すまで受注残が残ります。納期判断には、平均だけでなく時系列、最大値、上側分位点が必要です。
No.003:システムモデリングとは
実務での意味
システムモデリングは、対象範囲、構成要素、因果関係、境界条件を定める作業です。増員判断なら、人の詳細な動作すべてではなく、能力・故障・需要・在庫の関係を残すのが出発点です。
分析・モデル化の考え方
入力を需要 と能力 、状態を在庫 と受注残 、出力を出荷 とします。概念的には、
です。目的に不要な詳細を省くことで、説明可能で更新しやすいモデルにします。
Pythonで確認する
model_register = pd.DataFrame({
"区分": ["入力", "入力", "状態", "状態", "ルール", "出力KPI"],
"要素": ["日次需要", "実効能力", "完成品在庫", "受注残", "在庫・受注残更新式", "最大受注残"],
"単位": ["台/日", "台/日", "台", "台", "台", "台"],
"今回残す理由": ["負荷の源泉", "供給制約", "即納余力", "納期リスク", "要素間の因果", "施策比較"]
})
model_register
| 区分 | 要素 | 単位 | 今回残す理由 | |
|---|---|---|---|---|
| 0 | 入力 | 日次需要 | 台/日 | 負荷の源泉 |
| 1 | 入力 | 実効能力 | 台/日 | 供給制約 |
| 2 | 状態 | 完成品在庫 | 台 | 即納余力 |
| 3 | 状態 | 受注残 | 台 | 納期リスク |
| 4 | ルール | 在庫・受注残更新式 | 台 | 要素間の因果 |
| 5 | 出力KPI | 最大受注残 | 台 | 施策比較 |
結果の読み取り
モデル台帳により「何をモデル化し、何をまだ入れていないか」が明確になります。たとえば品種別段取りを入れていないため、品種構成が能力へ強く影響する判断には、このモデルをそのまま使えません。モデルの限界を明示することも品質の一部です。
No.004:状態変数とは
実務での意味
状態変数は、ある時点から将来計算を再開するために必要な情報です。在庫、受注残、設備の稼働状態、仕掛数などが該当します。
分析・モデル化の考え方
状態を日次で保存すると、悪化が始まった日と回復に要した期間を追跡できます。フロー量(需要・生産)とストック量(在庫・受注残)を混同しないことが重要です。
Pythonで確認する
state_snapshot = factory.loc[factory["backlog"].idxmax(),
["day", "inventory", "backlog", "downtime_h", "capacity"]]
print("受注残が最大となった日の状態")
display(state_snapshot.to_frame("値").round(2))
fig, ax = plt.subplots(figsize=(9, 4))
ax.step(factory["day"], factory["inventory"], where="post", label="完成品在庫")
ax.step(factory["day"], factory["backlog"], where="post", label="受注残")
ax.set_title("工場の状態変数の推移")
ax.set_xlabel("稼働日")
ax.set_ylabel("台")
ax.grid(True, alpha=0.3)
ax.legend()
fig.tight_layout()
plt.show()
受注残が最大となった日の状態
| 値 | |
|---|---|
| day | 48.00 |
| inventory | 0.00 |
| backlog | 40.00 |
| downtime_h | 2.47 |
| capacity | 86.00 |

結果の読み取り
在庫が緩衝材として減った後に受注残が増える流れが確認できます。最大受注残日のスナップショットは、能力不足だけでなく、故障時間や直前までの在庫水準を合わせて原因分析する起点になります。
No.005:イベントとは
実務での意味
イベントは、到着、加工完了、故障、復旧など、状態を瞬時に変える出来事です。イベント履歴は停止ロスや滞留の説明責任に役立ちます。
分析・モデル化の考え方
イベントを「時刻・種類・状態変化」の表で管理します。故障なら稼働状態を1から0へ、復旧なら0から1へ更新します。順序が結果へ影響するため、時刻順に処理します。
Pythonで確認する
events = pd.DataFrame([
(0.0, "始業", 1, 0), (0.8, "注文到着", 0, 12), (1.6, "加工完了", 0, -1),
(2.2, "設備故障", -1, 0), (3.4, "設備復旧", 1, 0), (4.1, "加工完了", 0, -1),
(5.0, "注文到着", 0, 8), (6.3, "加工完了", 0, -1),
], columns=["時刻(h)", "イベント", "稼働状態の変化", "待ち数の変化"])
events["稼働状態"] = events["稼働状態の変化"].cumsum().clip(0, 1)
events["待ち数"] = events["待ち数の変化"].cumsum().clip(lower=0)
events
| 時刻(h) | イベント | 稼働状態の変化 | 待ち数の変化 | 稼働状態 | 待ち数 | |
|---|---|---|---|---|---|---|
| 0 | 0.0 | 始業 | 1 | 0 | 1 | 0 |
| 1 | 0.8 | 注文到着 | 0 | 12 | 1 | 12 |
| 2 | 1.6 | 加工完了 | 0 | -1 | 1 | 11 |
| 3 | 2.2 | 設備故障 | -1 | 0 | 0 | 11 |
| 4 | 3.4 | 設備復旧 | 1 | 0 | 1 | 11 |
| 5 | 4.1 | 加工完了 | 0 | -1 | 1 | 10 |
| 6 | 5.0 | 注文到着 | 0 | 8 | 1 | 18 |
| 7 | 6.3 | 加工完了 | 0 | -1 | 1 | 17 |
結果の読み取り
故障から復旧まで設備状態は停止ですが、注文は別の時刻に到着し得ます。この例では簡略化していますが、実務では加工完了ごとに待ち数を減らし、停止中は完了イベントを発生させないルールを置きます。イベントログは、なぜその待ちが生じたかを時系列で説明できます。
No.006:時間進行方式
実務での意味
時間の進め方は、計算量と精度を左右します。固定時間刻みは日次・分次KPIに分かりやすく、イベント駆動は発生間隔が不規則な物流や設備挙動に向きます。
分析・モデル化の考え方
固定刻み方式は全時点を走査します。イベント駆動方式は次のイベント時刻へ時計を飛ばします。イベントが疎なほど後者の処理回数が少なくなります。
Pythonで確認する
horizon_min = 8 * 60
event_times = np.array([12, 48, 103, 177, 245, 332, 419, 475])
comparison = pd.DataFrame({
"方式": ["固定刻み(1分)", "固定刻み(10分)", "イベント駆動"],
"時計更新回数": [horizon_min, horizon_min // 10, len(event_times)],
"時刻表現": ["1分単位", "10分単位", "イベント時刻を保持"],
"適した用途": ["細かな連続監視", "日内KPIの概算", "待ち行列・故障・搬送"]
})
comparison
| 方式 | 時計更新回数 | 時刻表現 | 適した用途 | |
|---|---|---|---|---|
| 0 | 固定刻み(1分) | 480 | 1分単位 | 細かな連続監視 |
| 1 | 固定刻み(10分) | 48 | 10分単位 | 日内KPIの概算 |
| 2 | イベント駆動 | 8 | イベント時刻を保持 | 待ち行列・故障・搬送 |
結果の読み取り
同じ8時間でも処理回数は大きく異なります。ただし、回数の少なさだけで選ぶのではありません。温度や液位の連続変化を追うなら刻み幅の妥当性が重要で、加工完了や故障だけが状態を変えるならイベント駆動が自然です。
No.007:離散時間シミュレーション
実務での意味
離散時間モデルは、日次在庫、週次要員、月次需給のように、一定間隔で意思決定する業務と相性が良い方式です。
分析・モデル化の考え方
日末在庫を と更新し、不足量を欠品として数えます。刻み幅より短い日中変動は表現しないため、目的に合う時間粒度を選びます。
Pythonで確認する
weekly_demand = np.array([94, 106, 121, 88, 112, 97, 125, 101, 90, 116])
daily_capacity, stock = 105, 80
trajectory = []
for t, dem in enumerate(weekly_demand, 1):
available = stock + daily_capacity
shipped = min(available, dem)
shortage = dem - shipped
stock = available - shipped
trajectory.append((t, dem, daily_capacity, shipped, stock, shortage))
discrete = pd.DataFrame(trajectory, columns=["日", "需要", "生産", "出荷", "日末在庫", "欠品"])
discrete
| 日 | 需要 | 生産 | 出荷 | 日末在庫 | 欠品 | |
|---|---|---|---|---|---|---|
| 0 | 1 | 94 | 105 | 94 | 91 | 0 |
| 1 | 2 | 106 | 105 | 106 | 90 | 0 |
| 2 | 3 | 121 | 105 | 121 | 74 | 0 |
| 3 | 4 | 88 | 105 | 88 | 91 | 0 |
| 4 | 5 | 112 | 105 | 112 | 84 | 0 |
| 5 | 6 | 97 | 105 | 97 | 92 | 0 |
| 6 | 7 | 125 | 105 | 125 | 72 | 0 |
| 7 | 8 | 101 | 105 | 101 | 76 | 0 |
| 8 | 9 | 90 | 105 | 90 | 91 | 0 |
| 9 | 10 | 116 | 105 | 116 | 80 | 0 |
結果の読み取り
日次更新だけでも、在庫が需要変動を吸収する様子を確認できます。一方、同じ日内で午前に注文が集中する即納性は評価できません。日末在庫の計画には使えても、分単位の待ち時間評価には別の粒度が必要です。
No.008:連続時間シミュレーション
実務での意味
液位、温度、圧力、濃度のように時間とともに連続的に変化する量は、連続時間モデルで表します。制御設定や安全限界の検討に利用できます。
分析・モデル化の考え方
混合タンク水位 を、流入 と流出係数 から
とします。ここではオイラー法 で近似します。
Pythonで確認する
dt, end = 0.05, 12
t = np.arange(0, end + dt, dt)
h = np.zeros_like(t)
h[0] = 2.0
q_in, k = 0.8, 0.22
for i in range(len(t) - 1):
h[i + 1] = h[i] + dt * (q_in - k * h[i])
fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(t, h, label="タンク水位")
ax.axhline(q_in / k, color="tomato", linestyle="--", label="理論上の平衡水位")
ax.set_title("連続時間モデルによるタンク水位")
ax.set_xlabel("時間 (h)")
ax.set_ylabel("水位 (m)")
ax.grid(True, alpha=0.3)
ax.legend()
fig.tight_layout()
plt.show()
print(f"12時間後の水位: {h[-1]:.2f} m / 平衡水位: {q_in/k:.2f} m")

12時間後の水位: 3.52 m / 平衡水位: 3.64 m
結果の読み取り
水位は直ちに平衡値へ移るのではなく、徐々に近づきます。上限水位がある場合は、到達時刻を使って警報や流入制御を設計できます。実務適用では、実測値で係数を同定し、刻み幅を変えて数値誤差も確認します。
No.009:確率シミュレーション
実務での意味
需要、故障、加工時間には偶然変動があります。確率シミュレーションは、平均結果だけでなく、欠品確率や利益の下側分位点などのリスクを数値化します。
分析・モデル化の考え方
同じ施策を多数回反復するモンテカルロ法を使います。利益を
と仮定し、需要と故障の乱数を各反復で変えます。金額は教材用の相対的な比較尺度です。
Pythonで確認する
mc_rng = np.random.default_rng(SEED)
n_runs, horizon = 3000, 20
results = []
for run in range(n_runs):
dem = np.maximum(0, mc_rng.normal(100, 14, horizon)).round()
failures = mc_rng.binomial(1, 0.15, horizon)
cap = 108 - failures * mc_rng.integers(20, 45, horizon)
shortage = np.maximum(dem - cap, 0).sum()
shipped = np.minimum(dem, cap).sum()
profit = 1200 * shipped - 400 * cap.sum() - 3000 * shortage
results.append((shortage, profit))
mc = pd.DataFrame(results, columns=["累積欠品台数", "利益"])
metrics_009 = pd.Series({
"平均欠品台数": mc["累積欠品台数"].mean(),
"欠品発生確率": (mc["累積欠品台数"] > 0).mean(),
"利益5%点": mc["利益"].quantile(0.05),
"平均利益": mc["利益"].mean(),
})
display(metrics_009.to_frame("値").round(1))
fig, ax = plt.subplots(figsize=(8, 4))
ax.hist(mc["利益"] / 10000, bins=35, edgecolor="white")
ax.axvline(mc["利益"].quantile(0.05) / 10000, color="tomato", linestyle="--", label="利益5%点")
ax.set_title("20日間利益のシミュレーション分布")
ax.set_xlabel("利益(万円)")
ax.set_ylabel("試行回数")
ax.grid(True, alpha=0.3)
ax.legend()
fig.tight_layout()
plt.show()
| 値 | |
|---|---|
| 平均欠品台数 | 115.1 |
| 欠品発生確率 | 1.0 |
| 利益5%点 | 806540.0 |
| 平均利益 | 1091632.2 |

結果の読み取り
平均利益だけでは、厳しいケースの損失を見落とします。利益5%点は「前提どおりなら約20回に1回はこれ以下」という下振れ指標です。経営判断では、期待値とリスク許容度を併記し、分布仮定を実績データで検証します。
No.010:決定論的シミュレーション
実務での意味
決定論的モデルは、同じ入力なら必ず同じ結果を返します。基準計画の整合確認、損益分岐点、パラメータ感度の説明に向きます。
分析・モデル化の考え方
需要と能力を固定し、安全在庫水準だけを変えます。不確実性を表さない代わりに、入力と結果の因果が明快です。確率モデルの比較基準としても有効です。
Pythonで確認する
demand_plan = np.array([95, 100, 110, 115, 105, 98, 120, 108, 102, 112])
capacity_plan = np.full_like(demand_plan, 106)
rows = []
for initial_stock in range(0, 101, 10):
cumulative_net = initial_stock + np.cumsum(capacity_plan - demand_plan)
min_stock = cumulative_net.min()
shortage = max(0, -min_stock)
ending_stock = cumulative_net[-1] + shortage
rows.append((initial_stock, shortage, ending_stock))
deterministic = pd.DataFrame(rows, columns=["初期在庫", "計画上の不足", "補填後の期末在庫"])
display(deterministic)
fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(deterministic["初期在庫"], deterministic["計画上の不足"], marker="o")
ax.set_title("初期在庫に対する計画不足の感度")
ax.set_xlabel("初期在庫(台)")
ax.set_ylabel("計画上の不足(台)")
ax.grid(True, alpha=0.3)
fig.tight_layout()
plt.show()
| 初期在庫 | 計画上の不足 | 補填後の期末在庫 | |
|---|---|---|---|
| 0 | 0 | 5 | 0 |
| 1 | 10 | 0 | 5 |
| 2 | 20 | 0 | 15 |
| 3 | 30 | 0 | 25 |
| 4 | 40 | 0 | 35 |
| 5 | 50 | 0 | 45 |
| 6 | 60 | 0 | 55 |
| 7 | 70 | 0 | 65 |
| 8 | 80 | 0 | 75 |
| 9 | 90 | 0 | 85 |
| 10 | 100 | 0 | 95 |

結果の読み取り
固定計画のもとで不足をゼロにする初期在庫の目安を説明できます。しかし、故障や需要上振れが起きる確率は分かりません。まず決定論モデルで構造と基準値を確認し、重要な不確実性だけを確率化する段階的な進め方が実務的です。
対象ノックを通して見える実務上の示唆
| 判断対象 | 推奨する表現 | 主なKPI | 注意点 |
|---|---|---|---|
| 月次需給・在庫 | 離散時間・決定論 | 期末在庫、計画不足 | 日中の混雑は見えない |
| 故障・搬送・待ち | イベント駆動・確率 | 待ち時間、WIP、納期遵守率 | イベントルールの検証が必要 |
| 温度・液位・圧力 | 連続時間 | 上限到達時刻、安定値 | 係数同定と刻み幅確認が必要 |
| 設備投資 | 複数シナリオ+確率 | 期待利益、下側分位点、最大受注残 | 費用・制約も同じ境界に含める |
重要なのは、高度なモデルを最初から作ることではありません。意思決定、対象KPI、時間粒度、必要な状態とイベントを先に定め、単純な決定論モデルから検証可能な形で育てます。
実務導入する場合に必要なこと
- 意思決定を定義する:設備購入、人員応援、安全在庫変更など、比較する選択肢を明文化する
- KPIと許容値を合意する:平均だけでなく、納期遵守率、最大WIP、利益5%点などを置く
- データ品質を確認する:時刻定義、欠損、停止理由、計画値と実績値の区別をそろえる
- 妥当性を検証する:現場レビュー、過去期間の再現、極端条件テスト、感度分析を行う
- 運用責任を決める:前提更新、モデル版管理、再計算頻度、承認者を定める
シミュレーション結果を自動的な決定とみなさず、前提・適用範囲・不確実性と一緒に意思決定会議へ提示します。
まとめ
No.001〜No.010では、シミュレーションを「現実の重要部分を目的に合わせて表現し、施策を比較する実験」と捉えました。状態、イベント、時間進行方式を区別すると、日次在庫、設備故障、タンク水位などに適したモデルが選べます。決定論モデルは基準と因果を、確率モデルは下振れリスクを示します。次の段階では、実績との照合を通じてモデルを改善し、投資・納期・在庫の判断へ接続します。
法人向けのご相談
数理工房では、製造現場のデータ整理、シミュレーション設計、設備投資・人員配置・在庫施策の比較、社内研修まで、意思決定の段階に合わせて支援します。「まず対象工程とKPIを整理したい」という段階でもご相談いただけます。
📩 お問い合わせ: surikobo.co.jp/contact
まずはお気軽にご相談ください。