Time from sun's position and observer's location - matlab

I have satellite imagery with the latitude, longitude, and position of the sun (azimuth, zenith, and elevation), but no time-stamp.
Short of using an astronomy almanac, is there a way to calculate the time from the sun's position and image location?
I've seen Matlab scripts and ArcGIS tools that do the reverse of this, i.e. they calculate the sun's position based on the lat, lon, and time of the observer, but I'm missing the "time" variable in this case and would like to find it for all of the images.

Here's one (slightly rough) method, as the position calculators I've seen don't seem particularly easy to reverse-engineer for "time given a known date".
I took an existing sun position calculator, Sun Position from the file exchange. I then wrote two wrapper functions to this function to output info in a slightly more useful format for searching:
sun_hour → calculates hourly (zero minute) positions across a given date.
sun_min → given a date and hour, calculates minutely positions one hour either side of thate date/hour.
Since the original function is quick, both of these take fractions of a second even on my not particularly good computer.
Then, I wrote a quick time location function along the following lines, using measured azimuth alone (along with time/location inputs giving the date and position in the formats required by sun_position).
time.min = 0;
% find list of azimuths, find closest match
[azlist, zlist, hours] = sun_hour(time, location);
n = find(abs(azlist-azimuth)==min(abs(azlist-azimuth)));
time.hour = hours(n);
% ditto, but around the time found at previous step
[azlist, zlist, hours, minutes] = sun_min(time, location);
n = find(abs(azlist-azimuth)==min(abs(azlist-azimuth)));
% output time
time.hour = hours(n);
time.min = minutes(n);
I haven't thoroughly tested it but it seems to work fine for a rough estimate (of course, assuming the accuracy of the original position calculator is good). I'm assuming that you don't need any more accuracy than minutely (unless you're managing to measure the position very accurately). You will need to be careful about how whichever calculator you end up using handles time-zones, whether the output is local time or not, etc.

Since you know the day, in a loop you could make a guess at the time, get the sun position, use the result to automatically make a better guess until you get close enough. You could do this as a binary search.

Related

I want advice about how to optimize my code. It takes too long for execution

I wrote a MATLAB code for finding seismic signal (ex. P wave) from SAC(seismic) file (which is read via another code). This algorithm is called STA/LTA trigger algorithm (actually not that important for my question)
Important thing is that actually this code works well, but since my seismic file is too big (1GB, which is for two months), it takes almost 40 minutes for executing to see the result. Thus, I feel the need to optimize the code.
I heard that replacing loops with advanced functions would help, but since I am a novice in MATLAB, I cannot get an idea about how to do it, since the purpose of code is scan through the every time series.
Also, I heard that preallocation might help, but I have mere idea about how to actually do this.
Since this code is about seismology, it might be hard to understand, but my notes at the top might help. I hope I can get useful advice here.
Following is my code.
function[pstime]=classic_LR(tseries,ltw,stw,thresh,dt)
% This is the code for "Classic LR" algorithm
% 'ns' is the number of measurement in STW-used to calculate STA
% 'nl' is the number of measurement in LTW-used to calculate LTA
% 'dt' is the time gap between measurements i.e. 0.008s for HHZ and 0.02s for BHZ
% 'ltw' and 'stw' are long and short time windows respectively
% 'lta' and 'sta' are long and short time windows average respectively
% 'sra' is the ratio between 'sta' and 'lta' which will be each component
% for a vector containing the ratio for each measurement point 'i'
% Index 'i' denotes each measurement point and this will be converted to actual time
nl=fix(ltw/dt);
ns=fix(stw/dt);
nt=length(tseries);
aseries=abs(detrend(tseries));
sra=zeros(1,nt);
for i=1:nt-ns
if i>nl
lta=mean(aseries(i-nl:i));
sta=mean(aseries(i:i+ns));
sra(i)=sta/lta;
else
sra(i)=0;
end
end
[k]=find(sra>thresh);
if ~isempty(k)
pstime=k*dt;
else
pstime=0;
end
return;
If you have MATLAB 2016a or later, you can use movmean instead of your loop (this means you also don't need to preallocate anything):
lta = movmean(aseries(1:nt-ns),nl+1,'Endpoints','discard');
sta = movmean(aseries(nl+1:end),ns+1,'Endpoints','discard');
sra = sta./lta;
The only difference here is that you will get sra with no leading and trailing zeros. This is most likely to be the fastest way. If for instance, aseries is 'only' 8 MB than this method takes less than 0.02 second while the original method takes almost 6 seconds!
However, even if you don't have Matlab 2016a, considering your loop, you can still do the following:
Remove the else statement - sta(i) is already zero from the preallocating.
Start the loop from nl+1, instead of checking when i is greater than nl.
So your new loop will be:
for i=nl+1:nt-ns
lta = mean(aseries(i-nl:i));
sta = mean(aseries(i:i+ns));
sra(i)=sta/lta;
end
But it won't be so faster.

Converting from datenum back to actual time

Ok, so I've been messing with what should be a simple problem. I'm trying to plot an numerical array (double) vs. the associated time stamp (cell) with the format of the DD-MM-YY HH:MM:SS (for example: 13-Mar-15 07:23:10).
I'm able to plot a single set using datetime(time stamp). Due to the data set it outputs the nice HH:MM on the x-axis. Very nice.
Now in order to plot 2 sets of values on the same graph, I've found that Matlab doesn't like to use the date_time twice for the x-axis, so then I go to the infamous datenum function, which is able to plot both on the same graph. However, it's in the serial value of time and it jacks with my plot sizing (i.e. the x-axis doesn't autosize).
With what should be a simple problem has actually caused me days scouring the internet trying to reconvert it back to my beloved HH:MM after converting the "time stamp" into the serial time.
I don't think that a code sample or data set should be necessary for example purposes. (but can provide if needed)
I've tried to use the datetick function, but can't get seem to get it working.
The trick with datenum and datetick is to set limits and tick positions before you call datetick, then make sure it doesn't redo them.
So, after plotting your two sets of data against the datenums it would go something like:
step = 1/24; % for hourly - adjust to preference
ticks = datenum('mystarttime'):step:datenum('myendtime')
set(gca,'XTick',ticks)
datetick('x','HH:MM','keepticks','keeplimits')
I work a lot with time series and most often I have to plot my data versus time/date.
Since Matlab never gave me a definitively convenient solution, for many years now I work this way:
I defined once and for all a Matlab shortcut (in the matlab shortcut toolbar):
containing the following code:
xticktemp = get(gca,'Xtick') ;
ticklabel = {datestr(xticktemp(1)) datestr(xticktemp(2:end),15) } ;
set(gca,'Xticklabel',ticklabel)
clear xticktemp ticklabel
I convert all my times with datenum and use this format for working (or posix time when more convenient, but it's another story), calculating and plotting. When I need to now exactly the time of an event in a human readable format, I press the shortcut and I obtain something like:
Of course there are 2 major limitations with this method:
This does not control the steps of the ticks (it just replicate what Matlab initially set)
You have to re-click your shortcut to refresh the tick labels everytime you zoom or pan the figure
For these reasons, when I need to finalize figure for presentation to others I won't use this trick and define my ticks exactly like I want them, but when you are simply working away, this shortcut has saved me hours (may be even days?) of fiddling around over the last 10 years ....

Suppress kinks in a plot matlab

I have a csv file which contains data like below:[1st row is header]
Element,State,Time
Water,Solid,1
Water,Solid,2
Water,Solid,3
Water,Solid,4
Water,Solid,5
Water,Solid,2
Water,Solid,3
Water,Solid,4
Water,Solid,5
Water,Solid,6
Water,Solid,7
Water,Solid,8
Water,Solid,7
Water,Solid,6
Water,Solid,5
Water,Solid,4
Water,Solid,3
The similar pattern is repeated for State: "Solid" replaced with Liquid and Gas.
And moreover the Element "Water" can be replaced by some other element too.
Time as Integer's are in seconds (to simplify) but can be any real number.
Additionally there might by some comment line starting with # in between the file.
Problem Statement: I want to eliminate the first dip in Time values and smooth out using some quadratic or cubic or polynomial interpolation [please notice the first change from 5->2 --->8. I want to replace these numbers to intermediate values giving a gradual/smooth increase from 5--->8].
And I wish this to be done for all the combinations of Elements and States.
Is this possible through some sort of coding in Matlab etc ?
Any Pointers will be helpful !!
Thanks in advance :)
You can use the interp1 function for 1D-interpolation. The syntax is
yi = interp1(x,y,xi,method)
where x are your original coordinates, y are your original values, xi are the coordinates at which you want the values to be interpolated at and yi are the interpolated values. method can be 'spline' (cubic spline interpolation), 'pchip' (piece-wise Hermite), 'cubic' (cubic polynomial) and others (see the documentation for details).
You have alot of options here, it really depends on the nature of your data, but I would start of with a simple moving average (MA) filter (which replaces each data point with the average of the neighboring data points), and see were that takes me. It's easy to implement, and fine-tuning the MA-span a couple of times on some sample data is usually enough.
http://www.mathworks.se/help/curvefit/smoothing-data.html
I would not try to fit a polynomial to the entire data set unless I really needed to compress it, (but to do so you can use the polyfit function).

Vectorize matlab code to map nearest values in two arrays

I have two lists of timestamps and I'm trying to create a map between them that uses the imu_ts as the true time and tries to find the nearest vicon_ts value to it. The output is a 3xd matrix where the first row is the imu_ts index, the third row is the unix time at that index, and the second row is the index of the closest vicon_ts value above the timestamp in the same column.
Here's my code so far and it works, but it's really slow. I'm not sure how to vectorize it.
function tmap = sync_times(imu_ts, vicon_ts)
tstart = max(vicon_ts(1), imu_ts(1));
tstop = min(vicon_ts(end), imu_ts(end));
%trim imu data to
tmap(1,:) = find(imu_ts >= tstart & imu_ts <= tstop);
tmap(3,:) = imu_ts(tmap(1,:));%Use imu_ts as ground truth
%Find nearest indecies in vicon data and map
vic_t = 1;
for i = 1:size(tmap,2)
%
while(vicon_ts(vic_t) < tmap(3,i))
vic_t = vic_t + 1;
end
tmap(2,i) = vic_t;
end
The timestamps are already sorted in ascending order, so this is essentially an O(n) operation but because it's looped it runs slowly. Any vectorized ways to do the same thing?
Edit
It appears to be running faster than I expected or first measured, so this is no longer a critical issue. But I would be interested to see if there are any good solutions to this problem.
Have a look at knnsearch in MATLAB. Use cityblock distance and also put an additional constraint that the data point in vicon_ts should be less than its neighbour in imu_ts. If it is not then take the next index. This is required because cityblock takes absolute distance. Another option (and preferred) is to write your custom distance function.
I believe that your current method is sound, and I would not try and vectorize any further. Vectorization can actually be harmful when you are trying to optimize some inner loops, especially when you know more about the context of your data (e.g. it is sorted) than the Mathworks engineers can know.
Things that I typically look for when I need to optimize some piece of code liek this are:
All arrays are pre-allocated (this is the biggest driver of performance)
Fast inner loops use simple code (Matlab does pretty effective JIT on basic commands, but must interpret others.)
Take advantage of any special data features that you have, e.g. use sort appropriate algorithms and early exit conditions from some loops.
You're already doing all this. I recommend no change.
A good start might be to get rid of the while, try something like:
for i = 1:size(tmap,2)
C = max(0,tmap(3,:)-vicon_ts(i));
tmap(2,i) = find(C==min(C));
end

How to calculate value of short options call with Black-Scholes formula?

I am trying to calculate the profit/loss of a short call at various times in the future, but it isn't coming out correct. Compared to the time of expiration, the ones with time left have less profit above the strike price, but at some point below the strike they don't lose value as fast as the t=0 line. Below is the formula in pseudocode, what am I doing wrong?
profit(stockprice) = -1 * (black_scholes_price_of_call(stockPrice,optionStrike,daysTillExpiration) - premium);
Real matlab code:
function [ x ] = sell_call( current,strike,price,days)
if (days > 0)
Sigma = .25;
Rates = 0.05;
Settle = today;
Maturity = today + days;
RateSpec = intenvset('ValuationDate', Settle, 'StartDates', Settle, 'EndDates',...
Maturity, 'Rates', Rates, 'Compounding', -1);
StockSpec = stockspec(Sigma, current);
x = -1 * (optstockbybls(RateSpec, StockSpec, Settle, Maturity, 'call', strike) - price);
else
x = min(price,strike-current-price);
end
end
Your formula ain't right. I don't know why you need that leading -1 as a multiplier for, because when I distribute it out the "formula" is a simple one:
profit(stockprice) = premium - black_scholes_price_of_call(stockPrice,optionStrike,daysTillExpiration);
Pretty simple. So that means the problem is buried in that function for the price of the call, right?
When I compare your formula to what I see as the definition on Wikipedia, I don't see a correspondence at all. Your MATLAB code doesn't help, either. Dig into the functions and see where you went wrong.
Did you write those? How did you test them before you assembled them into this larger function. Test the smaller blocks before you assemble them into the bigger thing.
What baseline are you testing against? What known situation are you comparing your calculation to? There are lots of B-S calculators available. Maybe you can use one of those.
I'd assume that it's an error in your code rather than MATLAB. Or you've misunderstood the meaning of the parameters you're passing. Look at your stuff more carefully, re-read the documentation for that function, and get a good set of baseline cases.
I found the problem, it had to do with the RateSpec argument. When you pass in a interest rate, it affects the option pricing.