Commit b3b851a23e6321841a2d789d31d3d48b06557378
1 parent
3124193a36
Exists in
master
add cov test scripts
Showing 2 changed files with 616 additions and 0 deletions Inline Diff
allan_cov.m
File was created | 1 | function [retval, s, errorb, tau] = allan_cov(data,tau,name,verbose) | ||
2 | % ALLAN Compute the Allan deviation for a set of time-domain frequency data | |||
3 | % [RETVAL, S, ERRORB, TAU] = ALLAN(DATA,TAU,NAME,VERBOSE) | |||
4 | % | |||
5 | % Inputs: | |||
6 | % DATA should be a structure and have the following fields: | |||
7 | % DATA.freq or DATA.phase | |||
8 | % A vector of fractional frequency measurements (df/f) in | |||
9 | % DATA.freq *or* phase offset data (seconds) in DATA.phase . | |||
10 | % If frequency data is not present, it will be generated by | |||
11 | % differentiating the phase data. | |||
12 | % If both fields are present, then DATA.freq will be used. | |||
13 | % Note: for general-purpose calculations of Allan deviation, | |||
14 | % (i.e. a two-sample variance) use DATA.freq . | |||
15 | % | |||
16 | % DATA.rate or DATA.time | |||
17 | % The sampling rate in Hertz (DATA.rate) or a vector of | |||
18 | % timestamps for each measurement in seconds (DATA.time). | |||
19 | % DATA.rate is used if both fields are present. | |||
20 | % If DATA.rate == 0, then the timestamps are used. | |||
21 | % | |||
22 | % DATA.units (optional) | |||
23 | % The units for the data. If present, the string DATA.units | |||
24 | % is added to the plot y-axis label. | |||
25 | % | |||
26 | % TAU is an array of tau values for computing Allan deviation. | |||
27 | % TAU values must be divisible by 1/DATA.rate (data points cannot be | |||
28 | % grouped in fractional quantities!) and invalid values are ignored. | |||
29 | % Leave empty to use default values. | |||
30 | % NAME is an optional label that is added to the plot titles. | |||
31 | % VERBOSE sets the level of status messages: | |||
32 | % 0 = silent & no data plots; | |||
33 | % 1 = status messages & minimum plots; | |||
34 | % 2 = all messages and plots (default) | |||
35 | % | |||
36 | % Outputs: | |||
37 | % RETVAL is the array of Allan deviation values at each TAU. | |||
38 | % S is an optional output of other statistical measures of the data (mean, std, etc). | |||
39 | % ERRORB is an optional output containing the error estimates for a 1-sigma | |||
40 | % confidence interval. These values are shown on the figure for each point. | |||
41 | % TAU is an optional output containing the array of tau values used in the | |||
42 | % calculation (which may be a truncated subset of the input or default values). | |||
43 | % | |||
44 | % Example: | |||
45 | % | |||
46 | % To compute the Allan deviation for the data in the variable "lt": | |||
47 | % >> lt | |||
48 | % lt = | |||
49 | % freq: [1x86400 double] | |||
50 | % rate: 0.5 | |||
51 | % | |||
52 | % Use: | |||
53 | % | |||
54 | % >> ad = allan(lt,[2 10 100],'lt data',1); | |||
55 | % | |||
56 | % The Allan deviation will be computed and plotted at tau = 2,10,100 seconds. | |||
57 | % 1-sigma confidence intervals will be indicated by vertical lines at each point. | |||
58 | % You can also use the default settings, which are usually a good starting point: | |||
59 | % | |||
60 | % >> ad = allan(lt); | |||
61 | % | |||
62 | % | |||
63 | % Notes: | |||
64 | % This function calculates the standard Allan deviation (ADEV), *not* the | |||
65 | % overlapping ADEV. Use "allan_overlap.m" for overlapping ADEV. | |||
66 | % The calculation is performed using fractional frequency data. If only | |||
67 | % phase data is provided, frequency data is generated by differentiating | |||
68 | % the phase data. | |||
69 | % No pre-processing of the data is performed, except to remove any | |||
70 | % initial offset (i.e., starting gap) in the time record. | |||
71 | % For rate-based data, ADEV is computed only for tau values greater than the | |||
72 | % minimum time between samples and less than the half the total time. For | |||
73 | % time-stamped data, only tau values greater than the maximum gap between | |||
74 | % samples and less than half the total time are used. | |||
75 | % The calculation for fixed sample rate data is *much* faster than for | |||
76 | % time-stamp data. You may wish to run the rate-based calculation first, | |||
77 | % then compare with time-stamp-based. Often the differences are insignificant. | |||
78 | % To show the "tau bins" (y_k samples) on the data plot, set the variable | |||
79 | % TAUBIN to 1 (search for "#TAUBIN"). | |||
80 | % You can choose between loglog and semilog plotting of results by | |||
81 | % commenting in/out the appropriate line. Search for "#PLOTLOG". | |||
82 | % I recommend installing "dsplot.m", which improves the performance of | |||
83 | % plotting large data sets. Download from File Exchange, File ID: #15850. | |||
84 | % allan.m will use dsplot.m if it is present on your MATLAB path. | |||
85 | % This function has been validated using the test data from NBS Monograph | |||
86 | % 140, the 1000-point test data set given by Riley [1], and the example data | |||
87 | % given in IEEE standard 1139-1999, Annex C. | |||
88 | % The author welcomes other validation results, see contact info below. | |||
89 | % | |||
90 | % For more information, see: | |||
91 | % [1] W. J. Riley, "The Calculation of Time Domain Frequency Stability," | |||
92 | % Available on the web: | |||
93 | % http://www.ieee-uffc.org/frequency_control/teaching.asp?name=paper1ht | |||
94 | % | |||
95 | % | |||
96 | % M.A. Hopcroft | |||
97 | % mhopeng at gmail dot com | |||
98 | % | |||
99 | % I welcome your comments and feedback! | |||
100 | % | |||
101 | % MH Mar2014 | |||
102 | % v2.24 fix bug related to generating freq data from phase with timestamps | |||
103 | % (thanks to S. David-Grignot for finding the bug) | |||
104 | % MH Oct2010 | |||
105 | % v2.22 tau truncation to integer groups; tau sort | |||
106 | % plotting bugfix | |||
107 | % v2.20 sychronize updates across allan, allan_overlap, allan_modified | |||
108 | % v2.16 add TAU as output, fixed unusual error with dsplot v1.1 | |||
109 | % v2.14 update plotting behaviour, default tau values | |||
110 | % | |||
111 | ||||
112 | versionstr = 'allan v2.24'; | |||
113 | ||||
114 | % MH Jun2010 | |||
115 | % v2.12 bugfix for rate data row/col orientation | |||
116 | % add DATA.units for plotting | |||
117 | % use dsplot.m for plotting | |||
118 | % | |||
119 | % MH MAR2010 | |||
120 | % v2.1 minor interface and bugfixes | |||
121 | % update data consistency check | |||
122 | % | |||
123 | % MH FEB2010 | |||
124 | % v2.0 Consistent code behaviour for all "allan_x.m" functions: | |||
125 | % accept phase data | |||
126 | % verbose levels | |||
127 | % | |||
128 | % | |||
129 | % MH JAN2010 | |||
130 | % v1.84 code cleanup | |||
131 | % v1.82 typos in comments and code cleanup | |||
132 | % tau bin plotting changed for performance improvement | |||
133 | % v1.8 Performance improvements: | |||
134 | % vectorize code for rate data | |||
135 | % logical indexing for irregular rate data | |||
136 | % MH APR2008 | |||
137 | % v1.62 loglog plot option | |||
138 | % v1.61 improve error handling, plotting | |||
139 | % fix bug in regular data calc for high-rate data | |||
140 | % fix bug in timestamp data calc for large starting gap | |||
141 | % (thanks to C. B. Ruiz for identifying these bugs) | |||
142 | % uses timestamps for DATA.rate=0 | |||
143 | % progress indicator for large timestamp data processing | |||
144 | % MH JUN2007 | |||
145 | % v1.54 Improve data plotting and optional bin plotting | |||
146 | % MH FEB2007 | |||
147 | % v1.5 use difference from median for plotting | |||
148 | % added MAD calculation for outlier detection | |||
149 | % MH JAN2007 | |||
150 | % v1.48 plotting typos fixes | |||
151 | % MH DEC2006 | |||
152 | % v1.46 hack to plot error bars | |||
153 | % v1.44 further validation (Riley 1000-pt) | |||
154 | % plot mean and std | |||
155 | % MH NOV2006 | |||
156 | % v1.42 typo fix comments | |||
157 | % v1.4 fix irregular rate algorithm | |||
158 | % irregular algorithm rejects tau less than max gap in time data | |||
159 | % validate both algorithms using test data from NBS Monograph 140 | |||
160 | % v1.3 fix time calc if data.time not present | |||
161 | % add error bars (not possible due to bug in MATLAB R14SP3) | |||
162 | % remove offset calculation | |||
163 | % v1.24 improve feedback | |||
164 | % MH SEP2006 | |||
165 | % v1.22 updated comments | |||
166 | % v1.2 errors and warnings | |||
167 | % v1.1 handle irregular interval data | |||
168 | %#ok<*AGROW> | |||
169 | ||||
170 | % defaults | |||
171 | if nargin < 4, verbose=2; end | |||
172 | if nargin < 3, name=''; end | |||
173 | if nargin < 2 || isempty(tau), tau=2.^(-10:10); end | |||
174 | ||||
175 | % plot "tau bins"? #TAUBIN | |||
176 | TAUBIN = 0; % set 0 or 1 % WARNING: this has a significant impact on performance | |||
177 | ||||
178 | % Formatting for plots | |||
179 | FontName = 'Arial'; | |||
180 | FontSize = 14; | |||
181 | plotlinewidth=2; | |||
182 | ||||
183 | if verbose >= 1, fprintf(1,'allan: %s\n\n',versionstr); end | |||
184 | ||||
185 | %% Data consistency checks | |||
186 | if ~(isfield(data,'phase') || isfield(data,'freq')) | |||
187 | error('Either ''phase'' or ''freq'' must be present in DATA. See help file for details. [con0]'); | |||
188 | end | |||
189 | if isfield(data,'time') | |||
190 | if isfield(data,'phase') && (length(data.phase) ~= length(data.time)) | |||
191 | if isfield(data,'freq') && (length(data.freq) ~= length(data.time)) | |||
192 | error('The time and freq vectors are not the same length. See help for details. [con2]'); | |||
193 | else | |||
194 | error('The time and phase vectors are not the same length. See help for details. [con1]'); | |||
195 | end | |||
196 | end | |||
197 | if isfield(data,'phase') && (any(isnan(data.phase)) || any(isinf(data.phase))) | |||
198 | error('The phase vector contains invalid elements (NaN/Inf). [con3]'); | |||
199 | end | |||
200 | if isfield(data,'freq') && (any(isnan(data.freq)) || any(isinf(data.freq))) | |||
201 | error('The freq vector contains invalid elements (NaN/Inf). [con4]'); | |||
202 | end | |||
203 | if isfield(data,'time') && (any(isnan(data.time)) || any(isinf(data.time))) | |||
204 | error('The time vector contains invalid elements (NaN/Inf). [con5]'); | |||
205 | end | |||
206 | end | |||
207 | ||||
208 | % sort tau vector | |||
209 | tau=sort(tau); | |||
210 | ||||
211 | ||||
212 | %% Basic statistical tests on the data set | |||
213 | if ~isfield(data,'freq') | |||
214 | if isfield(data,'rate') && data.rate ~= 0 | |||
215 | data.freq=diff(data.phase).*data.rate; | |||
216 | elseif isfield(data,'time') | |||
217 | data.freq=diff(data.phase)./diff(data.time); | |||
218 | end | |||
219 | if verbose >= 1, fprintf(1,'allan: Fractional frequency data generated from phase data (M=%g).\n',length(data.freq)); end | |||
220 | data.time(1)=[]; % make time stamps correspond to freq data | |||
221 | end | |||
222 | if size(data.freq,2) > size(data.freq,1), data.freq=data.freq'; end % ensure columns | |||
223 | ||||
224 | s.numpoints=length(data.freq); | |||
225 | s.max=max(data.freq); | |||
226 | s.min=min(data.freq); | |||
227 | s.mean=mean(data.freq); | |||
228 | s.median=median(data.freq); | |||
229 | if isfield(data,'time') | |||
230 | if size(data.time,2) > size(data.time,1), data.time=data.time'; end % ensure columns | |||
231 | s.linear=polyfit(data.time(1:length(data.freq)),data.freq,1); | |||
232 | elseif isfield(data,'rate') && data.rate ~= 0; | |||
233 | s.linear=polyfit((1/data.rate:1/data.rate:length(data.freq)/data.rate)',data.freq,1); | |||
234 | else | |||
235 | error('Either "time" or "rate" must be present in DATA. Type "help allan" for details. [err1]'); | |||
236 | end | |||
237 | s.std=std(data.freq); | |||
238 | ||||
239 | if verbose >= 2 | |||
240 | fprintf(1,'allan: input data statistics:\n'); | |||
241 | disp(s); | |||
242 | end | |||
243 | ||||
244 | ||||
245 | % center at median for plotting | |||
246 | medianfreq=data.freq-s.median; | |||
247 | sm=[]; sme=[]; | |||
248 | ||||
249 | % Screen for outliers using 5x Median Absolute Deviation (MAD) criteria | |||
250 | s.MAD = median(abs(medianfreq)/0.6745); | |||
251 | if verbose >= 2 | |||
252 | fprintf(1, 'allan: 5x MAD value for outlier detection: %g\n',5*s.MAD); | |||
253 | end | |||
254 | if verbose >= 1 && any(abs(medianfreq) > 5*s.MAD) | |||
255 | fprintf(1, 'allan: NOTE: There appear to be outliers in the frequency data. See plot.\n'); | |||
256 | end | |||
257 | ||||
258 | ||||
259 | %%%% | |||
260 | % There are two cases, either using timestamps or fixed sample rate: | |||
261 | ||||
262 | %% Fixed Sample Rate Data | |||
263 | % If there is a regular interval between measurements, calculation is much | |||
264 | % easier/faster | |||
265 | if isfield(data,'rate') && data.rate > 0 % if data rate was given | |||
266 | if verbose >= 1, fprintf(1, 'allan: regular data (%g data points @ %g Hz)\n',length(data.freq),data.rate); end | |||
267 | ||||
268 | % string for plot title | |||
269 | name=[name ' (' num2str(data.rate) ' Hz)']; | |||
270 | ||||
271 | % what is the time interval between data points? | |||
272 | tmstep = 1/data.rate; | |||
273 | ||||
274 | % Is there time data? Just for curiosity/plotting, does not impact calculation | |||
275 | if isfield(data,'time') | |||
276 | % adjust time data to remove any starting gap; first time step | |||
277 | % should not be zero for comparison with freq data | |||
278 | dtime=data.time-data.time(1)+mean(diff(data.time)); | |||
279 | if verbose >= 2 | |||
280 | fprintf(1,'allan: End of timestamp data: %g sec.\n',dtime(end)); | |||
281 | if (data.rate - 1/mean(diff(dtime))) > 1e-6 | |||
282 | fprintf(1,'allan: NOTE: data.rate (%f Hz) does not match average timestamped sample rate (%f Hz)\n',data.rate,1/mean(diff(dtime))); | |||
283 | end | |||
284 | end | |||
285 | else | |||
286 | % create time axis data using rate (for plotting only) | |||
287 | dtime=(tmstep:tmstep:length(data.freq)*tmstep)'; % column oriented | |||
288 | end | |||
289 | ||||
290 | % check the range of tau values and truncate if necessary | |||
291 | % find halfway point of time record | |||
292 | halftime = round(tmstep*length(data.freq)/2); | |||
293 | % truncate tau to appropriate values | |||
294 | tau = tau(tau >= tmstep & tau <= halftime); | |||
295 | if verbose >= 2, fprintf(1, 'allan: allowable tau range: %g to %g sec. (1/rate to total_time/2)\n',tmstep,halftime); end | |||
296 | ||||
297 | % save the freq data for the loop | |||
298 | dfreq=data.freq; | |||
299 | dfreq2=data.freq2; | |||
300 | % find the number of data points in each tau group | |||
301 | m = data.rate.*tau; | |||
302 | % only integer values allowed (no fractional groups of points) | |||
303 | %tau = tau(m-round(m)<1e-8); % numerical precision issues (v2.1) | |||
304 | tau = tau(m==round(m)); % The round() test is only correct for values < 2^53 | |||
305 | %m = m(m-round(m)<1e-8); % change to round(m) for integer test v2.22 | |||
306 | m = m(m==round(m)); | |||
307 | %m=round(m); | |||
308 | ||||
309 | if verbose >= 1, fprintf(1,'allan: calculating Allan deviation...\n '); end | |||
310 | ||||
311 | % calculate the Allan deviation for each value of tau | |||
312 | k=0; tic; | |||
313 | for i = tau | |||
314 | if verbose >= 2, fprintf(1,'%g ',i); end | |||
315 | k=k+1; | |||
316 | ||||
317 | % truncate frequency set to an even multiple of this tau value | |||
318 | freq=dfreq(1:end-rem(length(dfreq),m(k))); | |||
319 | freq2=dfreq2(1:end-rem(length(dfreq2),m(k))); | |||
320 | % group the data into tau-length groups or bins | |||
321 | f = reshape(freq,m(k),[]); % Vectorize! | |||
322 | f2 = reshape(freq2,m(k),[]); % Vectorize! | |||
323 | % find average in each "tau group", y_k (each colummn of f) | |||
324 | fa=mean(f,1); | |||
325 | fa2=mean(f2,1); | |||
326 | % first finite difference | |||
327 | fd=diff(fa); | |||
328 | fd2=diff(fa2); | |||
329 | % calculate two-sample variance for this tau | |||
330 | M=length(fa); | |||
331 | sm(k)=sqrt(0.5/(M-1)*(sum(fd.*fd2))); | |||
332 | ||||
333 | % estimate error bars | |||
334 | sme(k)=sm(k)/sqrt(M+1); | |||
335 | ||||
336 | if TAUBIN == 1 | |||
337 | % save the binning points for plotting | |||
338 | fs(k,1:length(freq)/m(k))=m(k):m(k):length(freq); fval{k}=mean(f,1); | |||
339 | end | |||
340 | ||||
341 | end % repeat for each value of tau | |||
342 | ||||
343 | if verbose >= 2, fprintf(1,'\n'); end | |||
344 | calctime=toc; if verbose >= 2, fprintf(1,'allan: Elapsed time for calculation: %e seconds\n',calctime); end | |||
345 | ||||
346 | ||||
347 | ||||
348 | %% Irregular data (timestamp) | |||
349 | elseif isfield(data,'time') | |||
350 | % the interval between measurements is irregular | |||
351 | % so we must group the data by time | |||
352 | if verbose >= 1, fprintf(1, 'allan: irregular rate data (no fixed sample rate)\n'); end | |||
353 | ||||
354 | % string for plot title | |||
355 | name=[name ' (timestamp)']; | |||
356 | ||||
357 | % adjust time to remove any initial offset or zero | |||
358 | dtime=data.time-data.time(1)+mean(diff(data.time)); | |||
359 | %dtime=data.time; | |||
360 | % where is the maximum gap in time record? | |||
361 | gap_pos=find(diff(dtime)==max(diff(dtime))); | |||
362 | % what is average data spacing? | |||
363 | avg_gap = mean(diff(dtime)); | |||
364 | ||||
365 | if verbose >= 2 | |||
366 | fprintf(1, 'allan: WARNING: irregular timestamp data (no fixed sample rate).\n'); | |||
367 | fprintf(1, ' Calculation time may be long and the results subject to interpretation.\n'); | |||
368 | fprintf(1, ' You are advised to estimate using an average sample rate (%g Hz) instead of timestamps.\n',1/avg_gap); | |||
369 | fprintf(1, ' Continue at your own risk! (press any key to continue)\n'); | |||
370 | pause; | |||
371 | end | |||
372 | ||||
373 | if verbose >= 1 | |||
374 | fprintf(1, 'allan: End of timestamp data: %g sec\n',dtime(end)); | |||
375 | fprintf(1, ' Average rate: %g Hz (%g sec/measurement)\n',1/avg_gap,avg_gap); | |||
376 | if max(diff(dtime)) ~= 1/mean(diff(dtime)) | |||
377 | fprintf(1, ' Max. gap: %g sec at position %d\n',max(diff(dtime)),gap_pos(1)); | |||
378 | end | |||
379 | if max(diff(dtime)) > 5*avg_gap | |||
380 | fprintf(1, ' WARNING: Max. gap in time record is suspiciously large (>5x the average interval).\n'); | |||
381 | end | |||
382 | end | |||
383 | ||||
384 | ||||
385 | % find halfway point | |||
386 | halftime = fix(dtime(end)/2); | |||
387 | % truncate tau to appropriate values | |||
388 | tau = tau(tau >= max(diff(dtime)) & tau <= halftime); | |||
389 | if isempty(tau) | |||
390 | error('allan: ERROR: no appropriate tau values (> %g s, < %g s)\n',max(diff(dtime)),halftime); | |||
391 | end | |||
392 | ||||
393 | % save the freq data for the loop | |||
394 | dfreq=data.freq; | |||
395 | dtime=dtime(1:length(dfreq)); | |||
396 | ||||
397 | if verbose >= 1, fprintf(1,'allan: calculating Allan deviation...\n'); end | |||
398 | ||||
399 | k=0; tic; | |||
400 | for i = tau | |||
401 | if verbose >= 2, fprintf(1,'%d ',i); end | |||
402 | ||||
403 | k=k+1; fa=[]; %f=[]; | |||
404 | km=0; | |||
405 | ||||
406 | % truncate data set to an even multiple of this tau value | |||
407 | freq=dfreq(dtime <= dtime(end)-rem(dtime(end),i)); | |||
408 | time=dtime(dtime <= dtime(end)-rem(dtime(end),i)); | |||
409 | %freq=dfreq; | |||
410 | %time=dtime; | |||
411 | ||||
412 | % break up the data into groups of tau length in sec | |||
413 | while i*km < time(end) | |||
414 | km=km+1; | |||
415 | ||||
416 | % progress bar | |||
417 | if verbose >= 2 | |||
418 | if rem(km,100)==0, fprintf(1,'.'); end | |||
419 | if rem(km,1000)==0, fprintf(1,'%g/%g\n',km,round(time(end)/i)); end | |||
420 | end | |||
421 | ||||
422 | f = freq(i*(km-1) < time & time <= i*km); | |||
423 | f = f(~isnan(f)); % make sure values are valid | |||
424 | ||||
425 | if ~isempty(f) | |||
426 | fa(km)=mean(f); | |||
427 | else | |||
428 | fa(km)=0; | |||
429 | end | |||
430 | ||||
431 | if TAUBIN == 1 % WARNING: this has a significant impact on performance | |||
432 | % save the binning points for plotting | |||
433 | %if find(time <= i*km) > 0 | |||
434 | fs(k,km)=max(time(time <= i*km)); | |||
435 | %else | |||
436 | if isempty(fs(k,km)) | |||
437 | fs(k,km)=0; | |||
438 | end | |||
439 | fval{k}=fa; | |||
440 | end % save tau bin plot points | |||
441 | ||||
442 | end | |||
443 | ||||
444 | if verbose >= 2, fprintf(1,'\n'); end | |||
445 | ||||
446 | % first finite difference of the averaged results | |||
447 | fd=diff(fa); | |||
448 | % calculate Allan deviation for this tau | |||
449 | M=length(fa); | |||
450 | sm(k)=sqrt(0.5/(M-1)*(sum(fd.^2))); | |||
451 | ||||
452 | % estimate error bars | |||
453 | sme(k)=sm(k)/sqrt(M+1); | |||
454 | ||||
455 | ||||
456 | end | |||
457 | ||||
458 | if verbose == 2, fprintf(1,'\n'); end | |||
459 | calctime=toc; if verbose >= 2, fprintf(1,'allan: Elapsed time for calculation: %e seconds\n',calctime); end | |||
460 | ||||
461 | ||||
462 | else | |||
463 | error('allan: WARNING: no DATA.rate or DATA.time! Type "help allan" for more information. [err2]'); | |||
464 | end | |||
465 | ||||
466 | ||||
467 | %%%%%%%% | |||
468 | %% Plotting | |||
469 | ||||
470 | if verbose >= 2 % show all data | |||
471 | ||||
472 | % plot the frequency data, centered on median | |||
473 | if size(dtime,2) > size(dtime,1), dtime=dtime'; end % this should not be necessary, but dsplot 1.1 is a little bit brittle | |||
474 | try | |||
475 | % dsplot makes a new figure | |||
476 | hd=dsplot(dtime,medianfreq); | |||
477 | catch ME | |||
478 | figure; | |||
479 | if length(dtime) ~= length(medianfreq) | |||
480 | fprintf(1,'allan: Warning: length of time axis (%d) is not equal to data array (%d)\n',length(dtime),length(medianfreq)); | |||
481 | end | |||
482 | hd=plot(dtime,medianfreq); | |||
483 | if verbose >= 1, fprintf(1,'allan: Note: Install dsplot.m for improved plotting of large data sets (File Exchange File ID: #15850).\n'); end | |||
484 | if verbose >= 2, fprintf(1,' (Message: %s)\n',ME.message); end | |||
485 | end | |||
486 | set(hd,'Marker','.','LineStyle','none','Color','b'); % equivalent to '.-' | |||
487 | hold on; | |||
488 | ||||
489 | % show center (0) | |||
490 | plot(xlim,[0 0],':k'); | |||
491 | % show 5x Median Absolute Deviation (MAD) values | |||
492 | hm=plot(xlim,[5*s.MAD 5*s.MAD],'-r'); | |||
493 | plot(xlim,[-5*s.MAD -5*s.MAD],'-r'); | |||
494 | % show linear fit line | |||
495 | hf=plot(xlim,polyval(s.linear,xlim)-s.median,'-g'); | |||
496 | title(['Data: ' name],'FontSize',FontSize+2,'FontName',FontName); | |||
497 | %set(get(gca,'Title'),'Interpreter','none'); | |||
498 | xlabel('Time [sec]','FontSize',FontSize,'FontName',FontName); | |||
499 | if isfield(data,'units') | |||
500 | ylabel(['data - median(data) [' data.units ']'],'FontSize',FontSize,'FontName',FontName); | |||
501 | else | |||
502 | ylabel('freq - median(freq)','FontSize',FontSize,'FontName',FontName); | |||
503 | end | |||
504 | set(gca,'FontSize',FontSize,'FontName',FontName); |
allanplot_cov.m
File was created | 1 | #!/usr/bin/octave-cli --persist | ||
2 | ||||
3 | filename = argv(){1}; | |||
4 | col1 = eval(argv(){2}); | |||
5 | col2 = eval(argv(){3}); | |||
6 | mult1 = eval(argv(){4}); | |||
7 | mult2 = eval(argv(){5}); | |||
8 | ||||
9 | if length(col1) == length(mult1) | |||
10 | figure | |||
11 | hold all | |||
12 | grid on | |||
13 | cc = 'bkcgmry'; | |||
14 | for i = [1:length(col1)] | |||
15 | data.freq = load(filename)(:,col1(i)).*mult1(i); | |||
16 | data.freq2 = load(filename)(:,col2(i)).*mult2(i); | |||
17 | if eval(argv(){end-1}) == 1 | |||
18 | printf('\ndata1 drift removed\n\n') | |||
19 | data.freq = detrend(data.freq); | |||
20 | end | |||
21 | if eval(argv(){end}) == 1 | |||
22 | printf('\ndata2 drift removed\n\n') | |||
23 | data.freq2 = detrend(data.freq2); | |||
24 | end | |||
25 | data.rate = 1; | |||
26 | [ad, S, err, tau] = allan_cov(data, 2.^[0:nextpow2(length(data.freq))-3]./data.rate, strcat(strsplit(filename, '/'){end}, num2str(i)), 0); | |||
27 | loglogerr(tau, ad, err, strcat(cc(mod(i, length(cc))), '-s')) | |||
28 | leg{i} = strcat(filename, ' cov col', num2str(col1(i)), ' col', num2str(col2(i))); | |||
29 | axis(10.^ceil(log10([tau(1), tau(end)]))) | |||
30 | hold on | |||
31 | end | |||
32 | legend(leg) | |||
33 | input("Press to continue..."); |