Creates a Semiconductors Dashboard using SciChart.js, by leveraging the FastRectangleRenderableSeries, and its customTextureOptions property to have a custom tiling texture fill.
index.tsx
RandomWalkGenerator.ts
theme.ts
columnChart.ts
lineChart.ts
paretoChart.ts
styles.css
waferData.ts
waferGrid.ts
1import { IPointMetadata } from "scichart";
2
3// Define quality categories as a union type for type safety
4export type WaferQuality = "Good" | "Marginal" | "Fail";
5
6// Constants for measurement parameters
7const MEASUREMENT_PARAMS = {
8 INPUT1: { mean: 1100, stdDev: 20 }, // temperature (°C)
9 INPUT2: { mean: 500, stdDev: 150 }, // flow rate (units)
10 MEASURE1: { mean: 100, stdDev: 5 }, // thickness (nm)
11 MEASURE2: { mean: 50, stdDev: 3 }, // width (nm)
12 MEASURE3: { mean: 10, stdDev: 1 }, // resistance (Ω/□)
13};
14
15// Time constants in milliseconds
16const MS_PER_DAY = 24 * 60 * 60 * 1000;
17
18export interface WaferLotData extends IPointMetadata {
19 isSelected: boolean;
20 Date: string; // Timestamp of the run/lot/batch (ISO format)
21 Batch: number; // Processing group (1-10)
22 Quality: WaferQuality; // Categorical: 'Good', 'Marginal', or 'Fail'
23 Input1: number; // Process input variable (e.g., furnace temperature setpoint)
24 Input2: number; // Another process input (e.g., gas flow rate)
25 Measure1: number; // Output measurement (e.g., film thickness in nm)
26 Measure2: number; // Output measurement (e.g., line width in nm)
27 Measure3: number; // Output measurement (e.g., sheet resistance in Ω/sq)
28}
29
30export interface WaferDayData {
31 Date: string; // Timestamp of the run/lot/batch (ISO format)
32 Mean1: number;
33 Mean2: number;
34 Batches: WaferLotData[];
35}
36
37/**
38 * Generates a value from an approximate normal distribution
39 * Uses Box-Muller transform for better statistical properties
40 * @param mean Mean value of the distribution
41 * @param stdDev Standard deviation of the distribution
42 * @returns Random value from the normal distribution
43 */
44function randomNormal(mean: number, stdDev: number): number {
45 // Box-Muller transform for better normal distribution approximation
46 const u1 = Math.random();
47 const u2 = Math.random();
48
49 // Guard against u1 being zero
50 if (u1 === 0) return randomNormal(mean, stdDev);
51
52 const z0 = Math.sqrt(-2.0 * Math.log(u1)) * Math.cos(2.0 * Math.PI * u2);
53 return mean + z0 * stdDev;
54}
55
56/**
57 * Determines wafer quality based on predefined distribution
58 * 70% Good, 20% Marginal, 10% Fail
59 * @returns Quality category as a string
60 */
61function getQuality(input: number): WaferQuality {
62 if (input > 500) return "Good";
63 if (input > 350) return "Marginal";
64 return "Fail";
65}
66
67/**
68 * Formats a number to a specified precision without string conversion overhead
69 * @param value Number to format
70 * @param precision Decimal places to keep
71 * @returns Formatted number
72 */
73function formatNumber(value: number, precision: number = 2): number {
74 const factor = Math.pow(10, precision);
75 return Math.round(value * factor) / factor;
76}
77
78/**
79 * Generates an array of mock wafer data entries based on the specified structure.
80 * Includes improved error handling, performance optimizations, and better type safety.
81 *
82 * @param numDays Number of data entries to generate
83 * @param startDate Optional starting date (defaults to current date)
84 * @returns Array of WaferLotData objects
85 * @throws Error if numEntries is invalid
86 */
87export function generateWaferLotData(
88 numDays: number,
89 numBatches: number = 15,
90 startDate: Date = new Date()
91): WaferDayData[] {
92 // Validate inputs
93 if (!Number.isInteger(numDays) || numDays <= 0) {
94 throw new Error("numEntries must be a positive integer");
95 }
96
97 if (!(startDate instanceof Date) || isNaN(startDate.getTime())) {
98 throw new Error("startDate must be a valid Date object");
99 }
100
101 const data: WaferDayData[] = [];
102 const startTime = startDate.getTime();
103
104 for (let i = 0; i < numDays; i++) {
105 // Generate date: increment by days for temporal trends
106 const date = new Date(startTime + i * MS_PER_DAY);
107 const isoDate = date.toISOString().split("T")[0]; // YYYY-MM-DD format
108 const Batches: WaferLotData[] = [];
109 let total1 = 0;
110 let total2 = 0;
111 for (let b = 1; b <= numBatches; b++) {
112 const input2 = Math.round(randomNormal(MEASUREMENT_PARAMS.INPUT2.mean, MEASUREMENT_PARAMS.INPUT2.stdDev));
113 // Generate measurements using our helper functions
114 const batch = {
115 isSelected: false,
116 Date: isoDate,
117 Batch: b,
118 Quality: getQuality(input2),
119 Input1: Math.round(randomNormal(MEASUREMENT_PARAMS.INPUT1.mean, MEASUREMENT_PARAMS.INPUT1.stdDev)),
120 Input2: input2,
121 Measure1: formatNumber(randomNormal(input2, MEASUREMENT_PARAMS.MEASURE1.stdDev)),
122 Measure2: formatNumber(randomNormal(input2, MEASUREMENT_PARAMS.MEASURE2.stdDev)),
123 Measure3: formatNumber(randomNormal(input2, MEASUREMENT_PARAMS.MEASURE3.stdDev)),
124 };
125 Batches.push(batch);
126 total1 += batch.Input1;
127 total2 += batch.Input2;
128 }
129 data.push({
130 Date: isoDate,
131 Mean1: total1 / numBatches,
132 Mean2: total2 / numBatches,
133 Batches,
134 } as WaferDayData);
135 }
136
137 return data;
138}
139
140// Simple seeded random generator (LCG)
141function seededRandom(seed: number) {
142 let value = seed % 2147483647;
143 return () => {
144 value = (value * 48271) % 2147483647;
145 return (value - 1) / 2147483646;
146 };
147}
148
149// Simple hashCode for string/number seed generation
150function hashCode(obj: any, subChartIndex: number) {
151 const str = typeof obj === "string" ? obj : JSON.stringify(obj);
152 let hash = 0;
153 for (let i = 0; i < str.length; i++) {
154 hash = (Math.imul(31, hash) + str.charCodeAt(i)) | 0;
155 }
156
157 let result = Math.abs(hash) + subChartIndex;
158
159 return result;
160}
161
162export const generateGridOfPoints = (selectedPoint: WaferLotData, subChartIndex = 0) => {
163 const waferSize = 41;
164 const seed = hashCode(selectedPoint, subChartIndex); // Make seed depend on selectedPoint
165 const random = seededRandom(seed);
166
167 const dataJSON = [];
168
169 for (let row = 0; row < waferSize; row++) {
170 for (let col = 0; col < waferSize; col++) {
171 const centerX = waferSize / 2;
172 const centerY = waferSize / 2;
173 const distance = Math.sqrt(Math.pow(col - centerX, 2) + Math.pow(row - centerY, 2));
174
175 if (distance <= waferSize / 2) {
176 let defectType = "OK";
177
178 // Calculate defect probability inversely related to Input2
179 // Lower Input2 values result in higher defect probability
180 // Normalize Input2 to a 0-1 range based on expected range (200-800)
181 const normalizedInput2 = Math.max(0, Math.min(1, (selectedPoint.Input2 - 200) / 600));
182
183 // Invert the relationship: lower Input2 -> higher defect probability
184 const defectProbabilityMultiplier = 1 - normalizedInput2;
185
186 // Use seeded random with inverse relationship to Input2
187 const randomValue = random();
188
189 // Adjust thresholds based on Input2 - lower Input2 increases defect likelihood
190 const baseThreshold = defectProbabilityMultiplier * 1.5; // Scale factor for defect probability
191
192 if (distance > waferSize / 5) {
193 if (randomValue < 0.04 * baseThreshold) defectType = "S48"; // red
194 else if (randomValue < 0.05 * baseThreshold) defectType = "S36"; // orange
195 } else if (distance < waferSize / 5) {
196 if (randomValue < 0.03 * baseThreshold) defectType = "S28"; // blue
197 }
198
199 dataJSON.push({
200 MAP_ROW: row,
201 MAP_COL: col,
202 DEFECT: defectType,
203 MR: (random() - 0.5) * 20,
204 HR: (random() - 0.5) * 10,
205 HDI: (random() - 0.5) * 5,
206 MR2: (random() - 0.5) * 30,
207 });
208 }
209 }
210 }
211
212 return dataJSON;
213};
214
In this example we are simulating four channels of data showing that SciChart.js can be used to draw real-time ECG/EKG charts and graphs to monitor heart reate, body temperature, blood pressure, pulse rate, SPO2 blood oxygen, volumetric flow and more.

Demonstrates Logarithmic Axis on a JavaScript Chart using SciChart.js. SciChart supports logarithmic axis with scientific or engineering notation and positive and negative values

Demonstrating the capability of SciChart.js to create JavaScript 3D Point Cloud charts and visualize LiDAR data from the UK Defra Survey.

Demonstrates Vertically Stacked Axes on a JavaScript Chart using SciChart.js, allowing data to overlap

See the frequency of recordings with the JavaScript audio spectrum analyzer example from SciChart. This real-time visualizer demo uses a Fourier Transform.

Demonstrating the capability of SciChart.js to create a JavaScript Audio Analyzer Bars and visualize the Fourier-Transform of an audio waveform in realtime.

Demonstrates how to create a Waterfall chart in SciChart.js, showing chromotragraphy data with interactive selection of points.

See the JavaScript Phasor Diagram example to combine a Cartesian surface with a Polar subsurface. Get seamless JS integration with SciChart. View demo now.

Create JavaScript Correlation Plot with high performance SciChart.js. Easily render pre-defined point types. Supports custom shapes. Get your free trial now.

JavaScript **Wafer Analysis Chart** using SciChart.js, by leveraging the **FastRectangleRenderableSeries**, and crossfilter to enable live filtering.