est-il possible d'accélérer le traçage de matlab en appelant le code C / C++ dans matlab?

Il est généralement très facile d'appeler mex fichiers (écrit en c/c++) dans Matlab pour accélérer certains calculs. Dans mon expérience, cependant, le véritable goulot d'étranglement dans Matlab est traçage des données. La création de poignées est extrêmement coûteuse et même si vous ne mettez à jour que les données (par exemple, XData, YData, ZData), cela peut prendre des années. Pire encore, puisque Matlab est un seul programme fileté, il est impossible de mettre à jour plusieurs tracés en même temps.

D'où ma question: est-il possible d'écrire une interface graphique Matlab et d'appeler C++ (ou un autre code parallélisable) qui s'occuperait du traçage / visualisation? je suis à la recherche d'une solution multi-plateforme qui fonctionnera sur Windows, Mac et Linux, mais n'importe quelle solution que j'ai commencé sur l'un ou l'autre OS est grandement appréciée!

j'ai trouvé un bibliothèque C++ qui semble utiliser Matlab plot() syntaxe mais je ne suis pas sûr que cela pourrait accélérer les choses, puisque je crains que si je intrigue en Matlab figure() la fenêtre, les choses pourraient ralenti de nouveau.

j'apprécie les observations et les commentaires de personnes qui ont traité de ce genre de situation avant!

EDIT: évidemment, j'ai déjà profilé mon code et le goulot d'étranglement est le tracé (une douzaine de panneaux avec beaucoup de données).

EDIT2: pour que vous obteniez la prime, j'ai besoin d'une vraie vie, un exemple de travail minimal sur la façon de faire ceci-suggestif les réponses ne vais pas m'aider.

EDIT3: en ce qui concerne les données à tracer: dans le cas le plus simple, pensez à 20 tracés linéaires, qui doivent être mis à jour chaque seconde avec quelque chose comme 1000000 points de données.

EDIT4: je sais que c'est une énorme quantité de points de la parcelle, mais je n'ai jamais dit que le problème était facile. Je ne peux pas juste laisser de côté certains points de données, parce qu'il n'y a aucun moyen d'évaluer quels points sont importants, avant de les tracer (les données sont échantillonnées par résolution temporelle de sous-ms). En fait, mes données sont acquises en utilisant un système d'acquisition de données commerciales qui est livré avec un visualiseur de données (écrit en c++). Ce programme n'a aucun problème à visualiser jusqu'à 60 tracés de ligne avec même plus de 1000000 points de données.

EDIT5: Je n'aime pas où va la discussion actuelle. Je suis conscient que le sous-échantillonnage de mes données pourrait accélérer les choses - cependant, ce n'est pas la question. La question ici est comment obtenir une interface c / C++ / python / java pour travailler avec matlab afin d'accélérer le traçage en parlant directement au matériel (ou en utilisant n'importe quel autre truc)

14
demandé sur Andrey Rubshtein 2012-01-20 22:59:10

9 réponses

puisque vous voulez une performance maximale, vous devriez envisager d'écrire un visualiseur OpenGL minimal. Videz tous les points d'un fichier et lancez le visualiseur en utilisant la commande "system"dans MATLAB. Le spectateur peut être vraiment simple. Voici un implémenté en utilisant GLUT, compilé pour Mac OS X. Le code est multiplate-forme donc vous devriez être en mesure de le compiler pour toutes les plates-formes que vous mentionnez. Il devrait être facile de modifier ce visualiseur pour vos besoins.

si vous êtes capable d'intégrer ce visualiseur plus étroitement avec MATLAB, vous pourriez être en mesure de vous en tirer sans avoir à écrire et à lire à partir d'un fichier (= mises à jour beaucoup plus rapides). Cependant, je ne suis pas expérimenté en la matière. Peut-être Pouvez-vous mettre ce code dans un fichier mex?

EDIT: j'ai mis à jour le code pour dessiner une ligne à partir d'un pointeur de mémoire CPU.

// On Mac OS X, compile using: g++ -O3 -framework GLUT -framework OpenGL glview.cpp
// The file "input" is assumed to contain a line for each point:
// 0.1 1.0
// 5.2 3.0
#include <vector>
#include <sstream>
#include <fstream>
#include <iostream>
#include <GLUT/glut.h>
using namespace std;
struct float2 { float2() {} float2(float x, float y) : x(x), y(y) {} float x, y; };
static vector<float2> points;
static float2 minPoint, maxPoint;
typedef vector<float2>::iterator point_iter;
static void render() {
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(minPoint.x, maxPoint.x, minPoint.y, maxPoint.y, -1.0f, 1.0f);
    glColor3f(0.0f, 0.0f, 0.0f);
    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(2, GL_FLOAT, sizeof(points[0]), &points[0].x);
    glDrawArrays(GL_LINE_STRIP, 0, points.size());
    glDisableClientState(GL_VERTEX_ARRAY);
    glutSwapBuffers();
}
int main(int argc, char* argv[]) {
    ifstream file("input");
    string line;
    while (getline(file, line)) {
        istringstream ss(line);
        float2 p;
        ss >> p.x;
        ss >> p.y;
        if (ss)
            points.push_back(p);
    }
    if (!points.size())
        return 1;
    minPoint = maxPoint = points[0];
    for (point_iter i = points.begin(); i != points.end(); ++i) {
        float2 p = *i;
        minPoint = float2(minPoint.x < p.x ? minPoint.x : p.x, minPoint.y < p.y ? minPoint.y : p.y);
        maxPoint = float2(maxPoint.x > p.x ? maxPoint.x : p.x, maxPoint.y > p.y ? maxPoint.y : p.y);
    }
    float dx = maxPoint.x - minPoint.x;
    float dy = maxPoint.y - minPoint.y;
    maxPoint.x += dx*0.1f; minPoint.x -= dx*0.1f;
    maxPoint.y += dy*0.1f; minPoint.y -= dy*0.1f;
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
    glutInitWindowSize(512, 512);
    glutCreateWindow("glview");
    glutDisplayFunc(render);
    glutMainLoop();
    return 0;
}

EDIT: voici un nouveau code basé sur la discussion ci-dessous. Il rend une fonction de sin composée de 20 vbos, chacune contenant 100k points. 10k nouveaux points sont ajoutés chaque le rendu. Cela fait un total de 2m points. La performance est en temps réel sur mon ordinateur portable.

// On Mac OS X, compile using: g++ -O3 -framework GLUT -framework OpenGL glview.cpp
#include <vector>
#include <sstream>
#include <fstream>
#include <iostream>
#include <cmath>
#include <iostream>
#include <GLUT/glut.h>
using namespace std;
struct float2 { float2() {} float2(float x, float y) : x(x), y(y) {} float x, y; };
struct Vbo {
    GLuint i;
    Vbo(int size) { glGenBuffersARB(1, &i); glBindBufferARB(GL_ARRAY_BUFFER, i); glBufferDataARB(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW); } // could try GL_STATIC_DRAW
    void set(const void* data, size_t size, size_t offset) { glBindBufferARB(GL_ARRAY_BUFFER, i); glBufferSubData(GL_ARRAY_BUFFER, offset, size, data); }
    ~Vbo() { glDeleteBuffers(1, &i); }
};
static const int vboCount = 20;
static const int vboSize = 100000;
static const int pointCount = vboCount*vboSize;
static float endTime = 0.0f;
static const float deltaTime = 1e-3f;
static std::vector<Vbo*> vbos;
static int vboStart = 0;
static void addPoints(float2* points, int pointCount) {
    while (pointCount) {
        if (vboStart == vboSize || vbos.empty()) {
            if (vbos.size() >= vboCount+2) { // remove and reuse vbo
                Vbo* first = *vbos.begin();
                vbos.erase(vbos.begin());
                vbos.push_back(first);
            }
            else { // create new vbo
                vbos.push_back(new Vbo(sizeof(float2)*vboSize));
            }
            vboStart = 0;
        }

        int pointsAdded = pointCount;

        if (pointsAdded + vboStart > vboSize)
            pointsAdded = vboSize - vboStart;

        Vbo* vbo = *vbos.rbegin();
        vbo->set(points, pointsAdded*sizeof(float2), vboStart*sizeof(float2));

        pointCount -= pointsAdded;
        points += pointsAdded;
        vboStart += pointsAdded;
    }
}
static void render() {
    // generate and add 10000 points
    const int count = 10000;
    float2 points[count];
    for (int i = 0; i < count; ++i) {
        float2 p(endTime, std::sin(endTime*1e-2f));
        endTime += deltaTime;
        points[i] = p;
    }
    addPoints(points, count);
    // render
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(endTime-deltaTime*pointCount, endTime, -1.0f, 1.0f, -1.0f, 1.0f);
    glColor3f(0.0f, 0.0f, 0.0f);
    glEnableClientState(GL_VERTEX_ARRAY);
    for (size_t i = 0; i < vbos.size(); ++i) {
        glBindBufferARB(GL_ARRAY_BUFFER, vbos[i]->i);
        glVertexPointer(2, GL_FLOAT, sizeof(float2), 0);

        if (i == vbos.size()-1)
            glDrawArrays(GL_LINE_STRIP, 0, vboStart);
        else
            glDrawArrays(GL_LINE_STRIP, 0, vboSize);
    }
    glDisableClientState(GL_VERTEX_ARRAY);
    glutSwapBuffers();
    glutPostRedisplay();
}
int main(int argc, char* argv[]) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
    glutInitWindowSize(512, 512);
    glutCreateWindow("glview");
    glutDisplayFunc(render);
    glutMainLoop();
    return 0;
}
4
répondu rasmus 2012-02-12 12:26:07

avez-vous essayé la solution triviale de changer la méthode de rendu en