Mustererkennung von Messreihen zur Positionierung

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 59 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Mustererkennung von Messreihen zur Positionierung

    Hallo zusammen,

    ich hoffe ich bin hier im richtigen Forum und finde Hilfe :)

    ich habe eine Referenzmessreihe


    Die neue Messreihe ist ein Teilstück der Referenzmessreihe


    Jetzt suche ich eine Funktion die über eine Mustererkennung die neue Messreihe in die Referenzmessreihe einpasst.


    Die Werte der neuen Messreihe sind vom Verlauf ähnlich, im Detail weiten die Werte von der Referenz ab.

    Hat jemand eine Idee, wie ich das lösen kann?

    Danke für jeden Kommentar
    Bilder
    • Ref.JPG

      86,5 kB, 1.675×283, 72 mal angesehen
    • neu.JPG

      55,49 kB, 1.284×274, 68 mal angesehen
    • positioniert.JPG

      80,84 kB, 1.669×273, 74 mal angesehen
    @MarioRainer Willkommen im Forum. :thumbup:
    Pauschal würde ich sagen: Das Zauberwort heißt Kreuzkorrelation.
    Das würde aber voraussetzen, dass Messreihe und Referenzmessreihe aus derselben Anzahl von Werten bestehen.
    Kannst Du etwas mehr über die Beschaffenheit der Daten sagen?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany
    Vielen Dank für die prompte Antwort.
    Die Beschaffenheit sieht wie in den Bilder aus. Die Referenzmessung stellt einen kompletten Messabschnitt dar.
    Die neue Messreihe ist möglicherweise nur ein Teil der Referenzstrecke und kann in der Länge variieren. Die Anzahl der Werte sind nicht gleich
    jedoch die X Schrittweise im gleichen Raster.

    MarioRainer schrieb:

    Die Anzahl der Werte sind nicht gleich
    Ein Messwert ist ein numerischer welchen Datentyps?
    Wieviele Werte umfasst die Referenzmessung?
    Wieviele Werte umfasst eine normale Messung?
    Sind alle normalen Messungen gleich lang?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Alle Messwerte sind Typ Double
    Die Referenzmessung 7152 Werte
    Die neue Messung enthält 1481 Werte

    Das ist ein Messabschnitt von vielen und die neue Messung kann unterschiedlich viele Werte enthalten.

    Die Fragestellung ist, kann ich die neue Messung in X Richtung automatisch an die entsprechende Position schieben, sodass die Messung mit der Referenz vergleichbar ist.

    Datenmuster als CSV Datei
    Dateien

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „MarioRainer“ ()

    MarioRainer schrieb:

    Datenmuster als CSV Datei
    OK.
    Da die Werte äquidistant sind, können wir die erste Spalte ignorieren und arbeiten mit den Indizes.
    Ab Zeile 1482 fehlen 4 Werte?
    Also mal laut gedacht:
    Lineare Kreuzkorrelation geht recht fix (nicht FFT), Du teilst die Refenzwerte in n Abschnitte, n ~ 2 * (Refenzwerte.Count / Messwerte.Count)
    und machst n Kreuzkorrelationen zwischen Refenzwertabschnitt und Messwerten und suchst jeweils das Maximum der korrelierten Werte und den Index dazu.
    Im Anschnitt dieses Maximums solltest Du die beste Übereinstimmung finden.
    Das Problem lässt sich sicher parallelisieren.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Du bekommst hier nicht einfach Code geschenkt.

    MarioRainer schrieb:

    Kreuzkorrelation
    Was ist das?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    MarioRainer schrieb:

    Hat jemand eine Idee, wie ich das lösen kann?
    Wir sind aber kein Macht-Mir-Meine-Hausaufgaben-Forum, sondern wir helfen, indem wir Dir den Weg weisen.
    Du kümmerst Dich, wir finden dann die Fehler da, wo Du nicht weiter kommst.
    Ansonsten hast Du einen Code, von dem Du nicht weißt, was er tut und wie er es tut, machst die üblichen C&P-Fehler und beschwerst Dich dann im Forum, warum der Code aus dem Forum bei Dir nicht läuift.
    Also:
    Informiere Dich, entwickle einen Plan und wir setzen den dann um.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    *unnötiges Vollzitat entfernt*

    Danke für die konkrete Hilfe :)

    Ich habe es auch so geschafft!
    War dann doch nicht so schwer....

    VB.NET-Quellcode

    1. Try
    2. Dim refData As New List(Of Double)
    3. Dim pattern As New List(Of Double)
    4. Dim i As Integer
    5. Dim CSVreader As String() = File.ReadAllLines("D:\Test\!!Einpassen\Mustervergleich.csv")
    6. For Each s As String In CSVreader
    7. Dim cells() As String = s.Split(";"c)
    8. If cells.Count > 0 Then
    9. If i > 0 Then
    10. If cells(1) <> "" Then
    11. refData.Add(cells(1))
    12. End If
    13. If cells(2) <> "" Then
    14. pattern.Add(cells(2))
    15. End If
    16. End If
    17. End If
    18. i += 1
    19. Next
    20. Dim len As Integer = pattern.Count - 1
    21. Dim refPart(len) As Double
    22. Dim PearsonCorrList(refData.Count) As Double
    23. For i = 0 To refData.Count - 1 - pattern.Count
    24. Array.Copy(refData.ToArray, i, refPart, 0, len)
    25. PearsonCorrList(i) = PearsonCorrelation(pattern.ToArray, refPart)
    26. Next
    27. Dim val As Double = 0
    28. Dim index As Integer = -1
    29. For i = 0 To PearsonCorrList.Length - 1
    30. If PearsonCorrList(i) > val Then
    31. val = PearsonCorrList(i)
    32. index = i
    33. End If
    34. Next
    35. MessageBox.Show(Me, " best index = " + index.ToString)
    36. Catch ex As Exception
    37. MessageBox.Show(Me, ex.ToString)
    38. End Try
    39. End Sub
    40. Private Function PearsonCorrelation(p() As Double, q() As Double) As Double
    41. Dim pSum As Double = 0
    42. Dim qSum As Double = 0
    43. Dim pSumSq As Double = 0
    44. Dim qSumSq As Double = 0
    45. Dim productSum As Double = 0
    46. Dim pValue As Double
    47. Dim qValue As Double
    48. Dim n As Integer = p.Length
    49. If n <> q.Length Then
    50. Throw New ArgumentException("Input vectors must be of the same dimension.")
    51. End If
    52. For i As Integer = 0 To n - 1
    53. pValue = p(i)
    54. qValue = q(i)
    55. pSum += pValue
    56. qSum += qValue
    57. pSumSq += pValue * pValue
    58. qSumSq += qValue * qValue
    59. productSum += pValue * qValue
    60. Next
    61. Dim numerator As Double = productSum - ((pSum * qSum) / n)
    62. Dim denominator As Double = Math.Sqrt((pSumSq - (pSum * pSum) / n) * (qSumSq - (qSum * qSum) / n))
    63. If denominator = 0 Then
    64. Return 0
    65. Else
    66. Return (numerator / denominator)
    67. End If
    68. End Function

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Marcus Gräfe“ ()

    MarioRainer schrieb:

    War dann doch nicht so schwer....
    Sag ich doch.
    Allerdings ist die Pearson Correlation nicht die Kreuzkorrelation, von der ich sprach! de.wikipedia.org/wiki/Kreuzkorrelation
    Ob das trotzdem funktioniert, musst Du experimentell herausbekommen.
    Machst Du Option Strict On :!:
    Visual Studio – Empfohlene Einstellungen

    MarioRainer schrieb:

    VB.NET-Quellcode

    1. If i > 0 Then
    2. If cells(1) <> "" Then
    3. refData.Add(cells(1))
    4. End If
    5. If cells(2) <> "" Then
    6. pattern.Add(cells(2))
    7. End If
    8. End If

    RodFromGermany schrieb:

    Ab Zeile 1482 fehlen 4 Werte?
    Hier erzeugst Du eine lokale Phasenverschiebung zwischen den Messwerten und der Referenz, kläre das genau auf!
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Interessantes Thema.

    So wie ich das verstehe, wird aus der Referenzmenge immer ein prüfmengen-großer Teil ausgeschnitten und dann wird eine Art Differenz zwischen diesem und der Prüfmenge selbst gebildet.

    Wenn ich die Daten so angucke, dann fallen direkt die Minima und Maxima auf.
    Für die Referenzmenge und die Prüfmenge könnte man doch stattdessen die Positionen von ein paar lokalen Extrama bestimmen. (Größer/kleiner bestimmter Schwellenwert)
    Und dann diese Extrema-Teilmengen vergleichen.
    Je kleiner ich die Schwellenwerte wähle um ein lokales Extremum zu erkennen, desto präziser wird das Ganze, aber umso mehr Vergleiche muss ich machen, weil die Teilmengen größer werden.
    Umgekehrt habe ich bei prägnanten Extrema die Möglichkeit meine Vergleichsmengen massiv zu verkleinern.
    Im Beispiel reichen doch schon 10 Extremwerte aus der Prüfmenge um die Position eindeutig zu bestimmen.
    @Haudruferzappeltnoch Das wäre suboptimal.
    Die Kreuzkorrelation macht hier genau das, was getan werden soll.
    Das mit dem Stückeln muss natürlich explizit untersucht werden.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Das Prinzip der Kreuzkorrelation:
    Zwei gleich lange Felder, als Ring-Array gedacht (Index = Array.Length ==> Index = 0), werden beide mit Index 0 übereinander gelegt, dann wird Array2 verschoben.

    Quellcode

    1. Ziel-Array(j) = Summe der Produkte (Array1(i) * Array2(i + j)) ' mit j = 0 ... n-1
    Index des Maximums vom Ziel-Array ist die Position der besten Übereinstimmung beider Arrays.
    Ist der Betrag vom Minimums vom Ziel-Array größer als das Maximum des Ziel-Arrays, ist dies die beste Übereinstimmung für ein invertiertes Input-Feld.
    ====
    Das ganze lässt sich auch über FFT lösen, geht zwar schneller, ist aber wegen der 2^n Stützstellen und dem Sinus-Cosinus-Zeugs ungewollt effektbehaftet.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Haudruferzappeltnoch schrieb:

    Was ist n?
    Anzahl der Elemente.
    Circular buffer ja, aber die Indexrechnung selbst in einer Zeile implementieren, da brauchst Du keine eigene Klasse.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ok, dann verstehe ich das so, dass die Arrays weiterhin "normale" Arrays sind. Aber der Index wird zyklisch berechnet.

    VB.NET-Quellcode

    1. For j = 0 to n-1
    2. For i = 0 to n-1
    3. Zielarray(j) += Array1(i) * Array2((i+j) mod n)
    4. Next
    5. Next


    Aber ein großer Unterschied ist dann da doch nicht zu der anderen Methode.
    Und außerdem bleibt weiterhin noch zu klären was ich mache wenn die Referenzmenge größer ist als die Prüfmenge. Ich denke dann kriege ich verschieden ZielArrays und dann muss ich die auch noch wieder vergleichen?
    Da wäre mir nicht klar, ob ich da einfach das größte Maximum suche oder das Zielarray mit dem größten Durchschnitt und von diesem das Maximum. Aber vielleicht kommt das mathematisch aufs selbe raus. Müsste man sich mal Extremfälle zurecht basteln.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Haudruferzappeltnoch schrieb:

    Aber ein großer Unterschied ist dann da doch nicht zu der anderen Methode.
    Hier wird nix dividiert, dies ist signifikant!
    Und der Wertebereich ist beliebig groß.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!