Bucles de ubicaciones x,y a lo largo del tiempoHola,
Soy bastante nuevo en jmp (actualmente uso jmp 16) y tengo una pregunta sobre el siguiente escenario. Tengo un archivo csv que tiene las siguientes columnas para cada imperfección:
- Marca de tiempo, ID de serie, ubicación x, ubicación y, tamaño de la imperfección (en mm)
Trabajo con un proceso de limpieza y la herramienta de inspección brinda información para cada imperfección del día. Hay un par de cosas que necesito rastrear:
1) número de veces que se ha procesado un ID de serie en particular y averiguar si es la primera vez que se limpia, o la segunda, la tercera, etc.
2) si la identificación de serie se ha limpiado más de una vez, entonces necesito saber si alguna de las combinaciones de las ubicaciones (x,y) sigue en el mismo lugar después de cada limpieza
Graficando las ubicaciones x e y y luego filtrando por tiempo podría llegar a responder 2), pero es un paso muy manual. Espero encontrar una solución usando jsl que pueda automatizar la información que necesito rastrear.
ventanasRe: Bucle de ubicaciones x,y a lo largo del tiempo@Craige_Hales Definitivamente voy a agregar KDTable() << kNearestRows() a mi caja de herramientas. No sabía que esto existía y estoy muy feliz de saber que existe.
Re: Bucle de ubicaciones x,y a lo largo del tiempo@ngambles ¡Guau! ¡Debería agregar tabulate y dt<@DonMcCormack
Re: Bucle de ubicaciones x,y a lo largo del tiempo
me gusta Craige_Hales solución, pero también quiero proporcionar mi solución ya que me he enfrentado a tareas similares en el pasado.
Mi enfoque fue usar los datos disponibles para calcular información adicional, agregar esto a la tabla de datos y luego pude generar informes (generador de gráficos, tabular, etc.) que mostraban los resultados finales.
En su solicitud, desea poder calcular la cantidad de veces que se procesó una identificación de serie en particular.También me ha resultado muy útil crear una columna indicadora que identifique las entradas de datos del último/último procesamiento de una oblea.
Según los datos de ejemplo de "mock data.PNG", haría lo siguiente:
- calcular el número secuencial para cada vez que se ha procesado una oblea
- calcular la hora final en que se procesó cada oblea
- identificar ubicaciones de defectos por nombre en función de ubicaciones aproximadas
- calcular el número de veces que se ha identificado cada nombre de ubicación para cada oblea
Para lograr esto, genero varias tablas de datos temporales usando tabular, agrego algunas fórmulas para obtener las respuestas que quiero y luego las fusiono nuevamente en la tabla de datos original.
El código JSL se vería así
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 )
)
)
)
)
);Al nombrar las ubicaciones de los defectos, redondeé la coordenada x y la coordenada y a un lugar decimal para permitir alguna variación en las medidas de posición. Esto puede o no ser suficiente para sus necesidades, pero este enfoque le permite modificar la fórmula para X_Temp y Y_Temp y el resto seguirá funcionando como se esperaba.
La tabla de datos resultante contiene las siguientes columnas adicionales:
- Recuento de limpieza de obleas
- contiene el número secuencial del número de limpiezas realizadas en la oblea
- Limpieza final de obleas
- columna indicadora que es cero si la entrada no es la última vez que se procesó la oblea y uno si es la última vez que se procesó la oblea
- Localización
- un nombre asignado a la ubicación aproximada del defecto
- Recuento de ubicaciones de obleas
- contiene el número secuencial de veces que este nombre de ubicación de defecto ha ocurrido en cualquier oblea dada
Con la tabla de datos resultante, uno podría abordar las preguntas que hizo y más. Algunas de las posibles preguntas que podrían investigarse incluyen, entre otras:
- qué ubicaciones de defectos han persistido después de múltiples ciclos de limpieza
- ¿Cuál es la tasa general de defectos después del primer ciclo de limpieza de obleas?
- ¿Cuál es la tasa general de defectos después de que se hayan realizado todos los ciclos de limpieza?
- ¿Cuál es el número promedio de ciclos de limpieza por oblea?
- ¿Hay áreas que constantemente tienen áreas defectuosas que requieren limpieza?
Espero esta ayuda.
Re: Bucle de ubicaciones x,y a lo largo del tiempoAquí hay un código de inicio. Deberá estudiarlo para asegurarse de que hace lo que espera. La salida está en la ventana de registro. (Adjuntaré un archivo. El código a continuación podría estar en mal estado porque el sitio web eliminó algunos "html no válidos". )
// 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: Bucle de ubicaciones x,y a lo largo del tiempoHola Thierry,
Adjunté una captura de pantalla de los datos simulados. como puede ver, cada ID obtendrá múltiples resultados al mismo tiempo, ya que todas las imperfecciones se escriben al mismo tiempo, la principal diferencia sería la ubicación x, y y el tamaño. También tenga en cuenta que este ejemplo es solo de una limpieza por primera vez. La segunda vez, la misma identificación podría aparecer con más o menos filas y ahí es cuando me gustaría encontrar si se repite y también poder identificar que es un segundo, tercero, etc. bucles de limpieza.
Después de varias limpiezas de un número de serie, me gustaría saber si las ubicaciones son idénticas en todos los eventos.
Re: Bucle de ubicaciones x,y a lo largo del tiempo
hola craig
La ubicación xey sale 3 dígitos después del punto decimal. Mientras estén dentro del 3% de la misma ubicación, se consideraría una imperfección repetida. El tamaño no tiene nada que ver con la superposición. Lo que se ha hecho en el pasado es que una vez que se grafica, los primeros bucles se designan como un círculo en un color y los segundos bucles obtienen una "x" en otro color. Una vez que se superponen, es visualmente fácil ver si está en la misma ubicación.
En términos de filas, podría llegar a varios miles dependiendo de cuánto se ejecute en un día. nunca se cruzó en millones, aunque es una posibilidad si observamos un período muy largo a la vez.
Re: Bucle de ubicaciones x,y a lo largo del tiempoHola,
¿Podría ayudarnos a comprender mejor su estructura de datos compartiendo un ejemplo (los datos simulados funcionarían bien)? Según su descripción, supongo que cada evento de limpieza se puede identificar mediante una combinación única de marca de tiempo e identificación de serie. Además, ¿sus datos incluyen información duplicada (es decir, filas con una combinación idéntica de marca de tiempo e ID de serie? Si lo hace, hará que el proceso sea más exigente. Finalmente, después de identificar múltiples eventos de limpieza para una ID de serie, ¿está interesado en capturar solo si las ubicaciones son idénticas en todos los eventos, idénticas entre dos eventos u otra cosa?
Mejor,
TS
Re: Bucle de ubicaciones x,y a lo largo del tiempoHola @SEG
1: intente usar la plataforma de resumen Table <<. allí, simplemente coloque la identificación de serie, la ubicación x y la ubicación y en el grupo.
esto le dará una fila separada para cada combinación única de los tres.
sería útil graficar esta nueva tabla de resumen, solo use la columna N como color o tamaño
2: una vez que produzca un gráfico una vez, debajo del triángulo rojo en la parte superior izquierda, puede elegir guardar el script en la tabla de datos o en la ventana del script. jmp acaba de escribir el guión para ti.
si está utilizando jmp 16, haga clic en ver >> registro y obtendrá un script de todo lo que hizo en la sesión actual.
háganos saber si ayuda.
Ron
Re: Bucle de ubicaciones x,y a lo largo del tiempo¿Qué tipo de resolución tienen las ubicaciones x, y? Por ejemplo, siempre pueden ser números enteros del 1 al 100, o pueden ser valores de punto flotante del 0 al 100 que se redondean al 0,01 más cercano o pueden ser valores flotantes sin límite aparente para la resolución. ¿Qué tan cerca tendría que estar el par x,y para ser una repetición? ¿El tamaño de la imperfección tiene algo que ver con la superposición x,y? ¿O el tamaño es siempre más pequeño que la cuadrícula x,y y se ignora?
Si solo hay valores de 100 x y 100 y, y si el tamaño no es interesante, entonces combinaría los valores de x e y en una sola clave, x*100+y tal vez, eso podría facilitar la prueba de repeticiones . Tal vez lo mismo para los flotantes redondeados, hasta unos 6 dígitos significativos.
Pero si el tamaño es importante, o si hay que probar las distancias, podría usar una KDTable.
Además, ¿cuántas filas? menos de unos pocos miles probablemente no necesitarán ninguna optimización en particular. Más de un millón probablemente necesitará un algoritmo bien pensado. (Con menos de mil filas, cada fila puede pensar en todas las demás filas y solo hay 1,000,000 de comparaciones, pero el tamaño se duplica y las comparaciones se cuadruplican).