How to plot very low negative values in Matlab - matlab

I want to plot the following - see below.
The reason that I want to use semilogy - or something else, maybe you have suggestions? - is that the data goes so low that the scale is such that all the positive data appears to be zero.
Of course semilogy doesn't work with negative data. But what can I do? The goal is that positive and negative data are somehow visible in the plot as different from zero.
I saw this question (Positive & Negitive Log10 Scale Y axis in Matlab), but is there a simpler way?
Another issue I have with the semilogy command is that the data are plotted as if they go from November to April, whereas they really go from January to June!
%% Date vector
Y = [];
for year = 2008:2016
Y = vertcat(Y,[year;year]);
end
M = repmat([01;07],9,1);
D = [01];
vector = datetime(Y,M,D);
%% Data
operatingValue=...
1.0e+05 *...
[0.020080000000000, 0.000010000000000, 0.000430446606112, 0.000286376498540, 0.000013493575572, 0.000008797774209;...
0.020080000000000, 0.000020000000000, 0.000586846360023, 0.000445575962649, 0.000118642085670, 0.000105982759202;...
0.020090000000000, 0.000010000000000, 0.000304503221392, 0.000168068072591, -0.000004277640797, 0.000006977580173;...
0.020090000000000, 0.000020000000000, 0.000471819542315, 0.000318827321824, 0.000165018495621, 0.000188500216550;...
0.020100000000000, 0.000010000000000, 0.000366527395452, 0.000218539902929, 0.000032265798656, 0.000038839492621;...
0.020100000000000, 0.000020000000000, 0.000318807172600, 0.000170892065948, -0.000093830970932, -0.000096575559444;...
0.020110000000000, 0.000010000000000, 0.000341114962826, 0.000187311222835, -0.000118595282218, -0.000135188693035;...
0.020110000000000, 0.000020000000000, 0.000266317725166, 0.000128625220303, -0.000314547081599, -0.000392868178754;...
0.020120000000000, 0.000010000000000, 0.000104302824558, -0.000000079359646, -0.001817533087893, -0.002027417507676;...
0.020120000000000, 0.000020000000000, 0.000093484465168, -0.000019260661622, -0.002180826237198, -0.001955577709102;...
0.020130000000000, 0.000010000000000, 0.000052921606827, -0.000175185193313, -4.034665389612666, -4.573270848282296;...
0.020130000000000, 0.000020000000000, 0.000027218083520, -0.000167098897097, 0, 0;...
0.020140000000000, 0.000010000000000, 0.000044907412504, -0.000106127286095, -0.012248660549809, -0.010693498138601;...
0.020140000000000, 0.000020000000000, 0.000061663936450, -0.000070280400096, -0.015180683545658, -0.008942771925367;...
0.020150000000000, 0.000010000000000, 0.000029214681162, -0.000190870890021, 0, 0;...
0.020150000000000, 0.000020000000000, 0.000082672707169, -0.000031566292849, -0.003226048850797, -0.003527284081616;...
0.020160000000000, 0.000010000000000, 0.000084562787728, -0.000024916156477, -0.001438488940835, -0.000954872893879;...
0.020160000000000, 0.000020000000000, 0.000178181932848, 0.000054988621755, -0.000172520970578, -0.000139835312255]
figure;
semilogy( datenum(vector), operatingValue(:,3), '-+', datenum(vector), operatingValue(:,4), '-o',...
datenum(vector), operatingValue(:,5), '-*', datenum(vector), operatingValue(:,6), '-x',...
'LineWidth',1.2 ), grid on;
dateaxis('x', 12);

Save the function symlog in your directory.
function symlog(varargin)
% SYMLOG bi-symmetric logarithmic axes scaling
% SYMLOG applies a modified logarithm scale to the specified or current
% axes that handles negative values while maintaining continuity across
% zero. The transformation is defined in an article from the journal
% Measurement Science and Technology (Webber, 2012):
%
% y = sign(x)*(log10(1+abs(x)/(10^C)))
%
% where the scaling constant C determines the resolution of the data
% around zero. The smallest order of magnitude shown on either side of
% zero will be 10^ceil(C).
%
% SYMLOG(ax=gca, var='xyz', C=0) applies this scaling to the axes named
% by letter in the specified axes using the default C of zero. Any of the
% inputs can be ommitted in which case the default values will be used.
%
% SYMLOG uses the UserData attribute of the specified axes to record the
% current transformation applied so that subsequent calls to symlog
% operate on the original data rather than the newly transformed data.
%
% Example:
% x = linspace(-50,50,1e4+1);
% y1 = x;
% y2 = sin(x);
%
% subplot(2,4,1)
% plot(x,y1,x,y2)
%
% subplot(2,4,2)
% plot(x,y1,x,y2)
% set(gca,'XScale','log') % throws warning
%
% subplot(2,4,3)
% plot(x,y1,x,y2)
% set(gca,'YScale','log') % throws warning
%
% subplot(2,4,4)
% plot(x,y1,x,y2)
% set(gca,'XScale','log','YScale','log') % throws warning
%
% subplot(2,4,6)
% plot(x,y1,x,y2)
% symlog('x')
%
% s = subplot(2,4,7);
% plot(x,y1,x,y2)
% symlog(s,'y') % can but don't have to provide s.
%
% subplot(2,4,8)
% plot(x,y1,x,y2)
% symlog() % no harm in letting symlog operate in z axis, too.
%
% Created by:
% Robert Perrotta
%
% Referencing:
% Webber, J. Beau W. "A Bi-Symmetric Log Transformation for Wide-Range
% Data." Measurement Science and Technology 24.2 (2012): 027001.
% Retrieved 6/28/2016 from
% https://kar.kent.ac.uk/32810/2/2012_Bi-symmetric-log-transformation_v5.pdf
% default values
ax = []; % don't call gca unless needed
var = 'xyz';
C = 0;
% user-specified values
for ii = 1:length(varargin)
switch class(varargin{ii})
case 'matlab.graphics.axis.Axes'
ax = varargin{ii};
case 'char'
var = varargin{ii};
case {'double','single'}
C = varargin{ii};
otherwise
error('Don''t know what to do with input %d (type %s)!',ii,class(varargin{ii}))
end
end
if isempty(ax) % user did not specify a value
ax = gca;
end
% execute once per axis
if length(var) > 1
for ii = 1:length(var)
symlog(ax,var(ii),C);
end
return
end
% From here on we redefine C to be 10^C
C = 10^C;
% Axes must be in linear scaling
set(ax,[var,'Scale'],'linear')
% Check for existing transformation
userdata = get(ax,'UserData');
if isfield(userdata,'symlog') && isfield(userdata.symlog,lower(var))
lastC = userdata.symlog.(lower(var));
else
lastC = [];
end
userdata.symlog.(lower(var)) = C; % update with new value
set(ax,'UserData',userdata)
if strcmpi(get(ax,[var,'LimMode']),'manual')
lim = get(ax,[var,'Lim']);
lim = sign(lim).*log10(1+abs(lim)/C);
set(ax,[var,'Lim'],lim)
end
% transform all objects in this plot into logarithmic coordiates
transform_graph_objects(ax, var, C, lastC);
% transform axes labels to match
t0 = max(abs(get(ax,[var,'Lim']))); % MATLAB's automatically-chosen limits
t0 = sign(t0)*C*(10.^(abs(t0))-1);
t0 = sign(t0).*log10(abs(t0));
t0 = ceil(log10(C)):ceil(t0); % use C to determine lowest resolution
t1 = 10.^t0;
mt1 = nan(1,8*(length(t1))); % 8 minor ticks between each tick
for ii = 1:length(t0)
scale = t1(ii)/10;
mt1(8*(ii-1)+(1:8)) = t1(ii) - (8:-1:1)*scale;
end
% mirror over zero to get the negative ticks
t0 = [fliplr(t0),-inf,t0];
t1 = [-fliplr(t1),0,t1];
mt1 = [-fliplr(mt1),mt1];
% the location of our ticks in the transformed space
t1 = sign(t1).*log10(1+abs(t1)/C);
mt1 = sign(mt1).*log10(1+abs(mt1)/C);
lbl = cell(size(t0));
for ii = 1:length(t0)
if t1(ii) == 0
lbl{ii} = '0';
% uncomment to display +/- 10^0 as +/- 1
% elseif t0(ii) == 0
% if t1(ii) < 0
% lbl{ii} = '-1';
% else
% lbl{ii} = '1';
% end
elseif t1(ii) < 0
lbl{ii} = ['-10^{',num2str(t0(ii)),'}'];
elseif t1(ii) > 0
lbl{ii} = ['10^{',num2str(t0(ii)),'}'];
else
lbl{ii} = '0';
end
end
set(ax,[var,'Tick'],t1,[var,'TickLabel'],lbl)
set(ax,[var,'MinorTick'],'on',[var,'MinorGrid'],'on')
rl = get(ax,[var,'Ruler']);
try
set(rl,'MinorTick',mt1)
catch err
if strcmp(err.identifier,'MATLAB:datatypes:onoffboolean:IncorrectValue')
set(rl,'MinorTickValues',mt1)
else
rethrow(err)
end
end
function transform_graph_objects(ax, var, C, lastC)
% transform all lines in this plot
lines = findobj(ax,'Type','line');
for ii = 1:length(lines)
x = get(lines(ii),[var,'Data']);
if ~isempty(lastC) % undo previous transformation
x = sign(x).*lastC.*(10.^abs(x)-1);
end
x = sign(x).*log10(1+abs(x)/C);
set(lines(ii),[var,'Data'],x)
end
% transform all Patches in this plot
patches = findobj(ax,'Type','Patch');
for ii = 1:length(patches)
x = get(patches(ii),[var,'Data']);
if ~isempty(lastC) % undo previous transformation
x = sign(x).*lastC.*(10.^abs(x)-1);
end
x = sign(x).*log10(1+abs(x)/C);
set(patches(ii),[var,'Data'],x)
end
% transform all Retangles in this plot
rectangles = findobj(ax,'Type','Rectangle');
for ii = 1:length(rectangles)
q = get(rectangles(ii),'Position'); % [x y w h]
switch var
case 'x'
x = [q(1) q(1)+q(3)]; % [x x+w]
case 'y'
x = [q(2) q(2)+q(4)]; % [y y+h]
end
if ~isempty(lastC) % undo previous transformation
x = sign(x).*lastC.*(10.^abs(x)-1);
end
x = sign(x).*log10(1+abs(x)/C);
switch var
case 'x'
q(1) = x(1);
q(3) = x(2)-x(1);
case 'y'
q(2) = x(1);
q(4) = x(2)-x(1);
end
set(rectangles(ii),'Position',q)
end
Plot your functions including symlog(gca,'y',-1.7) in the end:
plot( datenum(vector), operatingValue(:,3), '-+', datenum(vector), operatingValue(:,4), '-o',...
datenum(vector), operatingValue(:,5), '-*', datenum(vector), operatingValue(:,6), '-x',...
'LineWidth',1.2 ), grid on;
symlog(gca,'y',-1.7)
Here is your plot with positive and negative values:
Hope this solves your problem.

Related

I would like to run the calculating of the following piece of code 30 times in MATLAB

I am trying to calculate the received optical power for an optical communication system for 30 times. When I run the code, I get a 41 x 41 double matrix of H0_LoS and power (P_r_LOS & P_rec_dBm) as shown below
The case above is only for one iteration.
I would like to get a matrix or a cell with results up to 30 times that of the implemented code.
Any assistance, please?
My try below
close all;
clear variables;
clc;
%% Simulation Parameters
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Main Simulation Parameters %%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%-------------------------%
% NUMBER OF LIGHT SOURCES %
%-------------------------%
N_t = 1; % Number of light sources
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% AP Parameters %%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%------------------------%
% LIGHT SOURCES GEOMETRY %
%------------------------%
L = 20; W = 20; H = 3; % Length, width and height of the room (m)
theta_half = 60;
m = -log(2)./log(cosd(theta_half)); % Lambertian order of emission
coord_t = [0 0 0]; % Positions of the light sources
n_t_LED = [0, 0, -1]; n_t_LED = n_t_LED/norm(n_t_LED); % Normalized normal vector of each light source
n_t = repmat(n_t_LED, N_t, 1); % Normalized normal vectors of the light sources
%-------------------------------------%
% LIGHT SOURCES ELECTRICAL PARAMETERS %
%-------------------------------------%
P_LED = 2.84; % Average electrical power consummed by each light source (W)
% P_LED = 1;
param_t = {coord_t, n_t, P_LED, m};
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Rx Parameters %%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%--------------------------%
% PHOTODETECTOR PARAMETERS %
%--------------------------%
A_det = 1e-4; % Photoreceiver sensitive area (m²)
FOV = 60*pi/180; % Fielf-of-view of the photoreceiver
T_s = 1; % Gain of the optical filter (ignore if not used)
index = 1.5; % Refractive index of the Rx concentrator/lens (ignore if not used)
G_Con = (index^2)/sin(FOV); % Gain of an optical concentrator; ignore if no lens is used
n_r = [0, 0, 1]; % Normal vector of the photoreceiver
n_r = n_r/norm(n_r); % Normal vector of the photoreceiver (normalized)
%---------------------------%
% RECEIVER PLANE PARAMETERS %
%---------------------------%
step = 0.5; % Distance between each receiving point (m)
X_r = -L/2:step:L/2; % Range of Rx points along x axis
Y_r = -W/2:step:W/2; % Range of Rx points along y axis
N_rx = length(X_r); N_ry = length(Y_r); % Number of reception points simulated along the x and y axis
z_ref = 0.85; % Height of the receiver plane from the ground (m)
z = z_ref-H; % z = -1.65; % Height of the Rx points ("-" because coordinates system origin at the center of the ceiling)
if( abs(z) > H )
fprintf('ERROR: The receiver plane is out of the room.\n');
return
end
param_r = {A_det, n_r, FOV}; % Vector of the Rx parameters used for channel simulation
%% LOS received optical power calculation
H0_LOS = zeros(N_rx,N_ry,N_t);
T = param_t{1}(1,:);
P_t = param_t{3};
for iter = 1:30
for r_x = 1:N_rx
for r_y = 1:N_ry
for i_t = 1:N_t
x = X_r(r_x); y = Y_r(r_y);
R = [x,y,z];
v_tr = (R-T)./norm(R-T);
d_tr = sqrt(dot(R-T,R-T));
phi = -5 + (5+5)*rand(1);
psi = -5 + (5+5)*rand(1);
H0_LOS(r_x,r_y,i_t) = (m+1)*A_det/(2*pi*d_tr^2)*cosd(phi)^m*cosd(psi);
end
end
end
end
P_r_LOS = P_t.*H0_LOS.*T_s.*G_Con;
P_rec_dBm = 10*log10(P_r_LOS*1000);

Failing to use interpolation instead of integration in chuncks with ODE45

I have written this code to integrate voltage V and gating conductances m, n and h in 30ms with injection of current from ms 10 to 20. So basically Current I is a vector that has 0 values until 10ms, 1 values until 20ms and 0 values until 30ms. The code works well and it shows the behaviour I want to see.
I'm trying to implement the same code with interpolation instead of integration in chunks. However, I'm failing to do so.
This is the integration with interpolation, which is giving the incorrect result:
myode = #(T,y0) [((1/Cm)*interp1(t, I, T, 'linear','extrap')-(INa+IK+Il)); % Normal case
alpham(y0(1,1))*(1-y0(2,1))-betam(y0(1,1))*y0(2,1);
alphan(y0(1,1))*(1-y0(3,1))-betan(y0(1,1))*y0(3,1);
alphah(y0(1,1))*(1-y0(4,1))-betah(y0(1,1))*y0(4,1)];
[time,V] = ode45(myode, t, y0, I);
This is the correct one, in chunks:
[time,V] = ode45(#ODEMAT, [t(chunk), t(chunk+1)], y);
%%% Calls ODEMAT, in which theres' the integration (extensive code posted below):
dydt = [((1/Cm)*(I(chunk)-(INa+IK+Il))); % Normal case
alpham(V)*(1-m)-betam(V)*m;
alphan(V)*(1-n)-betan(V)*n;
alphah(V)*(1-h)-betah(V)*h];
This is the code with the integration in chunks:
function Z2_chunks ()
%% Initial values
V=-60; % Initial Membrane voltage
m1=alpham(V)/(alpham(V)+betam(V)); % Initial m-value
n1=alphan(V)/(alphan(V)+betan(V)); % Initial n-value
h1=alphah(V)/(alphah(V)+betah(V)); % Initial h-value
y0=[V;m1;n1;h1];
t = [1:30];
I = [zeros(1,10),ones(1,10),zeros(1,10)];
% Plotting purposes (set I(idx) equal to last value of I)
idx = numel(t);
I(idx) = 0.1;
chunks = numel(t) - 1;
for chunk = 1:chunks
if chunk == 1
V=-60; % Initial Membrane voltage
m=alpham(V)/(alpham(V)+betam(V)); % Initial m-value
n=alphan(V)/(alphan(V)+betan(V)); % Initial n-value
h=alphah(V)/(alphah(V)+betah(V)); % Initial h-value
y=[V;m;n;h];
else
y = V(end, :); % Final position is initial value for next interval
end
[time,V] = ode45(#ODEMAT, [t(chunk), t(chunk+1)], y);
if chunk == 1
def_time = time;
def_v = V;
else
def_time = [def_time; time];
def_v = [def_v; V];
end
end
OD = def_v(:,1);
ODm = def_v(:,2);
ODn = def_v(:,3);
ODh = def_v(:,4);
time = def_time;
%% Plots
%% Voltage
figure
subplot(3,1,1)
plot(time,OD);
legend('ODE45 solver');
xlabel('Time (ms)');
ylabel('Voltage (mV)');
title('Voltage Change for Hodgkin-Huxley Model');
%% Current
subplot(3,1,2)
stairs(t,I)
ylim([0 5*max(I)])
legend('Current injected')
xlabel('Time (ms)')
ylabel('Ampere')
title('Current')
%% Gating variables
subplot(3,1,3)
plot(time,[ODm,ODn,ODh]);
legend('ODm','ODn','ODh');
xlabel('Time (ms)')
ylabel('Value')
title('Gating variables')
function [dydt] = ODEMAT(t,y)
%% Constants
ENa=55; % mv Na reversal potential
EK=-72; % mv K reversal potential
El=-49; % mv Leakage reversal potential
%% Values of conductances
gbarl=0.003; % mS/cm^2 Leakage conductance
gbarNa=1.2; % mS/cm^2 Na conductance
gbarK=0.36; % mS/cm^2 K conductancence
Cm = 0.01; % Capacitance
% Values set to equal input values
V = y(1);
m = y(2);
n = y(3);
h = y(4);
gNa = gbarNa*m^3*h;
gK = gbarK*n^4;
gL = gbarl;
INa=gNa*(V-ENa);
IK=gK*(V-EK);
Il=gL*(V-El);
dydt = [((1/Cm)*(I(chunk)-(INa+IK+Il))); % Normal case
alpham(V)*(1-m)-betam(V)*m;
alphan(V)*(1-n)-betan(V)*n;
alphah(V)*(1-h)-betah(V)*h];
end
end
This is the code with the integration with interpolation. As you can see, the plots are really different:
function Z1_interpol ()
%% Initial values
V=-60; % Initial Membrane voltage
m1=alpham(V)/(alpham(V)+betam(V)); % Initial m-value
n1=alphan(V)/(alphan(V)+betan(V)); % Initial n-value
h1=alphah(V)/(alphah(V)+betah(V)); % Initial h-value
y0=[V;m1;n1;h1];
t = [1:30];
I = [zeros(1,10),ones(1,10),zeros(1,10)];
% Plotting purposes (set I(idx) equal to last value of I)
idx = numel(t);
I(idx) = 0.1;
V=-60; % Initial Membrane voltage
m=alpham(V)/(alpham(V)+betam(V)); % Initial m-value
n=alphan(V)/(alphan(V)+betan(V)); % Initial n-value
h=alphah(V)/(alphah(V)+betah(V)); % Initial h-value
y=[V;m;n;h];
%% Constants
ENa=55; % mv Na reversal potential
EK=-72; % mv K reversal potential
El=-49; % mv Leakage reversal potential
%% Values of conductances
gbarl=0.003; % mS/cm^2 Leakage conductance
gbarNa=1.2; % mS/cm^2 Na conductance
gbarK=0.36; % mS/cm^2 K conductancence
Cm = 0.01; % Capacitance
%% Initial values
V=-60; % Initial Membrane voltage
m=alpham(V)/(alpham(V)+betam(V)); % Initial m-value
n=alphan(V)/(alphan(V)+betan(V)); % Initial n-value
h=alphah(V)/(alphah(V)+betah(V)); % Initial h-value
y0=[V;m;n;h];
gNa = gbarNa*m^3*h;
gK = gbarK*n^4;
gL = gbarl;
INa=gNa*(V-ENa);
IK=gK*(V-EK);
Il=gL*(V-El);
myode = #(T,y0) [((1/Cm)*interp1(t, I, T, 'linear','extrap')-(INa+IK+Il)); % Normal case
alpham(y0(1,1))*(1-y0(2,1))-betam(y0(1,1))*y0(2,1);
alphan(y0(1,1))*(1-y0(3,1))-betan(y0(1,1))*y0(3,1);
alphah(y0(1,1))*(1-y0(4,1))-betah(y0(1,1))*y0(4,1)];
[time,V] = ode45(myode, t, y0, I);
OD=V(:,1);
ODm=V(:,2);
ODn=V(:,3);
ODh=V(:,4);
time = time;
%% Plots
%% Voltage
figure
subplot(3,1,1)
plot(time,OD);
legend('ODE45 solver');
xlabel('Time (ms)');
ylabel('Voltage (mV)');
title('Voltage Change for Hodgkin-Huxley Model');
%% Current
subplot(3,1,2)
stairs(t,I)
ylim([0 5*max(I)])
legend('Current injected')
xlabel('Time (ms)')
ylabel('Ampere')
title('Current')
%% Gating variables
subplot(3,1,3)
plot(time,[ODm,ODn,ODh]);
legend('ODm','ODn','ODh');
xlabel('Time (ms)')
ylabel('Value')
title('Gating variables')
end

Looping my algorithm to plot for a different parameter value on the same graph(MATLAB)

I've implemented an algorithm for my physics project which does exactly what I want. The problem that I'm stuck which is not the Physics content itself hence I think it might be somewhat trivial to explain what my code does. I'm mainly stuck with the way MATLAB's plotting works if I was to loop over the same algorithm to produce similar graphs with a slight change of a value of my parameter. Here's my code below:
clear; clc; close all;
% Parameters:
z_nn = 4; % Number of nearest-neighbour in lattice (square = 4).
z_nnn = 4; % Number of next-nearest-neighbours in lattice (square = 4).
Lx = 40; % Number of sites along x-axis.
Ly = 40; % Number of sites along y-axis.
sigma = 1; % Size of a site (defines our units of length).
beta = 1.2; % Inverse temperature beta*epsilon.
mu = -2.53; % Chemical potential mu/epsilon.
mu_2 = -2.67; % Chemical potential mu/epsilon for 2nd line.
J = linspace(1, 11, 11);%J points for the line graph plot
potential = zeros(Ly);
attract = 1.6; %wall attraction constant
k = 1; %wall depth
rho_0 = 0.4; % Initial density.
tol = 1e-12; % Convergence tolerance.
count = 30000; % Upper limit for iterations.
alpha = 0.01; % Mixing parameter.
conv = 1; cnt = 1; % Convergence value and counter.
rho = rho_0*ones(Ly); % Initialise rho to the starting guess(i-th rho_old) in Eq(47)
rho_rhs = zeros(Ly); % Initialise rho_new to zeros.
% Solve equations iteratively:
while conv>=tol && cnt<count
cnt = cnt + 1; % Increment counter.
% Loop over all lattice sites:
for j=1:Ly
%Defining the Lennard-Jones potential
if j<k
potential(j) = 1000000000;
else
potential(j) = -attract*(j-k)^(-3);
end
% Handle the periodic boundaries for x and y:
%left = mod((i-1)-1,Lx) + 1; % i-1, maps 0 to Lx.
%right = mod((i+1)-1,Lx) + 1; % i+1, maps Lx+1 to 1.
if j<k+1 %depth of wall
rho_rhs(j) = 0;
rho(j) = 0;
elseif j<(20+k)
rho_rhs(j) = (1 - rho(j))*exp((beta*((3/2)*rho(j-1) + (3/2)*rho(j+1) + 2*rho(j) + mu) - potential(j)));
else
rho_rhs(j) = rho_rhs(j-1);
end
end
conv = sum(sum((rho - rho_rhs).^2)); % Convergence value is the sum of the differences between new and current solution.
rho = alpha*rho_rhs + (1 - alpha)*rho; % Mix the new and current solutions for next iteration.
end
% disp(['conv = ' num2str(conv_2) ' cnt = ' num2str(cnt)]); % Display final answer.
% figure(2);
% pcolor(rho_2);
figure(1);
plot(J, rho(1:11));
hold on;
% plot(J, rho_2(1,1:11));
hold off;
disp(['conv = ' num2str(conv) ' cnt = ' num2str(cnt)]); % Display final answer.
figure(3);
pcolor(rho);
Running this code should give you a graph like this
Now I want to produce a similar graph but with one of the variable's value changed and plotted on the same graph. My approach that I've tried is below:
clear; clc; close all;
% Parameters:
z_nn = 4; % Number of nearest-neighbour in lattice (square = 4).
z_nnn = 4; % Number of next-nearest-neighbours in lattice (square = 4).
Lx = 40; % Number of sites along x-axis.
Ly = 40; % Number of sites along y-axis.
sigma = 1; % Size of a site (defines our units of length).
beta = 1.2; % Inverse temperature beta*epsilon.
mu = [-2.53,-2.67]; % Chemical potential mu/epsilon.
mu_2 = -2.67; % Chemical potential mu/epsilon for 2nd line.
J = linspace(1, 10, 10);%J points for the line graph plot
potential = zeros(Ly, length(mu));
gamma = zeros(Ly, length(mu));
attract = 1.6; %wall attraction constant
k = 1; %wall depth
rho_0 = 0.4; % Initial density.
tol = 1e-12; % Convergence tolerance.
count = 30000; % Upper limit for iterations.
alpha = 0.01; % Mixing parameter.
conv = 1; cnt = 1; % Convergence value and counter.
rho = rho_0*[Ly,length(mu)]; % Initialise rho to the starting guess(i-th rho_old) in Eq(47)
rho_rhs = zeros(Ly,length(mu)); % Initialise rho_new to zeros.
figure(3);
hold on;
% Solve equations iteratively:
while conv>=tol && cnt<count
cnt = cnt + 1; % Increment counter.
% Loop over all lattice sites:
for j=1:Ly
for i=1:length(mu)
y = 1:Ly;
MU = mu(i).*ones(Ly)
%Defining the Lennard-Jones potential
if j<k
potential(j) = 1000000000;
else
potential(j) = -attract*(j-k).^(-3);
end
% Handle the periodic boundaries for x and y:
%left = mod((i-1)-1,Lx) + 1; % i-1, maps 0 to Lx.
%right = mod((i+1)-1,Lx) + 1; % i+1, maps Lx+1 to 1.
if j<k+1 %depth of wall
rho_rhs(j) = 0;
rho(j) = 0;
elseif j<(20+k)
rho_rhs(j) = (1 - rho(j))*exp((beta*((3/2)*rho(j-1) + (3/2)*rho(j+1) + 2*rho(j) + MU - potential(j)));
else
rho_rhs(j) = rho_rhs(j-1);
end
end
end
conv = sum(sum((rho - rho_rhs).^2)); % Convergence value is the sum of the differences between new and current solution.
rho = alpha*rho_rhs + (1 - alpha)*rho; % Mix the new and current solutions for next iteration.
disp(['conv = ' num2str(conv) ' cnt = ' num2str(cnt)]); % Display final answer.
figure(1);
pcolor(rho);
plot(J, rho(1:10));
end
hold off;
The only variable that I'm changing here is mu. I would like to loop my first code so that I can enter an arbitrary amount of different values of mu and plot them on the same graph. Naturally I had to change all of the lists dimension from (1 to size of Ly) to (#of mu(s) to size of Ly), such that when the first code is being looped, the i-th mu value in that loop is being turned into lists with dimension as long as Ly. So I thought I would do the plotting within the loop and use "hold on" encapsulating the whole loop so that every plot that was generated in each loop won't be erased. But I've been spending hours on trying to figure out the semantics of MATLAB but ultimately I can't figure out what to do. So hopefully I can get some help on this!
hold on only applies to the active figure, it is not a generic property shared among all figures. What is does is changing the value of the current figure NextPlot property, which governs the behavior when adding plots to a figure.
hold on is equivalent to set(gcf,'NextPlot','add');
hold off is equivalent to set(gcf,'NextPlot','replace');
In your code you have:
figure(3); % Makes figure 3 the active figure
hold on; % Sets figure 3 'NextPlot' property to 'add'
% Do some things %
while conv>=tol && cnt<count
% Do many things %
figure(1); % Makes figure 1 the active figure; 'hold on' was not applied to that figure
plot(J, rho(1:10)); % plots rho while erasing the previous plot
end
You should try to add another hold on statement after figure(1)
figure(1);
hold on
plot(J, rho(1:10));

Finite difference - wave equation - boundary conditions and setting things up

I am working on a project that has to do with solving the wave equation in 2D (x, y, t) numericaly using the central difference approximation in MATLAB with the following boundary conditions:
The general assembly formula is:
I understand some of the boundary conditions (BC), like
du/dy=0 at j=m,
,
but I am not sure how to implement these boundary conditions in MATLAB.
A friend has given me these equations:
Here is my try with the MATLAB code,
but I am not able to progress any further:
% The wave function
% Explicit
% Universal boundary conditions for all 3 cases:
% u=0 at t=0
% du/dt=0 at t=0
% Case 1 boundary conditions
% At x=0, u=2sin(2*pi*t/5);
% At y=0, du/dy=0;
% At y=2, du/dy=0;
% At x=5, du/dx=0;
% u=0 and du/dt=0 at t=0;
%-------------------------------------------------------------------------%
% Setting up
clc; clear all; close all;
% length, time, height
L = 5; % [m]
h = 2; % [m]
T = 10; % [s]
% Constants
c_x = 1; % arbitrary
c_y = 1; % arbitrary
dx = 0.1; % <x> increment
dy = 0.1; % <y> increment
dt = 0.1; % time increment
nx = L/dx + 1; % number of <x> samples
ny = h/dy + 1; % number of <y> samples
nt = T/dt + 1; % number of time samples
t(:,1) = linspace(0, T, nt);
theta_x = c_x*(dt^2)/(dx^2);
theta_y = c_y*(dt^2)/(dy^2);
% theta_x = theta_y
theta = theta_x;
%-------------------------------------------------------------------------%
% The matrix
U = zeros(nt, nx, ny);
% Setting up the <U> matrix with the boundary conditions - case 1
U(1, :, :) = 0; % U=0 at t=0
for tt=1:nt % U=2sin(2pi/5*t) at x=0
for jj=1:ny
U(tt, 1, jj)=2*sin(2*pi/5.*t(tt));
end
end
for it=2:t
for ix=2:nx-1
for iy=2:ny-1
% Boundary conditions
% General case (internal):
U1 = -U(it-1, ix, iy);
U2 = 2*(1-2*theta)*u(it, ix, iy);
U3 = theta*U(it, ix-1, iy);
U4 = theta*U(it, ix+1, iy);
U5 = theta*U(it, ix, iy-1);
U6 = theta*U(it, ix, iy+1);
end
end
end
The general assembly formula you have kind of applies to the boundaries as well.
The complication is that when you apply the formula when j = 1 and j = m, you have j = 0 and j = m+1 term that are off of your grid.
To ameliorate this problem, boundary conditions give you a relationship between the points off the grid and on the grid.
As you have indicated, the dudy = 0 condition has given you the relation that u(i,m-1) == u(u,m+1) on the boundary. So you use the general assembly formula and replace all of the m+1 terms with m-1 on the boundary. You'll have a similar relation for the lower boundary as well.

binary file write/read operation in Matlab

I am trying to write some 2D coordinates into a binary file. However, what I read from the file that had been writen is quite different from the original data. Details are given here.
For example, I have 45 (X,Y) points. Both X and Y are integral number less than 600. The simulation requires store each of them with two bytes (8 bits) and 2 upper bits of each byte is reserved (for X, the reserved bits are filled by .mrk which is 1 or 2; for Y, simply use 0 instead). In this case, 14 bits binary number is able to represent the maximum, 16383. I write the data in several ways:
in_tmp is structure consisted of points number (.nm), points reserved mark (.mrk) and points coordinates (.coor)
for i=1:in_tmp.nm
x1 = dec2bin(in_tmp.coor(i,1));
y1 = dec2bin(in_tmp.coor(i,2));
t1 = in_tm.mrk(i);
if(t1==1)
t2 = '01';
t2b = 1;
elseif(t1==2)
t2 = '10';
t2b = 2;
end
lenx = 16-length(x1);
leny = 16-length(y1);
x1hl = strcat(t2, '00000000000000'); % High and low
y1hl = '0000000000000000';
x1a = strcat(x1hl(1:lenx), num2str(x1));
y1a = strcat(y1hl(1:leny), num2str(y1));
y1a(1:2) = '00';
% x1b = in_tmp.coor(i,1);
% y1b = in_tmp.coor(i,2);
% fwrite(fp1, t2b, 'ubit2');
% fwrite(fp1, x1b, 'ubit14');
%
% fwrite(fp1, 0, 'ubit2');
% fwrite(fp1, y1b, 'ubit14');
fwrite(fp1, bin2dec(x1a), 'uint16');
fwrite(fp1, bin2dec(y1a), 'uint16');
% fwrite(fp1, bin2dec(x1a(1:8)), 'uint8');
% fwrite(fp1, bin2dec(x1a(9:end)), 'uint8');
% fwrite(fp1, bin2dec(y1a(1:8)), 'uint8');
% fwrite(fp1, bin2dec(y1a(9:end)), 'uint8');
% x1c = in_tmp.coor(i,1);
% y1c = in_tmp.coor(i,2);
%
% x1hex = dec2hex(x1c);
% y1hex = dec2hex(y1c);
% if(length(x1hex)>2)
% x1h = x1hex(1:end-2);
% x1l = x1hex(end-1:end);
% else
% x1h = dec2hex(0);
% x1l = x1hex;
% end
%
% tx1h = dec2bin(hex2dec(x1h));
% l1 = length(tx1h);
% bin0 = dec2bin(128); % '10000000'
% if(t1==1)
% bin0(end-l1+1:end) = tx1h;
% bin0(1)=0;
% bin0(2)=1;
%
% elseif(t1==2)
% bin0(end-l1+1:end) = tx1h;
% end
% x1h = bin2dec(tx1h);
%
% if(length(y1hex)>2)
% y1h = y1hex(1:end-2);
% y1l = y1hex(end-1:end);
% else
% y1h = dec2hex(0);
% y1l = y1hex;
% end
% fwrite(fp1, x1h, 'uint8');
% fwrite(fp1, hex2dec(x1l), 'uint8');
% fwrite(fp1, hex2dec(y1h), 'uint8');
% fwrite(fp1, hex2dec(y1l), 'uint8');
end
The way I read it
for i=1:mt.nm % nm points.
mred(i,6) = fread(fp1, 1, 'uint8'); % Raw X coordinates.
mred(i,7) = fread(fp1, 1, 'uint8'); % upper 2 bits are reserved info.
tmpx = [dec2bin(mred(i,6)), dec2bin(mred(i,7))];
if(length(tmpx)==16)
mred(i,4) = bin2dec(tmpx(1:2)); % Real Mark.
mred(i,1) = bin2dec(tmpx(3:end)); % Real X.
elseif(length(tmpx)==15)
mred(i,4) = bin2dec(tmpx(1)); % Real Type.
mred(i,1) = bin2dec(tmpx(2:end)); % Real X.
else
mred(i,4) = bin2dec(tmpx(1:2)); % Type unknown.
mred(i,1) = bin2dec(tmpx(3:end)); % Real X.
end
mred(i,8) = fread(fp1, 1, 'uint8'); % Y coordinates.
mred(i,9) = fread(fp1, 1, 'uint8'); % upper 2 bits are reserved.
tmpy = [dec2bin(mred(i,8)), dec2bin(mred(i,9))];
if(length(tmpy)==16)
mred(i,10) = bin2dec(tmpy(1:2)); % Real reserved.
mred(i,2) = bin2dec(tmpy(3:end)); % Real Y.
elseif(length(tmpy)==15)
mred(i,10) = bin2dec(tmpy(1)); % Real reserved.
mred(i,2) = bin2dec(tmpy(2:end)); % Real Y.
else
mred(i,10) = -1; % Reserved unknown.
mred(i,2) = bin2dec(tmpy); % Real Y.
end
end
The read() function works well for a given software which is implemented via C++. The software generates coordinates series in such a format. Then, I prepare a read() to get the information in the binary file generated by C++ software. Then, I want to implement the write() with Matlab in that format, but the read() fails to obtain what I had written to the binary file. Anybody help? Thanks.
The problem is probably (at least in part) an endian issue.
On intel architecture (little endian), reading two bytes as uint8 followed by appending the binary representations is not going to give you the same result in general as reading two bytes as uint16.
The following script illustrates how swapping the order of the two uint8's will do the trick.
I changed some variable names and made things more concise for readability.
% declare an input int and the header (in binary string rep)
v = 68;
t2 = '01';
% write to file
x1 = dec2bin(v);
lenx = 16-length(x1);
x1hl = strcat(t2, '00000000000000'); % High and low
x1a = strcat(x1hl(1:lenx), num2str(x1));
% x1a = 0100000001000100
fp1=fopen('temp','w+');
fwrite(fp1, bin2dec(x1a), 'uint16');
% read the file
frewind(fp1);
vtest = fread(fp1, 1, 'uint16'); % upper 2 bits are reserved info.
dec2bin(vtest)
% ans = 100000001000100
% now read *two* bytes as two uint8
frewind(fp1);
byte1 = fread(fp1, 1, 'uint8'); % Raw X coordinates.
byte2 = fread(fp1, 1, 'uint8'); % upper 2 bits are reserved info.
tmpx = [dec2bin(byte2) dec2bin(byte1)]; % <-- swap the order
% tmpx = 10000001000100
Alternately just read the whole 2 bytes as uint16 and work from there.