MATLAB find row and column index of closest to specified value - matlab

I have latitude LAT, longitude LON and windspeed from a netCDF file.
I want to find the windspeed at a given LAT,LON coordinate %Location of Met Mast 51.94341,1.922094888. I am trying to find the nearest value to RefLAT and RefLONin the LAT and LON matrices respectively. When I have the nearest values in LAT and LON I will then use the addresses to locate my windspeed at this location.
When I use the code below, I expect a single value for each of the column and row values CLON, CLAT, RLAT and RLON. Instead I get CLON, CLAT, RLAT and RLON as arrays of 972 values, the matrices I am searching LAT and LON are size 848 x 972.
LAT = ncread('wind_level2.nc','latitude');
LON = ncread('wind_level2.nc','longitude');
wind = ncread('wind_level2.nc','wind');
LAT = double(LAT);
LON =double(LON);
%Location of Met Mast 51.94341,1.922094888
RefLAT=51.94341;
LATcalc = abs(LAT - RefLAT);
[RLAT,CLAT]=find(min(LATcalc));
RefLON=1.922094888;
LONcalc = abs(LON - RefLON);
[RLON,CLON]=find(min(LONcalc));`
Any help appreciated. Thanks
Data sample as requested:
LAT: 848x972 double:
51.6652641296387 51.6608505249023 51.6564369201660 51.6520233154297 51.6476097106934 51.6431961059570 51.6387825012207
51.6663322448731 51.6619186401367 51.6575050354004 51.6530914306641 51.6486778259277 51.6442642211914 51.6398506164551
51.6674041748047 51.6629867553711 51.6585731506348 51.6541595458984 51.6497459411621 51.6453323364258 51.6409187316895
51.6684722900391 51.6640548706055 51.6596412658691 51.6552276611328 51.6508140563965 51.6464004516602 51.6419868469238
51.6695404052734 51.6651229858398 51.6607093811035 51.6562957763672 51.6518821716309 51.6474685668945 51.6430549621582
51.6706047058106 51.6661911010742 51.6617774963379 51.6573638916016 51.6529502868652 51.6485366821289 51.6441192626953
51.6716728210449 51.6672592163086 51.6628456115723 51.6584320068359 51.6540145874023 51.6496009826660 51.6451873779297
51.6727409362793 51.6683235168457 51.6639099121094 51.6594963073731 51.6550827026367 51.6506690979004 51.6462554931641
51.6738052368164 51.6693916320801 51.6649780273438 51.6605644226074 51.6561470031738 51.6517333984375 51.6473197937012
51.6748695373535 51.6704559326172 51.6660423278809 51.6616287231445 51.6572151184082 51.6528015136719 51.6483840942383
51.6759376525879 51.6715240478516 51.6671066284180 51.6626930236816 51.6582794189453 51.6538658142090 51.6494522094727
LON 848x972 double:
3.04663085937500 3.04491543769836 3.04320049285889 3.04148554801941 3.03977084159851 3.03805613517761 3.03634166717529
3.03959774971008 3.03788304328918 3.03616857528687 3.03445434570313 3.03274011611938 3.03102612495422 3.02931237220764
3.03256440162659 3.03085041046143 3.02913665771484 3.02742290496826 3.02570939064026 3.02399611473084 3.02228283882141
3.02553081512451 3.02381753921509 3.02210426330566 3.02039122581482 3.01867818832397 3.01696562767029 3.01525306701660
3.01849699020386 3.01678419113159 3.01507163047791 3.01335930824280 3.01164698600769 3.00993490219116 3.00822281837463
3.01146292686462 3.00975084304810 3.00803875923157 3.00632715225220 3.00461530685425 3.00290393829346 3.00119256973267
3.00442862510681 3.00271701812744 3.00100588798523 2.99929451942444 2.99758362770081 2.99587273597717 2.99416208267212
2.99739408493042 2.99568319320679 2.99397253990173 2.99226188659668 2.99055147171021 2.98884129524231 2.98713135719299
2.99035930633545 2.98864889144897 2.98693895339966 2.98522901535034 2.98351931571960 2.98180961608887 2.98010015487671
2.98332428932190 2.98161458969116 2.97990512847900 2.97819590568543 2.97648668289185 2.97477769851685 2.97306895256043

As noted by #excaza, your syntax of find is not appropriate in your case. Without any comparison operator, find assumes a logical comparison and will return a vector containing the indices of all non-zero elements. That is not what you want.
Try the following :
[RLAT,CLAT]=find(LATcalc<eps);
where eps is an error tolerance, for instance 0.00001.
You can't give find a perfect equality because the figure you are seeking may be not present in the matrix. With abs(LAT - RefLAT), you will have a matrix of difference between two values. As before, you may not have a perfect zero so you find the closest result to zero by an error tolerance low enough to be sure to catch the minimum.

Related

Different ST_Distance calculation with degrees and metres in PostGIS

I have noticed that sometimes the results from ST_Distance for geometry types do not correspond correctly to those for geography types.
For example:
SELECT ST_Distance('SRID=4326;MULTIPOLYGON(((13.1654379639367 48.0163296656575,
13.1654405823308 48.0163326202901,13.1654809135407 48.0163781648167,
13.1655095556032 48.0164104945946,13.1656825124596 48.0166031792699,
13.1658285825017 48.0167559797112,13.1658385904811 48.0167667179682,
13.1660097634653 48.0169315381006,13.1661737540995 48.0170911295992,
13.166336100685 48.0172329598378,13.1677079127931 48.0150783894135,
13.1677278111466 48.0150450062427,13.1670716137939 48.0148839705059,
13.1667911667995 48.0148062288149,13.1665512255895 48.0147411405409,
13.1665145733757 48.0147311909654,13.1654379639367 48.0163296656575)))'::geometry,
'SRID=4326;POINT(16.096346 47.2786129)'::geometry);
returns 3.0197908442784636 as a result in degrees.
But, when computing the distance of the same shapes in metres:
SELECT ST_Distance(gg1,gg2) from (select 'SRID=4326;MULTIPOLYGON(((13.1654379639367 48.0163296656575,
13.1654405823308 48.0163326202901,13.1654809135407 48.0163781648167,13.1655095556032 48.0164104945946,
13.1656825124596 48.0166031792699,13.1658285825017 48.0167559797112,13.1658385904811 48.0167667179682,
13.1660097634653 48.0169315381006,13.1661737540995 48.0170911295992,13.166336100685 48.0172329598378,
13.1677079127931 48.0150783894135,13.1677278111466 48.0150450062427,13.1670716137939 48.0148839705059,
13.1667911667995 48.0148062288149,13.1665512255895 48.0147411405409,13.1665145733757 48.0147311909654,
13.1654379639367 48.0163296656575)))'::geography as gg1,
'SRID=4326;POINT(16.096346 47.2786129)'::geography as gg2) as foo;
it returns 0 metres. This can't be right. By looking the shapes in wkt playground the distance is indeed much more than 0 metres.
Any idea of what I could be doing wrong?
Thank you!

Find value in vector "p" that corresponds to maximum value in vector "r = f(p)"

As simple as in title. I have nx1 sized vector p. I'm interested in the maximum value of r = p/foo - floor(p/foo), with foo being a scalar, so I just call:
max_value = max(p/foo-floor(p/foo))
How can I get which value of p gave out max_value?
I thought about calling:
[max_value, max_index] = max(p/foo-floor(p/foo))
but soon I realised that max_index is pretty useless. I'm sorry asking this, real beginner here.
Having dropped the issue to pieces, I realized there's no unique corrispondence between values p and values in my related vector p/foo-floor(p/foo), so there's a logical issue rather than a language one.
However, given my input data, I know that the solution is unique. How can I fix this?
I ended up doing:
result = p(p/foo-floor(p/foo) == max(p/foo-floor(p/foo)))
Looks terrible, so if you know any other way...
Once you have the index, use it:
result = p(max_index)
You can create a new vector with your lets say "transformed" values:
p2 = (p/foo-floor(p/foo))
and then just use find to find the max values on p2:
max_index = find(p2 == max(p2))
that will return the index or indices of p2 with the max value of that operation, and finally just lookup the original value in p
p(max_index)
in 1 line, this is:
p(find((p/foo-floor(p/foo) == max((p/foo-floor(p/foo))))))
which is basically the same thing you did in the end :)

find value in a string of cell considering some margin

Suppose that I have a string of values corresponding to the height of a group of people
height_str ={'1.76000000000000';
'1.55000000000000';
'1.61000000000000';
'1.71000000000000';
'1.74000000000000';
'1.79000000000000';
'1.74000000000000';
'1.86000000000000';
'1.72000000000000';
'1.82000000000000';
'1.72000000000000';
'1.63000000000000'}
and a single height value.
height_val = 177;
I would like to find the indices of the people that are in the range height_val +- 3cm.
To find the exact match I would do like this
[idx_height,~]=find(ismember(cell2mat(height_str),height_val/100));
How can I include the matches in the previous range (174-180)?
idx_height should be = [1 5 6 7]
You can convert you strings into an numeric array (as #Divakar mentioned) by
height = str2num(char(height_str))*100; % in cm
Then just
idx_height = find(height>=height_val-3 & height<=height_val+3);
Assuming that the precision of heights stays at 0.01cm, you can use a combination of str2double and ismember for a one-liner -
idx_height = find(ismember(str2double(height_str)*100,[height_val-3:height_val+3]))
The magic with str2double is that it works directly with cell arrays to get us a numeric array without resorting to a combined effort of converting that cell array to a char array and then to a numeric array.
After the use of str2double, we can use ismember as you tried in your problem to get us the matches as a logical array, whose indices are picked up with find. That's the whole story really.
Late addition, but for binning my first choice would be to go with bsxfun and logical operations:
idx_height = find(bsxfun(#le,str2double(height_str)*100,height_val+3) & ...
bsxfun(#ge,str2double(height_str)*100,height_val-3))

Generalised Birthday Calculation Given Hash Length

Let us assume that we are given the following:
The length of the hash
The chance of obtaining a collision
Now, knowing the above, how can we obtain the number of "samples" needed to obtain the given chance percentage?
When we take the Simplified formula for the birthday paradox we get:
probability = k^2/2N
So:
sqr(probability*2*n) = k
Where we know that n = 2^lenghtHash
A small test:
Hash = 16 bit : N= 65536
probability = 50% = 0.5
sqr(0.5*2*65536) = 256 samples
This is not 100% correct as we started of with the Simplified formula, but for big hashes and lager sample sets it gets very close.
for a link on the formula you can look here.
here is a little javascript function to calculate the chance, based on the "Simplified Approximations" algorithm from https://preshing.com/20110504/hash-collision-probabilities/ (thanks for the link #Frank ) to calculate the chance of collision, and using the Decimal.js bignum library to manage bigger numbers than Javascript's Number can handle, example:
samples=2**64; //
hash_size_bytes=20; // 160 bit hash
number_of_possible_hashes=Decimal("2").pow(8*hash_size_bytes);
console.log(collision_chance(samples,number_of_possible_hashes));
// ~ 0.00000001 % chance of a collision with 2**64 samples and 20-byte-long hashes.
samples=77163;
hash_size_bytes=4; // 32bit hash
number_of_possible_hashes=Decimal("2").pow(8*hash_size_bytes);
console.log(collision_chance(samples,number_of_possible_hashes));
// ~ 49.999% chance of a collision for a 4-byte hash with 77163 samples.
function:
// with https://github.com/MikeMcl/decimal.js/blob/master/decimal.min.js
function collision_chance(samples,number_of_possible_hashes){
var Decimal100 = Decimal.clone({ precision: 100, rounding: 8 });
var k=Decimal100(samples);
var N=Decimal100(number_of_possible_hashes);
var MinusK=Decimal100(samples);
MinusK.s=-1;
var ret=((MinusK.mul(k.sub(1))).div(N.mul(2))).exp();
ret=ret.mul(100);
ret=Decimal100(100).sub(ret);
return ret.toFixed(100);
}

IDL and MatLab getting strange values from NetCDF file

I have a NetCDF file, which contains data representing total precipitation across the globe over several months (so it's stored in a three dimensional array). I first ensured that the data was sensible, and the way it was formed, both in XConv and ncdump. All looks sensible - values vary from very small (~10^-10 - this makes sense, as this is model data, and effectively represents zero) to about 5x10^-3.
The problems start when I try to handle this data in IDL or MatLab. The arrays generated in these programs are full of huge negative numbers such as -4x10^4, with occasional huge positive numbers, such as 5000. Strangely, looking at a plot of the data in MatLab with respect to latitude and longitude (at a specific time), the pattern of rainfall looks sensible, but the values are just completely wrong.
In IDL, I'm reading the file in to write it to a text file so it can be handled by some software that takes very basic text files. Here's the code I'm using:
PRO nao_heaps
address = '/Users/levyadmin/Downloads/'
file_base = 'output'
ncid = ncdf_open(address + file_base + '.nc')
MONTHS=['january','february','march','april','may','june','july','august','september','october','november','december']
varid_field = ncdf_varid(ncid, "tp")
varid_lon = ncdf_varid(ncid, "longitude")
varid_lat = ncdf_varid(ncid, "latitude")
varid_time = ncdf_varid(ncid, "time")
ncdf_varget,ncid, varid_field, total_precip
ncdf_varget,ncid, varid_lat, lats
ncdf_varget,ncid, varid_lon, lons
ncdf_varget,ncid, varid_time, time
ncdf_close,ncid
lats = reform(lats)
lons = reform(lons)
time = reform(time)
total_precip = reform(total_precip)
total_precip = total_precip*1000. ;put in mm
noLats=(size(lats))(1)
noLons=(size(lons))(1)
noMonths=(size(time))(1)
; the data may not be an integer number of years (otherwise we could make this next loop cleaner)
av_precip=fltarr(noLons,noLats,12)
for month=0, 11 do begin
year = 0
while ( (year*12) + month lt noMonths ) do begin
av_precip(*,*,month) = av_precip(*,*,month) + total_precip(*,*, (year*12)+month )
year++
endwhile
av_precip(*,*,month) = av_precip(*,*,month)/year
endfor
fname = address + file_base + '.dat'
OPENW,1,fname
PRINTF,1,'longitude'
PRINTF,1,lons
PRINTF,1,'latitude'
PRINTF,1,lats
for month=0,11 do begin
PRINTF,1,MONTHS(month)
PRINTF,1,av_precip(*,*,month)
endfor
CLOSE,1
END
Anyone have any ideas why I'm getting such strange values in MatLab and IDL?!
AH! Found the answer. NetCDF files use an offset, and a scale factor for the data to keep the size of the file to a minimum. To get the correct values, I simply need to:
total_precip = offset + (scale_factor * total_precip) ;put into correct range
At present I'm getting the scale factor and offset from ncdump, and hard coding them into my IDL program, but does anyone know how I can get them dynamically in my IDL code..?