2016-10-17 3 views
2

I possède un capteur (un transducteur de pression Quartzonix, en fait) qui crache données via le port série, environ 3 fois par seconde. Je voudrais mettre en place un code pour me donner une lecture moyenne basée sur x-quantité d'échantillons.moyen de roulement, vb.net

La sortie ressemble à ceci:

01+ 1.502347091823e01 
01+ 1.501987234092e01 
01+ 1.50234524524e01 
01+ 1.502123412341e01 
01+ 1.502236234523e01 
01+ 1.50198345e01 
01+ 1.502346234523e01 

.. et continuer indéfiniment jusqu'à ce que le port COM est fermé ou le transducteur reçoit une autre commande.

C'est ce code que j'ai jusqu'à présent, et le code fonctionne pour me montrer ce que le transducteur est la sortie en fait:

Private Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click 
    Dim a As String 
    a = "$01MC" & Chr(13) 
    MyComPort.WriteLine(a) 

    Do 
     Dim Incoming As String = MyComPort.ReadLine() 
     Dim incomingtext As String = Incoming.Remove(0, 3) 

     If Incoming Is Nothing Then 
      Exit Do 
     Else 
      txtRawData.Text = Incoming 
      boxPSIA.Text = Format(Val(incomingtext), "##0.000") 

     End If 
     Application.DoEvents() 
    Loop 

End Sub 

Le « $ 01MC » est la commande du transducteur doit commencer crachant la Les données. J'ai quelque chose de bizarre qui se passe quand je clique sur le bouton de démarrage, mais c'est un autre spectacle (peut-être un ajustement .readtimeout est nécessaire, pas sûr).

J'ai une zone de texte txtReadingsToAvg pour l'entrée du nombre de lectures à la moyenne .. Je ne suis pas juste enveloppant ma tête autour de comment l'obtenir pour calculer la moyenne (sur, disons, un clic, puis cracher dans un msgbox, ou même dans une autre zone de texte).

+3

Pour obtenir des mesures de n, qu'en une file d'attente ou registre à décalage n éléments de long. Chaque fois que vous obtenez une nouvelle lecture, poussez-la dans la file d'attente et la lecture la plus ancienne disparaît puis terminez. Puis faites la moyenne de la file d'attente. – peterG

+0

Voulez-vous une moyenne depuis le début de votre programme ou une moyenne depuis que le capteur a commencé à enregistrer? –

+0

Ou la moyenne des derniers n secondes/m échantillons? – djv

Répondre

1

Je ne sais pas comment votre code fonctionne même. Vous avez dit que vous obtenez des valeurs @ environ 3 Hz? Ensuite, un Do...Loop serait trop rapide. Un événement est déclenché lorsque le port série reçoit des données. Faites-en usage.

Vous aurez probablement besoin de changer cela un peu pour répondre à vos besoins

' WithEvents allows events to be handled with "Handles" keyword 
Private WithEvents myComPort As SerialPort 
Private dataQueue As Queue(Of Double) 
Private numReadingsToAvg As Integer = 0 

Private Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click 
    ' make a new queue here to initialize or clear an old queue 
    dataQueue = New Queue(Of Double)() 
    ' read the num avgs text box. you may want to change on the fly also 
    numReadingsToAvg = Integer.Parse(Me.txtReadingsToAvg.Text) 
    myComPort.WriteLine("$01MC" & Chr(13)) 
End Sub 

Private Sub myComPort_DataReceived(sender As Object, e As SerialDataReceivedEventArgs) Handles myComPort.DataReceived 
    Dim incomingLine As String = myComPort.ReadLine() 
    ' DataReceived event happens on its own thread, not the UI 
    ' must invoke call back to UI to change properties of controls 
    txtRawData.Invoke(Sub() txtRawData.Text = incomingLine) 
    Dim incomingValue As String = incomingLine.Remove(0, 3).Trim() 
    If Not String.IsNullOrWhiteSpace(incomingValue) Then 
     Exit Sub 
    Else 
     Dim measurement As Double = Double.Parse(incomingValue) 
     boxPSIA.Invoke(Sub() boxPSIA.Text = Format(measurement, "##0.000")) 
     dataQueue.Enqueue(measurement) 
     ' if there are too many items, remove the last one 
     If dataQueue.Count > numReadingsToAvg Then 
      dataQueue.Dequeue() 
     End If 
     Dim average As Double = dataQueue.Average() 
     ' you need to add this textbox 
     anotherTextBox.Invoke(Sub() anotherTextBox.Text = Format(average, "##0.000")) 
    End If 
End Sub 

Par ailleurs, Application.DoEvents() should rarely (never) be used, as there's always a better way to remedy whatever problem you are bandaging with DoEvents. Votre exemple original souffrait du colmatage du thread de l'interface utilisateur avec une boucle interminable s'exécutant sur l'interface utilisateur. Si jamais vous deviez exécuter une boucle comme celle-ci, elle devrait presque toujours tourner sur un thread différent de celui de l'interface utilisateur. Dans mon exemple, il n'y a pas de boucle, et le timing est déterminé par le port lui-même. Pas besoin de tout cela pour se produire sur le thread de l'interface utilisateur.

+0

Cela ne semble pas fonctionner .. boxPSIA et anotherTextBox ne sont pas mis à jour. – diashto

+0

Vous devez le déboguer. Mettez un point d'arrêt sur 'sortie Sub' et voir ce que' incomingLine' est égal à – djv

+0

bien, si j'ajouter boxPSIA.Text = Format (Val (incomingValue), « ## 0,000 ») au-dessus du si/then, les mises à jour boxpsia ainsi le texte rawdata (mais dans le format correct) .. – diashto