Mímisbrunnr知恵の泉

← オペレーションズマネジメント 一覧

🎓 レベル:標準 | 重要度:A(必須)

📎 前提:プロセス分析とリトルの法則I=RTI=R\,T=WIPとフロータイム)・制約理論TOCとスループット(ロープ=投入を制約に縛る) | 関連:定量発注と定期発注(補充の発注方式) | 次:ばらつきと改善の数理

要点(BLUF)

1. リーンとJIT:プル生産と7つのムダ

リーンの出発点は「顧客にとっての価値を生まない活動はすべてムダ(muda)」という見方です。TPS は典型的なムダを7つに分類しました。

ムダ中身
作りすぎ売れる前に・必要より多く作る(最悪のムダ。他の6つを誘発し在庫を生む)
手待ち部品・情報・前工程を待って止まっている時間(制約の枯渇もこれ)
運搬必要のない移動・積み替え
加工そのもの過剰な精度・不要な工程
在庫必要以上の原材料・仕掛・製品。問題を覆い隠す
動作探す・かがむ・持ち替えるなど価値を生まない動き
不良作り直し・手直し・廃棄(源流で止める=シックスシグマと検査設計 の 1-10-100)

中でも作りすぎが最悪とされるのは、それが在庫を生み、手待ちや運搬や不良を覆い隠すから。前章 制約理論TOCとスループット の言葉で言えば、作りすぎは TT(スループット)を増やさずに II(在庫)と OEOE(保管・管理)だけを膨らませます。

作りすぎを断つ仕組みが**プル(後工程引き取り)**です。

flowchart LR
  START["顧客の引き取り"] -. "起点(プルの号砲)" .-> POST
  PRE["前工程"] -->|"モノは下流へ流れる"| POST["後工程"]
  POST -. "かんばん(作ってよい信号)は上流へ戻る" .-> PRE

プッシュ(計画先行)では、前工程はスケジュールや予測に従って先に作り込みます。需要や下流の進み具合がずれると、作ったものが下流の手前で滞留する(作りすぎ・在庫)。プルでは、後工程が実際に引き取った(消費した)ぶんだけ、かんばんという信号が上流に戻って初めて前工程が補充します。だからWIP が需要に縛られ、作りすぎが構造的に起きません。なお JIT・かんばん・5S・自働化といった運営管理の概論は 中小企業診断士テキスト も参照してください。本ノートは「なぜプルでリードタイムと在庫が縮むのか」を数理で扱います。

2. かんばん:枚数の式とWIP上限

かんばん(看板)は、部品の入った1コンテナに付くカードで、「このコンテナを補充してよい/運んでよい」という許可証です。カードの枚数が、ループ内に存在できるコンテナ数=WIP の上限を物理的に決めます。では何枚要るか。

補充のリードタイム LL(カードが外れてから補充が戻るまで)の間、後工程は DLD\cdot L 個を消費します。これにばらつきへの安全係数 α\alpha を上乗せした量を、入数 CC 個のコンテナで賄うので、必要なカード枚数は

K=DL(1+α)CK=\frac{D\,L\,(1+\alpha)}{C}

(実枚数は切り上げ)。このループに存在できる最大の仕掛在庫

WIPmax=KC\text{WIP}_{\max}=K\cdot C

です。ここで プロセス分析とリトルの法則I=RTI=R\,T を当てます。このループのスループット(フローレート)は需要率 R=DR=D、在庫は I=WIPmax=KCI=\text{WIP}_{\max}=KC で頭打ち。よってループを通る平均フロータイムの上限

Tmax=WIPmaxD=KCDL(1+α)T_{\max}=\frac{\text{WIP}_{\max}}{D}=\frac{K\,C}{D}\approx L\,(1+\alpha)

かんばん枚数を絞ること=WIP に上限をかけること=フロータイム(リードタイム)に上限をかけること。これがプルの数理的な正体です。そして KKLL に比例するので、リードタイム短縮が在庫削減に直結します。

3. タクトタイムと平準化

タクトタイム(独 Takt=拍子)は需要の歩調そのもので、

タクトタイム=利用可能な生産時間その間の需要数\text{タクトタイム}=\frac{\text{利用可能な生産時間}}{\text{その間の需要数}}

「1個を何秒ごとに仕上げれば需要にちょうど追いつくか」を表します(ボトルネックとキャパシティ のタクトタイムと同じ)。各工程のサイクルタイム(実際に1個作るのにかかる時間)をタクトタイム以下に揃えることで、過不足なく流れます。タクト > サイクルなら能力過剰(手待ち)、タクト < サイクルなら能力不足(欠品)。

プルを安定させる前提が平準化(heijunka)です。需要のばらつきをそのまま生産に流すと、プルは山と谷で破綻します。そこで生産量と品種を時間軸でならして(たとえば AABABAAB… のように小ロットで混流)、各工程への負荷を一定に近づける。平準化と一個流し(ロットでまとめず1個ずつ流す)でロット待ちと仕掛を減らし、リードタイムを短縮します。なぜ平準化=ばらつき低減がここまで効くのかは、次の ばらつきと改善の数理 でキングマンの式として定量化します。

4. かんばん枚数とリードタイム短縮(コード)

かんばん枚数 K=DL(1+α)/CK=DL(1+\alpha)/C を、需要率・リードタイム・入数から計算します。リードタイム LL を縮めるとかんばん枚数(=WIP 上限)が減ること、そして WIP 上限を需要率で割るとフロータイム上限になる(リトルの法則)ことを確かめます。

import numpy as np
import pandas as pd

# かんばん枚数 K = D*L*(1+alpha)/C (実枚数は切り上げ)
D = 60.0      # 需要率(個/時)
C = 10        # コンテナ入数(個/枚)
alpha = 0.20  # 安全係数

rows = []
for L in [4.0, 3.0, 2.0, 1.0, 0.5]:   # リードタイム(時)
    K_raw = D * L * (1 + alpha) / C
    K = int(np.ceil(K_raw))            # 実際のかんばん枚数は切り上げ
    WIP = K * C                        # WIP上限 = かんばん枚数 × 入数(個)
    T_cap = WIP / D                    # リトル I=R*T -> フロータイム上限 = WIP/D(時)
    rows.append({"リードL_時": L, "K_理論": K_raw, "K_枚数": K,
                 "WIP上限_個": WIP, "フロータイム上限_時": T_cap})
df = pd.DataFrame(rows)
print(f"需要率 D={D} 個/時, コンテナ入数 C={C} 個, 安全係数 alpha={alpha}")
print(df.to_string(index=False, float_format=lambda x: f"{x:.3f}"))
print()
K4 = int(np.ceil(D * 4.0 * (1 + alpha) / C))
K05 = int(np.ceil(D * 0.5 * (1 + alpha) / C))
print(f"リードタイム 4.0時間 -> 0.5時間 の短縮で:")
print(f"  かんばん {K4} 枚 -> {K05} 枚,  WIP上限 {K4*C} 個 -> {K05*C} 個")
print(f"リトルの法則の確認(L=2.0時間の行):WIP上限/D = {15*C}/{D} = {15*C/D:.3f} 時間"
      f" = フロータイム上限")

出力:

需要率 D=60.0 個/時, コンテナ入数 C=10 個, 安全係数 alpha=0.2
 リードL_時   K_理論  K_枚数  WIP上限_個  フロータイム上限_時
  4.000 28.800    29      290       4.833
  3.000 21.600    22      220       3.667
  2.000 14.400    15      150       2.500
  1.000  7.200     8       80       1.333
  0.500  3.600     4       40       0.667

リードタイム 4.0時間 -> 0.5時間 の短縮で:
  かんばん 29 枚 -> 4 枚,  WIP上限 290 個 -> 40 個
リトルの法則の確認(L=2.0時間の行):WIP上限/D = 150/60.0 = 2.500 時間 = フロータイム上限

出力の意味:需要 D=60D=60 個/時・入数 C=10C=10・安全係数 α=0.2\alpha=0.2 のとき、リードタイム L=4L=4 時間なら必要かんばんは約28.8枚 → 切り上げて29枚、ループ内 WIP の上限は 29×10=29029\times10=290 個です。リードタイムを縮めていくと、L=2L=2 で15枚・150個、L=1L=1 で8枚・80個、L=0.5L=0.5 では4枚・40個リードタイムを8分の1(4→0.5時間)にすると、かんばんは29→4枚、WIP は290→40個へ激減しました。KKLL に比例するからです。そして右端の「フロータイム上限」列は、各行で WIP 上限 ÷ 需要率 DD(リトルの法則 I=RTI=R\,TT=I/RT=I/R と解いたもの)。L=2L=2 の行で確認すると 150/60=2.500150/60=2.500 時間で、計画リードタイム L(1+α)=2×1.2=2.4L(1+\alpha)=2\times1.2=2.4 時間に切り上げぶんが乗った上限になっています。かんばんを減らす=WIP に蓋をする=フロータイムに蓋をする。在庫削減とリードタイム短縮が同じコインの裏表だと、リトルの法則が教えてくれます。

5. プル vs プッシュ:WIP は有界に保たれる(コード)

プルの真価は「ばらつきがあっても WIP とフロータイムが暴走しない」点にあります。同じ変動するボトルネック(平均能力10個/期)と同じ需要(平均9.5個/期)に対し、プッシュ(計画どおり能力ぴったり10個/期を先行投入)とプル(CONWIP:総 WIP を上限15個に縛り、需要に引かれたぶんだけ投入)を400期シミュレーションし、WIP の推移を比べます。

import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib

rng = np.random.default_rng(7)
T = 400
mu = 10.0                          # 1期あたり平均処理能力(ボトルネック)
cap = rng.poisson(mu, T)           # 各期の実処理能力(ばらつきあり)
demand = rng.poisson(9.5, T)       # 各期の需要(平均9.5 < 能力10)

def run_push(release_rate):
    """プッシュ:毎期 release_rate だけ投入(ライン状態を見ない=計画先行)。"""
    wip = np.zeros(T + 1)
    processed_tot = 0
    for t in range(T):
        inflow = release_rate
        processed = min(wip[t] + inflow, cap[t])       # 能力の範囲で処理
        processed_tot += processed
        wip[t + 1] = wip[t] + inflow - processed
    return wip, processed_tot

def run_conwip(wip_cap):
    """プル(CONWIP):WIP を上限 wip_cap 以下に保つよう投入を絞る(後工程引き取り)。"""
    wip = np.zeros(T + 1)
    backlog = 0.0
    processed_tot = 0
    for t in range(T):
        backlog += demand[t]                            # 需要は受注残として積む
        room = max(0.0, wip_cap - wip[t])               # 投入できる空き
        inflow = min(backlog, room)                     # 空きと需要の小さい方だけ投入
        backlog -= inflow
        processed = min(wip[t] + inflow, cap[t])
        processed_tot += processed
        wip[t + 1] = wip[t] + inflow - processed
    return wip, processed_tot

wip_push, thru_push = run_push(release_rate=10)   # 能力ぴったりを計画投入(高稼働志向)
wip_pull, thru_pull = run_conwip(wip_cap=15)      # CONWIP 上限15

mwp, mwl = wip_push.mean(), wip_pull.mean()
print(f"総需要 = {demand.sum()} 個")
print(f"プッシュ:平均WIP={mwp:6.1f} 個, 最大WIP={wip_push.max():3.0f} 個, "
      f"最終WIP={wip_push[-1]:3.0f} 個, 総産出={thru_push:.0f} 個")
print(f"プル    :平均WIP={mwl:6.1f} 個, 最大WIP={wip_pull.max():3.0f} 個, "
      f"最終WIP={wip_pull[-1]:3.0f} 個, 総産出={thru_pull:.0f} 個")
# リトルの法則:フロータイム = 平均WIP / スループット(期)
rp_push, rp_pull = thru_push / T, thru_pull / T
print()
print(f"スループット(個/期):プッシュ={rp_push:.3f}, プル={rp_pull:.3f}")
print(f"フロータイム I=R*T -> T=I/R(期):プッシュ={mwp/rp_push:.2f}, プル={mwl/rp_pull:.2f}")
print(f"プルのフロータイム上限 = WIP上限/スループット = 15/{rp_pull:.3f} = {15/rp_pull:.2f} 期")

plt.figure(figsize=(9.5, 5.5))
plt.plot(wip_push, color="#d62728", lw=1.4, label=f"プッシュ(計画先行)平均WIP={mwp:.0f}")
plt.plot(wip_pull, color="#1f77b4", lw=1.4, label=f"プル CONWIP(上限15)平均WIP={mwl:.0f}")
plt.axhline(15, ls="--", color="#1f77b4", alpha=0.6, label="CONWIP の WIP上限=15")
plt.xlabel("期"); plt.ylabel("仕掛在庫 WIP(個)")
plt.title("プッシュは WIP が膨らむ/プル(CONWIP)は WIP が有界")
plt.legend(loc="upper left"); plt.tight_layout()
plt.show()

出力:

総需要 = 3773 個
プッシュ:平均WIP=  17.4 個, 最大WIP= 49 個, 最終WIP= 30 個, 総産出=3970 個
プル    :平均WIP=   3.8 個, 最大WIP= 12 個, 最終WIP=  0 個, 総産出=3773 個

スループット(個/期):プッシュ=9.925, プル=9.432
フロータイム I=R*T -> T=I/R(期):プッシュ=1.75, プル=0.40
プルのフロータイム上限 = WIP上限/スループット = 15/9.432 = 1.59 期

出力の意味プッシュは「能力を遊ばせない」ために毎期10個を計画投入します。能力もばらつく(平均10)ので、投入が能力をわずかに上回る期が積み重なり、WIP は平均17.4個・最大49個まで膨れ上がり(図の赤い線が天井知らずにさまよう)、フロータイムは1.75期に伸びます。しかも総産出3970個は総需要3773個を197個も上回る——これは売れる前に作った作りすぎ(最悪のムダ)で、余分な完成在庫として滞留します。一方プルは WIP を上限15個に縛るので、平均WIP 3.8個・最大でも12個(需要に引かれたぶんしか投入しないため上限15にすら届かない)。図の青い線は破線の上限15を一度も超えません。総産出3773個は総需要にぴたり一致(作りすぎゼロ)、フロータイムは0.40期。そして決定的なのが最終行——プルのフロータイムは WIP 上限 ÷ スループット =15/9.432=1.59=15/9.432=1.59 期で構造的に頭打ちプロセス分析とリトルの法則I=RTI=R\,T)。WIP に蓋をすれば、リトルの法則がフロータイムにも蓋をする。プッシュの「高稼働を狙って先行投入」は、待ち行列の基礎とリトルの法則 で見た「稼働率を1に近づけると待ちが爆発する」のと同じ罠で、WIP と作りすぎを生むのです。

⚠️ よくある誤解

関連ノート