160 lines
6.2 KiB
Python
160 lines
6.2 KiB
Python
# mos_transfer_temp_sweep.py
|
|
# Parent script for Multi-Temperature MOSFET Transfer Sweep
|
|
# Runs mos_transfer_single_temp.py for various temperatures, combines data, and plots results
|
|
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
import time
|
|
import numpy as np
|
|
import matplotlib.pyplot as plt
|
|
|
|
# Configuration
|
|
import argparse
|
|
parser = argparse.ArgumentParser(description="Run multi-temperature MOSFET transfer curves sweep.")
|
|
parser.add_argument("--vds", type=float, default=float(os.environ.get("VDS", 1.0)), help="Drain-Source Voltage Vds (V).")
|
|
args = parser.parse_args(sys.argv[1:] if len(sys.argv) > 1 else [])
|
|
vds_target = args.vds
|
|
|
|
DEV_DIR = os.environ.get("DEV_DIR", "devices/LDMOS")
|
|
default_out_dirname = f"output_transfer_temp_{time.strftime('%y%m%d')}_01"
|
|
OUT_DIR = os.path.join(os.environ.get("OUT_DIR", os.path.join(DEV_DIR, default_out_dirname)), "")
|
|
os.makedirs(OUT_DIR, exist_ok=True)
|
|
|
|
# Temperature list in Celsius
|
|
temps_C = [-40.0, -20.0, 0.0, 25.0, 50.0, 75.0, 100.0, 125.0]
|
|
|
|
print("=============================================================================")
|
|
# простые математические выражения, избегаем латекса в stdout
|
|
print("MOSFET Transfer Sweep across Temperatures")
|
|
print("=============================================================================")
|
|
print(f"Device directory: {DEV_DIR}")
|
|
print(f"Output directory: {OUT_DIR}")
|
|
print(f"Vds: {vds_target:.3f} V")
|
|
print(f"Temperatures (C): {temps_C}")
|
|
print("=============================================================================")
|
|
|
|
# Run simulation subprocesses
|
|
start_time = time.time()
|
|
for temp in temps_C:
|
|
print(f"\n>>> Running simulation at T = {temp:.1f} C...")
|
|
cmd = [
|
|
sys.executable,
|
|
"mos_transfer_single_temp.py",
|
|
"--temp", str(temp),
|
|
"--out_dir", OUT_DIR,
|
|
"--vds", str(vds_target)
|
|
]
|
|
# Set DEV_DIR env for child
|
|
child_env = os.environ.copy()
|
|
child_env["DEV_DIR"] = DEV_DIR
|
|
|
|
proc_start = time.time()
|
|
try:
|
|
# Run process and wait for completion
|
|
subprocess.run(cmd, env=child_env, check=True)
|
|
print(f"Finished T = {temp:.1f} C in {time.time() - proc_start:.1f}s.")
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"Error: Simulation for T = {temp:.1f} C failed: {e}")
|
|
# Continue to other temperatures instead of hard-failing
|
|
|
|
print(f"\nAll simulations completed in {time.time() - start_time:.1f}s.")
|
|
|
|
# --- Combine Data and Plot ---
|
|
print("\nCombining data and generating plots...")
|
|
|
|
sweep_results = {}
|
|
for temp in temps_C:
|
|
csv_file = os.path.join(OUT_DIR, f"transfer_vgs_sweep_{temp:+.1f}C.csv")
|
|
if os.path.exists(csv_file):
|
|
try:
|
|
data = np.loadtxt(csv_file, delimiter=",", skiprows=1)
|
|
if data.ndim == 2 and data.shape[0] > 0:
|
|
vgs = data[:, 0]
|
|
ids = data[:, 1]
|
|
iav = data[:, 2]
|
|
sweep_results[temp] = (vgs, ids, iav)
|
|
else:
|
|
print(f"Warning: Empty or malformed data in {csv_file}")
|
|
except Exception as e:
|
|
print(f"Warning: Could not read {csv_file}: {e}")
|
|
|
|
if not sweep_results:
|
|
print("Error: No sweep results found to plot or combine. Aborting.")
|
|
sys.exit(1)
|
|
|
|
# Write combined CSV file
|
|
combined_csv_file = os.path.join(OUT_DIR, "mos_transfer_all_temps.csv")
|
|
with open(combined_csv_file, "w") as f_combined:
|
|
headers = []
|
|
for temp in sorted(sweep_results.keys()):
|
|
headers.append(f"Vgs_T_{temp:+.1f}C(V)")
|
|
headers.append(f"Ids_T_{temp:+.1f}C(A)")
|
|
headers.append(f"Iav_T_{temp:+.1f}C(A)")
|
|
f_combined.write(",".join(headers) + "\n")
|
|
|
|
# Find max length to align columns
|
|
max_len = max(len(v[0]) for v in sweep_results.values())
|
|
for idx in range(max_len):
|
|
row_cells = []
|
|
for temp in sorted(sweep_results.keys()):
|
|
vgs_vals, ids_vals, iav_vals = sweep_results[temp]
|
|
if idx < len(vgs_vals):
|
|
row_cells.append(f"{vgs_vals[idx]:.6e}")
|
|
row_cells.append(f"{ids_vals[idx]:.6e}")
|
|
row_cells.append(f"{iav_vals[idx]:.6e}")
|
|
else:
|
|
row_cells.append("")
|
|
row_cells.append("")
|
|
row_cells.append("")
|
|
f_combined.write(",".join(row_cells) + "\n")
|
|
|
|
print(f"Saved combined curves data to {combined_csv_file}")
|
|
|
|
# Set styling for premium looks
|
|
plt.rcParams.update({
|
|
'font.family': 'sans-serif',
|
|
'font.size': 11,
|
|
'grid.alpha': 0.3,
|
|
'grid.linestyle': '--'
|
|
})
|
|
|
|
# Generate distinct premium colors
|
|
colors = plt.cm.plasma(np.linspace(0.1, 0.9, len(sweep_results)))
|
|
|
|
# Plot 1: Linear Scale Plot (Ids in mA)
|
|
plt.figure(figsize=(10, 7))
|
|
for color_idx, temp in enumerate(sorted(sweep_results.keys())):
|
|
vgs_vals, ids_vals, _ = sweep_results[temp]
|
|
plt.plot(vgs_vals, ids_vals * 1e3, '-', color=colors[color_idx], linewidth=2, label=f"T = {temp:+.1f} °C")
|
|
plt.grid(True)
|
|
plt.xlabel("Gate-Source Voltage Vgs (V)", fontsize=12)
|
|
plt.ylabel("Drain-Source Current Ids (mA)", fontsize=12)
|
|
plt.title(f"LDMOS Transfer Characteristics vs Temperature (Linear Scale, Vds={vds_target:.3f}V)", fontsize=14, fontweight="bold")
|
|
plt.legend(loc="upper left", fontsize=10)
|
|
plt.tight_layout()
|
|
plot_path_linear = os.path.join(OUT_DIR, "mos_transfer_curves_linear.png")
|
|
plt.savefig(plot_path_linear, dpi=300)
|
|
plt.close()
|
|
print(f"Saved linear scale plot to {plot_path_linear}")
|
|
|
|
# Plot 2: Logarithmic Scale Plot (Ids in Amperes)
|
|
plt.figure(figsize=(10, 7))
|
|
for color_idx, temp in enumerate(sorted(sweep_results.keys())):
|
|
vgs_vals, ids_vals, _ = sweep_results[temp]
|
|
plt.plot(vgs_vals, np.abs(ids_vals), '-', color=colors[color_idx], linewidth=2, label=f"T = {temp:+.1f} °C")
|
|
plt.yscale('log')
|
|
plt.ylim(1e-12, 1e-1) # standard bounds for threshold inspection
|
|
plt.grid(True, which="both")
|
|
plt.xlabel("Gate-Source Voltage Vgs (V)", fontsize=12)
|
|
plt.ylabel("Drain-Source Current Ids (A)", fontsize=12)
|
|
plt.title(f"LDMOS Transfer Characteristics vs Temperature (Log Scale, Vds={vds_target:.3f}V)", fontsize=14, fontweight="bold")
|
|
plt.legend(loc="lower right", fontsize=10)
|
|
plt.tight_layout()
|
|
plot_path_log = os.path.join(OUT_DIR, "mos_transfer_curves_log.png")
|
|
plt.savefig(plot_path_log, dpi=300)
|
|
plt.close()
|
|
print(f"Saved log scale plot to {plot_path_log}")
|
|
|
|
print("\nAll tasks finished successfully!")
|