Thinning algorithm in Octave, index error - octave

I'm trying to code the Zhang Suen thinning algorithm using Octave. I'm not used at using Octave and I corrected many errors already, but there is this error: imgSeuil(0,_): subscripts must be either integers 1 to (2^63)-1 or logicals which explains that i'm trying to access a pixel of the image using incorrect index, but I didn't find how to correct it. The mistake is probably obvious, I just need a fresh look at it. Here is some code:
clear all;
close all;
img=imread("ED_3_6_originale.png");
imshow(img);
colorbar();
sizeImg = size(img);
NL=sizeImg(1,1);
NC=sizeImg(1,2);
tab=zeros(2,256); %grey lvl table
tab(1,1:256)=0:255;
%Grey level table and
%chart printing
for y=1:NL
for x= 1:NC
val=img(y,x);
tab(2,val+1)=tab(2,val+1)+1;
end
end
ticktab=zeros(1,25);
for i=1:25
ticktab(1, i)=10*i;
end
figure(2);
plot(tab(1, 1:256),tab(2, 1:256));
set(gca,'XTick',ticktab(1, 1:25));
xlim([0, 255]);
%seuillage de l'img
figure(3);
imgSeuil=img;
for y=1:NL
for x= 1:NC
val=imgSeuil(y,x);
if(val<30)
imgSeuil(y,x)=0;
else
imgSeuil(y,x)=255;
end
end
end
imgSeuil=~imgSeuil;%inversion pour lignes blanches
imshow(imgSeuil);
%%%--------------
%%stopCond=1;
%%while stopCond = 1
ap1 = 0;
bp1 = 0;
tabPixel = zeros(2,1);
for x=2:NL-1
for y= 2:NC-1
p1 = imgSeuil(x,y);
p2 = imgSeuil(x-1, y);
p3 = imgSeuil(x-1, y+1);
p4 = imgSeuil(x, y+1);
p5 = imgSeuil(x+1, y+1);
p6 = imgSeuil(x+1, y);
p7 = imgSeuil(x+1, y-1);
p8 = imgSeuil(x, y-1);
p9 = imgSeuil(x-1, y-1);
tabNeighbour = [p2, p3, p4, p5, p6, p7, p8, p9];
tmpTabl = diff([tabNeighbour, p2]);
tmpTabl = max(tmpTabl, 0);
ap1 = sum(tmpTabl);
bp1 = sum(tabNeighbour);
## disp(bp1);
if((p1==0)&&(bp1>=2)&&(bp1<=6)&&(ap1==1)&&
((p2==1)||(p4==1)||(p6==1))&&
((p4==1)||(p6==1)||(p8==1)))
tabPixel = [tabPixel, [x; y]];
endif
endfor
endfor
## disp(tabPixel);
for i=1:columns(tabPixel)
%%---------Error occurs on the next line ------%%
imgSeuil(tabPixel(1, i), tabPixel(2, i)) = 255;
endfor
%%endwhile
The first step begins after %%%-----, I didn't include the second because it's almost the same.
The first lines are basically just printing the original picture, use a threshold to make it binary instead of grey scale.

For i = 1 in your last loop, you're indexing imgSeuil(tabPixel(1, 1), tabPixel(2, 1)), which evaluates to imgSeuil(0, 0), which is indeed impossible to index. You'll need to change how you define it. Judging your code, either initialising as tabPixel = [], i.e. empty, or letting your final for loop run from i = 2 (or even removing the first column of tabPixel after your nested for loop), will all do the trick.

Related

Can't save data using push button (MATLAB)

I'm trying to create a figure where the user can select cells to turn on or off. Then, the user can click a button 'Enter' to save the board as an array. I successfully found a way to create interactivity in my plot thanks to a very useful explanation I found here. I just made some changes to suit my needs.
However, I can't find a way to save the board. The button is working (or at least isn't not working), but the data isn't saved. And I don't know how to fix that. Any help would be appreciated.
Here is my code:
function CreatePattern
hFigure = figure;
hAxes = axes;
axis equal;
axis off;
hold on;
% create a button to calculate the difference between 2 points
h = uicontrol('Position',[215 5 150 30],'String','Enter','Callback', #SaveArray);
function SaveArray(ButtonH, eventdata)
global initial
initial = Board;
close(hFigure)
end
N = 1; % for line width
M = 20; % board size
squareEdgeSize = 1;
% create the board of patch objects
hPatchObjects = zeros(M,M);
for j = M:-1:1
for k = 1:M
hPatchObjects(M - j+ 1, k) = rectangle('Position', [k*squareEdgeSize,j*squareEdgeSize,squareEdgeSize,squareEdgeSize], 'FaceColor', [0 0 0],...
'EdgeColor', 'w', 'LineWidth', N, 'HitTest', 'on', 'ButtonDownFcn', {#OnPatchPressedCallback, M - j+ 1, k});
end
end
%global Board
Board = zeros(M,M);
playerColours = [1 1 1; 0 0 0];
xlim([squareEdgeSize M*squareEdgeSize]);
ylim([squareEdgeSize M*squareEdgeSize]);
function OnPatchPressedCallback(hObject, eventdata, rowIndex, colIndex)
% change FaceColor to player colour
value = Board(rowIndex,colIndex);
if value == 1
set(hObject, 'FaceColor', playerColours(2, :));
Board(rowIndex,colIndex) = 0; % update board
else
set(hObject, 'FaceColor', playerColours(1, :));
Board(rowIndex,colIndex) = 1; % update board
end
end
end
%imwrite(~pattern,'custom_pattern.jpeg')

Interp1 function in ODE45

I am trying to solve a 3 Degree Of Freedom vessel-crane system in MATLAB using ode45. In my ode function, the vessel motion is determined by simple spring and damper constants, but the device below the main hoist system, a cranemaster, has a displacement-dependent stiffness and thus depends on one of the Degrees Of Freedom. To determine this value, I use the interp1 function to determine the stiffness from a dataset:
vq = interp1(x,v,xq,method,extrapolation)
This all works fine, but only when I add the extrapolation option in the interp1 function, even though the xq values all fall inside the dataset x-values. If I do not specify extrapolation, the function returns NAN.
I have checked if the stiffness values in the dataset make sense by taking the median value as a constant value and then the ode45 solver works just fine and the displacement never falls outside of the dataset. I have also noticed that if I switch to ode23 as a solver, it also works. This all makes me believe it has something to do with the solving method and the stepsize the ode solver takes as its initial value.
I have provided (a simplified version of) my code and a picture of the system to get a feel for the problem. I know that switching to ode23 solves the problem but I would like to understand why and, if possible, stay with ode45 as it is a more general solver.
Any help would be appreciated!
Regards,
Diederik
Overview of the system I am solving
close all
tspan = [0 100];
x0 = [0.0; 0; 0.0; 0; 0.0; 0]; % initial disp. and vel. is 0. for all 3 DOF.
% x = [z; zdot; theta; thetadot; u; udot]
[t,x] = ode45(#Three_DOF,tspan,x0);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Plots
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
figure()
subplot(2,1,1)
plot(t,x(:,5),'color','b','LineWidth',1)
grid on
xlabel('Time (s)')
ylabel('Displacement (m)')
title('Displacement Vs Time')
subplot(2,1,2)
plot(t,x(:,6),'color','#D95319','LineWidth',1)
grid on
xlabel('Time (s)')
ylabel('Velocity (m/s)')
title('Velocity Vs Time')
function [dxdt] = Three_DOF(t,x)
% vessel parameters
m = 570.5e6;
m55 = 4.591e12;
mh = 200e3;
c33 = 3.83952e8;
c55 = 3.66116e12;
wnh = 0.360;
wnp = 0.596;
a33 = (c33-wnh^2*m)/wnh^2;
a55 = (c55-wnp^2*m55)/wnp^2;
zeta33 = 0.386;
zeta55 = 0.121;
b33 = zeta33*2*sqrt(c33*(m+a33));
b55 = zeta55*2*sqrt(c55*(m55+a55));
Fa = 153e6;
Ma = 3.013e9;
w1 = 0.21/0.36;
w2 = 0.18/0.28;
%%%% Cable parameters
k_c = 496e6;
b_c = 5.01e6;
%%% CRANEMASTER parameters
x_data = [-2.0; -1.87; -1.73; -1.60; -1.47; -1.33; -1.20; -1.07; -0.93; -0.8; -0.67; -0.53; -0.4; -0.27; -0.13; 0.0; 0.13; 0.27; 0.40; 0.53; 0.67; 0.80; 0.93; 1.07; 1.20; 1.33; 1.47; 1.60; 1.73; 1.87; 2.0];
k_data = [760; 792.1; 784.8; 813.9; 828.4; 850.2; 879.3; 901.1; 922.9; 959.2; 981.0; 1010.1; 1039.1; 1068.2; 1104.5; 1133.6; 1177.2; 1206.3; 1242.6; 1286.2; 1329.8; 1373.4; 1409.7; 1460.6; 1511.5; 1562.3; 1620.5; 1671.3; 1729.5; 1794.9; 1853];
k_cm = 30000*interp1(x_data,k_data,x(5));%,'linear','extrap');
%k_cm = 30000*1133.61; % middle value of dataset k_data
b_cm = 6e4;
l = 217.5;
% Matrices & solve
Mass = [m+a33 0 0; 0 m55+a55 0; 0 0 mh];
k = [c33+k_c -k_c*l -k_c; -k_c*l c55+k_c*l^2 k_c*l; -k_c k_c*l k_c+k_cm];
b = [b33+b_c -b_c*l -b_c; -b_c*l b55+b_c*l^2 b_c*l; -b_c b_c*l b_c+b_cm];
F = [Fa*sin(w1*t); Ma*sin(w2*t); 0];
EOM = Mass\(F-b*([x(2); x(4); x(6)])-k*([x(1); x(3); x(5)]));
dxdt = [x(2); EOM(1); x(4); EOM(2); x(6); EOM(3)];
% x = [z; zdot; theta; thetadot; u; udot]
end

Dimension problem when converting a MATLAB .m script into an Octave compatible syntax

I want to run a MATLAB script M-file to reconstruct a point cloud in Octave. Therefore I had to rewrite some parts of the code to make it compatible with Octave. Actually the M-file works fine in Octave (I don't get any errors) and also the plotted point cloud looks good at first glance, but it seems that the variables are only half the size of the original MATLAB variables. In the attached screenshots you can see what I mean.
Octave:
MATLAB:
You can see that the dimension of e.g. M in Octave is 1311114x3 but in MATLAB it is 2622227x3. The actual number of rows in my raw file is 2622227 as well.
Here you can see an extract of the raw file (original data) that I use.
Rotation angle Measured distance
-0,090 26,295
-0,342 26,294
-0,594 26,294
-0,846 26,295
-1,098 26,294
-1,368 26,296
-1,620 26,296
-1,872 26,296
In MATLAB I created my output variable as follows.
data = table;
data.Rotationangle = cell2mat(raw(:, 1));
data.Measureddistance = cell2mat(raw(:, 2));
As there is no table function in Octave I wrote
data = cellfun(#(x)str2num(x), strrep(raw, ',', '.'))
instead.
Octave also has no struct2array function, so I had to replace it as well.
In MATLAB I wrote.
data = table2array(data);
In Octave this was a bit more difficult to do. I had to create a struct2array function, which I did by means of this bug report.
%% Create a struct2array function
function retval = struct2array (input_struct)
%input check
if (~isstruct (input_struct) || (nargin ~= 1))
print_usage;
endif
%convert to cell array and flatten/concatenate output.
retval = [ (struct2cell (input_struct)){:}];
endfunction
clear b;
b.a = data;
data = struct2array(b);
Did I make a mistake somewhere and could someone help me to solve this problem?
edit:
Here's the part of my script where I'm using raw.
delimiter = '\t';
startRow = 5;
formatSpec = '%s%s%[^\n\r]';
fileID = fopen(filename,'r');
dataArray = textscan(fileID, formatSpec, 'Delimiter', delimiter, 'HeaderLines' ,startRow-1, 'ReturnOnError', false, 'EndOfLine', '\r\n');
fclose(fileID);
%% Convert the contents of columns containing numeric text to numbers.
% Replace non-numeric text with NaN.
raw = repmat({''},length(dataArray{1}),length(dataArray)-1);
for col=1:length(dataArray)-1
raw(1:length(dataArray{col}),col) = mat2cell(dataArray{col}, ones(length(dataArray{col}), 1));
end
numericData = NaN(size(dataArray{1},1),size(dataArray,2));
for col=[1,2]
% Converts text in the input cell array to numbers. Replaced non-numeric
% text with NaN.
rawData = dataArray{col};
for row=1:size(rawData, 1)
% Create a regular expression to detect and remove non-numeric prefixes and
% suffixes.
regexstr = '(?<prefix>.*?)(?<numbers>([-]*(\d+[\.]*)+[\,]{0,1}\d*[eEdD]{0,1}[-+]*\d*[i]{0,1})|([-]*(\d+[\.]*)*[\,]{1,1}\d+[eEdD]{0,1}[-+]*\d*[i]{0,1}))(?<suffix>.*)';
try
result = regexp(rawData(row), regexstr, 'names');
numbers = result.numbers;
% Detected commas in non-thousand locations.
invalidThousandsSeparator = false;
if numbers.contains('.')
thousandsRegExp = '^\d+?(\.\d{3})*\,{0,1}\d*$';
if isempty(regexp(numbers, thousandsRegExp, 'once'))
numbers = NaN;
invalidThousandsSeparator = true;
end
end
% Convert numeric text to numbers.
if ~invalidThousandsSeparator
numbers = strrep(numbers, '.', '');
numbers = strrep(numbers, ',', '.');
numbers = textscan(char(numbers), '%f');
numericData(row, col) = numbers{1};
raw{row, col} = numbers{1};
end
catch
raw{row, col} = rawData{row};
end
end
end
You don't see any raw in my workspaces because I clear all temporary variables before I reconstruct my point cloud.
Also my original data in row 1311114 and 1311115 look normal.
edit 2:
As suggested here is a small example table to clarify what I want and what MATLAB does with the table2array function in my case.
data =
-0.0900 26.2950
-0.3420 26.2940
-0.5940 26.2940
-0.8460 26.2950
-1.0980 26.2940
-1.3680 26.2960
-1.6200 26.2960
-1.8720 26.2960
With the struct2array function I used in Octave I get the following array.
data =
-0.090000 26.295000
-0.594000 26.294000
-1.098000 26.294000
-1.620000 26.296000
-2.124000 26.295000
-2.646000 26.293000
-3.150000 26.294000
-3.654000 26.294000
If you compare the Octave array with my original data, you can see that every second row is skipped. This seems to be the reason for 1311114 instead of 2622227 rows.
edit 3:
I tried to solve my problem with the suggestions of #Tasos Papastylianou, which unfortunately was not successful.
First I did the variant with a struct.
data = struct();
data.Rotationangle = [raw(:,1)];
data.Measureddistance = [raw(:,2)];
data = cell2mat( struct2cell (data ).' )
But this leads to the following structure in my script. (Unfortunately the result is not what I would like to have as shown in edit 2. Don't be surprised, I only used a small part of my raw file to accelerate the run of my script, so here are only 769 lines.)
[766,1] = -357,966
[767,1] = -358,506
[768,1] = -359,010
[769,1] = -359,514
[1,2] = 26,295
[2,2] = 26,294
[3,2] = 26,294
[4,2] = 26,296
Furthermore I get the following error.
error: unary operator '-' not implemented for 'cell' operands
error: called from
Cloud_reconstruction at line 137 column 11
Also the approach with the dataframe octave package didn't work. When I run the following code it leads to the error you can see below.
dataframe2array = #(df) cell2mat( struct(df).x_data );
pkg load dataframe;
data = dataframe();
data.Rotationangle = [raw(:, 1)];
data.Measureddistance = [raw(:, 2)];
dataframe2array(data)
error:
warning: Trying to overwrite colum names
warning: called from
df_matassign at line 147 column 13
subsasgn at line 172 column 14
Cloud_reconstruction at line 106 column 20
warning: Trying to overwrite colum names
warning: called from
df_matassign at line 176 column 13
subsasgn at line 172 column 14
Cloud_reconstruction at line 106 column 20
warning: Trying to overwrite colum names
warning: called from
df_matassign at line 147 column 13
subsasgn at line 172 column 14
Cloud_reconstruction at line 107 column 23
warning: Trying to overwrite colum names
warning: called from
df_matassign at line 176 column 13
subsasgn at line 172 column 14
Cloud_reconstruction at line 107 column 23
error: RHS(_,2): but RHS has size 768x1
error: called from
df_matassign at line 179 column 11
subsasgn at line 172 column 14
Cloud_reconstruction at line 107 column 23
Both error messages refer to the following part of my script where I'm doing the reconstruction of the point cloud in cylindrical coordinates.
distLaserCenter = 47; % Distance between the pipe centerline and the blind zone in mm
m = size(data,1); % Find the length of the first dimension of data
zincr = 0.4/360; % z increment in mm per deg
data(:,1) = -data(:,1);
for i = 1:m
data(i,2) = data(i,2) + distLaserCenter;
if i == 1
data(i,3) = 0;
elseif abs(data(i,1)-data(i-1)) < 100
data(i,3) = data(i-1,3) + zincr*(data(i,1)-data(i-1));
else abs(data(i,1)-data(i-1)) > 100;
data(i,3) = data(i-1,3) + zincr*(data(i,1)-(data(i-1)-360));
end
end
To give some background information for a better understanding. The script is used to reconstruct a pipe as a point cloud. The surface of the pipe was scanned from inside with a laser and the laser measured several points (distance from laser to the inner wall of the pipe) at each deg of rotation. I hope this helps to understand what I want to do with my script.
Not sure exactly what you're trying to do, but here's a toy example of how a struct could be used in an equivalent manner to a table:
matlab:
data = table;
data.A = [1;2;3;4;5];
data.B = [10;20;30;40;50];
table2array(data)
octave:
data = struct();
data.A = [1;2;3;4;5];
data.B = [10;20;30;40;50];
cell2mat( struct2cell (data ).' )
Note the transposition operation (.') before passing the result to cell2mat, since in a table, the 'fieldnames' are arranged horizontally in columns, whereas the struct2cell ends up arranging what used to be the 'fieldnames' as rows.
You might also be interested in the dataframe octave package, which performs similar functions to matlab's table (or in fact, R's dataframe object): https://octave.sourceforge.io/dataframe/ (you can install this by typing pkg install -forge dataframe in your console)
Unfortunately, the way to display the data as an array is still not ideal (see: https://stackoverflow.com/a/55417141/4183191), but you can easily convert that into a tiny function, e.g.
dataframe2array = #(df) cell2mat( struct(df).x_data );
Your code can then become:
pkg load dataframe;
data = dataframe();
data.A = [1;2;3;4;5];
data.B = [10;20;30;40;50];
dataframe2array(data)

How to handle outliers in this octave boxplot for improved readability

Outliers between 1,5 - 3 times the interquantile range is marked with an "+" and above 3 times the IQR with an "o". But due to this data set with multiple outliers the below boxplot is very hard to read since the "+" and "o" symbols are plotted on top of each other creating what appears to be a thick red line.
I need to plot all data so removing them is not an option but I would be fine to display "longer" boxes, i.e. stretch the q1 and q4 to reach the true min/max values and skip the "+" and "o" outlier symbols. I would also be fine if just the min and max outliers was displayed.
I'm totally in the dark here and the octave boxplot documentation found here did not include any helpful examples on how to handle outliers. A search here at stackoverflow didn't get me closer to a solution either. So any help or directions is very appreciated!
How can I modify the below code to create a boxplot based on the same data set that is readable (i.e. doesn't plot outliers on top of each other creating a thick red line)?
I'm using Octave 4.2.1 64-bits on a Windows 10 machine with qt as the graphics_toolkit and with GDAL_TRANSLATE called from within Octave to handle the tif-files.
It's not an option to switch graphics_toolkit to gnuplot etc. since I haven't been able to "rotate" the plot (horizontal boxes instead of vertical). And it's in the .pdf file the results must have an effect, not only in octaves viewer.
Please forgive my totally "newbie-style" coding-work-around to get a proper high resolution pdf-exported:
pkg load statistics
clear all;
fns = glob ("*.tif");
for k=1:numel (fns)
ofn = tmpnam;
cmd = sprintf ('gdal_translate -of aaigrid "%s" "%s"', fns{k}, ofn);
[s, out] = system (cmd);
if (s != 0)
error ('calling gdal_translate failed with "%s"', out);
endif
fid = fopen (ofn, "r");
# read 6 headerlines
hdr = [];
for i=1:6
s = strsplit (fgetl (fid), " ");
hdr.(s{1}) = str2double (s{2});
endfor
d = dlmread (fid);
# check size against header
assert (size (d), [hdr.nrows hdr.ncols])
# set nodata to NA
d (d == hdr.NODATA_value) = NA;
raw{k} = d;
# create copy with existing values
raw_v{k} = d(! isna (d));
fclose (fid);
endfor
## generate plot
boxplot (raw_v)
set (gca, "xtick", 1:numel(fns),
"xticklabel", strrep (fns, ".tif", ""));
ylabel ("Plats kvar (meter)");
set (gca, "ytick", 0:50:600);
set (gca, "ygrid", "on");
set (gca, "gridlinestyle", "--");
set (gcf, "paperunit", "centimeters", "papersize", [35, 60], "paperposition", [0 0 60 30], "paperorientation", "landscape")
zoom (0.95)
view ([90 90])
print ("loudden_box_dotted.pdf", "-F:14")
I would just delete the outliers. This is easy because the handles are returned. I've also included some caching algorithm so you don't have to reload all tifs if you are playing with plots. Splitting the conversion, processing and plotting in different scripts is always a good idea (but not for stackoverflow where minimalistic examples are prefered). Here we go:
pkg load statistics
cache_fn = "input.raw";
# only process tif if not already done
if (! exist (cache_fn, "file"))
fns = glob ("*.tif");
for k=1:numel (fns)
ofn = tmpnam;
cmd = sprintf ('gdal_translate -of aaigrid "%s" "%s"', fns{k}, ofn);
printf ("calling '%s'...\n", cmd);
fflush (stdout);
[s, out] = system (cmd);
if (s != 0)
error ('calling gdal_translate failed with "%s"', out);
endif
fid = fopen (ofn, "r");
# read 6 headerlines
hdr = [];
for i=1:6
s = strsplit (fgetl (fid), " ");
hdr.(s{1}) = str2double (s{2});
endfor
d = dlmread (fid);
# check size against header
assert (size (d), [hdr.nrows hdr.ncols])
# set nodata to NA
d (d == hdr.NODATA_value) = NA;
raw{k} = d;
# create copy with existing values
raw_v{k} = d(! isna (d));
fclose (fid);
endfor
# save result
save (cache_fn, "raw_v", "fns");
else
load (cache_fn)
endif
## generate plot
[s, h] = boxplot (raw_v);
## in h you'll find now box, whisker, median, outliers and outliers2
## delete them
delete (h.outliers)
delete (h.outliers2)
set (gca, "xtick", 1:numel(fns),
"xticklabel", strrep (fns, ".tif", ""));
ylabel ("Plats kvar (meter)");
set (gca, "ytick", 0:50:600);
set (gca, "ygrid", "on");
set (gca, "gridlinestyle", "--");
set (gcf, "paperunit", "centimeters", "papersize", [35, 60], "paperposition", [0 0 60 30], "paperorientation", "landscape")
zoom (0.95)
view ([90 90])
print ("loudden_box_dotted.pdf", "-F:14")
gives

Plotting a function in matlab involving an integral

I'm trying to plot a function that contains a definite integral. My code uses all anonymous functions. When I run the file, it gives me an error. My code is below:
%%% List of Parameters %%%
gamma_sp = 1;
cap_gamma = 15;
gamma_ph = 0;
omega_0 = -750;
d_omega_0 = 400;
omega_inh = 100;
d_omega_inh = 1000;
%%% Formulae %%%
gamma_t = gamma_sp/2 + cap_gamma/2 + gamma_ph;
G = #(x) exp(-(x-omega_inh).^2./(2*d_omega_inh.^2))./(sqrt(2*pi)*d_omega_inh);
F = #(x) exp(-(x-omega_0).^2./(2*d_omega_0.^2))./(sqrt(2*pi)*d_omega_0);
A_integral = #(x,y) G(x)./(y - x + 1i*gamma_t);
Q_integral = #(x,y) F(x)./(y - x + 1i*gamma_t);
A = #(y) integral(#(x)A_integral(x,y),-1000,1000);
Q = #(y) integral(#(x)Q_integral(x,y),-3000,0);
P1 = #(y) -1./(1i.*(gamma_sp + cap_gamma)).*(1./(y + 2.*1i.*gamma_t)*(A(y)-conj(A(0)))-1./y.*(A(y)-A(0))+cap_gamma./gamma_sp.*Q(y).*(A(0)-conj(A(0))));
P2 = #(y) conj(P1(y));
P = #(y) P1(y) - P2(y);
sig = #(y) abs(P(y)).^2;
rng = -2000:0.05:1000;
plot(rng,sig(rng))
It seems to me that when the program runs the plot command, it should put each value of rng into sig(y), and that value will be used as the y value in A_integral and Q_integral. However, matlab throws an error when I try to run the program.
Error using -
Matrix dimensions must agree.
Error in #(x,y)G(x)./(y-x+1i*gamma_t)
Error in #(x)A_integral(x,y)
Error in integralCalc/iterateScalarValued (line 314)
fx = FUN(t);
Error in integralCalc/vadapt (line 133)
[q,errbnd] = iterateScalarValued(u,tinterval,pathlen);
Error in integralCalc (line 76)
[q,errbnd] = vadapt(#AtoBInvTransform,interval);
Error in integral (line 89)
Q = integralCalc(fun,a,b,opstruct);
Error in #(y)integral(#(x)A_integral(x,y),-1000,1000)
Error in
#(y)-1./(1i.*(gamma_sp+cap_gamma)).*(1./(y+2.*1i.*gamma_t)*(A(y)-conj(A(0)))-1. /y.*(A(y)-A(0))+cap_gamma./gamma_sp.*Q(y).*(A(0)-conj(A(0))))
Error in #(y)P1(y)-P2(y)
Error in #(y)abs(P(y)).^2
Error in fwm_spec_diff_paper_eqn (line 26)
plot(rng,sig(rng))
Any ideas about what I'm doing wrong?
You have
>> rng = -2000:0.05:1000;
>> numel(rng)
ans =
60001
all 60001 elements get passed down to
A = #(y) integral(#(x)A_integral(x,y),-1000,1000);
which calls
A_integral = #(x,y) G(x)./(y - x + 1i*gamma_t);
(similar for Q). The thing is, integral is an adaptive quadrature method, meaning (roughly) that the amount of x's it will insert into A_integral varies with how A_integral behaves at certain x.
Therefore, the amount of elements in y will generally be different from the elements in x in the call to A_integral. This is why y-x +1i*gamma_t fails.
Considering the complexity of what you're trying to do, I think it is best to re-define all anonymous functions as proper functions, and integrate a few of them into single functions. Look into the documentation of bsxfun to see if that can help (e.g., bsxfun(#minus, y.', x) instead of y-x could perhaps fix a few of these issues), otherwise, vectorize only in x and loop over y.
Thanks Rody, that made sense to me. I keep trying to use matlab like mathematica and I forget how matlab does things. I modified the code a bit, and it produces the right result. The integrals are evaluated very roughly, but it should be easy to fix that. I've posted my modified code below.
%%% List of Parameters %%%
gamma_sp = 1;
cap_gamma = 15;
gamma_ph = 0;
omega_0 = -750;
d_omega_0 = 400;
omega_inh = 100;
d_omega_inh = 1000;
%%% Formulae %%%
gamma_t = gamma_sp/2 + cap_gamma/2 + gamma_ph;
G = #(x) exp(-(x-omega_inh).^2./(2*d_omega_inh.^2))./(sqrt(2*pi)*d_omega_inh);
F = #(x) exp(-(x-omega_0).^2./(2*d_omega_0.^2))./(sqrt(2*pi)*d_omega_0);
A_integral = #(x,y) G(x)./(y - x + 1i*gamma_t);
Q_integral = #(x,y) F(x)./(y - x + 1i*gamma_t);
w = -2000:0.05:1000;
sigplot = zeros(size(w));
P1plot = zeros(size(w));
P2plot = zeros(size(w));
Pplot = zeros(size(w));
aInt_range = -1000:0.1:1200;
qInt_range = -2000:0.1:100;
A_0 = sum(A_integral(aInt_range,0).*0.1);
for k=1:size(w,2)
P1plot(k) = -1./(1i*(gamma_sp + cap_gamma)).*(1./(w(k)+2.*1i.*gamma_t).*(sum(A_integral(aInt_range,w(k)).*0.1)-conj(A_0))-1./w(k).*(sum(A_integral(aInt_range,w(k)).*0.1)-A_0)+cap_gamma./gamma_sp.*sum(Q_integral(qInt_range,w(k)).*0.1).*(A_0-conj(A_0)));
P2plot(k) = conj(P1plot(k));
Pplot(k) = P1plot(k) - P2plot(k);
sigplot(k) = abs(Pplot(k)).^2;
end
plot(w,sigplot)