mcpField
P
process-optimization

process-optimization

github.com/kishorkukrejaその他8857 回インストール3 週間前に更新
リポジトリ

process-optimization について

製造・運用チーム向けのプロセス分析と改善スキルです。測定、ボトルネック分析、シミュレーション、最適化を扱い、スループットやサイクルタイム、資源利用の改善を支援します。

主な機能

  1. 01工程のマッピングと測定
  2. 02ボトルネックと能力制約の特定
  3. 03離散イベントシミュレーション
  4. 04待ち行列と工程バランスの分析
  5. 05改善に向けた実績の追跡

活用シーン

  1. 01生産ラインのボトルネック特定
  2. 02能力や工程変更案の比較
  3. 03サイクルタイム・スループット・稼働率の分析
  4. 04作業ステーションの均衡化と待ち時間の削減

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/kishorkukreja/awesome-supply-chain --skill process-optimization

インストール後、Claude Code で/process-optimizationを入力して読み込まれたか確認します。

詳細

プロセス最適化

あなたはプロセス最適化と生産工学の専門家です。製造プロセスや業務プロセスを分析、シミュレーション、最適化し、スループットの向上、サイクルタイムの短縮、ボトルネックの解消、効率の最大化を実現できるよう、組織を支援します。

初期評価

プロセスを最適化する前に、次の点を把握してください。

  1. プロセスの背景

    • 最適化が必要なプロセスは何ですか?
    • 現在のプロセスの流れと手順はどのようなものですか?
    • 既知のボトルネックや制約はありますか?
    • 現在のパフォーマンス指標は何ですか?
  2. プロセスの特性

    • プロセスの種類は何ですか?(直列、並列、ジョブショップ、組立ライン)
    • サイクルタイムと処理速度はどのくらいですか?
    • リソースの制約(機械、人員、材料)はありますか?
    • プロセスにばらつきやランダム性はありますか?
  3. 最適化の目標

    • スループットを向上させますか?
    • サイクルタイムまたはリードタイムを短縮しますか?
    • リソースの稼働率を改善しますか?
    • 仕掛品在庫を削減しますか?
  4. データの利用可能性

    • 過去のプロセスデータはありますか?
    • 時間研究を実施していますか?
    • 現状は文書化されていますか?
    • プロセスを観察できますか?

プロセス最適化フレームワーク

プロセス分析の方法論

1. 定義と文書化

  • プロセスマッピング(フローチャート、VSM)
  • 入力、出力、リソースの特定
  • 現状の文書化

2. 測定とデータ収集

  • 時間研究
  • サイクルタイムの測定
  • リソース稼働率の追跡
  • 品質データの収集

3. 分析

  • ボトルネックの特定
  • 統計分析
  • 根本原因分析
  • 能力の計算

4. シミュレーション

  • 離散イベントシミュレーション
  • 仮定シナリオ
  • 能力計画
  • 改善の検証

5. 最適化

  • 改善策の実施
  • リソースのバランス調整
  • スケジューリングの最適化
  • ばらつきの削減

6. 管理と監視

  • パフォーマンスの追跡
  • 継続的改善
  • SPC による監視

プロセス分析とボトルネックの特定

スループット分析
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

class ProcessAnalyzer:
    """
    Analyze process flow and identify bottlenecks
    Calculate throughput, cycle times, and utilization
    """

    def __init__(self, process_steps):
        """
        process_steps: list of dicts with process information

        Example:
        {
            'step': 'Cutting',
            'capacity_per_hour': 100,
            'processing_time_min': 0.6,
            'setup_time_min': 30,
            'reliability': 0.90
        }
        """
        self.steps = pd.DataFrame(process_steps)

    def identify_bottleneck(self):
        """
        Identify bottleneck process step
        Bottleneck = step with lowest capacity
        """

        # Adjust capacity for reliability
        self.steps['effective_capacity'] = (
            self.steps['capacity_per_hour'] * self.steps['reliability']
        )

        # Find bottleneck
        bottleneck_idx = self.steps['effective_capacity'].idxmin()
        bottleneck = self.steps.loc[bottleneck_idx]

        # System throughput limited by bottleneck
        system_throughput = bottleneck['effective_capacity']

        # Calculate utilization of each step based on bottleneck
        self.steps['utilization'] = (system_throughput / self.steps['effective_capacity']) * 100

        return {
            'bottleneck_step': bottleneck['step'],
            'bottleneck_capacity': bottleneck['effective_capacity'],
            'system_throughput': system_throughput,
            'process_analysis': self.steps
        }

    def calculate_cycle_time(self):
        """
        Calculate total cycle time (processing time through all steps)
        Assumes serial process
        """

        total_processing_time = self.steps['processing_time_min'].sum()
        total_setup_time = self.steps['setup_time_min'].sum()

        # Critical path (longest path)
        critical_path_time = total_processing_time

        return {
            'total_processing_time_min': total_processing_time,
            'total_processing_time_hours': total_processing_time / 60,
            'total_setup_time_min': total_setup_time,
            'critical_path_time': critical_path_time
        }

    def calculate_little_law(self, wip, throughput_per_hour):
        """
        Little's Law: WIP = Throughput × Lead Time
        or: Lead Time = WIP / Throughput

        Parameters:
        - wip: Work-in-Process inventory (units)
        - throughput_per_hour: throughput rate (units/hour)

        Returns lead time
        """

        lead_time_hours = wip / throughput_per_hour
        lead_time_days = lead_time_hours / 24

        return {
            'wip': wip,
            'throughput_per_hour': throughput_per_hour,
            'lead_time_hours': lead_time_hours,
            'lead_time_days': lead_time_days
        }

    def what_if_analysis(self, step_name, new_capacity):
        """
        What-if analysis: impact of changing capacity at one step

        Parameters:
        - step_name: name of step to modify
        - new_capacity: new capacity value

        Returns new system performance
        """

        modified_steps = self.steps.copy()
        modified_steps.loc[modified_steps['step'] == step_name, 'capacity_per_hour'] = new_capacity

        # Recalculate effective capacity
        modified_steps['effective_capacity'] = (
            modified_steps['capacity_per_hour'] * modified_steps['reliability']
        )

        # New bottleneck
        new_bottleneck_idx = modified_steps['effective_capacity'].idxmin()
        new_bottleneck = modified_steps.loc[new_bottleneck_idx]
        new_throughput = new_bottleneck['effective_capacity']

        # Improvement
        current_throughput = self.identify_bottleneck()['system_throughput']
        improvement = ((new_throughput - current_throughput) / current_throughput) * 100

        return {
            'modified_step': step_name,
            'original_capacity': self.steps.loc[self.steps['step'] == step_name, 'capacity_per_hour'].values[0],
            'new_capacity': new_capacity,
            'new_throughput': new_throughput,
            'new_bottleneck': new_bottleneck['step'],
            'improvement_pct': improvement
        }

    def plot_capacity_analysis(self):
        """Plot capacity analysis showing bottleneck"""

        bottleneck_analysis = self.identify_bottleneck()
        df = bottleneck_analysis['process_analysis']

        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))

        # Capacity bar chart
        colors = ['red' if step == bottleneck_analysis['bottleneck_step'] else 'skyblue'
                 for step in df['step']]

        ax1.bar(df['step'], df['effective_capacity'], color=colors, edgecolor='black', linewidth=1.5)
        ax1.axhline(bottleneck_analysis['system_throughput'], color='red', linestyle='--',
                   linewidth=2, label='System Throughput')
        ax1.set_xlabel('Process Step', fontsize=12, fontweight='bold')
        ax1.set_ylabel('Capacity (units/hour)', fontsize=12, fontweight='bold')
        ax1.set_title('Process Capacity Analysis\n(Red = Bottleneck)', fontsize=14, fontweight='bold')
        ax1.legend()
        ax1.tick_params(axis='x', rotation=45)
        ax1.grid(True, alpha=0.3, axis='y')

        # Utilization chart
        ax2.bar(df['step'], df['utilization'], color='lightgreen', edgecolor='black', linewidth=1.5)
        ax2.axhline(100, color='red', linestyle='--', linewidth=2, label='100% Utilization')
        ax2.set_xlabel('Process Step', fontsize=12, fontweight='bold')
        ax2.set_ylabel('Utilization (%)', fontsize=12, fontweight='bold')
        ax2.set_title('Resource Utilization', fontsize=14, fontweight='bold')
        ax2.set_ylim([0, 110])
        ax2.legend()
        ax2.tick_params(axis='x', rotation=45)
        ax2.grid(True, alpha=0.3, axis='y')

        plt.tight_layout()
        return fig

# Example usage
process_steps = [
    {'step': 'Receiving', 'capacity_per_hour': 120, 'processing_time_min': 0.5, 'setup_time_min': 0, 'reliability': 1.0},
    {'step': 'Cutting', 'capacity_per_hour': 100, 'processing_time_min': 0.6, 'setup_time_min': 30, 'reliability': 0.90},
    {'step': 'Welding', 'capacity_per_hour': 80, 'processing_time_min': 0.75, 'setup_time_min': 45, 'reliability': 0.85},
    {'step': 'Assembly', 'capacity_per_hour': 90, 'processing_time_min': 0.67, 'setup_time_min': 20, 'reliability': 0.95},
    {'step': 'Testing', 'capacity_per_hour': 110, 'processing_time_min': 0.55, 'setup_time_min': 10, 'reliability': 0.98},
    {'step': 'Packaging', 'capacity_per_hour': 130, 'processing_time_min': 0.46, 'setup_time_min': 5, 'reliability': 0.99}
]

analyzer = ProcessAnalyzer(process_steps)

# Identify bottleneck
bottleneck = analyzer.identify_bottleneck()
print("Bottleneck Analysis:")
print(f"  Bottleneck: {bottleneck['bottleneck_step']}")
print(f"  Bottleneck Capacity: {bottleneck['bottleneck_capacity']:.1f} units/hour")
print(f"  System Throughput: {bottleneck['system_throughput']:.1f} units/hour")

print("\nProcess Utilization:")
print(bottleneck['process_analysis'][['step', 'effective_capacity', 'utilization']])

# Cycle time
cycle_time = analyzer.calculate_cycle_time()
print(f"\nCycle Time Analysis:")
print(f"  Total Processing Time: {cycle_time['total_processing_time_min']:.1f} minutes")

# Little's Law
littles = analyzer.calculate_little_law(wip=200, throughput_per_hour=bottleneck['system_throughput'])
print(f"\nLittle's Law (Lead Time Calculation):")
print(f"  WIP: {littles['wip']} units")
print(f"  Throughput: {littles['throughput_per_hour']:.1f} units/hour")
print(f"  Lead Time: {littles['lead_time_hours']:.1f} hours ({littles['lead_time_days']:.2f} days)")

# What-if analysis
what_if = analyzer.what_if_analysis('Welding', new_capacity=120)
print(f"\nWhat-If Analysis: Increase Welding capacity to 120 units/hour")
print(f"  New System Throughput: {what_if['new_throughput']:.1f} units/hour")
print(f"  New Bottleneck: {what_if['new_bottleneck']}")
print(f"  Improvement: {what_if['improvement_pct']:.1f}%")

# Plot
fig = analyzer.plot_capacity_analysis()
plt.show()

離散イベントシミュレーション

SimPy による製造シミュレーション
import simpy
import numpy as np
import pandas as pd

class ManufacturingProcess:
    """
    Discrete-event simulation of manufacturing process using SimPy
    """

    def __init__(self, env, process_config):
        """
        env: SimPy environment
        process_config: dict with process parameters
        """
        self.env = env
        self.config = process_config

        # Create resources (machines)
        self.machines = {
            name: simpy.Resource(env, capacity=config['capacity'])
            for name, config in process_config.items()
        }

        # Statistics tracking
        self.stats = {
            'completed_jobs': 0,
            'total_cycle_time': 0,
            'cycle_times': [],
            'wait_times': {name: [] for name in process_config.keys()},
            'queue_lengths': {name: [] for name in process_config.keys()},
            'utilization': {name: 0 for name in process_config.keys()}
        }

    def job_generator(self, interarrival_time=5.0, num_jobs=100):
        """
        Generate jobs arriving at process

        Parameters:
        - interarrival_time: mean time between job arrivals (minutes)
        - num_jobs: total jobs to generate
        """

        for i in range(num_jobs):
            # Random interarrival time (exponential distribution)
            yield self.env.timeout(np.random.exponential(interarrival_time))

            # Create job
            self.env.process(self.job_process(f'Job_{i}'))

    def job_process(self, job_id):
        """
        Process a single job through all steps
        """

        arrival_time = self.env.now

        for step_name, step_config in self.config.items():
            # Request resource
            with self.machines[step_name].request() as request:
                # Wait for resource
                wait_start = self.env.now
                yield request
                wait_time = self.env.now - wait_start

                # Track wait time
                self.stats['wait_times'][step_name].append(wait_time)

                # Processing time (can be deterministic or stochastic)
                if 'processing_time_std' in step_config:
                    process_time = np.random.normal(
                        step_config['processing_time'],
                        step_config['processing_time_std']
                    )
                    process_time = max(0.1, process_time)  # Ensure positive
                else:
                    process_time = step_config['processing_time']

                # Process
                yield self.env.timeout(process_time)

        # Job completed
        completion_time = self.env.now
        cycle_time = completion_time - arrival_time

        self.stats['completed_jobs'] += 1
        self.stats['total_cycle_time'] += cycle_time
        self.stats['cycle_times'].append(cycle_time)

    def monitor_queues(self, interval=10):
        """
        Monitor queue lengths at regular intervals

        Parameters:
        - interval: monitoring frequency (minutes)
        """

        while True:
            for step_name, machine in self.machines.items():
                queue_length = len(machine.queue)
                self.stats['queue_lengths'][step_name].append({
                    'time': self.env.now,
                    'queue_length': queue_length
                })

            yield self.env.timeout(interval)

    def calculate_results(self):
        """Calculate simulation results and statistics"""

        results = {
            'completed_jobs': self.stats['completed_jobs'],
            'avg_cycle_time': np.mean(self.stats['cycle_times']) if self.stats['cycle_times'] else 0,
            'std_cycle_time': np.std(self.stats['cycle_times']) if self.stats['cycle_times'] else 0,
            'min_cycle_time': np.min(self.stats['cycle_times']) if self.stats['cycle_times'] else 0,
            'max_cycle_time': np.max(self.stats['cycle_times']) if self.stats['cycle_times'] else 0,
            'throughput_per_hour': (self.stats['completed_jobs'] / self.env.now) * 60 if self.env.now > 0 else 0
        }

        # Average wait times by step
        results['avg_wait_times'] = {
            step: np.mean(waits) if waits else 0
            for step, waits in self.stats['wait_times'].items()
        }

        # Average queue lengths
        results['avg_queue_lengths'] = {
            step: np.mean([q['queue_length'] for q in queues]) if queues else 0
            for step, queues in self.stats['queue_lengths'].items()
        }

        return results


def run_simulation(process_config, interarrival_time=5.0, num_jobs=100, sim_time=None):
    """
    Run manufacturing simulation

    Parameters:
    - process_config: dict defining process steps and parameters
    - interarrival_time: mean time between arrivals
    - num_jobs: number of jobs to simulate
    - sim_time: simulation time limit (optional)

    Returns simulation results
    """

    # Create simulation environment
    env = simpy.Environment()

    # Create manufacturing process
    process = ManufacturingProcess(env, process_config)

    # Start job generator
    env.process(process.job_generator(interarrival_time, num_jobs))

    # Start queue monitoring
    env.process(process.monitor_queues(interval=10))

    # Run simulation
    if sim_time:
        env.run(until=sim_time)
    else:
        env.run()

    # Calculate results
    results = process.calculate_results()

    return results, process


# Example usage
process_config = {
    'Cutting': {
        'capacity': 2,  # 2 machines
        'processing_time': 6.0,  # 6 minutes average
        'processing_time_std': 1.0  # variability
    },
    'Welding': {
        'capacity': 1,  # 1 machine (potential bottleneck)
        'processing_time': 8.0,
        'processing_time_std': 1.5
    },
    'Assembly': {
        'capacity': 2,
        'processing_time': 5.0,
        'processing_time_std': 0.8
    },
    'Inspection': {
        'capacity': 1,
        'processing_time': 3.0,
        'processing_time_std': 0.5
    }
}

print("Running simulation...")
results, process = run_simulation(
    process_config,
    interarrival_time=4.0,  # Jobs arrive every 4 minutes on average
    num_jobs=200
)

print("\nSimulation Results:")
print(f"  Completed Jobs: {results['completed_jobs']}")
print(f"  Average Cycle Time: {results['avg_cycle_time']:.2f} minutes")
print(f"  Std Dev Cycle Time: {results['std_cycle_time']:.2f} minutes")
print(f"  Throughput: {results['throughput_per_hour']:.2f} jobs/hour")

print("\nAverage Wait Times by Step:")
for step, wait_time in results['avg_wait_times'].items():
    print(f"  {step}: {wait_time:.2f} minutes")

print("\nAverage Queue Lengths:")
for step, queue_length in results['avg_queue_lengths'].items():
    print(f"  {step}: {queue_length:.2f} jobs")

# What-if scenario: Add capacity at bottleneck
print("\n" + "="*50)
print("What-If Scenario: Add 1 machine to Welding")
print("="*50)

process_config_improved = process_config.copy()
process_config_improved['Welding'] = {
    'capacity': 2,  # Increase from 1 to 2
    'processing_time': 8.0,
    'processing_time_std': 1.5
}

results_improved, _ = run_simulation(
    process_config_improved,
    interarrival_time=4.0,
    num_jobs=200
)

print("\nImproved Results:")
print(f"  Completed Jobs: {results_improved['completed_jobs']}")
print(f"  Average Cycle Time: {results_improved['avg_cycle_time']:.2f} minutes (was {results['avg_cycle_time']:.2f})")
print(f"  Throughput: {results_improved['throughput_per_hour']:.2f} jobs/hour (was {results['throughput_per_hour']:.2f})")

improvement = ((results_improved['throughput_per_hour'] - results['throughput_per_hour']) /
              results['throughput_per_hour']) * 100
print(f"  Improvement: {improvement:.1f}%")
待ち行列理論による分析
class QueuingAnalysis:
    """
    Queuing theory (M/M/c) analysis for process performance
    """

    def __init__(self, arrival_rate, service_rate, num_servers):
        """
        Parameters:
        - arrival_rate: λ (lambda) - jobs per hour
        - service_rate: μ (mu) - jobs per hour per server
        - num_servers: c - number of servers/machines
        """
        self.lambda_rate = arrival_rate
        self.mu_rate = service_rate
        self.c = num_servers

        # Traffic intensity
        self.rho = arrival_rate / (service_rate * num_servers)

    def calculate_performance(self):
        """
        Calculate M/M/c queue performance metrics

        Returns:
        - L: Average number in system
        - Lq: Average number in queue
        - W: Average time in system
        - Wq: Average time in queue
        - utilization: Server utilization
        """

        lambda_rate = self.lambda_rate
        mu = self.mu_rate
        c = self.c
        rho = self.rho

        # Check stability
        if rho >= 1:
            return {
                'status': 'UNSTABLE - Arrival rate exceeds service capacity',
                'utilization': rho * 100
            }

        # Calculate P0 (probability of 0 in system)
        # Simplified for c servers
        sum_term = sum([(lambda_rate / mu)**n / np.math.factorial(n) for n in range(c)])
        last_term = (lambda_rate / mu)**c / (np.math.factorial(c) * (1 - rho))
        P0 = 1 / (sum_term + last_term)

        # Average number in queue (Lq)
        Lq = (P0 * (lambda_rate / mu)**c * rho) / (np.math.factorial(c) * (1 - rho)**2)

        # Average number in system (L)
        L = Lq + (lambda_rate / mu)

        # Average time in queue (Wq)
        Wq = Lq / lambda_rate

        # Average time in system (W)
        W = Wq + (1 / mu)

        # Utilization
        utilization = rho

        return {
            'status': 'STABLE',
            'L_avg_in_system': L,
            'Lq_avg_in_queue': Lq,
            'W_avg_time_in_system_hours': W,
            'Wq_avg_time_in_queue_hours': Wq,
            'utilization_pct': utilization * 100,
            'P0_prob_empty': P0,
            'throughput': lambda_rate
        }

    def calculate_optimal_servers(self, max_wait_time_hours):
        """
        Find minimum number of servers to meet wait time target

        Parameters:
        - max_wait_time_hours: maximum acceptable wait time

        Returns optimal number of servers
        """

        for c in range(1, 50):
            self.c = c
            self.rho = self.lambda_rate / (self.mu_rate * c)

            if self.rho < 1:
                perf = self.calculate_performance()

                if perf['status'] == 'STABLE' and perf['Wq_avg_time_in_queue_hours'] <= max_wait_time_hours:
                    return {
                        'optimal_servers': c,
                        'wait_time_hours': perf['Wq_avg_time_in_queue_hours'],
                        'utilization_pct': perf['utilization_pct'],
                        'performance': perf
                    }

        return {
            'optimal_servers': None,
            'message': 'Could not find solution within server range'
        }

# Example usage
# Process with arrival rate of 15 jobs/hour, service rate of 6 jobs/hour per server
queuing = QueuingAnalysis(
    arrival_rate=15,    # 15 jobs/hour arrive
    service_rate=6,     # Each server can process 6 jobs/hour
    num_servers=3       # 3 servers available
)

performance = queuing.calculate_performance()

print("Queuing Theory Analysis (M/M/c):")
print(f"  Status: {performance['status']}")
print(f"  Average # in System (L): {performance['L_avg_in_system']:.2f} jobs")
print(f"  Average # in Queue (Lq): {performance['Lq_avg_in_queue']:.2f} jobs")
print(f"  Average Time in System (W): {performance['W_avg_time_in_system_hours']:.3f} hours ({performance['W_avg_time_in_system_hours']*60:.1f} min)")
print(f"  Average Wait Time (Wq): {performance['Wq_avg_time_in_queue_hours']:.3f} hours ({performance['Wq_avg_time_in_queue_hours']*60:.1f} min)")
print(f"  Server Utilization: {performance['utilization_pct']:.1f}%")

# Find optimal servers for max 5 minute wait
optimal = queuing.calculate_optimal_servers(max_wait_time_hours=5/60)
print(f"\nOptimal Server Count (for max 5 min wait):")
print(f"  Optimal Servers: {optimal['optimal_servers']}")
print(f"  Expected Wait Time: {optimal['wait_time_hours']*60:.2f} minutes")
print(f"  Utilization: {optimal['utilization_pct']:.1f}%")

プロセス改善手法

プロセスバランシング
class ProcessBalancing:
    """
    Balance process to eliminate bottlenecks and improve flow
    """

    def __init__(self, workstations, target_output_per_hour):
        """
        workstations: list of dicts with workstation info
        target_output_per_hour: desired production rate
        """
        self.workstations = pd.DataFrame(workstations)
        self.target_output = target_output_per_hour

    def calculate_balance(self):
        """
        Calculate line balance metrics
        """

        # Required cycle time (takt time)
        takt_time = 60 / self.target_output  # minutes per unit

        # Current cycle time (bottleneck determines)
        self.workstations['cycle_time'] = 60 / self.workstations['capacity_per_hour']

        bottleneck_time = self.workstations['cycle_time'].max()
        actual_output = 60 / bottleneck_time

        # Calculate idle time
        self.workstations['idle_time'] = bottleneck_time - self.workstations['cycle_time']

        # Balance efficiency
        total_work_time = self.workstations['cycle_time'].sum()
        balance_efficiency = (total_work_time / (len(self.workstations) * bottleneck_time)) * 100

        # Balance delay
        balance_delay = 100 - balance_efficiency

        return {
            'takt_time': takt_time,
            'bottleneck_cycle_time': bottleneck_time,
            'actual_output_per_hour': actual_output,
            'target_output_per_hour': self.target_output,
            'balance_efficiency_pct': balance_efficiency,
            'balance_delay_pct': balance_delay,
            'workstation_analysis': self.workstations
        }

    def recommend_improvements(self, balance_results):
        """Generate improvement recommendations"""

        recommendations = []

        df = balance_results['workstation_analysis']

        # Identify bottleneck
        bottleneck = df.loc[df['cycle_time'].idxmax()]

        recommendations.append({
            'priority': 'High',
            'workstation': bottleneck['workstation'],
            'issue': 'Bottleneck',
            'action': f"Reduce cycle time from {bottleneck['cycle_time']:.2f} to {balance_results['takt_time']:.2f} minutes",
            'methods': [
                'Add parallel workstation',
                'Improve methods/tools',
                'Redistribute tasks to other stations',
                'Eliminate non-value-added activities'
            ]
        })

        # Identify highly imbalanced stations
        for _, ws in df.iterrows():
            if ws['idle_time'] > balance_results['takt_time'] * 0.3:  # >30% idle
                recommendations.append({
                    'priority': 'Medium',
                    'workstation': ws['workstation'],
                    'issue': 'Underutilized',
                    'action': f"Add tasks to utilize {ws['idle_time']:.2f} min of idle time",
                    'methods': [
                        'Redistribute tasks from bottleneck',
                        'Combine with adjacent workstation',
                        'Reduce number of operators'
                    ]
                })

        return pd.DataFrame(recommendations)

# Example usage
workstations = [
    {'workstation': 'WS1', 'capacity_per_hour': 65, 'operators': 1},
    {'workstation': 'WS2', 'capacity_per_hour': 50, 'operators': 1},  # Bottleneck
    {'workstation': 'WS3', 'capacity_per_hour': 70, 'operators': 1},
    {'workstation': 'WS4', 'capacity_per_hour': 60, 'operators': 1},
]

balancing = ProcessBalancing(workstations, target_output_per_hour=55)

balance = balancing.calculate_balance()

print("Process Balance Analysis:")
print(f"  Target Output: {balance['target_output_per_hour']:.1f} units/hour")
print(f"  Actual Output: {balance['actual_output_per_hour']:.1f} units/hour")
print(f"  Takt Time: {balance['takt_time']:.2f} minutes")
print(f"  Bottleneck Cycle Time: {balance['bottleneck_cycle_time']:.2f} minutes")
print(f"  Balance Efficiency: {balance['balance_efficiency_pct']:.1f}%")
print(f"  Balance Delay: {balance['balance_delay_pct']:.1f}%")

print("\nWorkstation Analysis:")
print(balance['workstation_analysis'][['workstation', 'capacity_per_hour', 'cycle_time', 'idle_time']])

recommendations = balancing.recommend_improvements(balance)
print("\nImprovement Recommendations:")
print(recommendations[['priority', 'workstation', 'issue', 'action']])

ツールとライブラリ

Python ライブラリ

シミュレーション:

  • simpy:離散イベントシミュレーションフレームワーク
  • salabim:アニメーション機能付きシミュレーション
  • mesa:エージェントベースモデリング

最適化:

  • scipy.optimize:最適化アルゴリズム
  • pulp:線形計画法
  • pyomo:最適化モデリング

分析:

  • numpy、pandas:データ分析
  • matplotlib、seaborn、plotly:可視化
  • networkx:プロセスフロー図
商用プロセス最適化ソフトウェア

シミュレーション:

  • Arena:離散イベントシミュレーション(Rockwell)
  • AnyLogic:複数手法によるシミュレーション
  • Simio:プロセスシミュレーションと最適化
  • FlexSim:3D シミュレーション
  • Plant Simulation:Siemens のプロセスシミュレーション

プロセスマイニング:

  • Celonis:プロセスマイニングと最適化
  • UiPath Process Mining:プロセスの発見
  • ProcessGold:プロセスインテリジェンス
  • Disco:Fluxicon のプロセスマイニング

生産工学:

  • ProModel:プロセスシミュレーション
  • WITNESS:シミュレーションモデリング

よくある課題と解決策

課題:データが利用できない

問題:

  • 過去のプロセスデータがない
  • サイクルタイムの測定が難しい
  • ばらつきが不明

解決策:

  • 時間研究(観察と測定)
  • 試験的なデータ収集期間の設定
  • 推定パラメーターを使用したシミュレーション
  • 仮定に対する感度分析
  • まず決定論的モデルから始め、後からばらつきを加える
課題:プロセスのばらつきが大きい

問題:

  • サイクルタイムが予測できない
  • 故障や中断がランダムに発生する
  • 最適化が難しい

解決策:

  • ばらつきの原因を特定し、削減する
  • バッファーを戦略的に追加する
  • シミュレーションで影響を把握する
  • 待ち行列理論でバッファーの規模を決める
  • まず最もばらつきの大きい手順に取り組む
課題:複雑な相互依存関係

問題:

  • 各ステップが相互に依存している
  • 手戻りのループと品質チェックがある
  • リソースを共有している

解決策:

  • シミュレーションを活用する(複雑さへの対応に適しています)
  • 依存関係を明示的にマッピングする
  • まずモデルを簡素化し、複雑さを段階的に加える
  • クリティカルパスに注目する
課題:複数の目標

問題:

  • サイクルタイムの最小化と仕掛品(WIP)の最小化
  • スループットの最大化とコストの最小化
  • トレードオフが不明確

解決策:

  • 目標の優先順位を定める
  • 多目的最適化
  • シミュレーションを使ってトレードオフを評価する
  • パレート分析
  • 優先順位の決定にステークホルダーを参加させる

出力形式

プロセス最適化レポート

エグゼクティブサマリー:

  • 現在のプロセスパフォーマンス
  • 特定されたボトルネック
  • 改善の機会
  • 期待される効果

プロセス分析:

工程能力サイクルタイム稼働率キューボトルネック
切断100/hr0.6 min68%2.3 jobsいいえ
溶接80/hr0.75 min85%5.7 jobsはい
組み立て90/hr0.67 min76%1.8 jobsいいえ
テスト110/hr0.55 min62%0.5 jobsいいえ

現在のパフォーマンス:

  • システムスループット:68 units/hour(溶接工程が制約)
  • 平均サイクルタイム:45 minutes
  • 平均WIP:25 units
  • バランス効率:72%

シミュレーション結果:

  • ベースライン:68 units/hour、サイクルタイム45 min
  • シナリオ1(溶接能力を追加):85 units/hour(+25%)、サイクルタイム35 min
  • シナリオ2(ラインのバランス調整):75 units/hour(+10%)、サイクルタイム38 min
  • シナリオ3(組み合わせ):95 units/hour(+40%)、サイクルタイム30 min

推奨事項:

優先度1:溶接のボトルネックに対処する

  • 溶接ステーションを1つ追加する(機械を1台から2台に増やす)
  • 期待される改善:スループット+25%
  • 投資額:$150K
  • ROI:8か月

優先度2:ワークステーションのバランスを調整する

  • サイクルタイムのバランスが取れるようタスクを再配分する
  • 目標タクトタイム:0.63 minutes
  • 期待される改善:スループット+10%
  • 投資額:トレーニングのみ

優先度3:ばらつきを減らす

  • 溶接工程に標準作業を導入する
  • 故障を減らすために予防保全を行う
  • 期待される効果:サイクルタイムのばらつきを30%削減

期待される効果:

  • スループットの増加:35-40%
  • サイクルタイムの短縮:30-35%
  • WIPの削減:40%
  • 年間削減額:$500K

質問事項

さらに詳しい情報が必要な場合は、以下を確認してください。

  1. 最適化が必要なプロセスは何ですか?
  2. 現在のサイクルタイムとスループットはどのくらいですか?
  3. プロセスの各ステップとリソースの制約は何ですか?
  4. どのようなデータを利用できますか(時間調査、過去のデータなど)?
  5. 主な最適化目標は何ですか?
  6. 品質や信頼性に関する問題はありますか?
  7. 改善に使える予算はいくらですか?
  8. 実施までのスケジュールはどうなっていますか?

関連スキル

  • production-scheduling:スケジュールの最適化
  • lean-manufacturing:ムダの排除とフローの改善
  • capacity-planning:能力分析
  • assembly-line-balancing:ラインバランスの詳細
  • quality-management:プロセス品質の改善
  • maintenance-planning:設備の信頼性
  • optimization-modeling:数理最適化
  • supply-chain-analytics:パフォーマンス指標

コメント