2015-09-05 3 views
1

J'essaie de simuler la distribution de chaleur sur une plaque infinie au fil du temps. Pour ce faire, j'ai écrit un script Scilab. Maintenant, le point crucial de celui-ci, est le calcul de la température pour tous les points de la plaque, et il doit être fait pour chaque instance de temps, je veux observer:Comment effectuer une opération pour tous les éléments de la matrice dans Scilab?

for j=2:S-1 
    for i=2:S-1 
     heat(i, j) = tcoeff*10000*(plate(i-1,j) + plate(i+1,j) - 4*plate(i,j) + plate(i, j-1) + plate(i, j+1)) + plate(i,j);   
    end; 
end 

Le problème est que, si je voudrais pour le faire pour une plaque de 100x100 points, cela signifie qu'ici (c'est seulement pour la partie interne, sans conditions aux limites), je devrais boucler 98x98 = 9604 fois, à chaque tour de calcul de la chaleur à un point i,j donné. Si je veux observer que, par exemple, 100 secondes, avec un pas de 1 s, je dois le répéter 100 fois, ce qui donne 960 400 itérations au total. Ce qui prend beaucoup de temps, et j'aimerais l'éviter. Jusqu'à 50x50 plaque, tout se passe dans un délai raisonnable, 4-5 secondes.

Maintenant, ma question est - est-il nécessaire de faire tout cela en utilisant for boucles? Existe-t-il une fonction d'agrégat intégrée dans Scilab, qui me permettra de faire cela pour tous les éléments d'une matrice? La raison pour laquelle je n'ai pas encore trouvé de solution, c'est que le résultat de chaque point dépend des valeurs des autres points de la matrice, ce qui m'a amené à le faire avec des boucles imbriquées. Toutes les idées sur la façon de le rendre plus rapide apprécié.

Répondre

2

Il me semble que vous voulez calculer une intercorrélation 2D de votre champ de chaleur et d'un certain type de diffusion. Ce modèle peut être considéré comme un noyau «filtre», qui est un moyen courant de modifier des images avec une matrice de filtre linéaire. Votre « filtre » est:

F=[0,1,0;1,-4,1;0,1,0]; 

Si vous installez l'image, vous aurez une fonction MaskFilter pour ce faire intercorrélation 2D Boîte à outils Traitement (IPD).

S=500; 
plate=rand(S,S); 
tcoeff=1; 

//your solution with nested for loops 
t0=getdate(); 
for j=2:S-1 
    for i=2:S-1 
    heat(i, j) = tcoeff*10000*(plate(i-1,j)+plate(i+1,j)-.. 
    4*plate(i,j)+plate(i,j-1)+plate(i, j+1))+plate(i,j);   
    end 
end 
t1=getdate(); 
T0=etime(t1,t0); 
mprintf("\nNested for loops: %f s (100 %%)",T0); 

//optimised nested for loop 
F=[0,1,0;1,-4,1;0,1,0]; //"filter" matrix 
F=tcoeff*10000*F; 
heat2=zeros(plate); 
t0=getdate(); 
for j=2:S-1 
    for i=2:S-1 
    heat2(i,j)=sum(F.*plate(i-1:i+1,j-1:j+1)); 
    end 
end 
heat2=heat2+plate; 
t1=getdate(); 
T2=etime(t1,t0); 
mprintf("\nNested for loops optimised: %f s (%.2f %%)",T2,T2/T0*100); 

//MaskFilter from IPD toolbox 
t0=getdate(); 
heat3=MaskFilter(plate,F); 
heat3=heat3+plate; 
t1=getdate(); 
T3=etime(t1,t0); 
mprintf("\nWith MaskFilter: %f s (%.2f %%)",T3,T3/T0*100); 

disp(heat3(1:10,1:10)-heat(1:10,1:10),"Difference of the results (heat3-heat):"); 

S'il vous plaît noter que l'image MaskFilter pads (la matrice d'origine) avant d'appliquer le filtre, et pour autant que je sais qu'il utilise un tableau « miroir » à travers la frontière. Vous devriez vérifier si ce comportement vous convient ou non.

L'augmentation de la vitesse est d'environ * 320 (le temps d'exécution est de 0,32% de votre code d'origine). Est-ce assez rapide?

En théorie, cela pourrait être fait avec deux Transformée de Fourier 2D (avec Scilab intégré à mfft peut-être) mais cela pourrait ne pas être plus rapide que cela. Voir ici: http://mailinglists.scilab.org/Image-processing-filter-td2618144.html#a2618168

+0

Oui, c'est certainement assez rapide. Réponse géniale, merci! –