Bouclage des emplacements x,y dans le tempsBonjour,
Je suis assez nouveau sur jmp (utilisant actuellement jmp 16) et j'ai une question sur le scénario suivant. J'ai un fichier csv qui contient les colonnes suivantes pour chaque imperfection :
- Horodatage, ID de série, emplacement x, emplacement y, taille de l'imperfection (en mm)
Je travaille avec un processus de nettoyage et l'outil d'inspection donne des informations pour chaque imperfection de la journée. Il y a deux ou trois choses que je dois suivre :
1) nombre de fois qu'un numéro de série particulier a été traité et déterminer si c'est la première fois qu'il a été nettoyé, ou la deuxième, la troisième, etc.
2) si l'ID de série a été nettoyé plus d'une fois, j'ai besoin de savoir si l'une des combinaisons des emplacements (x, y) est toujours au même endroit après chaque nettoyage
En représentant graphiquement les emplacements x et y, puis en filtrant par le temps, je pourrais obtenir la réponse 2) mais c'est une étape très manuelle. J'espère trouver une solution utilisant jsl qui pourrait automatiser les informations dont j'ai besoin pour suivre.
les fenêtresRe : Boucler les emplacements x, y dans le temps@Craige_Hales Je vais certainement ajouter KDTable() << kNearestRows() à ma boîte à outils. Je ne savais pas que cela existait et je suis tellement heureux d'apprendre que c'est le cas.
Re : Boucler les emplacements x, y dans le temps@ngambles Ouah! Je devrais ajouter tabulate et dt<@DonMcCormack
Re : Boucler les emplacements x, y dans le temps
J'aime Craige_Hales solution, mais je veux aussi fournir ma solution car j'ai été confronté à des tâches similaires dans le passé.
Mon approche consistait à utiliser les données disponibles pour calculer des informations supplémentaires, à les ajouter au tableau de données, puis j'ai pu générer des rapports (créateur de graphiques, tabulation, etc.) montrant les résultats finaux.
Dans votre demande, vous souhaitez pouvoir calculer le nombre de fois qu'un numéro de série particulier a été traité.J'ai également trouvé très utile de créer une colonne d'indicateurs qui identifie les entrées de données du dernier/dernier traitement d'une plaquette.
Sur la base des données d'exemple de "mock data.PNG", je ferais ce qui suit :
- calculer le numéro séquentiel pour chaque fois qu'une plaquette a été traitée
- calculer la dernière fois que chaque plaquette a été traitée
- identifier les emplacements des défauts par leur nom en fonction des emplacements approximatifs
- calculer le nombre de fois que chaque nom d'emplacement a été identifié pour chaque plaquette
Pour ce faire, je génère plusieurs tables de données temporaires à l'aide de tabulation, j'ajoute des formules pour obtenir les réponses souhaitées, puis je les fusionne dans la table de données d'origine.
Le code JSL ressemblerait à ceci
names default to here(1);
/////////// make example data table /////////////////////
dt = New Table( "example data set",
Add Rows( 13 ),
New Column( "Time",
Numeric,
"Nominal",
Format( "Best", 12 ),
Set Values( [1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4] )
),
New Column( "WaferID",
Numeric,
"Nominal",
Format( "Best", 12 ),
Set Values( [1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 1, 1, 1] )
),
New Column( "X location",
Numeric,
continuous,
Format( "Best", 12 ),
Set Values(
[2.745, 1.566, -28.143, -4.793, -29.251, 19.527, 6.581, 29.37, 4.907,
21.699, 2.745, -4.793, 6.581]
)
),
New Column( "Y location",
Numeric,
continuous,
Format( "Best", 12 ),
Set Values(
[44.164, 61.915, -42.954, -38.091, -46.659, 32.201, -24.715, 41.533,
60.217, -60.26, 44.164, -38.091, -24.715]
)
),
New Column( "Size",
Numeric,
"Continuous",
Format( "Best", 12 ),
Set Values(
[0.164, 0.136, 0.125, 0.122, 0.122, 0.036, 0.035, 0.035, 0.035, 0.034,
0.164, 0.122, 0.035]
)
)
);
//dt = current data table();
/////////// create temporary data table to determine Clean Count and Final Clean /////////////////
tab = dt << Tabulate(
Show Control Panel( 0 ),
Full Path Column Name( 1 ),
Add Table( Row Table( Grouping Columns( :WaferID, :Time ) ) )
);
dtx = tab << make into data table();
tab << close window();
dtx << New Column("Wafer Clean Count", Numeric, "Nominal", Formula(Col Rank(:Time, :WaferID)));
dtx << New Column("Final Wafer Clean", Numeric, "Nominal", Formula(If(:Time == Col Maximum(:Time, :WaferID), 1, 0)));
dtx << delete Column("N");
///////// move Clean Count and Final Clean information back to original data table //////////////
dt << Update(
With( dtx ),
Match Columns( :WaferID = :WaferID, :Time = :Time ),
Add Columns from Update Table( :Wafer Clean Count, :Final Wafer Clean ),
Replace Columns in Main Table( :Wafer Clean Count, :Final Wafer Clean )
);
//////// close data table //////////////////////////////////////////////////////
close(dtx, no save);
//////// modify X & Y values to allow variation in measurements////////////////
dt << new column("X_Temp", numeric, continuous, formula(round(:X location, 1)));
dt << new column("Y_Temp", numeric, continuous, formula(round(:Y location, 1)));
/////// create temporary data table to name defect locations ///////////////
tab = dt << Tabulate(
Show Control Panel( 0 ),
Include missing for grouping columns( 1 ),
Full Path Column Name( 1 ),
Add Table( Row Table( Grouping Columns( :X_Temp, :Y_Temp ) ) )
);
dtx = tab << make into data table();
tab << close window();
dtx << new column("Location", character, nominal, formula("L" || char(row())));
dtx << delete column("N");
//////// move Location information back to original data table ////////////////
dt << Update(
With( dtx ),
Match Columns( :X_Temp = :X_Temp, :Y_Temp = :Y_Temp ),
Add Columns from Update Table( :Location ),
Replace Columns in Main Table( :Location )
);
/////// clean up /////////////////////////
close(dtx, no save);
dt << delete columns(
{
"X_Temp",
"Y_Temp"
}
);
/////// calculate the number of times a defect location occured on a given wafer ////////
dt << new column("Wafer Location Count", numeric, nominal, formula(Col Rank( :Time, :Location, :WaferID )));
/////// make some reports /////////////
nw = new window("results",
h list box(
gb = dt << Graph Builder(
Show Control Panel( 0 ),
Variables(
X( :X location ),
Y( :Y location ),
Group X( :Wafer Clean Count ),
Group Y( :WaferID ),
Color( :Wafer Location Count )
),
Elements( Points( X, Y, Legend( 7 ) ) )
),
tab = dt << Tabulate(
Show Control Panel( 0 ),
Include missing for grouping columns( 1 ),
Full Path Column Name( 1 ),
Add Table(
Column Table( Statistics( Max ), Analysis Columns( :Wafer Location Count ) ),
Row Table( Grouping Columns( :WaferID, :X location, :Y location ) )
),
Local Data Filter(
Add Filter(
columns( :Final Wafer Clean ),
Where( :Final Wafer Clean == 1 )
)
)
)
)
);Lors de la désignation des emplacements des défauts, j'ai arrondi la coordonnée x et la coordonnée y à une décimale pour permettre une certaine variation dans les mesures de position. Cela peut être suffisant ou non pour vos besoins, mais cette approche vous permet de modifier la formule pour X_Temp et Y_Temp et le reste fonctionnera toujours comme prévu.
La table de données résultante contient les colonnes supplémentaires suivantes :
- Nombre de nettoyage de plaquette
- contient le numéro séquentiel du nombre de nettoyages effectués sur la plaquette
- Nettoyage final de la plaquette
- colonne d'indicateur qui est zéro si l'entrée n'est pas la dernière fois que la plaquette a été traitée et un un si c'est la dernière fois que la plaquette a été traitée
- Emplacement
- un nom attribué à l'emplacement approximatif du défaut
- Nombre d'emplacements de plaquettes
- contient le nombre séquentiel de fois où ce nom d'emplacement de défaut s'est produit sur une tranche donnée
Avec le tableau de données résultant, on pourrait répondre aux questions que vous avez posées et plus encore. Certaines des questions possibles qui pourraient être étudiées incluent, mais ne sont pas limitées à :
- quels emplacements de défaut ont persisté après plusieurs cycles de nettoyage
- quel est le taux global de défauts après le premier cycle de nettoyage de tranche
- quel est le taux global de défauts après que tous les cycles de nettoyage ont été effectués
- quel est le nombre moyen de cycles de nettoyage par wafer
- y a-t-il des zones qui ont constamment des zones défectueuses qui nécessitent un nettoyage
J'espère que cette aide.
Re : Boucler les emplacements x, y dans le tempsVoici un code de démarrage. Vous devrez l'étudier pour vous assurer qu'il fait ce que vous attendez. La sortie se trouve dans la fenêtre Journal. (Je vais joindre un fichier. Le code ci-dessous peut être foiré car le site Web a supprimé du "html invalide". )
// synthesize some data
radius = 1;
dt = New Table( "Untitled",
Add Rows( 1000 ), // <<<<<<<<<<<<<< change number of rows here
New Column( "time", Numeric, "Continuous", Format( "Best", 12 ) ),
New Column( "waferID", Numeric, "Continuous", Format( "Best", 12 ) ),
New Column( "xLocation", Numeric, "Continuous", Format( "Best", 12 ) ),
New Column( "yLocation", Numeric, "Continuous", Format( "Best", 12 ) )
);
here:time = 0; // for this synth data, time just increments by 1
here:waferID = 0; // and the waferID is random 0-9
For( row = 1, row <= N Rows( dt ), row += 1,
If( Random Uniform() > .8, // determines how many points in a cleaning, before time changes and wafer re-randomizes
here:time += 1;
here:waferID = Random Integer( 0, 9 );
);
dt:time[row] = here:time;
dt:waferID[row] = here:waferID;
dt:xLocation[row] = Round( Random Uniform( -radius, radius ), 2 );
dt:yLocation[row] = Round( Random Uniform( -radius, radius ), 2 );
);
// find the unique waferIDs using summary
dtWafer = dt << Summary( Group( :waferID ), Link to original data table( 1 ) );
dtWaferTime = dt << Summary( Group( :waferID, :time ) );
dtNWafer = dtWaferTime << Summary( Group( :waferID ) ); //number of distinct times for this wafer is number of cleanings
close = .03; // <<< this determines how close makes a hit
// produce a report for each waferID that shows up in the cleaning data...
For( iWafer = 1, iWafer <= N Rows( dtWafer ), iWafer += 1,
dtWafer << clear select << selectrows( iWafer ); // dtWafer selection also selects rows in dt because linked
rows = dt << get selected rows; // all the rows for this wafer, across all times
// rows is a 1-column matrix of row numbers in dt for this wafer. the argument to KDTable
// is all the locations over all cleanings for this wafer.
kdt = KDTable( dt[rows, {xLocation, yLocation}] );
// report header for each waferID... the report might have no lines below the header, or a bunch... Not indented.
Write( Eval Insert( "\!n\!nprocessing waferID=^dtWafer:waferID[iWafer]^, ^nrows(rows)^ points during ^dtNWafer:nrows[iWafer]^ cleanings" ) );
For( irow = 1, irow <= N Rows( rows ), irow += 1, // the rows should be ascending time
row = rows[irow]; // row (singular) is an index to dt
// find rows {up to this many,up to this far} near irow
{index, distance} = kdt << kNearestRows( {dtWafer:NRows[iWafer], close}, irow );
// above, index is into the 1-column matrix of row numbers. below, it becomes index into dt
index = rows[index];
printedHeader = 0; // don't print this header unless there are duplicates to go with it
// distance[] and index[] have same number of rows; index is indexes to near neighbors and distance is to the neighbor
For( idistance = 1, idistance <= N Items( distance ), idistance += 1,
If( dt:waferID[index[idistance]] != dt:waferID[row] | dt:waferID[row] != dtWafer:waferID[iWafer],
Throw( "wafer mismatch" )
);// sanity check
If( distance[idistance] <= close, // typically there is one item with a bigger distance than we care about, must be ignored by else-break below.
If( !printedHeader, // a little indented...
Write(
Eval Insert(
"\!n matches for row ^row^ time ^dt:time[row]^ loc [^char(dt:xLocation[row],7,3)^,^char(dt:yLocation[row],7,3)^]"
)
);
printedHeader = 1;
);
// there can be more than one subsequent cleaning, indented more...
Write( Eval Insert( "\!n row ^index[idistance]^ time ^dt:time[index[idistance]]^ " ) );
Write( Eval Insert( "[^char(dt:xLocation[index[idistance]],7,3)^,^char(dt:yLocation[index[idistance]],7,3)^]) " ) );
Write( Eval Insert( "dist(^distance[idistance]^)" ) );
, //else
Break()
);
);
kdt << removerows( irow ); // never look back at this row from future rows
);
);
// a graph to examine the rows found to be close.
dt << Graph Builder(
Size( 867, 787 ),
Show Control Panel( 0 ),
Variables( X( :xLocation ), Y( :yLocation ) ),
Elements( Points( X, Y, Legend( 5 ) ) ),
Local Data Filter( Add Filter( columns( :waferID ), Modeling Type( :waferID, Nominal ), Display( :waferID, N Items( 14 ) ) ) )
);
Re : Boucler les emplacements x, y dans le tempsBonjour Thierry,
J'ai joint une capture d'écran des données fictives. comme vous pouvez le voir, chaque ID obtiendra plusieurs résultats en même temps car toutes les imperfections sont écrites en même temps, la principale différence serait l'emplacement x, y et la taille. Notez également que cet exemple ne concerne qu'un premier nettoyage. La deuxième fois, le même identifiant peut apparaître avec plus ou moins de lignes et c'est à ce moment-là que j'aimerais savoir s'il se répète et également être en mesure d'identifier qu'il s'agit d'une deuxième, troisième, etc. boucles de nettoyage.
Après plusieurs nettoyages pour un numéro de série, j'aimerais savoir si les emplacements sont identiques pour tous les événements
Re : Boucler les emplacements x, y dans le temps
Bonjour Craig
L'emplacement x et y sort 3 chiffres après la virgule décimale. Tant qu'ils se trouvent à moins de 3% du même emplacement, cela serait considéré comme une imperfection répétée. La taille n'a rien à voir avec le chevauchement. Ce qui a été fait dans le passé, c'est qu'une fois qu'elles sont représentées graphiquement, les premières boucles sont désignées comme un cercle d'une couleur et les secondes boucles reçoivent un "x" d'une autre couleur. Une fois qu'ils se chevauchent, il est visuellement facile de voir s'il se trouve au même endroit.
En termes de rangées, il pourrait atteindre plusieurs milliers en fonction de la quantité exécutée par jour. il n'a jamais dépassé les millions, bien que ce soit une possibilité si nous regardons sur une très longue période à la fois.
Re : Boucler les emplacements x, y dans le tempsSalut,
Pourriez-vous nous aider à mieux comprendre votre structure de données en partageant un exemple (des données fictives fonctionneraient bien) ? Sur la base de votre description, je suppose que chaque événement de nettoyage est identifiable par une combinaison unique d'horodatage et d'identifiant de série. En outre, vos données incluent-elles des informations répliquées (c'est-à-dire des lignes avec une combinaison identique d'horodatage et d'ID de série ? Si c'est le cas, cela rendra le processus plus exigeant. Enfin, après avoir identifié plusieurs événements de nettoyage pour un numéro de série, souhaitez-vous uniquement capturer si les emplacements sont identiques pour tous les événements, identiques entre deux événements ou autre chose ?
Meilleur,
TS
Re : Boucler les emplacements x, y dans le tempsSalut @SEG
1 : essayez d'utiliser la plate-forme de résumé Tableau <<. là, il suffit de mettre l'ID de série, l'emplacement x et l'emplacement y dans le groupe.
cela vous donnera une ligne distincte pour chaque combinaison unique des trois.
représenter graphiquement ce nouveau tableau récapitulatif serait utile, utilisez simplement la colonne N comme couleur ou taille
2 : une fois que vous avez produit un graphique une fois, sous le triangle rouge en haut à gauche, vous pouvez choisir d'enregistrer le script dans la table de données ou la fenêtre de script. jmp vient d'écrire le script pour vous.
si vous utilisez jmp 16, cliquez sur view>>log et vous obtiendrez un script de tout ce que vous avez fait dans la session en cours.
faites-nous savoir si cela aide.
Ron
Re : Boucler les emplacements x, y dans le tempsQuelle sorte de résolution les emplacements x,y ont-ils ? Par exemple, il peut toujours s'agir d'entiers de 1 à 100, de valeurs à virgule flottante de 0 à 100 arrondies au 0,01 le plus proche ou de flottants sans limite apparente de résolution. À quelle distance la paire x,y doit-elle être pour être une répétition ? La taille de l'imperfection a-t-elle quelque chose à voir avec le chevauchement x,y ? Ou la taille est-elle toujours plus petite que la grille x, y et ignorée ?
S'il n'y a que 100 valeurs x et 100 y, et si la taille n'est pas intéressante, alors je combinerais les valeurs x et y en une seule clé, x*100+y peut-être, ce qui pourrait faciliter le test des répétitions . Peut-être la même chose pour les flottants arrondis, jusqu'à environ 6 chiffres significatifs.
Mais si la taille compte, ou si les distances doivent être testées, je peux utiliser un KDTable.
Aussi, combien de rangées ? moins de quelques milliers n'auront probablement pas besoin d'optimisation particulière. Plus d'un million auront probablement besoin d'un algorithme bien pensé. (Avec moins d'un millier de lignes, chaque ligne peut penser à toutes les autres lignes et il n'y a que 1 000 000 de comparaisons, mais la taille double et les comparaisons quadruplent.)