mikrocontroller.net

Forum: Digitale Signalverarbeitung / DSP Matlab: warum dauert das so lange?


Autor: Benni Nori (benninori)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich importiere meine Messungen, csv mit einigen Milionen Zeilen, in 
Matlab. So weit so gut. Um die Messwerte durch einen Filter zu jagen 
muss ich vorher noch die Zeit "zurechtrücken" und die "messwerte" auf 
die drei Phasen aufteilen. Das mache ich wie folgt:

messwerte = csvread('blabla');
schritte = size(messwerte);
null = messwerte(1,1);

for i:1:1:schritte(1,1)
  u(i,1) = messwerte(i,1) - null;
  u(i,2) = messwerte(i,2);
  v(i,1) = messwerte(i,1) - null;
  v(i,2) = messwerte(i,3);
  w(i,1) = messwerte(i,1) - null;
  w(i,2) = messwerte(i,4);
end;

Es klappt alles wunderbar, nur dauert dieses verschieben, die 
for-Schleife, richtig ewig. Ich kann mir das nicht so ganz erklären. 
Gibt es da einen Trick wie das schneller geht oder mach ich sogar was 
falsch?

Autor: Walter Tarpan (nicolas)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das wird schonmal schneller gehen:
for i = schritte(1,1):-1:1
  u(i,1) = messwerte(i,1) - null;
  u(i,2) = messwerte(i,2);
  v(i,1) = messwerte(i,1) - null;
  v(i,2) = messwerte(i,3);
  w(i,1) = messwerte(i,1) - null;
  w(i,2) = messwerte(i,4);
end;

Ansonsten: Bitte richtiges Codebeispiel posten! Das, was dort oben steht 
wird nicht laufen.

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kopier es ohne Schleife:

u = zeros(schritte(1,1), 2);
v = zeros(schritte(1,1), 2);
w = zeros(schritte(1,1), 2);

u(:,1) = messwerte(:,1) - null;
u(:,2) = messwerte(:,2);
v(:,1) = messwerte(:,1) - null;
v(:,2) = messwerte(:,3);
w(:,1) = messwerte(:,1) - null;
w(:,2) = messwerte(:,4);

Wenn null ein Skalar ist, wird dieser automatisch auf einen Vektor 
erweitert.

Autor: Benni Nori (benninori)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
super, danke für die hilfe. das probier ich gleich aus.

Autor: Andreas Auer (Firma: Embedded Microtec) (andi) Flattr this
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Generell sollte man in Matlab versuchen Schleifen so weit es geht zu 
vermeiden und Dinge anhand von Matrizenoperationen implementieren.

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was für ein Matlab (welches Jahr) benutzt Du eigentlich? Dass Schleifen 
langsamer laufen als vektorisierter Code konnte ich schon seit ein paar 
Jahren nicht mehr feststellen.

Was genau dauert eigentlich so lange an Deinem Code? Die for-Schleife 
oder der Aufruf von csvread?

Autor: benninori (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich benutze die letzten beiden versionen 2009 und 2010. bei beiden das 
gleiche problem: die for-schleife

Autor: Anon Nymous (fuechslein)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
profile on;

.. dein code ..

profile off; profile viewer;

Das erste was ich mach wenn was langsam is. Aber stimm natuerlich: Die 
for Schleife is natuerlich sehr langsam. ;)

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Würd mich mal interessieren: Wieviel schneller ist denn jetzt die 
Version mit dem vektorisierten Code? (hab leider kein Matlab hier)

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habs jetzt mal ausprobiert. Vektorisierter Code:

%messwerte = csvread('blabla');
Nx = 3000000;
messwerte = rand(Nx,4);
schritte = size(messwerte);
null = messwerte(1,1);

u = zeros(Nx,2);
v = zeros(Nx,2);
w = zeros(Nx,2);

tic

u(:,1) = messwerte(:,1) - null;
u(:,2) = messwerte(:,2);
v(:,1) = messwerte(:,1) - null;
v(:,2) = messwerte(:,3);
w(:,1) = messwerte(:,1) - null;
w(:,2) = messwerte(:,4);

toc

% Elapsed time is 0.149645 seconds.


Und der nicht-vektorisierte Code (mit for-Schleife):

%messwerte = csvread('blabla');
Nx = 3000000;
messwerte = rand(Nx,4);
schritte = size(messwerte);
null = messwerte(1,1);

u = zeros(Nx,2);
v = zeros(Nx,2);
w = zeros(Nx,2);

tic

for i=1:1:Nx
  u(i,1) = messwerte(i,1) - null;
  u(i,2) = messwerte(i,2);
  v(i,1) = messwerte(i,1) - null;
  v(i,2) = messwerte(i,3);
  w(i,1) = messwerte(i,1) - null;
  w(i,2) = messwerte(i,4);
end;

toc

% Elapsed time is 0.517368 seconds.


Der vektorisierte Code läuft (unter Matlab 2007) also wirklich etwas 
schneller (immerhin Faktor drei). Hierbei ist mir aufgefallen, dass die 
Definition von Nx und die Benutzung von Nx als obere Grenze der 
for-Schleife das Ganze etwa doppelt so schnell laufen lässt, als wenn 
ich schritte(1,1) also obere Grenze setze.
Wichtig ist auf jeden Fall bei for-loops, dass die Matrizen u,v,w vorher 
mit der entsprechenden Größe angelegt werden. Wenn nicht, wachsen die 
mit jeder Interation der Loop, und es muss ständig neuer Speicher 
allokiert werden (mit der entsprechenden Größe), was natürlich sehr 
lange dauert.

Aber gut: Ich hätte nicht gedacht, dass die vektorisierte Form überhaupt 
nennenswert (>10% oder so) schneller läuft.

Autor: Benni Nori (benninori)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei meinen auswertungen hat sich mächtig was getan. während es vorher 
kaum machbar war, tage und wochen. sind die meißten auswertungen jetzt 
in ein paar stunden erledigt. habe halt richtig viele messwerte, einige 
millionen.

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Einige Millionen sind eigentlich nicht wirklich viel. Falls Du 
feststellen solltest, dass bei Deinen Berechnungen die Festplatte heftig 
rattert, bedeutet das, dass Du nicht genug Speicher hast, um alles 
gleichzeitig zu laden (die Festplatte swappt). Dann solltest Du nach 
Möglichkeit scheibchenweise vorgehen, also z.B. eine Million Daten nach 
der anderen prozessieren. Tage und Wochen sollten so nicht vorkommen.

Autor: Karl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch eine gaaanz böse Falle bei Matlab: Vektoren dynamisch wachsen 
lassen. Dabei muss jedesmal der Speicher freigegeben werden und neu 
allokiert werden. Wenn das mal in den MiB-Bereich geht, wirds extrem 
langsam! deshalb immer mit x = zeros() vorbelegen, wenn möglich.

Autor: Anon Nymous (fuechslein)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nananan jetzt nicht gleich den Teufel an die Wand malen. Jedesmal 
speicher allokieren und dann wieder frei geben is auch nicht rightig. 
Jemand der ne Algorithmenvorlesung besucht hat weis das man normal den 
Speicher immer verdoppelt um eine Amortisierte Laufzeit von O(1) zu 
bekommen. So ist es AFAIK auch in der STL implementiert.
Klar is das allokierten davor um Welten besser allerding ist es jetzt 
nicht so das eine Element jedes mal ein realloc triggert.

Autor: Karl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wir reden hier nicht von C oder C++, sondern von Matlab! Das Vorbelegen 
ist explizit in der Doku erwähnt und bei größeren Datensätzen kann man 
sonst wirklich zuschauen, wie lange ein Schleifendurchlauf braucht! 
(Nein, ich habe keine Algorithmenvorlesung besucht: Was ist einen 
"Amortisierte Laufzeit" und wie passt das mit O(1) zusammen?)

Autor: Anon Nymous (fuechslein)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
MATLAB ist aber in C/C++ implementiert. (Auser der GUI die ist in 
Java...)


http://en.wikipedia.org/wiki/Amortized_analysis

"As a simple example, in a specific implementation of the dynamic array, 
we double the size of the array each time it fills up. Because of this, 
array reallocation may be required, and in the worst case an insertion 
may require O(n). However, a sequence of n insertions can always be done 
in O(n) time, because the rest of the insertions are done in constant 
time, so n insertions can be completed in O(n) time. The amortized time 
per operation is therefore O(n) / n = O(1)."

Autor: Zwölf Mal Acht (hacky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich wuerd mal auf eine ineffiziente Stringread- oder Stringconvert 
operation tippen...

Autor: Karl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie dem auch sei, die messbare Performance sagt (mit Matlab 2006b), dass 
dieser Algorithmus nicht zum Einsatz kommt und ein initiales Anlegen des 
Arrays richtig was bringt. So gesehen bin ich froh, diese Vorlesung 
nicht besucht zu haben, weil dann wäre ich der Meinung, dass dynamische 
Arrays quasi nichts kosten.

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Zusammenhang mit dem Matlab-internen Just-In-Time-Compiler, der 
Matlab-Code seit einigen Jahren gerade auch bei for-Schleifen 
beschleunigt, ist auch etwas schwierig. Scheinbar wird der JIT-Compiler 
bei solchen for-loops nur angeworfen, wenn die for-loop in einer 
Matlab-Function auftaucht, oder wenn sie eben keine dynamisch wachsenden 
Arrays hat. Siehe z.B. http://www.scholarpedia.org/article/MATLAB unter 
dem Abschnitt "Interpretation, just-in-time compilation, and 
performance".

Hier wird eine for-Schleife gezeigt, die 1.5*0.018469s (etwa 0.025s) 
braucht, wenn sie in einem m-file steht und in der keine dynamischen 
Arrays auftauchen, gegenüber einer for-Schleife, die 34.178847s braucht, 
in der dynamische Arrays drinstehen. Also ein Unterschied vom Faktor 
1000. Mag aber immer noch O(1) (auch wenn ich es nicht glaube) sein - 
der Zusammenhang mit der Größe des Arrays wurde nicht untersucht.

Autor: Fred (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch wenn diese Frage schon uralt ist, falls einer das selbe Problem 
hat, dann liegt das einfach daran, dass die Vektoren u, v, w vom 
Fragensteller nicht initialisiert wurden! Bei einigen der gegebenen 
Antworten aber schon!

Wenn man bspw. den Vektor u nicht initialisiert, so wird intern u beim 
ersten Schleifendurchgang als Skalar betrachtet, beim zweiten Durchgang 
wird dann u zu einem Vektor mit 2 Einträgen. Damit dies aber 
funktioniert wird Matlab neuen Speicher anfordern, das alte u in das 
neue u kopieren und zusätzlich den neuen Messwert ablegen. Jetzt kann 
man sich denken, dass genau dieser Prozess des Speicher anforderns, 
alten Vektor kopieren und neuen Messwert ablegen bei hohen 
Schleifendurchgängen immens dauern wird. Das wird das Problem gewesen 
sein, dem der Fragensteller gegenüber gestanden hat.

Also: u,v,w mit den Dimensionen der Messwerte initialisieren! Dann wird 
von vorn herein der richtige Speicherbedarf bereitgestellt und es müssen 
nur noch die Werte reingeschrieben werden. Kein Anfragen nach neuem 
Speicher und auch kein rumkopieren des alten Vektors in den aktuellen.

Autor: Markus W. (elektrowagi78) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das nenne ich mal einen guten Tipp!!

Autor: Jan K. (jan_k)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Das sagt einem doch sogar der Editor (gelbe Dreiecke mit entsprechenden 
Tips). Generell siehe Matlab Best practices: 
http://blogs.mathworks.com/loren/2012/01/13/best-p... 
und 
https://www.google.at/url?sa=t&source=web&rct=j&ur...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.