Matlab: Protokoll zerlegen und verarbeiten

OP Persönliche Seite #4969368
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
Gast #4970206
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
OP Persönliche Seite #4970252
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?
#4972675
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.
Gast #4974121
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
OP Persönliche Seite #4979319
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren