@wafertools/wafermap 0.30.3 → 0.30.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/README.md +2 -2
- package/dist/packages/canvas-adapter/charts/boxplot.js +1 -1
- package/dist/packages/canvas-adapter/charts/capability.js +1 -1
- package/dist/packages/canvas-adapter/charts/chartShell.d.ts +1 -1
- package/dist/packages/canvas-adapter/charts/chartShell.js +1 -1
- package/dist/packages/canvas-adapter/charts/histogram.js +1 -1
- package/dist/packages/canvas-adapter/charts/scatter.d.ts +5 -1
- package/dist/packages/canvas-adapter/charts/scatter.js +1 -1
- package/dist/packages/canvas-adapter/charts/sweep.js +1 -1
- package/dist/packages/canvas-adapter/charts/testPassRate.js +1 -1
- package/dist/packages/canvas-adapter/charts/trend.js +1 -1
- package/dist/packages/canvas-adapter/insightsTab.d.ts +11 -1
- package/dist/packages/canvas-adapter/insightsTab.js +1 -1
- package/dist/packages/canvas-adapter/maplessSummary.js +1 -1
- package/dist/packages/canvas-adapter/renderWaferGallery.js +1 -1
- package/dist/packages/canvas-adapter/renderWaferMap.js +1 -1
- package/dist/packages/canvas-adapter/summaryPanel.js +3 -3
- package/dist/packages/canvas-adapter/toCanvas.js +1 -1
- package/dist/packages/canvas-adapter/toolbar.js +1 -1
- package/dist/packages/canvas-adapter/userGuideHtml.d.ts +1 -1
- package/dist/packages/canvas-adapter/userGuideHtml.js +38 -36
- package/dist/packages/canvas-adapter/version.d.ts +2 -2
- package/dist/packages/canvas-adapter/version.js +1 -1
- package/dist/packages/canvas-adapter/warnings.js +1 -1
- package/dist/packages/core/dies.d.ts +1 -1
- package/dist/packages/renderer/binColors.js +1 -1
- package/dist/packages/renderer/buildView.js +1 -1
- package/dist/packages/renderer/buildWaferMap.d.ts +40 -12
- package/dist/packages/renderer/buildWaferMap.js +1 -1
- package/dist/packages/renderer/derivedTests/apply.js +1 -1
- package/dist/packages/renderer/derivedTests/parser.js +1 -1
- package/dist/packages/renderer/spec.d.ts +17 -0
- package/dist/packages/renderer/spec.js +1 -1
- package/dist/packages/stats/analyzeWaferMap.js +1 -1
- package/dist/packages/stats/capability.d.ts +4 -2
- package/dist/packages/stats/capability.js +1 -1
- package/dist/packages/stats/correlation.d.ts +1 -1
- package/dist/packages/stats/deprecated.d.ts +1 -1
- package/dist/packages/stats/deprecated.js +1 -1
- package/dist/packages/stats/mergeTestDefs.d.ts +1 -1
- package/dist/packages/stats/mergeTestDefs.js +1 -1
- package/dist/packages/stats/renderSummaryReport.js +11 -11
- package/dist/packages/stats/sweep.d.ts +8 -0
- package/dist/packages/stats/sweep.js +1 -1
- package/dist/packages/stats/types.d.ts +9 -3
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isYieldEligibleDie as
|
|
1
|
+
import{isYieldEligibleDie as G}from"../core/dies.js";import{isParametricTest as M}from"../renderer/buildWaferMap.js";import{markedTestLabel as H,derivedFields as J}from"../renderer/testLabel.js";import{parseTestReference as K}from"../renderer/derivedTests/parser.js";import{quantile as V}from"./math.js";import{compileXNamePattern as Q,readXFromName as W}from"./sweepXFromName.js";function j(o,a,s){const e=[];let t=!1;for(const r of o.tests){if(typeof r=="number"){Number.isInteger(r)?e.push(r):s.push(`"${o.label}": ${r} is not a test number.`);continue}const i=K(String(r),a);if(!i.ok){s.push(`"${o.label}": "${r}" \u2014 ${i.message}.`);continue}i.range&&(t=!0),e.push(...i.tests)}return{spec:o,tests:e,usedRange:t}}export function sweepAppliesTo(o,a){const s=new Map((a??[]).map(e=>[e.testNumber,e]));return o.series.some(e=>j(e,s,[]).tests.some(t=>{const r=s.get(t);return r!==void 0&&M(r)}))}function B(o,a=16){return o.length<=a?o.join(", "):`${o.slice(0,a).join(", ")}, \u2026 (${o.length-a} more)`}function Z(o,a){const s=o?.[a];return s!==void 0&&Number.isFinite(s)?s:a}function _(o,a,s){const e=o.spec;if(e.xValues!==void 0&&e.xFromName!==void 0)return s.push(`"${e.label}": gives both xValues and xFromName \u2014 use one.`),{asked:!0};if(e.xValues!==void 0){const t=e.xValues.length;return t===o.tests.length?{xs:e.xValues,asked:!0}:(s.push(o.usedRange?`"${e.label}": ${t} x values for ${o.tests.length} tests \u2014 the ranges matched ${B(o.tests)}.`:`"${e.label}": ${t} x values for ${o.tests.length} tests.`),{asked:!0})}if(e.xFromName!==void 0){const t=Q(e.xFromName);if("error"in t)return s.push(`"${e.label}": xFromName "${e.xFromName}" \u2014 ${t.error}.`),{asked:!0};const r=[],i=[],u=[];for(const l of o.tests){const c=a.get(l)?.name,f=c===void 0?null:W(t,c);typeof f=="number"?r.push(f):(i.push(l),f!==null&&u.push(f.ambiguous))}return i.length>0?(s.push(`"${e.label}": xFromName "${e.xFromName}" found no x value in the name of ${i.length===1?"test":"tests"} ${B(i)}`+(u.length>0?` \u2014 "${u[0]}" is written in capitals, where M could be milli or mega; put the letter in the pattern ("\u2026{x}M\u2026") and the unit in xLabel.`:".")),{asked:!0}):{xs:r,asked:!0}}return{asked:!1}}function ee(o,a,s){const e=new Map;for(let t=0;t<s.length;t++){const r=e.get(s[t]);if(r!==void 0)return`"${o}": tests ${a[r]} and ${a[t]} have the same x value (${s[t]}) \u2014 a curve cannot be measured where it revisits an x.`;e.set(s[t],t)}return null}function D(o,a){const s=o.filter(e=>e.count>0);for(let e=1;e<s.length;e++){const t=s[e-1],r=s[e],i=Math.min(t.median,r.median),u=Math.max(t.median,r.median);if(a<i||a>u)continue;if(t.median===r.median)return t.x;const l=(a-t.median)/(r.median-t.median);return t.x+l*(r.x-t.x)}return null}function ne(o,a){const s=new Map(a.filter(i=>i.count>0).map(i=>[i.x,i])),e=[];for(const i of o){if(i.count===0)continue;const u=s.get(i.x);u!==void 0&&e.push({x:i.x,d:i.median-u.median,y:i.median})}if(e.length<2)return null;const t=[];for(let i=0;i<e.length;i++){const u=e[i];if(u.d===0){t.push({x:u.x,y:u.y});continue}if(i===0)continue;const l=e[i-1];if(l.d===0||l.d<0==u.d<0)continue;const c=l.d/(l.d-u.d);t.push({x:l.x+c*(u.x-l.x),y:l.y+c*(u.y-l.y)})}const r=t[0];return r===void 0?null:{x:r.x,y:r.y,multiple:t.length>1}}export function buildSweepData(o,a,s){const e=[],t=new Map((a??[]).map(n=>[n.testNumber,n])),r=o.filter(n=>G(n)),i=s.series.map(n=>j(n,t,e)),u=i.map(n=>_(n,t,e)),l=i.length>0&&u.every(n=>n.xs!==void 0),c=!l&&u.some(n=>n.asked);c&&u.some(n=>!n.asked)&&e.push("x values are given for some series but not all.");const f=l?i.map((n,d)=>ee(n.spec.label,n.tests,u[d].xs)).find(n=>n!==null)??null:null;f!==null&&e.push(f);const S=s.xScale==="log",T=l&&u.every(n=>n.xs.every(d=>d>0)),b=S&&T?"log":"linear";S&&!T&&e.push(l?"A log x axis needs every x value to be positive \u2014 drawn on a linear axis.":"A log x axis needs x values (xValues or xFromName) \u2014 drawn in test order.");const L=i.map(({spec:n,tests:d},p)=>{const v=l?u[p].xs:void 0,N=d.map((x,z)=>{const h=t.get(x);h===void 0?e.push(`"${n.label}": test ${x} is not in this program's test definitions.`):M(h)||e.push(`"${n.label}": test ${x} is functional and has no measured value.`);const m=[];if(h!==void 0&&M(h))for(const F of r){const g=F.testValues?.[x];g!==void 0&&Number.isFinite(g)&&m.push(g)}return m.sort((F,g)=>F-g),{testNumber:x,label:H(h,x),...J(h),x:Z(v,z),median:m.length?V(m,.5):NaN,p10:m.length?V(m,.1):NaN,p90:m.length?V(m,.9):NaN,count:m.length}});return{label:n.label,color:n.color,points:N}}),[X,C]=L,$=X!==void 0&&C!==void 0&&!c&&f===null,I=s.crossing??!0,Y=n=>b==="log"?Math.log10(n):n,k=n=>b==="log"?10**n:n,P=n=>n.map(d=>({...d,x:Y(d.x)})),q=$?P(X.points):[],R=$?P(C.points):[],E=(c||f!==null?[]:s.separationAt??[]).map(n=>{if(!$)return{y:n,distance:null};const d=D(q,n),p=D(R,n);if(d===null)return{y:n,distance:null,reason:"first-series-never-reaches"};if(p===null)return{y:n,distance:null,reason:"second-series-never-reaches"};const v=k(d),N=k(p);return{y:n,distance:Math.abs(N-v),from:v,to:N,...b==="log"?{ratio:10**Math.abs(d-p)}:{}}}),w=$&&I?ne(q,R):null,O=w&&{...w,x:k(w.x)},U=n=>n===void 0?void 0:t.get(n.tests[0]??-1)?.unit,y=U(i[0]),A=U(i[1]);return y!==void 0&&A!==void 0&&y!==A&&e.push(`Series measure different units (${y} and ${A}) \u2014 crossing and separation compare unlike quantities.`),{title:s.title,xLabel:c?"Test":s.xLabel??(l?"Sweep value":"Test"),yLabel:s.yLabel??"Value",series:L,xIsPhysical:l,...l&&s.xUnit?{xUnit:s.xUnit}:{},xScale:b,crossing:O,separations:E,dieCount:r.length,warnings:e,...c&&s.series.length>=2?{notMeasured:"x values do not match the tests, so the sweep is drawn in test order and the crossing and widths are not measured"}:f!==null&&s.series.length>=2?{notMeasured:"a series revisits an x value, so its points cannot be paired with the other series"}:{}}}
|
|
@@ -233,7 +233,7 @@ export interface StatsSummary {
|
|
|
233
233
|
/** Number of wafers in the lot stack. Present only when isLotStack is true. */
|
|
234
234
|
lotSize?: number;
|
|
235
235
|
/**
|
|
236
|
-
* Per-test
|
|
236
|
+
* Per-test yield against the test limits, for each test that has at least one limit defined.
|
|
237
237
|
* Only populated when testDefs with limitLow/limitHigh are provided.
|
|
238
238
|
*/
|
|
239
239
|
testSpecYield?: Array<{
|
|
@@ -293,7 +293,7 @@ export interface StatsSummary {
|
|
|
293
293
|
capability?: TestCapability[];
|
|
294
294
|
/**
|
|
295
295
|
* Per-test pass rate by the tester's recorded verdict, for parametric tests
|
|
296
|
-
* with recorded verdicts — the counterpart of `testSpecYield` (
|
|
296
|
+
* with recorded verdicts — the counterpart of `testSpecYield` (test limits)
|
|
297
297
|
* and `functionalYield` (functional tests). Worst first.
|
|
298
298
|
*/
|
|
299
299
|
testFlagYield?: TestVerdictYield[];
|
|
@@ -339,10 +339,16 @@ export interface TestCapability {
|
|
|
339
339
|
derived?: true;
|
|
340
340
|
/** The expression a `derived` test was computed from, for display. */
|
|
341
341
|
expression?: string;
|
|
342
|
-
/**
|
|
342
|
+
/**
|
|
343
|
+
* Limits to judge capability against exist: both spec limits (`specLow`/
|
|
344
|
+
* `specHigh`), or failing that both test limits (`limitLow`/`limitHigh`). When
|
|
345
|
+
* false, `lsl`/`usl` are absent and every index is null.
|
|
346
|
+
*/
|
|
343
347
|
hasSpec: boolean;
|
|
344
348
|
lsl?: number;
|
|
345
349
|
usl?: number;
|
|
350
|
+
/** `'spec'` when `lsl`/`usl` are the spec limits, `'test'` when they are the test limits. */
|
|
351
|
+
limitBasis?: 'spec' | 'test';
|
|
346
352
|
mean: number;
|
|
347
353
|
/** Sample stddev (ddof = 1) over every value. */
|
|
348
354
|
stdOverall: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wafertools/wafermap",
|
|
3
|
-
"version": "0.30.
|
|
3
|
+
"version": "0.30.4",
|
|
4
4
|
"description": "Interactive wafer map visualization and yield analysis for semiconductor test data. Hard bins, soft bins, test values, retests, edge exclusion, reticle overlays, spatial statistics, failure clustering, and lot-level trend analysis — pure ES modules, no runtime dependencies, no server required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|