For this tutorial you will generate some sample (fake) measurement data so you can post it to your project.
You're going to create a new folder and populate it with JSON files containing the fake measurement data for the whole wafer.
import json
import shutil
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
np.random.seed(42)
def iv_resistance(resistance, current) -> np.ndarray:
"""Returns IV.
Args:
resistance: in Ohms.
current: electrical intensity in A.
"""
v = resistance * current
return v
i = np.linspace(0, 100, 21)
v = iv_resistance(resistance=30, current=i)
plt.plot(i, v)
plt.title("Resistance")
plt.xlabel("Current (A)")
plt.ylabel("V")
plt.grid(True)
plt.show()
You can define different wafer maps for each wafer.
wafer_definitions = Path("wafer_definitions.json")
wafers = ["2eq221eqewq2", "334abd342zuq", "6d4c615ff105"]
dies = [{"x": x, "y": y} for y in range(-2, 3) for x in range(-2, 3) if not (abs(y) == 2 and abs(x) == 2)]
# Wrap in a list with the wafer information
data = [{"wafer": wafer_pkey, "dies": dies} for wafer_pkey in wafers]
with open(wafer_definitions, "w") as f:
json.dump(data, f, indent=2)
You can easily generate some data and add some noise to make it look like a real measurement.
wafers_path = Path("wafers").resolve()
shutil.rmtree(wafers_path, ignore_errors=True)
wafers_path.mkdir(parents=True, exist_ok=True)
metadata = {"measurement_type": "Spectral MEAS", "temperature": 25}
length = 20
ohms_per_square = 100
resistances = []
for wafer in wafers:
wafer_per_cent_variation = 0.20 # 20% variation
wafer_variation_factor = 1 + wafer_per_cent_variation * (2 * np.random.rand() - 1)
for die in dies:
die = f"{(die['x'])}_{(die['y'])}"
for (_, row), (_, device_row) in zip(df.iterrows(), df.iterrows(), strict=False):
cell_id = row["cell"]
basic_resistance = ohms_per_square * row["width_um"] * length * 1e-12
device_per_cent_variation = 0.05 # 5% variation
device_variation_factor = 1 + device_per_cent_variation * (2 * np.random.rand() - 1)
resistance = basic_resistance * wafer_variation_factor * device_variation_factor
# Special resistance cases (open and short circuits)
rand_num = np.random.rand()
if rand_num < 0.05:
resistance = 3000 # 5% with infinite resistance (open circuit)
elif rand_num < 0.08: # Additional 3% (total 8% chance)
resistance = 0 # 3% with zero resistance (short circuit)
top_cell_id = "resistance"
device_id = f"{top_cell_id}_{cell_id}_{device_row['x']}_{device_row['y']}"
resistances.append(resistance)
v = iv_resistance(resistance=resistance, current=i)
noise = 5e-2 * np.random.rand(len(v)) * v # add 5% noise
v += noise
dirpath = wafers_path / wafer / die / device_id
dirpath.mkdir(exist_ok=True, parents=True)
data_file = dirpath / "data.parquet"
metadata_file = dirpath / "attributes.json"
metadata_file.write_text(json.dumps(metadata))
d = {
"v": v,
"i": i,
"polyfit": resistance,
}
data = pd.DataFrame(d)
data.attrs.update(metadata)
data.to_parquet(data_file)
resistances = np.array(resistances)
plt.title("resistance distribution")
plt.plot(resistances[resistances < 1000], ".")
plt.xlabel("measurement index")
plt.ylabel("resistance")
plt.grid(True)
plt.show()
df = pd.read_parquet("./wafers/2eq221eqewq2/-2_-1/resistance_resistance_sheet_W20_0_157500/data.parquet")
plt.plot(df.i.values, df.v.values)
a, b = np.polyfit(df.i.values, df.v.values, deg=1)
i_arr = np.linspace(df.i.values.min(), df.i.values.max())
plt.plot(i_arr, a * i_arr + b)
plt.grid(True)
plt.show()