简体   繁体   中英

How to generate a matrix with a function pattern?

Background info (Optional reading):

I'm running simulations of reflections of sound waves in against boundaries. The medium conditions for the points in space are set using a matrix. Let's say the dimensions of the space is an N by N grid, and there are two speeds of sound I care about, c0 and c1 .

Right now I'm using code like the following to generate barrier patterns

medium.sound_speed = c0*ones(N,N);   % set the speed of sound to be c0 everywhere
medium.sound_speed(:, N/2:N) = c1;   % set the right half of the grid to a different speed
medium.sound_speed(50:70, 50:70) = c1; % set a box to have a different speed

Or

% set all speeds to c0 except set the diagonal to c1
medium.sound_speed = c0*ones(N,N)-(c0*eye(N,N))+c1*eye(N,N); 

However, I can't generate more complex boundaries with different curvatures.

Question

I want to programmatically create matrices with patterns reflecting functions. For instance, I want to enter f(x)=2 and for that to create a matrix that looked something like this, assuming N=6 .

[ 0 0 0 0 0 0
  0 0 0 0 0 0
  0 0 0 0 0 0 
  1 1 1 1 1 1 
  0 0 0 0 0 0 
  0 0 0 0 0 0 ]

Or f(x)=0.5*x+1

[ 0 0 0 0 0 0
  0 0 0 0 0 0
  0 0 0 0 1 1
  0 0 1 1 0 0 
  1 1 0 0 0 0 
  0 0 0 0 0 0]

I would also be able to generate curved patterns like f(x)=1/x , which seems to require some form of the Midpoint circle algorithm , used for drawing curvatures with pixels.

[ 1 0 0 0 0 0
  1 0 0 0 0 0
  0 1 0 0 0 0
  0 0 1 1 0 0
  0 0 0 0 1 1  
  0 0 0 0 0 0 ]

In reality, N is at least 128, so manually creating these matrices for shapes with some level of complexity is impractical, and I thought this was an interesting problem.

Does anyone know of some way to do this, or suggestions for alternative approaches?

Thank you in advance.

Edit: I modified this implementation of Bresenham's algorithm to provide a matrix with the desired line given an origin and an ending point.

function M=bresenham_line(point)

if (abs(point(4)-point(2)) > abs(point(3)-point(1)))       % If the line is steep                                
    x0 = point(2);y0 = point(1); x1 = point(4);y1=point(3);% then it would be converted to 
    token =1;                                              % non steep by changing coordinate
else
    x0 = point(1);y0 = point(2); x1 = point(3);y1=point(4);
    token = 0; 
end
if(x0 >x1)
    temp1 = x0; x0 = x1; x1 = temp1;
    temp2 = y0; y0 = y1; y1 = temp2;
end
dx = abs(x1 - x0) ;                              % Distance to travel in x-direction
dy = abs(y1 - y0);                               % Distance to travel in y-direction
sx = sign(x1 - x0);                              % sx indicates direction of travel in X-dir
sy = sign(y1 - y0);                              % Ensures positive slope line

x = x0; y = y0;                                  % Initialization of line
param = 2*dy - dx ;                              % Initialization of error parameter
for i = 0:dx-1                                   % FOR loop to travel along X
    x_coord(i+1) = x;                            % Saving in matrix form for plot
    y_coord(i+1) = y;

    param = param + 2*dy;                        % parameter value is modified
    if (param >0)                                % if parameter value is exceeded
        y = y +1*sy;                             % then y coordinate is increased
        param = param - 2*(dx );                 % and parameter value is decreased

    end
    x = x + 1*sx;                                % X-coordinate is increased for next point
end

M = zeros(size(x_coord,2), size(y_coord,2));

for i=1:1:size(x_coord,2)
    x = x_coord(i);
    y = y_coord(i);

    M(x,y) = 1;
end

M

Implemented like so:

c1 = 0;
M = bresenham_line([1 1 Nx/2+1 Ny+1]);
medium.sound_speed = c0*ones(Nx,Ny) - (c0*M) + c1*M; 

No progress on curved function shapes yet.

This is a slightly 'dirty' way of getting something like this, although I you best bet might Bresenham's algorithm.

N = 128;
[X,Y] = meshgrid(1:N,1:N);
bound1 = Y<2*X;
bound2 = Y<2*X+1;
M = xor(bound1,bound2);

bound1 you can define any function y=f(x) , and mark the area under it. with bound2 you select and area that is slightly higher (shifted up). Once you take and xor of the two area you get just the desired y=f(x) marked. I think that in order to get reasonable results the shift might be different for more complicated function.

For illustration I used imagesc (the flipud is just for make the (0,0) in the bottom left, instead of the top left):

imagesc(flipud(M));

Edit

Indeed for some function this might not be the best. For example for y=x^2 , you have to increase the shift and still does not look great.

bound1 = Y<X.^2;
bound2 = Y<X.^2+15;
M = xor(bound1,bound2);

A way to get some similar results:

f = @(x)0.5*x; %create the function (x should be written even if the function doesn't depend on x: @(x) 0*x + 2)
N = 6; %choose the size of the atrix
M = zeros(N,N); %create an empty matrix
x = (1:N); 
y = round(f(x-1)); %discretization
x(y>N-1|y<0) = [];
y(y>N-1|y<0) = [];
M(sub2ind(size(M),y+1,x)) = 1;
M = flipud(M)

So you can choose your function, then the result in your matrix will look like a discretization of a normal plot .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM