Forum: PC-Programmierung Matlab: Protokoll zerlegen und verarbeiten


von Daniel V. (voda) Benutzerseite


Lesenswert?

Hallo liebes Forum,

für mein Bildverarbeitungsprojekt habe ich folgendes realisiert:

Mit einem ADNS3090 und einem BMA020 lese ich über ein STM32F4 die Bild- 
sowie die Beschleunigungswerte auf. Diese sende ich über eine USART wie 
folgt:

0xAA Markierungsbyte -> Ab hier fangen die Bilddaten an
0x7B Markierungsbyte -> Ab hier fangen die Beschleunigungsdaten an

Mein Gedanke ist folgender:

Findet Matlab 0xAA und ist das 901. Byte 0x7F so ist das mein Bild.
Das 931. Byte muss wieder 0xAA sein, somit sind dies meine 
Beschleunigungsdaten.

Wie kann ich in Matlab dies implementieren? Meine jetzige Lösung ist 
sehr, sehr langsam.
1
% USART Kommunikation
2
clc; clear all, close all;
3
4
% Prüfe ob serielle Schnittstelle frei ist, wenn nicht
5
% schließe diese
6
if ~isempty(instrfind)
7
   fclose(instrfind); 
8
end
9
10
%% USART-Einstellungen
11
12
mesaurement_device_data = serial ('COM32');
13
set(mesaurement_device_data,'BaudRate',115200);
14
set(mesaurement_device_data, 'DataBits', 8);
15
set(mesaurement_device_data, 'Parity','none');
16
set(mesaurement_device_data, 'StopBit',1);
17
set(mesaurement_device_data, 'ReadAsyncMode','continuous');      
18
mesaurement_device_data.InputBufferSize = 2000;
19
 set(mesaurement_device_data,'Timeout', 20);
20
fopen(mesaurement_device_data);
21
22
%% Definiere Bildarray
23
horizontal_pixel = 30;
24
vertical_pixel   = 30;
25
26
start_frame   = 170;
27
Spalte        = 1;
28
start_acc     = 123;
29
for (i = 0:100)
30
pause(0.001)
31
 while (1) 
32
    temp_data = fread(mesaurement_device_data);
33
    [I170 Zeile170]=min(abs(temp_data(:,Spalte)-start_frame));
34
    [I123 Zeile123]=min(abs(temp_data(:,Spalte)-start_acc));
35
    vergleich=abs(Zeile123-Zeile170);
36
     
37
    if (vergleich == 901)
38
      %TESTMATRIX -> MUSS IN EINER FOR-SCHLEIFE !!!! 
39
      picture ...  
40
  
41
      colormap(gray(256));
42
      image(picture);
43
    break;
44
    end;
45
 end;       
46
end;

Danke euch und Gruß
Daniel

von Freddy (Gast)


Lesenswert?

Hallo Daniel,

ich persönlich fand Matlab's fopen immer recht umständlich.
Manche Sachen sind in C einfacher zu realisieren und dann per DLL 
einzubinden. Aber das nur so am Rande.

temp_data wird neu angelegt, das kostet Zeit.
Probier die Variable vorzubelegen
temp_data = one(1:ende);
oder
temp_data = zeros(1:ende);

Statt (if) kann auch die Matlab Funktion find genutzt werden.

Matlab hat einen Profiler mit dem man seinen Code auch auf Performance 
testen kann. Probier mal aus mit diesem Deinen Code laufen zu lassen.

Gruß,
Freddy

von Daniel V. (voda) Benutzerseite


Lesenswert?

Hallo freddy,

Freddy schrieb:
> ich persönlich fand Matlab's fopen immer recht umständlich.
> Manche Sachen sind in C einfacher zu realisieren und dann per DLL
> einzubinden. Aber das nur so am Rande

erstmal danke für Deine Antwort. Das mit einer externen DLL in C, die 
Idee ist mir auch schon gekommen, d.h. ich lagere die Suchfunktion aus? 
Kannst Du mir ein Beispiel geben bzw. zeigen?

: Bearbeitet durch User
von Daniel V. (voda) Benutzerseite


Lesenswert?

Freddy schrieb:
> Statt (if) kann auch die Matlab Funktion find genutzt werden.

Das verstehe ich jetzt nicht. Ich muss doch überprüfen, ob der Abstand 
zwischen 0xAA und 0x7F genau 901 Byte sind, denn es kann durchaus sein, 
das diese Werte im Datenpaket enthalten ist.

: Bearbeitet durch User
von Jim M. (turboj)


Lesenswert?

Daniel V. schrieb:
> Freddy schrieb:
>> Statt (if) kann auch die Matlab Funktion find genutzt werden.
>
> Das verstehe ich jetzt nicht. Ich muss doch überprüfen, ob der Abstand
> zwischen 0xAA und 0x7F genau 901 Byte sind, denn es kann durchaus sein,
> das diese Werte im Datenpaket enthalten ist.

Das muss dann die nachfolgende Verarbeitung beachten, die ist dann nicht 
mehr  völlig trivial aber machbar, zum Bleistift mit find.

Die generelle Idee ist, statt einer Schleife mit einzelnen Werten - was 
in Mathlab sehr langsam ist - möglichst nur auf Vektoren zu arbeiten, 
das läuft sehr viel schneller.

von vorticon (Gast)


Lesenswert?

Hallo Daniel,

wie schon von anderen erwaehnt, waere es sinnvoller, die Daten 
blockweise einzulesen. Puffergroesse auf 1 - x kB erhoehen und dann:

1000 Bytes auf einmal empfangen:

data=fread(mesaurement_device_data,[1000 1]);

start_index=find(data==start_frame & circshift(data,-901)==start_acc,1);

if ~isempty(start_index)
weitere Verarbeitung...
end

den unverarbeiteten Rest der empfangenen Daten muesstest du dann inder 
Endlosschleife fuer den naechsten Schleifendurchlauf aufheben.

Vermutlich kannst du nicht sicherstellen, dass die Startsymbole nicht 
auch im Datenstrom auftreten. Falls doch, koenntest du die 
Terminator-Property des serial-Objektes benutzen, das waere dann nochmal 
einfacher.

Gruss vorticon

von Daniel V. (voda) Benutzerseite


Lesenswert?

Guten morgen, diesen Thread hatte ich ja ganz vergessen ;)

Der Fix war in der Tat sehr aufwändig.

Dies ist das Herz meiner sehr umfangreichen Funktion:
1
 bytesIn = fread(serialPort,serialPort.BytesAvailable);
2
 z_start_frame_0xAA_s = find(bytesIn==start_frame_0xAA);
3
 z_start_acc_0x7F_s = find(bytesIn==start_acc_0x7F);

Das alles ist in einer if-Abfrage (sind Daten vorhanden?) und dann in 
eine for-Schleife mit der Länge des jeweiligen Daten.

Danke an euch alle, ihr habt mir sehr weitergeholfen.

Gruß
Daniel

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.