I like to read in the locations of oil platforms using this file in Matlab. I obtained the file from here. "Platform.gen" looks like this:
Id Lat Lon
1 0.100000000000000D+02 0.890000000000000D+02
2 -0.941577040000000D+02 0.294488400000000D+02
3 -0.941241560000000D+02 0.292748680000000D+02
4 -0.941225830000000D+02 0.292251370000000D+02
5 -0.943647730000000D+02 0.292845940000000D+02
I read it into Matlab using:
[id lat
lon]=textread('platform.gen','%s %s
%s');
However, I am lost on how to decode the lat/lon values...help?
I would suggest instead using the conversion specifier %f to read the values. This will automatically handle the format for the double-precision floating point numbers. The character D is just another way to display scientific notation, so 0.10D+02 is 10 in double precision:
>> [id,lat,lon] = textread('platform.gen','%u %f %f','headerlines',1)
id =
1
2
3
4
5
lat =
10.0000
-94.1577
-94.1242
-94.1226
-94.3648
lon =
89.0000
29.4488
29.2749
29.2251
29.2846
Also, the function TEXTREAD will be removed in a future MATLAB version in favor of TEXTSCAN, which you could use like so:
>> fid = fopen('platform.gen','r');
>> data = textscan(fid,'%f %f %f','HeaderLines',1,'CollectOutput',true);
>> fclose(fid);
>> data{1}
ans =
1.0000 10.0000 89.0000
2.0000 -94.1577 29.4488
3.0000 -94.1242 29.2749
4.0000 -94.1226 29.2251
5.0000 -94.3648 29.2846
Related
I am using Matlab's backslash operator to solve a system of equations written as two matrices M1 and M2. These two matrices are square and tridiagonal, and so I have defined them as sparse. For example, with the dimensions of each being 5x5, they are defined as follows, with the values in each entry being dependent on some constant a:
N = 5;
a = 1e10;
M1 = spdiags([-a*ones(N,1)... % Sub diagonal
(1 + 2*a)*ones(N,1)... % Main Diagonal
-a*ones(N,1)],... % Super diagonal
-1:1,N,N);
M2 = spdiags([+a*ones(N,1)...
(1 - 2*a)*ones(N,1)...
+a*ones(N,1)],...
-1:1,N,N);
M_out = M1\M2;
So for example, M1 looks like the following in full form:
>> full(M1)
ans =
1.0e+10 *
2.0000 -1.0000 0 0 0
-1.0000 2.0000 -1.0000 0 0
0 -1.0000 2.0000 -1.0000 0
0 0 -1.0000 2.0000 -1.0000
0 0 0 -1.0000 2.0000
Now, if I examine the number of non-zero entries in the result M_out, then I can see they are all non-zero, which is fine:
>> nnz(M_out)
ans =
25
The problem is that I also need to do this for larger values of the constant a. However, if, for example, a=1e16 instead, then the off-diagonal entries of M_out are automatically set to zero, presumably because they have become too small:
>> nnz(M_out)
ans =
5
Is there a better way in Matlab of going about this problem of inverting sparse matrices? Or am I using the backslash operator in the wrong way?
If the size of your matrices doesn't grow too much, I recommend doing a full symbolic computation:
N = 5;
syms a
M1 = diag(-a*ones(N-1,1),-1) + diag((1 + 2*a)*ones(N,1),0) + diag(-a*ones(N-1,1),+1);
M2 = diag(+a*ones(N-1,1),-1) + diag((1 - 2*a)*ones(N,1),0) + diag(+a*ones(N-1,1),+1);
M_out = M1\M2;
M_num_1e10 = subs(M_out,a,1e10);
M_num_1e16 = subs(M_out,a,1e16);
vpa(M_num_1e10)
vpa(M_num_1e16)
In that case, you will need the Symbolic Math Toolbox. If you don't have it, I think you should considerer migrating to Python and work with SymPy.
EDIT:
Considering the way you defined your problem, you need extended precision for your computations. The double precision isn't enough. For example, in double precision (1e16+1) has to be rounded to (1e16), in other words (1e16+1)-(1e16) is equal to zero. So your problem starts in the main diagonal of your matrices. MATLAB only provides extended precision through its symbolic toolbox.
If you want to stick with double precision, you may extend the double precision yourself relying on the so called double-double arithmetic. I say that you will have to do it by yourself because I don't think there is a open source double-double library for MATLAB.
I need to exclude some error data from matrix. I know what data is correct and i am trying to interpolate values between so I can get decent diagrams with not so big errors. I must use that form of matrix and I must preserve its shape. I must only substitute some data that is marked as errors. I will show you my work so far:
M=[0.1000
0.6000
0.7000
0.8000
0.9000
0.9500
1.0000
1.0500
1.1000
1.1500
1.2000
1.2500
1.3000
1.5000
1.7500
2.0000
2.2500
2.5000
3.0000];
CZ1=[ 9.4290
9.5000
9.3250
9.2700
9.2950
9.4350
9.6840
10.0690
10.1840
10.2220
10.2160
9.6160
9.6890
9.4880
9.5000
9.5340
9.3370
9.0990
8.5950];
N1=11;
Nn=13;
Mx1=M(N1);
Mx2=M(Nn);
Mx=[Mx1 Mx2]';
CN1=CZ1(N1);
CN2=CZ1(Nn);
CNy=[C1 C2]';
y1=interp1q(Mx,CNy,M(N1:Nn));
CNf=CZ1;
NEWRangeC=y1;
Cfa=changem(CZ1,[NEWRangeC], [CNf(N1:Nn)]);
figure
plot(M,Cf,'-*b',M,Cfa,'r')
So far as you can see I used points 11 and 13 and i excluded point 12 interpolating that point from 11 to 13. This is working but i want to make a modification.
My question is: How can I select values that are errors and remove them but interpolate space between their neighbors. I want to use a M matrix values as my reference (not points as my example).
Assuming you know which elements are incorrect, you can use Matlab's interp1 function to interpolate them (this will only work if the M matrix is actually a vector`:
error_indices = [11 13];
all_indices = 1:length(M)
% Get the indices where we have valid data
all_correct_indices = setdiff(all_indices, error_indices)
% the first two arguments are the available data.
% the third arguments is what indices you are looking for
M_new = interp1(all_correct_indices, M(all_correct_indices), all_indices)
The above interpolates values at all_indices -- including the missing elements. Where you already have valid data (all_correct_indices), Matlab will return that data. In other places, it will interpolate using the two nearest neighbors.
Try help interp1 for more information on how this function works.
Update - an example
x = 1:10; % all indices
y = x*10;
e = 3:7; % the unknown indices
s = setdiff(x, e); % the known indices
y_est = interp1(s, y(s), x)
ans =
10 20 30 40 50 60 70 80 90 100
And we see that interp1 had interpolated all values from 30 to 70 linearly using the available data (specifically the adjacent points 20 and 80).
Well, you can start out by finding the elements that are errors, with the find command (this will return the indices). This should also work for matrices.
You can then grab the elements around each of the indices, and interpolate between, as you did.
Given two vectors containing numerical values, say for example
a=1.:0.1:2.;
b=a+0.1;
I would like to select only the differing values. For this Matlab provides the function setdiff. In the above example it is obvious that setdiff(a,b) should return 1. and setdiff(b,a) gives 2.1. However, due to computational precision (see the questions here or here) the result differs. I get
>> setdiff(a,b)
ans =
1.0000 1.2000 1.4000 1.7000 1.9000
Matlab provides a function which returns a lower limit to this precision error, eps. This allows us to estimate a tolerance like tol = 100*eps;
My question now, is there an intelligent and efficient way to select only those values whose difference is below tol? Or said differently: How do I write my own version of setdiff, returning both values and indexes, which includes a tolerance limit?
I don't like the way it is answered in this question, since matlab already provides part of the required functionality.
Introduction and custom function
In a general case with floating point precision issues, one would be advised to use a tolerance value for comparisons against suspected zero values and that tolerance must be a very small value. A little robust method would use a tolerance that uses eps in it. Now, since MATLAB basically performs subtractions with setdiff, you can use eps directly here by comparing for lesser than or equal to it to find zeros.
This forms the basis of a modified setdiff for floating point numbers shown here -
function [C,IA] = setdiff_fp(A,B)
%//SETDIFF_FP Set difference for floating point numbers.
%// C = SETDIFF_FP(A,B) for vectors A and B, returns the values in A that
%// are not in B with no repetitions. C will be sorted.
%//
%// [C,IA] = SETDIFF_FP(A,B) also returns an index vector IA such that
%// C = A(IA). If there are repeated values in A that are not in B, then
%// the index of the first occurrence of each repeated value is returned.
%// Get 2D matrix of absolute difference between each element of A against
%// each element of B
abs_diff_mat = abs(bsxfun(#minus,A,B.')); %//'
%// Compare each element against eps to "negate" the floating point
%// precision issues. Thus, we have a binary array of true comparisons.
abs_diff_mat_epscmp = abs_diff_mat<=eps;
%// Find indices of A that are exclusive to it
A_ind = ~any(abs_diff_mat_epscmp,1);
%// Get unique(to account for no repetitions and being sorted) exclusive
%// A elements for the final output alongwith the indices
[C,IA] = intersect(A,unique(A(A_ind)));
return;
Example runs
Case1 (With integers)
This will verify that setdiff_fp works with integer arrays just the way setdiff does.
A = [2 5];
B = [9 8 8 1 2 1 1 5];
[C_setdiff,IA_setdiff] = setdiff(B,A)
[C_setdiff_fp,IA_setdiff_fp] = setdiff_fp(B,A)
Output
A =
2 5
B =
9 8 8 1 2 1 1 5
C_setdiff =
1 8 9
IA_setdiff =
4
2
1
C_setdiff_fp =
1 8 9
IA_setdiff_fp =
4
2
1
Case2 (With floating point numbers)
This is to show that setdiff_fp produces the correct results, while setdiff doesn't. Additionally, this will also test out the output indices.
A=1.:0.1:1.5
B=[A+0.1 5.5 5.5 2.6]
[C_setdiff,IA_setdiff] = setdiff(B,A)
[C_setdiff_fp,IA_setdiff_fp] = setdiff_fp(B,A)
Output
A =
1.0000 1.1000 1.2000 1.3000 1.4000 1.5000
B =
1.1000 1.2000 1.3000 1.4000 1.5000 1.6000 5.5000 5.5000 2.6000
C_setdiff =
1.2000 1.4000 1.6000 2.6000 5.5000
IA_setdiff =
2
4
6
9
7
C_setdiff_fp =
1.6000 2.6000 5.5000
IA_setdiff_fp =
6
9
7
For Tolerance of 1 epsilon This should work:
a=1.0:0.1:2.0;
b=a+0.1;
b=[b b-eps b+eps];
c=setdiff(a,b)
The idea is to expand b to include also its closest values.
I have an input file which has rows of integers like this:
1 2 3
4 5 6
7 8 9
I want to read in the file, I have used the textscan function for this kind of task before.
But there are a few lines in the data (at random positions) which contain double numbers, for example
<large number of integer lines>
0.12 12.44 65.34
<large number of integer lines>
When reading in the file, I want to ignore these lines. What's the best approach to do this? Can I tell textscan to ignore certain patterns?
The formatSpec argument could be the one you're searching for:
http://www.mathworks.de/de/help/matlab/ref/textscan.html#inputarg_formatSpec
It terminates the reading, if the content does not match the given format. If you call textscan a second time with the same file, it has to start reading where it last terminated.
From linked site:
If you resume a text scan of a file by calling textscan with the same
file identifier (fileID), then textscan automatically resumes reading
at the point where it terminated the last read.
One option is to simply just read everything in as floats - use either textscan or if your data is all numeric dlmread or similar might be simpler.
Then just remove the lines you don't want:
data =
1.0000 2.0000 3.0000
4.0000 5.0000 6.0000
0.1200 12.4400 65.3400
7.0000 8.0000 9.0000
data(data(:,1)~=round(data(:,1)),:)=[]
data =
1 2 3
4 5 6
7 8 9
If your later code requires that the type of your data matrix is non-float, use uint8 or similar to convert at this point.
Assuming that you don't know the location and number of the lines with floats, and that you don't want lines such as 1.0 2.0 3.0 or 1 2 3.0 my idea would be to read the file line by line and not store lines which contain a . character.
fid = fopen('file.txt');
nums = [];
line = fgetl(fid);
while line ~= -1 % #read until end of file
if isempty(strfind(line, '.'))
line = textscan(line, '%d %d %d');
nums = [nums; line{:}];
end
line = fgetl(fid);
end
fclose(fid);
nums is the matrix containing your data.
I want to read COMPLEX data present in a txt file into 1D array in MATLAB. I'm novice in MATLAB. Please help me out.
Excuse me for the ambiguous question. Sincere Apologies..
Actually I have a .txt file containing strings that represents complex numbers(Single line in .txt file represents ) for eg:
1+3i
i
-1-i
.
.
.
So on...
I want to read the same in 1 * N Matrix (where N represents number of complex numbers in .txt file) in MATLAB. How I may do so?
I assume you mean you have a text file with two columns, the real and imaginary parts. In which case, you can do this:
>> type cplx.txt % real and imaginary parts are two columns
1 2
3 4
5 6
>> rawData = dlmread('cplx.txt')
rawData =
1 2
3 4
5 6
>> complexData = complex(rawData(:, 1), rawData(:, 2))
complexData =
1.0000 + 2.0000i
3.0000 + 4.0000i
5.0000 + 6.0000i
EDIT
Ok, with that file format, you should be able to use TEXTSCAN.
>> type cplx2.txt
1+3i
1i
2
4-4i
>> fid = fopen('cplx2.txt', 'rt');
>> x = textscan(fid, '%f');
>> fclose(fid);
>> x{1}
ans =
1.000000000000000 + 3.000000000000000i
0.000000000000000 + 1.000000000000000i
2.000000000000000 + 0.000000000000000i
4.000000000000000 - 4.000000000000000i
Note that TEXTSCAN can't handle a line that consists of 'i' on its own. Which is a shame.