Domanda da principiante sulla generazione (estrazione) di tabelle dati dai dati grezzi della sondaCiao a tutti, questo è il mio primo post in questa community. Recentemente ho cambiato lavoro e farò molti test al banco e analisi dei dati. Ho usato un po' JMP, ma niente di avanzato.
In questo momento, il mio test genera sempre un grande file CSV e i dati di misurazione sono sepolti insieme a informazioni non interessate (come impostazione del test, condizioni, ecc.), vorrei ricevere aiuto per estrarre le informazioni utili utilizzando lo script JMP e da qui, inizia il mio apprendimento avanzato degli script.
Spiego il mio compito nello screenshot allegato. In alto a destra c'è un esempio di singolo punto dati di scansione IV (per misurare R) per darti un'idea di come appare il mio gigantesco CVS (contiene centinaia di strutture simili). "Informazioni non interessate su più righe" rappresenta quelle righe inutili che non voglio importare. Oltre a copiare e incollare la porzione di dati I/V/R, mi piace anche estrarre l'ID del lotto del wafer, l'ID del wafer, l'indice del reticolo (o, ad esempio, del campo stepper) e il numero del sito secondario da alcune stringhe. La casella in alto a destra mostra l'output JMP desiderato.
Come lettura facoltativa, ci sono alcune curiosità nei due riquadri inferiori. In basso a sinistra ci sono i miei commenti generali sulla struttura dei dati e in basso a destra spiega il significato delle stringhe da cui devo estrarre determinate informazioni.
Spero che lo screenshot ti fornisca informazioni sufficienti per la mia domanda. Facevo questo lavoro utilizzando la macro VBA di Excel: scansionavo le stringhe della firma di ricerca, quindi importavo selettivamente determinati caratteri/stringhe/righe vicino a quella posizione, quindi continuavo la ricerca fino alla fine del file di dati non elaborati. Mi chiedo che lo script JMP farebbe lo stesso?
Automazione e scriptingRi: Domanda da principiante sulla generazione (estrazione) di tabelle dati dai dati grezzi della sondaNessuna schermata. Sarebbe possibile allegare un piccolo set di dati anonimo o un file .csv?
Ri: Domanda da principiante sulla generazione (estrazione) di tabelle dati dai dati grezzi della sondaCome altri hanno già detto, questo può dipendere fortemente dal formato dei dati reali. Di seguito è riportato un esempio che utilizza la copia dei dati incollata da Excel in un file di testo
Names Default To Here(1);
filepath = "$DOWNLOADS/744027.txt";
txt = Load Text File(filepath);
lines = Words(txt, "\!N");
project_pattern = "^(.+)_(\d+\.\d*)(W\d{1,2})_(T\d+)_(.+):(.+)?";
subsite_pattern = "<SUBSITE>(\d+)</SUBSITE>";
datastart_pattern = "^DataName";
data_start = 0;
For Each({line, idx}, lines,
If(!IsMissing(Regex(line, project_pattern)),
matches = Regex Match(line, project_pattern);
projname = matches[2];
lotid = matches[3];
waferid = matches[4];
time = matches[5];
notes = matches[6];
reticles = Words(Trim Whitespace(matches[7]), " ");
, !IsMissing(Regex(line, subsite_pattern)),
subsite = Regex(line, subsite_pattern, "\1");
, !IsMissing(Regex(line, datastart_pattern)),
data_start = idx;
break();
);
);
data_str = Concat Items(lines[data_start::N Items(lines)], "\!N");
dt = Open(Char To Blob(data_str), "text");
dt << New Column("lot", Character, Nominal, Set Each Value(lotid));
dt << New Column("waferid", Character, Nominal, Set Each Value(waferid));
dt << New Column("x", Character, Nominal, Set Each Value(reticles[1]));
dt << New Column("y", Character, Nominal, Set Each Value(reticles[2]));
dt << New Column("subsite", Character, Nominal, Set Each Value(subsite));
dt << Move Selected Columns({:lot, :waferid, :x, :y, :subsite}, To First);
dt << Delete Columns("DataName");
Utilizza regex per trovare linee specifiche e poi le analizza. Per i dati trova l'indice della riga da cui inizia e quindi lo analizza consentendo a JMP di aprirlo (a seconda dei dati reali, ciò potrebbe richiedere passaggi aggiuntivi).

Ri: Domanda da principiante sulla generazione (estrazione) di tabelle dati dai dati grezzi della sondaIl formato che stai mostrando non dovrebbe essere un grosso problema da leggere. Le righe di informazioni poco interessanti mi preoccupano perché ciò che c'è può interferire con la lettura dei dati. L'altra mia preoccupazione è come fare in modo che JMP riconosca la riga che contiene il nome del progetto. Inizia sempre con Proj?
Fornire un file reale sarebbe molto utile.
Ri: Domanda da principiante sulla generazione (estrazione) di tabelle dati dai dati grezzi della sondaCiao pmroz, grazie per la pronta risposta. Ho dimenticato l'allegato al primo invio, ma poi, entro 1 minuto, modifico il post e allego lo screenshot. Puoi controllare di nuovo.
Inoltre, secondo la tua richiesta, carico l'Excel qui. Ho eliminato la maggior parte delle informazioni inutili per rendere il file pulito, ma puoi copiare e incollare la casella in alto a sinistra come esempio "dati grezzi".
Re: Domanda da principiante sulla generazione (estrazione) di tabelle dati da dati di sonda grezzi- Mi è sfuggito il sottosito, mi dispiace. L'ho aggiunto allo script.
- Lo scopo del forum di discussione è aiutare gli utenti JMP con i problemi che hanno nell'esecuzione di JMP. Non è un servizio di scrittura di script gratuito. Il motivo per cui scrivo script per i membri della Community è per aiutarli a insegnare loro come usare JSL. Spero che i destinatari degli script che fornisco si prendano il tempo di imparare da loro, così saranno in grado di risolvere il loro problema totale.
- Ho modificato le colonne dinamiche (proprietà delle colonne di porzione) in numeriche
- Lo script ora aggiunge insieme ogni tabella creata
- Per quanto riguarda la compressione del codice...perché? Se lo scopo della compressione lo fa girare più velocemente, potrei essere d'accordo. Ma se comprimere un pezzo di codice lo rende più difficile da leggere per il prossimo essere umano che deve guardarlo, allora il codice non è un buon codice. Pertanto, la mia risposta alla tua domanda se il codice potrebbe essere compresso in un formato più conciso, è che sono sicuro che si può.
names default to here(1);
clear symbols( dtOut );
file = pick file();
dt = Open(
File,
Import Settings(
End Of Line( CRLF, CR, LF ),
End Of Field( Comma, CSV( 0 ) ),
Treat Leading Zeros as Character( 1 ),
Strip Quotes( 1 ),
Use Apostrophe as Quotation Mark( 0 ),
Use Regional Settings( 0 ),
Scan Whole File( 1 ),
Treat empty columns as numeric( 0 ),
CompressNumericColumns( 0 ),
CompressCharacterColumns( 0 ),
CompressAllowListCheck( 0 ),
Labels( 0 ),
Column Names Start( 1 ),
First Named Column( 1 ),
Data Starts( 1 ),
Lines To Read( "All" ),
Year Rule( "20xx" )
)
);
// Change column names to simplify coding
for( i=1,i<=ncols(dt), i++, column(i)<< set name( "C" || char(i)));
// Create a base output table
dtFinal = New Table( "Final" );
// Loop through the data
for(theRow = 1, theRow <= NRows(dt), theRow++,
If( dt:C1[theRow] == "SetupTitle",
memoryProjectName = "";
memoryLotName = "";
memoryWaferID = "";
memoryT0 = "";
memory1strun = "";
memoryIndexX = .;
memoryIndexY = .;
memorySubsite = .;
setupFlag = 1;
projFlag = 0;
// If this is not the first read in table, then append the table
// to the Final table, and close the current dtOut table
If( nrows(dtFinal) != 0 | isEmpty( dtOut ) == 0,
dtFinal << concatenate( dtOut, append to first table(1));
close( dtOut, nosave )
)
,
dt:C1[theRow] == "" & setupFlag == 1,
projFlag = 1;
setupFlag = 0;
,
projFlag == 1 & dt:C1[theRow] != "",
dt:C1[theRow] = trim(dt:C1[theRow]);
memoryProjectName = word(1, dt:C1[theRow], "_");
memoryLotName = word(2, dt:C1[theRow], "_W");
memoryWaferID = word(3, dt:C1[theRow], "_W");
memoryT0 = word(4, dt:C1[theRow], "_W");
memory1strun = word(5, dt:C1[theRow], "_W:");
memoryIndexX = num(word(2, dt:C1[theRow], ": "));
memoryIndexY = num(word(3, dt:C1[theRow], ": "));
memorySubsite = num(word(2, trim(dt:C1[theRow + 2 ]),"<>"));
projFlag = 0;
,
dt:C1[theRow] == "DataName",
colList = {};
col=2;
while( column(dt,col)[theRow] != "",
insert into(colList, column(dt,col)[theRow]);
col++
);
dtOut = New Table( "Lot " || memoryLotName || " WaferID " || memoryWaferID,
new column( "Project Name", character),
new column( "Lot Name", character),
new column( "WaferID", character),
new column( "Time Readout", character),
new column( "Personal Note", character),
new column( "SubSite", numeric, ordinal),
new column( "Index X", numeric, ordinal),
new column( "Index Y", numeric, ordinal)
);
for each( {colName}, colList,
dtOut << new column( eval(colName), numeric, continuous);
);
,
dt:C1[theRow] == "DataValue",
dtOut << Add Rows(1);
dtOut:Project Name[nrows(dtOut)] = memoryProjectName;
dtOut:Lot Name[nrows(dtOut)] = memoryLotName;
dtOut:WaferID[nrows(dtOut)] = memoryWaferID;
dtOut:Time Readout[nrows(dtOut)] = memoryT0;
dtOut:Personal Note[nrows(dtOut)] = memory1strun;
dtOut:SubSite[nrows(dtOut)] = memorysubsite;
dtOut:Index X[nrows(dtOut)] = memoryIndexX;
dtOut:Index Y[nrows(dtOut)] = memoryIndexY;
for each( {colName, index}, colList,
column( dtOut, colName )[nrows(dtOut)] = num(column(dt,index+1)[theRow])
)
)
);
// Close the last work file
close( dtOut, nosave );
// Uncomment the below line if you want the raw table deleted
// close( dt, nosave );
Re: Domanda da principiante sulla generazione (estrazione) di tabelle dati da dati di sonda grezziProseguendo con la mia idea precedente, separando il file di testo in sezioni e quindi analizzando tali sezioni (questa registrazione copre parzialmente questo argomento Scripters Club 2024: Sessione 2 - Preparazione dei dati in arrivo non strutturati per l'analisi ).
Names Default To Here(1);
// Test sections seem to always start with a line starting with "SetupTitle"
// and end to same UNLESS it is last section when it ends with
// line of ",,,,,,,,,,,,,,,,,,,,,,,"
TEST_SECTION_START = "SetupTitle, ";
EMPTY_LINE = ",,,,,,,,,,,,,,,,,,,,,,,";
// Section patterns for regex
PROJECT_PATTERN = "^(.+)_(\d+\.\d*)(W\d{1,2})_(T\d+)_(.+): (\d+ \d+)\,+?";
SUBSITE_PATTERN = "<SUBSITE>(\d+)</SUBSITE>";
DATASTART_PATTERN = "^DataName";
find_test_section_lines = function({lines}, {Default Local},
start_idx = 0;
end_idx = 0;
TEST_SECTION_START = TEST_SECTION_START; // JMP "feature", 00075244
TEST_SECTION_END = TEST_SECTION_END; // JMP "feature", 00075244
For Each({line, idx}, lines,
If(Starts With(line, TEST_SECTION_START),
If(start_idx == 0,
start_idx = idx;
,
end_idx = idx;
break();
);
);
);
If(start_idx != 0 & end_idx == 0,
end_idx = N Items(lines);
);
return(Eval List({start_idx, end_idx}));
);
parse_test_section = function({lines}, {Default Local},
data_start = 0;
PROJECT_PATTERN = PROJECT_PATTERN; //JMP "feature", 00075244
SUBSITE_PATTERN = SUBSITE_PATTERN; //JMP "feature", 00075244
DATASTART_PATTERN = DATASTART_PATTERN; //JMP "feature", 00075244
For Each({line, idx}, lines,
If(!IsMissing(Regex(line, PROJECT_PATTERN)),
matches = Regex Match(line, PROJECT_PATTERN);
projname = matches[2];
lotid = matches[3];
waferid = matches[4];
time = matches[5];
notes = matches[6];
reticles = Words(Trim Whitespace(matches[7]), " ");
, !IsMissing(Regex(line, SUBSITE_PATTERN)),
subsite = Regex(line, SUBSITE_PATTERN, "\1");
, !IsMissing(Regex(line, DATASTART_PATTERN)),
data_start = idx;
break();
);
);
data_str = Concat Items(lines[data_start::N Items(lines)], "\!N");
dt = Open(Char To Blob(data_str), "text", invisible);
For Each({colname}, Reverse(dt << Get Column Names("String")), // drop empty columns
If(Col Number(Column(dt, colname)) == 0,
dt << Delete Column(colname);
,
break(); // break on first "ok" column
);
);
// define order and names here
dt << New Column("project", Character, Nominal, Set Each Value(projname));
dt << New Column("lot", Character, Nominal, Set Each Value(lotid));
dt << New Column("waferid", Character, Nominal, Set Each Value(waferid));
dt << New Column("time", Character, Nominal, Set Each Value(time));
dt << New Column("notes", Character, Nominal, Set Each Value(notes));
dt << New Column("x", Character, Nominal, Set Each Value(reticles[1]));
dt << New Column("y", Character, Nominal, Set Each Value(reticles[2]));
dt << New Column("subsite", Character, Nominal, Set Each Value(subsite));
dt << Move Selected Columns({:project, :lot, :waferid, :time, :notes, :x, :y, :subsite}, To First);
dt << Delete Columns("DataName");
return(dt);
);
// Start parsing
filepath = "$DOWNLOADS/Raw data examples_3DP.csv";
txt = Load Text File(filepath);
lines = Words(txt, "\!N");
lines = Filter Each({line}, lines, line != EMPTY_LINE); // drop empty lines
{start, end} = find_test_section_lines(lines);
dt_result = Empty();
While(All(start, end),
cur_testset = Remove From(lines, start, end - 1);
dt = parse_test_section(cur_testset);
If(Is Empty(dt_result),
dt_result = dt;
,
dt_result << Concatenate(
dt,
"Append to first table"
);
Close(dt, no save);
);
{start, end} = find_test_section_lines(lines);
);
dt_result << Show Window(1);

Re: Domanda da principiante sulla generazione (estrazione) di tabelle dati da dati di sonda grezziEcco uno script che legge tutti e 3 i dati del progetto presenti nel file CSV di esempio e crea 3 tabelle di dati separate.
names default to here(1);
file = pick file();
dt = Open(
File,
Import Settings(
End Of Line( CRLF, CR, LF ),
End Of Field( Comma, CSV( 0 ) ),
Treat Leading Zeros as Character( 1 ),
Strip Quotes( 1 ),
Use Apostrophe as Quotation Mark( 0 ),
Use Regional Settings( 0 ),
Scan Whole File( 1 ),
Treat empty columns as numeric( 0 ),
CompressNumericColumns( 0 ),
CompressCharacterColumns( 0 ),
CompressAllowListCheck( 0 ),
Labels( 0 ),
Column Names Start( 1 ),
First Named Column( 1 ),
Data Starts( 1 ),
Lines To Read( "All" ),
Year Rule( "20xx" )
)
);
// Change column names to simplify coding
for( i=1,i<=ncols(dt), i++, column(i)<< set name( "C" || char(i)));
// Loop through the data
for(theRow = 1, theRow <= NRows(dt), theRow++,
If( dt:C1[theRow] == "SetupTitle",
memoryProjectName = "";
memoryLotName = "";
memoryWaferID = "";
memoryT0 = "";
memory1strun = "";
memoryIndexX = .;
memoryIndexY = .;
setupFlag = 1;
projFlag = 0;
,
dt:C1[theRow] == "" & setupFlag == 1,
projFlag = 1;
setupFlag = 0;
,
projFlag == 1 & dt:C1[theRow] != "",
dt:C1[theRow] = trim(dt:C1[theRow]);
memoryProjectName = word(1, dt:C1[theRow], "_");
memoryLotName = word(2, dt:C1[theRow], "_W");
memoryWaferID = word(3, dt:C1[theRow], "_W");
memoryT0 = word(4, dt:C1[theRow], "_W");
memory1strun = word(5, dt:C1[theRow], "_W:");
memoryIndexX = num(word(2, dt:C1[theRow], ": "));
memoryIndexY = num(word(3, dt:C1[theRow], ": "));
projFlag = 0;
,
dt:C1[theRow] == "DataName",
colList = {};
col=2;
while( column(dt,col)[theRow] != "",
insert into(colList, column(dt,col)[theRow]);
col++
);
dtOut = New Table( "Lot " || memoryLotName || " WaferID " || memoryWaferID,
new column( "Project Name", character),
new column( "Lot Name", character),
new column( "WaferID", character),
new column( "Time Readout", character),
new column( "Personal Note", character),
new column( "Index X", numeric, ordinal),
new column( "Index Y", numeric, ordinal)
);
for each( {colName}, colList,
dtOut << new column( eval(colName), numeric, continuous);
);
,
dt:C1[theRow] == "DataValue",
dtOut << Add Rows(1);
dtOut:Project Name[nrows(dtOut)] = memoryProjectName;
dtOut:Lot Name[nrows(dtOut)] = memoryLotName;
dtOut:WaferID[nrows(dtOut)] = memoryWaferID;
dtOut:Time Readout[nrows(dtOut)] = memoryT0;
dtOut:Personal Note[nrows(dtOut)] = memory1strun;
dtOut:Index X[nrows(dtOut)] = memoryIndexX;
dtOut:Index Y[nrows(dtOut)] = memoryIndexY;
for each( {colName, index}, colList,
column( dtOut, colName )[nrows(dtOut)] = column(dt,index+1)[theRow]
)
)
);
Re: Domanda da principiante sulla generazione (estrazione) di tabelle dati da dati di sonda grezziCiao txnelson , ben detto. Scusate la mia pigrizia. So che potrei trovare la risposta da solo se ci dedicassi del tempo (e mi fa bene a lungo termine), ma mi sono sentito pressato a trovare la risposta corretta il prima possibile.
Tornerò e aiuterò i nuovi arrivati come hai fatto tu quando ho acquisito esperienza. Penso che questa sia una vera comunità di utenti in cui tutti si aiutano a vicenda. Ogni risposta è personalizzata in base alle esigenze individuali. JMP dovrebbe davvero incentivare gli utenti attivi qui. Spero che la tua risposta in questo thread possa essere utile anche ad altri utenti ingegneri.
Re: Domanda da principiante sulla generazione (estrazione) di tabelle dati da dati di sonda grezziCIAO txnelson , funziona! Mi servirà letteralmente questo script per il mio report della prossima settimana. Grazie!!!~~~
Nel frattempo, potresti apportare qualche miglioramento se non è troppo complicato?
1. Mancano le informazioni sul sottosito (colonna).
//Per aiutare i futuri osservatori, un wafer ha più reticoli (alias stepper field o die); ogni reticolo ha il suo unico (indice X, indice Y); ogni reticolo ha numerosi dispositivi chiamati "subsite" (alias subdie). La misurazione viene eseguita per subsite-reticle-wafer.

2. Emettere tutti i DP in una singola tabella JMP
//Senza pensarci troppo, ho applicato il tuo script al mio file raw completo (centinaia di DP...), puoi immaginare cosa è successo: ho lottato con numerose finestre JMP che si aprivano di continuo e alla fine mi sono arreso ricorrendo al task manager...
3. Modificare le proprietà della colonna della tabella dati da carattere a numerico.
4. È possibile comprimere la codifica in un formato più conciso?
//Quello attuale è molto intuitivo, ottimo per me che sono un principiante. Ma, in futuro, un codice più breve potrebbe essere più user-friendly. Per favore, dimenticatelo se è complicato o non è più user-friendly per chi lo guarda per la prima volta.
Re: Domanda da principiante sulla generazione (estrazione) di tabelle dati da dati di sonda grezziCIAO jthi , ti ringrazio! Dedicherò sicuramente del tempo per imparare questa funzione regex più avanti.
Spero che questo thread non solo mi dia le risposte di cui ho bisogno (davvero apprezzato), ma che serva anche come modello di partenza per simili attività di scansione ed estrazione JMP. Salverò tutti gli script per i miei lavori futuri!
Solo per contribuire ulteriormente a questo argomento, il problema più probabile quando uso tali script è la coerenza del formato dell'ID del lavoro . Presta molta attenzione a come costruire l'ID del lavoro e non modificarlo arbitrariamente, il che distorcerebbe la programmazione se non fosse seguito. Per fare due esempi, il mio formato standard dell'ID del lavoro è: Projname_Lot id_wafer id_personal note: index X index Y
Tuttavia, poiché si tratta di un test di laboratorio e ho nominato manualmente tutti i test, ci sono stati alcuni casi in cui ho violato la regola e NON ho seguito ESATTAMENTE lo stile sopra:
1. ho perso il "_" tra l'ID del lotto e l'ID del wafer, ad esempio, invece di "753367.1_W11", in alcuni casi ho digitato "753367.1W11";
2. Ho aggiunto due note personali invece di una: ad esempio, quando faccio un nuovo test dopo la prima esecuzione, invece di usare "_2nd_", ho usato "_1st_redo_". Dal momento che uso "_" come divisore della sezione informativa, ciò causerebbe problemi lì e in qualsiasi cosa successiva a quella sezione, poiché il conteggio non funziona correttamente.
Grazie ancora a jthi e txnelson per avermi aiutato a compiere i primi passi nello scripting JMP avanzato!
Re: Domanda da principiante sulla generazione (estrazione) di tabelle dati da dati di sonda grezziA seconda della tua applicazione, potresti riuscire a rendere il parser più robusto cercando pattern ripetuti invece di affidarti a pattern regex che corrispondono a linee specifiche. Ad esempio, sembra che il nome del tuo progetto, ad esempio, sia tra le linee MetaData

A seconda delle ipotesi che puoi fare, potresti estrarlo in base a quei MetaData e alle righe "vuote" invece di basarti su "la riga inizia con Proj" o "la riga corrisponde a questo schema regex".
R: Domanda da principiante sulla generazione (estrazione) di tabelle dati da dati di sonda grezziCiao Jthi,
Da qualche parte ricevo questo errore durante l'esecuzione di questo script. Puoi per favore darmi una guida?

R: Domanda da principiante sulla generazione (estrazione) di tabelle dati da dati di sonda grezziPunto interessante, jthi. Ci penserò.
Si noti che le informazioni sono incorporate nella riga dell'ID del job; il problema principale è come estrarle, non come individuarle. La mia lezione è come rendere coerente la dicitura "la riga inizia con Proj". Molto, molto importante. Per confermarlo ulteriormente, potremmo aggiungere uno script di verifica del pattern e assicurarci che le informazioni estratte siano conformi alle aspettative. Regex è uno strumento intuitivo per questo scopo.
R: Domanda da principiante sulla generazione (estrazione) di tabelle dati da dati di sonda grezziHai definito TEST_SECTION_END?
R: Domanda da principiante sulla generazione (estrazione) di tabelle dati da dati di sonda grezziSì, sto usando lo stesso script che hai postato prima.

R: Domanda da principiante sulla generazione (estrazione) di tabelle dati da dati di sonda grezziAh... per qualche motivo sono stati omessi nel mio script e dovrai determinare TEST_SECTION_END. A pensarci bene, potrebbe essere uguale a EMPTY_LINE.