2015-09-05 3 views
1

Я пытаюсь имитировать распределение тепла на бесконечной плите с течением времени. Для этого я написал сценарий Scilab. Теперь, решающий момент его, является расчет температуры во всех точках пластины, и это должно быть сделано для каждого экземпляра раз, когда я хочу заметить:Как выполнить операцию для всех матричных элементов в 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 

Проблема заключается в том, что, если бы я хотел сделать это для пластины 100х100 точек, это означает, что здесь (это только для внутренней части, без граничных условий), мне пришлось бы зацикливать 98х98 = 9604 раза, на каждом повороте рассчитывать тепло при заданной точке i,j. Если я хотел бы заметить, что, скажем, 100 secons, с шагом в 1 секунду, я должен повторить его 100 раз, давая в общей сложности 960 400 итераций. Это занимает довольно много времени, и я хотел бы избежать этого. Плата размером до 50x50, все это происходит в разумный, 4-5 секунд.

Теперь мой вопрос - нужно ли все это сделать с помощью for петель? Есть ли встроенная функция агрегата в Scilab, которая позволит мне сделать это для всех элементов матрицы? Причина, по которой я еще не нашел пути, заключается в том, что результат для каждой точки зависит от значений других матричных точек, и это заставляло меня делать это с вложенными циклами. Любые идеи о том, как сделать это быстрее оценены.

ответ

2

Мне кажется, что вы хотите вычислить двумерную межкорреляцию своего теплового поля и определенный диффузионный рисунок. Этот шаблон можно рассматривать как «фильтрующее» ядро, что является распространенным способом изменения изображений с помощью линейной матрицы фильтров. Ваш "фильтр" является:

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

При установке Image Processing Toolbox (IPD), вы будете иметь MaskFilter функцию, чтобы сделать это 2D интеркорреляций.

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):"); 

Пожалуйста, обратите внимание, что MaskFilter подушечки изображения (исходная матрица) до применения фильтра, и насколько я знаю, он использует «зеркальный» массив через границу. Вы должны проверить, подходит ли вам это поведение или нет.

Увеличение скорости около * 320 (время выполнения составляет 0,32% от исходного кода). Это достаточно быстро?

В теории это можно сделать с помощью двух 2D преобразования Фурье (возможно, с помощью Scilab mfft), но это может быть не быстрее этого. См. Здесь: http://mailinglists.scilab.org/Image-processing-filter-td2618144.html#a2618168

+0

Да, это, конечно, достаточно быстро. Удивительный ответ, спасибо! –