Fronte di salita di una matrice di Double.

Pirelli72
Buongiorno a tutti e ringrazio anticipatamente a tutti coloro che mi daranno una mano.

Ho una matrice di Double di n elementi ricavata da un'acquisizione analogica di un segnale in tensione. Vorrei ricavare quale sia il primo l'indice della matrice in cui i valori iniziano a salire.

La mia matrice potrebbe essere così composta:
{0.0567677;0.0568677;0.0565677;0.0567677;0.0667677;1.0567677;1.1567677}

Ovviamente non posso impostare una soglia di rilevamento perchè i valori potrebbero cambiare, ad esempio:
{1.0567677;1.0568677;1.0565677;1.0567677;1.0667677;2.0567677;2.1567677}

Attualmente uso questo tipo di algoritmo:
-prendo 5 punti della matrice
-calcolo il coefficiente angolare della retta calcolata tramite la regressione lineare
-lo confronto con una soglia
-se la condizione non viene soddisfatta
-prendo altri 5 punti della matrice e proseguo con la matrice.

L'algoritmo funziona ma vorrei sapere se c'è qualcosa di più performante.

Risposte
apatriarca
C'è un motivo per cui non calcoli semplicemente il rapporto (o la differenza) tra due valori consecutivi e se questo rapporto (o differenza) è maggiore di una certa soglia lo consideri un aumento?

Pirelli72
Il motivo per cui non posso calcolare la differenza tra due valori consecutivi è che la matrice essendo popolata da un'acquisizione analogica è instabile nell'andamento, per cui potrei avere valori che salgono o scendono anche lievemente. Purtroppo a me interessa sapere quando i valori iniziano a salire oltre una certa soglia, ovvero il valore analogico misurato alla fonte inizia ad impennarsi e non frutto dell'instabilità dell'acquisizione.

[img]https://lh5.googleusercontent.com/-Zih6bEIthSdpM7f3jgTdeBFzdz5xSJUBdPVIvJLZ62C-jkRZOa3vgOlyd803gdQRWxQtOx-xrHgamyCK5Fat0OkzOoaXJf6ULg=w1600[/img]

Come vedi l'andamento non è lineare, a me interessa stabilire i fronti con la freccia rossa.

apatriarca
Vuoi insomma trovare i picchi del tuo segnale? Che ne dici di fare qualcosa come considerare una finestra di \(k\) valori che fai scorrere e consideri il valore massimo e minimo all'interno di questa finestra. Se la differenza tra il massimo e il minimo è sufficientemente ampio, hai un picco. Ovviamente è importante scegliere bene questa finestra. Ma non vedo perché l'analisi della differenza (o del rapporto) tra due o più valori consecutivi non sia sufficiente a stabilire i picchi nel tuo programma. Mi sembra abbastanza evidente che normalmente le variazione sono abbastanza limitate in rapporto all'intensità del segnale, mentre i picchi sono un incremento molto alto.

Pirelli72
In realtà non mi serve trovare tutti i picchi della matrice ma solo i due indicati con la freccia rossa.
Nel dettaglio la mia situazione è la seguente: ho un tamburo che ruota. Su questo tamburo viene depositato un materiale e devo misurare la giunta che viene creata a fine erogazione (il materiale erogato ha uno spessore di circa 1mm). Io calcolo il primo fronte (prima freccia rossa) ovvero quando il materiale passa e poi misuro il secondo fronte di salita (seconda freccia rossa) partendo dalla fine della matrice verso l'indice 0. La matrice è abbastanza cospicua, circa 60.000 elementi.
Provo sicuramente domani la tua prima idea, a quel punto ti chiedo quale potrebbe essere il numero dei K elementi tenendo conto dei parametri che ti ho detto.

Pirelli72
Ok ho inserito come mi hai detto il controllo tra il valore massimo/minimo della mini matrice (nel mio caso di 5 elementi) considerando che a tale intervallo corrispondono circa 3 decimo di millimetro in termine di spazio, Ho comunque lasciato il calcolo del coefficiente angolare in quando mi serve rilevare un fronte positivo e nella mia matrice posso avere alla fine un inizio in discesa. L'unica pecca di tale algoritmo è che è abbastanza lento, l'elaborazione costa circa 200ms e considerando che ne devo fare 4....!!!

apatriarca
Mostreresti il codice?

Pirelli72
Ok, non posto tutto il codice contenuto nella classe ma solo quello relativo all'elaborazione:

 id2 = start + (punti_matrice_tl - 1)
            max = Double.MinValue
            min = Double.MaxValue
            For idx As Integer = start To mmStartEnd
                For u As Integer = idx To id2
                    valoriY(idc) = sx_tl(u)
                    valoriX(idc) = idc
                    If sx_tl(u) > max Then max = sx_tl(u)
                    If sx_tl(u) < min Then min = sx_tl(u)
                    idc += 1
                Next
                idc = 0
                slopeTemp = Nothing
                intercept = Nothing
                mse = Nothing
                trendLineTemp = Nothing
                myAnalisysStat.LinFit(valoriX, valoriY, trendLineTemp, slopeTemp, intercept, mse)
                If CDbl(slopeTemp) > 0.1 AndAlso max - min > soglia_min_fronte Then
                    start = idx
                    Dim media As Single = CSng(myAnalisysStat.Mean(valoriY))
                    For xx As Integer = start To start + punti_matrice_tl
                        If sx_tl(xx) >= media Then
                            _indice1 = xx
                            Exit For
                        End If
                    Next
                    Exit For
                End If
                id2 += 1
            Next



La matrice su cui effettuare l'elaborazione è sx_tl che contiene circa 60000 elementi. Per snellire l'elaborazione ho limitato la quantità di punti da elaborare sia all'inizio che alla fine.

apatriarca
Che linguaggio stai usando? Ci sono diverse cose che non capisco dei tuoi valori (cosa sono ad esempio start, mmStartEnd, id2...) e ho l'impressione che tu faccia più cicli di quanti non siano necessari sui dati. Avevo in mente qualcosa di più minimal, anche se non vedendo più l'immagine non mi è chiaro che cosa abbiano effettivamente di particolare i due picchi a cui siamo interessati e se sia possibile trovarli in modo più diretto.

Pirelli72
Sto usando VB.NET.
Non riesco a snellire piu di così.
Alla ricapitoliamo: ho una matrice di circa 60000 elementi. Il primo fronte sicuramente c'è l'ho dopo il 20.000° indice, per cui la mia variabile start mi indica quale sia l'indice di partenza (è parametrizzato per poterlo spostare, se necessario) e diciamo che ora è 20.000. L'altra variabile mmStartEnd indica dove fermarsi perchè per me è inutile proseguire la ricerca del fronte oltre questo indice e diciamo che questa variabile è impostata a 24.000.
Per cui semplificando ho:

 max = Double.MinValue
 min = Double.MaxValue
            For idx As Integer = 20000 To 24000
                For u As Integer = idx To id2
                    valoriY(idc) = sx_tl(u)
                    valoriX(idc) = idc
                    If sx_tl(u) > max Then max = sx_tl(u)
                    If sx_tl(u) < min Then min = sx_tl(u)
                    idc += 1
                Next

                idc = 0
                slopeTemp = Nothing
                intercept = Nothing
                mse = Nothing
                trendLineTemp = Nothing
                myAnalisysStat.LinFit(valoriX, valoriY, trendLineTemp, slopeTemp, intercept, mse)
                If CDbl(slopeTemp) > 0.1 AndAlso max - min > soglia_min_fronte Then
                    start = idx
                    Dim media As Single = CSng(myAnalisysStat.Mean(valoriY))
                    For xx As Integer = start To start + punti_matrice_tl
                        If sx_tl(xx) >= media Then
                            _indice1 = xx
                            _indice1_h = sx_tl(_indice1 - ((1000 / unita_ing_tl) * 5))
                            Exit For
                        End If
                    Next
                    Exit For
                End If
                id2 += 1
            Next


...popolo la mia mini matrice valoriY di 5 elementi shiftando l'indice di 1 ogni volta in questo modo:
Se la mia matrice sx_tl ad esempio è così composta: {1,2,1,3,2,4,5,8,9,11,8,9,8......}
le mie mini matrici saranno così composte:
{1,2,1,3,2}
{2,1,3,2,4}
{1,3,2,4,5}
{3,2,4,5,8}

di ogni mini matrice calcolo lo slope e il massimo e il minimo.
Se lo slope è positivo e la differenza tra Max e Min è superiore a un certo valore allora sono di fronte ad un picco positivo.

Ora ho la mini matrice che soddisfa le mie condizioni ma a me interessa sapere qual'è l'indice preciso in cui la curva inizia a salire. Per cui mi sono inventato di calcolarmi la media della mini matrice, fare un confronto, il primo valore che supera la media è l'indice che mi interessa.

apatriarca
La mia idea era un po' diversa, vediamo comunque come semplificare le cose. Ti presento un po' di idee non necessariamente compatibili una con l'altra.

Calcolo media e varianza
È possibile mantenere aggiornata la media degli ultimi \(n\) elementi senza doverla ricalcolare ogni volta. In particolare, la media di \(k\) elementi di un qualche vettore \(X\) che partono da un indice \(s\) ha la forma:
\[ m_s = \frac{1}{k} \sum_{i = s}^{s + k - 1} X_i . \]
Supponiamo di voler a questo punto calcolare \( m_{s+1} \) a partire da \( m_s \). Per farlo è sufficiente osservare che nella sommatoria di \(m_s\) compare un solo addendo che non compare anche in quella di \(m_{s+1}\), cioè \( X_s/k \), e nella sommatoria di \(m_{s+1}\) compare un solo addendo che non compare anche in quella di \(m_s\), cioè \(X_{s+k}/k\). Da questa osservazione concludiamo che
\[ m_{s+1} = m_s + \frac{X_{s+k} - X_s}{k}. \]
A questo punto vorremmo stimare anche la differenza tra il massimo e il minimo in qualche modo. Credo che il modo migliore per ottenere un'informazione più o meno equivalente, considerando che abbiamo già la media, è quella di calcolare la varianza. Ricordando quindi le formule precedenti per la media dovremmo ottenere se non ho sbagliato i calcoli:
\[ v_{s+1} = v_s + \frac{X_{s+k} - X_s}{k}\left( (X_{s+k} + X_s) + 2\,m_s - \frac{X_{s+k} - X_s}{k}\right) \]

Verifica se la funzione è crescente
Per verificare se la funzione è globalmente crescente nel tuo blocco utilizzi la regressione lineare. Essendo una operazione abbastanza costosa (non eccessivamente ma se la calcoli \(60000 - k + 1\) volte inizia a pesare sulle performance), allora potrebbe valer la pena di saltare quanto possibile questo test. In particolare, se la soglia per la differenza tra massimo e minimo è stata settata sufficientemente ampia, allora per la maggior parte dei campioni questo test dovrebbe essere negativo. Per cui la prima cosa che farei è verificare se è davvero necessario verificare se la curva è crescente o meno. A questo punto utilizzerei però un metodo euristico più semplice. Stavo in particolare pensando di calcolare una media tra le differenze tra elementi consecutivi. Per quello che dobbiamo fare mi sembrerebbe sufficientemente accurato come metodo.

Ricerca meno fine
Se per un qualche blocco abbiamo una bassa varianza/differenza tra massimo e minimo allora anche il blocco shiftato di una posizione avrà probabilmente la stessa caratteristica. Viceversa, se ci fosse una grossa variazione di valori e abbiamo o meno trovato un picco, troveremmo lo stesso picco shiftando di poco. Si potrebbe quindi ad esempio shiftare ogni volta di un numero \(1 < d < k\) posizioni ignorando quindi alcuni casi. In questo modo potresti quindi per esempio avanzare ogni volta di ad esempio tre posizioni e considerare il blocco di cinque elementi.

Posizione picco
Se il blocco è sufficientemente piccolo, difficilmente si trovano più picchi nello stesso blocco e puoi forse scegliere come picco una posizione che sia facile da calcolare come il centro del blocco senza commettere un errore troppo grosso. Scegliendo la posizione in questo modo ti eviti molti calcoli e ottieni un errore massimo di \(0.15 mm\).

Pirelli72
Ok ci siamo sono di nuovo operativo, scusami.
Dunque, l'algoritmo che utilizzo funziona alla meraviglia fino a che il gradino di tensione e netto o quasi: Quando il gradino di tensione non è proprio netto inizia ad avere qualche problema, ad esempio con questa curva:

[img]https://lh3.googleusercontent.com/bnGh-yo7nqd0VG9vW8Za6hWQVqe36pEUMoeLCfXvzFZSkL5iOiM7jUVWaJbX6EZR-rwNQp01NhCaLp2CCljV13UFHNd4ucmKzbk=w1600[/img]

di cui riporto solo la parte finale:

[img]https://lh6.googleusercontent.com/w0p4ZVYgTjeCQGTB3l4M7pYhZ9K0NsS7dPt1JJr_m7s0L1m7PpixymUhMLoR3W_oUfz6d6gcV0XCvSe_dUdFRMek0w07jwyinNQ=w1600[/img]

inizio ad avere problemi di analisi, in quanto lo slope delle mini matrici inizia a calare cosi come la diff. tra min e max.

Mi parlavi di come calcolare la differenza tra min e max nella prima ideea, ovvero di calcolo di media e varianza......come primo metodo alternativo....

apatriarca
Non riesco a vedere le immagini, ma capisco quale possa essere il problema. In questo caso una possibile soluzione potrebbe essere quella di allargare la finestra di ricerca.

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.