Looping x, y posizioni nel tempoCiao,
Sono abbastanza nuovo in jmp (attualmente utilizzo jmp 16) e ho una domanda sul seguente scenario. Ho un file csv che ha le seguenti colonne per ogni imperfezione:
- Timestamp, ID seriale, posizione x, posizione y, dimensione dell'imperfezione (in mm)
Lavoro con un processo di pulizia e lo strumento di ispezione fornisce informazioni per ogni singola imperfezione della giornata. Ci sono un paio di cose che devo tenere traccia:
1) numero di volte in cui un particolare ID seriale è stato elaborato e scoprire se è la prima volta che è stato pulito, o la seconda, la terza, ecc.
2) se l'ID seriale è stato pulito più di una volta, devo sapere se una qualsiasi combinazione delle posizioni (x, y) è ancora nello stesso punto dopo ogni pulizia
Rappresentando graficamente le posizioni x e y e quindi filtrando per tempo potrei arrivare alla risposta 2) ma è un passaggio molto manuale. Spero di trovare una soluzione usando jsl che possa automatizzare le informazioni che devo tenere traccia.
finestreRe: Ciclare posizioni x,y nel tempo@Craige_Hales Sicuramente aggiungerò KDTable() << kNearestRows() alla mia cassetta degli attrezzi. Non sapevo che esistesse e sono così felice di apprendere che esiste.
Re: Ciclare posizioni x,y nel tempo@ngambles Oh! Dovrei aggiungere tabulate e dt<@DonMcCormack
Re: Ciclare posizioni x,y nel tempo
mi piace Craige_Hales soluzione, ma voglio anche fornire la mia soluzione poiché ho dovuto affrontare compiti simili in passato.
Il mio approccio consisteva nell'utilizzare i dati disponibili per calcolare informazioni aggiuntive, aggiungerle alla tabella dei dati e quindi sono stato in grado di generare report (costruttore di grafici, tabulati, ecc.) che mostravano i risultati finali.
Nella tua richiesta, vuoi essere in grado di calcolare il numero di volte in cui un particolare ID seriale è stato elaborato.Ho anche trovato molto utile creare una colonna di indicatori che identifichi le voci di dati dall'ultima/finale elaborazione di un wafer.
Sulla base dei dati di esempio di "mock data.PNG", farei quanto segue:
- calcolare il numero sequenziale per ogni volta che un wafer è stato elaborato
- calcolare l'ora finale in cui ogni wafer è stato elaborato
- identificare le posizioni dei difetti per nome in base a posizioni approssimative
- calcolare il numero di volte in cui ogni nome di posizione è stato identificato per ogni wafer
Per fare ciò, genero diverse tabelle di dati temporanee utilizzando tabulate, aggiungo alcune formule per ottenere le risposte che desidero e quindi le unisco nuovamente nella tabella di dati originale.
Il codice JSL sarebbe simile a questo
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 )
)
)
)
)
);Quando ho nominato le posizioni dei difetti, ho arrotondato la coordinata x e la coordinata y a una cifra decimale per consentire alcune variazioni nelle misurazioni della posizione. Questo può o non può essere sufficiente per le tue esigenze, ma questo approccio ti consente di modificare la formula per X_Temp e Y_Temp e il resto funzionerà comunque come previsto.
La tabella di dati risultante contiene le seguenti colonne aggiuntive:
- Conteggio pulito wafer
- contiene il numero sequenziale per il numero di pulizie effettuate sul wafer
- Wafer finale pulito
- colonna dell'indicatore che è zero se la voce non è l'ultima volta che il wafer è stato elaborato e uno se è l'ultima volta che il wafer è stato elaborato
- Posizione
- un nome assegnato alla posizione approssimativa del difetto
- Conteggio posizione wafer
- contiene il numero sequenziale di volte in cui questo nome della posizione del difetto si è verificato su un dato wafer
Con la tabella dei dati risultante, si sarebbe in grado di rispondere alle domande poste e altro ancora. Alcune delle possibili domande che potrebbero essere esaminate includono ma non sono limitate a:
- quali posizioni dei difetti sono persistite dopo più cicli di pulizia
- qual è il tasso complessivo di difetti dopo il primo ciclo di pulizia dei wafer
- qual è il tasso complessivo di difetti dopo che sono stati eseguiti tutti i cicli di pulizia
- qual è il numero medio di cicli di pulizia per wafer
- ci sono aree che presentano costantemente aree difettose che richiedono la pulizia
Spero che questo aiuti.
Re: Ciclare posizioni x,y nel tempoEcco un po' di codice iniziale. Dovrai studiarlo per assicurarti che faccia quello che ti aspetti. L'output è nella finestra Log. (Allegherò un file. il codice qui sotto potrebbe essere incasinato perché il sito web ha rimosso alcuni "html non validi". )
// 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 ) ) ) )
);
Ri: Looping x, y posizioni nel tempoCiao Thierry,
Ho allegato uno screenshot dei dati fittizi. come puoi vedere, ogni ID riceverà più hit con lo stesso timestamp poiché tutte le imperfezioni vengono scritte contemporaneamente, la differenza principale sarebbe la posizione x, y e la dimensione. Si noti inoltre che questo esempio riguarda solo la prima pulizia. La seconda volta, lo stesso ID potrebbe apparire con più o meno righe ed è allora che vorrei scoprire se si ripete ed essere anche in grado di identificare che si tratta di un secondo, terzo, ecc. Ciclo di pulizia.
Dopo più pulizie per un numero di serie, vorrei acquisire se le posizioni sono identiche in tutti gli eventi
Ri: Looping x, y posizioni nel tempo
Ciao Craig
La posizione xey esce 3 cifre dopo la virgola decimale. Fintanto che si trovano entro il 3% della stessa posizione, sarebbe considerata un'imperfezione ripetuta. La dimensione non ha nulla a che fare con la sovrapposizione. Ciò che è stato fatto in passato è che, una volta rappresentato graficamente, i primi loop vengono designati come un cerchio in un colore e i secondi loop ottengono una "x" in un altro colore. Una volta che si sovrappongono è visivamente facile vedere se si trova nella stessa posizione.
In termini di righe potrebbe arrivare a diverse migliaia a seconda di quanto viene eseguito in un giorno. non è mai arrivato a milioni, anche se è una possibilità se guardiamo a un periodo molto lungo alla volta.
Ri: Looping x, y posizioni nel tempoCiao,
Potresti aiutarci a comprendere meglio la struttura dei tuoi dati condividendo un esempio (i dati fittizi funzionerebbero bene)? Sulla base della tua descrizione, suppongo che ogni evento di pulizia sia identificabile da una combinazione univoca di timestamp e ID seriale. Inoltre, i tuoi dati includono informazioni replicate (ad esempio righe con una combinazione identica di timestamp e ID seriale? Se lo fa, renderà il processo più impegnativo. Infine, dopo aver identificato più eventi di pulizia per un ID seriale, ti interessa acquisire solo se le posizioni sono identiche in tutti gli eventi, identiche tra due eventi qualsiasi o qualcos'altro?
Migliore,
ST
Ri: Looping x, y posizioni nel tempoCiao @SEG
1: prova a utilizzare la piattaforma di riepilogo Tabella <<. lì, basta inserire l'ID seriale, la posizione x e la posizione y nel gruppo.
questo ti darà una riga separata per ogni combinazione unica dei tre.
rappresentare graficamente questa nuova tabella riassuntiva sarebbe utile, basta usare la colonna N come colore o dimensione
2: una volta prodotto un grafico una volta, sotto il triangolo rosso in alto a sinistra puoi scegliere di salvare lo script nella tabella dati o nella finestra dello script. jmp ha appena scritto la sceneggiatura per te.
se stai usando jmp 16 fai clic su view>>log e otterrai uno script di tutto ciò che hai fatto nella sessione corrente.
facci sapere se aiuta.
Ron
Ri: Looping x, y posizioni nel tempoChe tipo di risoluzione hanno le posizioni x,y? Ad esempio, potrebbero essere sempre numeri interi compresi tra 1 e 100 oppure potrebbero essere valori in virgola mobile compresi tra 0 e 100 arrotondati allo 0,01 più vicino oppure potrebbero essere numeri mobili senza alcun limite apparente alla risoluzione. Quanto dovrebbe essere vicina la coppia x,y per essere una ripetizione? La dimensione dell'imperfezione ha qualcosa a che fare con la sovrapposizione x,y? Oppure la dimensione è sempre inferiore alla griglia x, y e viene ignorata?
Se ci sono solo 100 valori x e 100 y, e se la dimensione non è interessante, allora combinerei i valori x e y in un'unica chiave, forse x*100+y, che potrebbe rendere più semplice il test per le ripetizioni . Forse lo stesso per i float arrotondati, fino a circa 6 cifre significative.
Ma se le dimensioni sono importanti o le distanze devono essere testate, potrei usare un KDTable.
Inoltre, quante righe? meno di qualche migliaio probabilmente non avrà bisogno di alcuna particolare ottimizzazione. Più di un milione probabilmente avranno bisogno di un algoritmo ben congegnato. (Con meno di mille righe, ogni riga può pensare a ogni altra riga e ci sono solo 1.000.000 di confronti, ma il doppio delle dimensioni e il confronto quadruplo.)