I have a function that interpolates between two values on a logarithmic scale, so as to have more values around the lower end of my values.
public void logspace(double lower, double upper, double amount) {
double start = Math.log(Math.min(lower, upper));
double end = Math.log(Math.max(lower, upper));
double step = (end - start) / amount;
for(double level = start; level <= end; level += step) {
System.out.println(Math.exp(level));
}
}
However I do not know how to correctly handle if one of the values is 0. If one of the values if 0 then we end up with -Infinity as one of our boundaries, which produces unexpected results.
I can't simply use 0 in place of log(0) as this would result in 0 values between 0 and 1, as log(1) is 0.
How can I produce logarithmically spaced values between two arbitrary values?
You can use two different formulas depending on whether your value is above or below some arbitrary cutoff. With a little care those two formulas will have the same value at the cutoff point.
For example, we'll assume your data doesn't have any interesting values below 1.0. If we use the log scale for everything above 1.0, the lowest output will be 0.0. Then for everything below 1.0, we switch to a linear scale.
public double logscale(double value) {
if (value > 1.0)
return Math.log(value);
else
return value - 1.0;
}
You can improve the linear portion of the formula by using a multiplier to set the slope of the curve from that point.
It's also possible to use something other than linear below the inflection point, but I'll leave that as an exercise for the reader.
Related
My post is related to the following questions:
Avoid division by zero between matrices in MATLAB
How to stop MATLAB from rounding extremely small values to 0?
I am writing a matlab function that I am exporting with codegen. When codegen executes division between two numbers, both primitive doubles, codegen mentions that the result is a type of :Inf x :Inf. Here is my code snip:
travel_distance = stop_position - start_position;
duration = stop_time - start_time;
velocity = (travel_distance / duration);
Neither travel_distance or duration variables are zero. During codegen, when I examine the variables of travel_distance and duration, they are both :Inf x 1. However, velocity is showing as :Inf x :Inf . This is being shown also for the (travel_distance / duration) block of code. I suspect that I am running into the scenario mentioned by the author in the second link, which mentions this quote:
MATLAB will not change the value to 0. However, it is possible that the result if using the value in an operation is indistinguishable from using 0
I've tried several things to try and solve my problem, and am still getting the same thing. For example:
% increment by a small number
velocity = ((travel_distance + 0.0001) / (duration + 0.0001));
% check if nan, and set to 0
velocity(isnan(velocity)) = 0;
% check if nan or inf and set to 0
if (isnan(velocity) || isinf(velocity))
velocity = 0;
end
I'd actually expect that the travel_distance, duration, and velocity are all of type 1x1, since I know these should be primitive results.
What can I do to ensure matlab performs codegen correctly, by allowing the velocity variable to be either an :Inf x 1 or a 1x1? ( Double or Int output is fine )
I don't think this is related to division by zero, as shown by the attempts you made at avoiding that. :Inf x 1 refers to a vector of unknown length, and :Inf x :Inf to a matrix of unknown size. If duration is a vector, then travel_distance / duration is trying to solve a system of linear equations.
If you use ./ (element-wise division) instead of /, then Codegen might be able to generate the right code:
velocity = travel_distance ./ duration;
I've declared a function that will be used to calculate the convolution of an image using an arbitrary 3x3 kernel. I also created a script that will prompt the user to select both an image as well as enter the convolution kernel of their choice. However, I do not know how to go about dealing with negative pixel values that will arise for various kernels. How would I implement a condition into my script that will deal with these negative values?
This is my function:
function y = convul(x,m,H,W)
y=zeros(H,W);
for i=2:(H-1)
for j=2:(W-1)
Z1=(x(i-1,j-1))*(m(1,1));
Z2=(x(i-1,j))*(m(1,2));
Z3=(x(i-1,j+1))*(m(1,3));
Z4=(x(i,j-1))*(m(2,1));
Z5=(x(i,j))*(m(2,2));
Z6=(x(i,j+1))*(m(2,3));
Z7=(x(i+1,j-1))*(m(3,1));
Z8=(x(i+1,j))*(m(3,2));
Z9=(x(i+1,j+1))*(m(3,3));
y(i,j)=Z1+Z2+Z3+Z4+Z5+Z6+Z7+Z8+Z9;
end
end
And this is the script that I've written that prompts the user to enter an image and select a kernel of their choice:
[file,path]=uigetfile('*.bmp');
x = imread(fullfile(path,file));
x_info=imfinfo(fullfile(path,file));
W=x_info.Width;
H=x_info.Height;
L=x_info.NumColormapEntries;
prompt='Enter a convulation kernel m: ';
m=input(prompt)/9;
y=convul(x,m,H,W);
imshow(y,[0,(L-1)]);
I've tried to use the absolute value of the convolution, as well as attempting to locate negatives in the output image, but nothing worked.
This is the original image:
This is the image I get when I use the kernel [-1 -1 -1;-1 9 -1; -1 -1 -1]:
I don't know what I'm doing wrong.
MATLAB is rather unique in how it handles operations between different data types. If x is uint8 (as it likely is in this case), and m is double (as it likely is in this case), then this operation:
Z1=(x(i-1,j-1))*(m(1,1));
returns a uint8 value, not a double. Arithmetic in MATLAB always takes the type of the non-double argument. (And you cannot do arithmetic between two different types unless one of them is double.)
MATLAB does integer arithmetic with saturation. That means that uint8(5) * -1 gives 0, not -5, because uint8 cannot represent a negative value.
So all your Z1..Z9 are uint8 values, negative results have been set to 0. Now you add all of these, again with saturation, leading to a value of at most 255. This value is assigned to the output (a double). So it looks like you are doing your computations correctly and outputting a double array, but you are still clamping your result in an odd way.
A Correct implementation would cast each of the values of x to double before multiplying by a potentially negative number. For example:
for i = 2:H-1
for j = 2:W-1
s = 0;
s = s + double(x(i-1,j-1))*m(1,1);
s = s + double(x(i-1,j))*m(1,2);
s = s + double(x(i-1,j+1))*m(1,3);
s = s + double(x(i,j-1))*m(2,1);
s = s + double(x(i,j))*m(2,2);
s = s + double(x(i,j+1))*m(2,3);
s = s + double(x(i+1,j-1))*m(3,1);
s = s + double(x(i+1,j))*m(3,2);
s = s + double(x(i+1,j+1))*m(3,3);
y(i,j) = s;
end
end
(Note that I removed your use of 9 different variables, I think this is cleaner, and I also removed a lot of your unnecessary brackets!)
A simpler implementation would be:
for i = 2:H-1
for j = 2:W-1
s = double(x(i-1:i+1,j-1:j+1)) .* m;
y(i,j) = sum(s(:));
end
end
First, the data:
orig = reshape([0.0000000000000000 0.3480000000000000 0.7570000000000000 1.3009999999999999 2.8300000000000001 4.7519999999999998 5.2660000000000000 5.8120000000000003 14.3360000000000000 15.3390000000000000 ],[10 1])
change = reshape([0.0000000000000000 0.3480000000000000 0.0000000000000000 0.9530000000000000 1.5290000000000001 1.9219999999999997 0.5140000000000002 0.5460000000000003 0.0000000000000000 9.5270000000000010 ],[10 1])
change = cumsum(change)
orig is a vector of seconds elapsed. change is a vector derived by taking differences between (some) elements of orig. The cumulative sum of change has some elements actually equal to the corresponding element in orig.
However, due to precision issues:
diff = orig - change
gives
diff =
0
0
0.409
0
0
0
0
0
8.524
-1.77635683940025e-15
It seems that if I run the following command:
diff(abs(diff) <= eps(orig)) = 0
then this sets entries which should be zero, but are not due to precision issues, to be zero.
My question is, is this the correct way to do it? Why is the comparison <= instead of <? Should the statement be:
diff(abs(diff) < k*eps(orig)) = 0
for some k > 1 to give some tolerance? If so, how would one pick k?
In case it is necessary to know how change is derived from orig, the following alternate example also shows this behaviour:
orig = reshape([0.0000000000000000 0.3480000000000000 0.7570000000000000 1.3009999999999999 2.8300000000000001 4.7519999999999998 5.2660000000000000 5.8120000000000003 14.3360000000000000 15.3390000000000000 ],[10 1])
change = orig - [0; orig(1:end-1)]
change = cumsum(change)
diff = orig - change
The following statement will be true only if the "almost zero" happens because 1 bit is offseted.
abs(diff) <= eps(orig)
1 bit is a ridiculously high precision to ask, a precision that most likely you can not achieve. Generally, you need to define your treshold yourself, such as
abs(diff) <= 1e-12
You also ask how to choose this value. Answer: there is no way we can tell you that. Its algorithm, application, unit, computer, [...] specific.
You are computing distance between particles? Maybe you need a smaller tolerance. You are doing economic profit calculus? 1e-12 is then a decimal you won't get in cash, for sure. Use 1e-4 instead. Or are you using an algorithm that does numerical approximations? Then you need a higher tolerance. How much tolerance you are OK with is, and will always be, a user choice.
Note: you need to be aware of the types you are using to set this minimum threshold right. MATLAB uses double as default, but if you are using other types, them this threshold is too strict. As an alternative, you can use
abs(diff) <= 100*eps(class(diff))
If your data type is not fixed/known.
I want to compare two double values. I know the value of MinimumValue, which is 3.5261e+04. This MinimumValue I got from an array e. My code has to print first statement 'recognized face' because both value are same. But my code is displaying second statement 'unrecognized face'.
What is the mistake in my code?
MinimumValue = min(e)
theta = 3.5261e+04;
if (MinimumValue <= theta)
fprintf('recognized face\n');
else
fprintf('unrecognized face\n');
end
There are two approaches:
Replace if MinimumValue<=theta with if MinimumValue == theta. This is the easier but probably poorer approach for your problem.
Chances are, MinimumValue is different from theta by a very small amount. If you are doing some calculations by hand to determine that theta = 3.5261e+04, and believe there are more decimal places, you should use format long to determine the actual value of theta to 15 significant figures. After that, you can use if abs(MinimumValue - theta) <= eps (edit: As patrick has noted in the comment below, you should compare to some user-defined tolerance or eps instead of realmin('double').
I have a homework problem, I think I did it correctly but need to make sure 100%. Can anyone check for me, before I hand it in?
Thank you.
Question:
Plot the function given by f (x) = 2 sin(2x) − 3 cos(x/2) over the in-
terval [0, 2π] using steps of length .001 (How?). Use the commands max and min to estimate the maximum and minimum points. Include the maximum and minimum points as tick marks on the x-axis and the maximum and minimum values as tick marks on the y-axis.
My code:
x=linspace(0,2*pi,6280);
f=#(x)...
2.*sin(2.*x)-3.*cos(x./2);
%f = #(x)2.*sin(2.*x)-3.*cos(x./2)
g=#(x)...
-1*(2.*sin(2.*x)-3.*cos(x./2));
%g = #(x)-1*(2.*sin(2.*x)-3.*cos(x./2))
[x3,y5]=fminbnd(g,0,2*pi);
%x3 = 4.0968
%y3 = -3.2647
[x2,y4]=fminbnd(f,0,2*pi);
%x2 =2.1864
%y2 = -3.2647
y2=max(f(x));
y3=min(f(x));
plot(x,f(x));
set(gca,'XTick',[x2 x3]);
set(gca,'YTick',[y2 y3]);
(*after I paste this code here, it appeared not as nice as I had it in my program, don't know why)
To create a vector with certain step do
x=0:0.001:2*pi;
Why do you have g(x) function and why are you using fminbind? Use MIN and MAX, return index of those values and find related x values.
[ymin, minindex] = min(f(x));
xmin = x(minindex);
For general case if you have multiple min/max values, index will contain only the first occurrence. Instead you can do:
minindex = find(y==ymin);
Or for real values to avoid precision error:
minindex = find(abs(y-ymin)<=eps);
Also your last statement returns error Values must be monotonically increasing. To avoid it sort your tick values.
set(gca,'XTick',sort([xmin xmax]));
set(gca,'YTick',sort([ymin ymax]));