aboutsummaryrefslogtreecommitdiff
path: root/Tools/sdlog2/logconv.m
blob: e19c97fa3cef1cab5f403cd070606d301b983583 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
% This Matlab Script can be used to import the binary logged values of the
% PX4FMU into data that can be plotted and analyzed.

%% ************************************************************************
% PX4LOG_PLOTSCRIPT: Main function
% ************************************************************************
function PX4Log_Plotscript

% Clear everything
clc
clear all
close all

% ************************************************************************
% SETTINGS
% ************************************************************************

% Set the path to your sysvector.bin file here
filePath = 'log001.bin';

% Set the minimum and maximum times to plot here [in seconds]
mintime=0;        %The minimum time/timestamp to display, as set by the user [0 for first element / start]
maxtime=0;        %The maximum time/timestamp to display, as set by the user [0 for last element / end]

%Determine which data to plot. Not completely implemented yet.
bDisplayGPS=true;

%conversion factors
fconv_gpsalt=1; %[mm] to [m]
fconv_gpslatlong=1; %[gps_raw_position_unit] to [deg]
fconv_timestamp=1E-6; % [microseconds] to [seconds]

% ************************************************************************
% Import the PX4 logs
% ************************************************************************
ImportPX4LogData();

%Translate min and max plot times to indices
time=double(sysvector.TIME_StartTime) .*fconv_timestamp;
mintime_log=time(1);        %The minimum time/timestamp found in the log
maxtime_log=time(end);      %The maximum time/timestamp found in the log
CurTime=mintime_log;        %The current time at which to draw the aircraft position

[imintime,imaxtime]=FindMinMaxTimeIndices();

% ************************************************************************
% PLOT & GUI SETUP
% ************************************************************************
NrFigures=5;
NrAxes=10;
h.figures(1:NrFigures)=0.0;  % Temporary initialization of figure handle array - these are numbered consecutively
h.axes(1:NrAxes)=0.0;        % Temporary initialization of axes handle array - these are numbered consecutively
h.pathpoints=[];             % Temporary initiliazation of path points

% Setup the GUI to control the plots
InitControlGUI();
% Setup the plotting-GUI (figures, axes) itself.
InitPlotGUI();

% ************************************************************************
% DRAW EVERYTHING
% ************************************************************************
DrawRawData();
DrawCurrentAircraftState();

%% ************************************************************************
%  *** END OF MAIN SCRIPT ***
%  NESTED FUNCTION DEFINTIONS FROM HERE ON
%  ************************************************************************


%% ************************************************************************
%  IMPORTPX4LOGDATA (nested function)
%  ************************************************************************
%  Attention:  This is the import routine for firmware from ca. 03/2013.
%              Other firmware versions might require different import 
%              routines.

%% ************************************************************************
%  IMPORTPX4LOGDATA (nested function)
%  ************************************************************************
%  Attention:  This is the import routine for firmware from ca. 03/2013.
%              Other firmware versions might require different import 
%              routines.

function ImportPX4LogData()

    % ************************************************************************
    % RETRIEVE SYSTEM VECTOR
    % *************************************************************************
    % //All measurements in NED frame
    
    % Convert to CSV
    %arg1 = 'log-fx61-20130721-2.bin';
    arg1 = filePath;
    delim = ',';
    time_field = 'TIME';
    data_file = 'data.csv';
    csv_null = '';
    
    if not(exist(data_file, 'file'))
        s = system( sprintf('python sdlog2_dump.py "%s" -f "%s" -t"%s" -d"%s" -n"%s"', arg1, data_file, time_field, delim, csv_null) );
    end

    if exist(data_file, 'file')

        %data = csvread(data_file);
        sysvector = tdfread(data_file, ',');

        % shot the flight time
        time_us = sysvector.TIME_StartTime(end) - sysvector.TIME_StartTime(1);
        time_s = uint64(time_us*1e-6);
        time_m = uint64(time_s/60);
        time_s = time_s - time_m * 60;
        
        disp([sprintf('Flight log duration: %d:%d (minutes:seconds)', time_m, time_s) char(10)]);

        disp(['logfile conversion finished.' char(10)]);
    else
        disp(['file: ' data_file ' does not exist' char(10)]);
    end
end

%% ************************************************************************
%  INITCONTROLGUI (nested function)
%  ************************************************************************
%Setup central control GUI components to control current time where data is shown
function InitControlGUI()
    %**********************************************************************
    % GUI size definitions
    %**********************************************************************
    dxy=5; %margins
    %Panel: Plotctrl
    dlabels=120;
    dsliders=200;
    dedits=80;
    hslider=20;
        
    hpanel1=40; %panel1
    hpanel2=220;%panel2
    hpanel3=3*hslider+4*dxy+3*dxy;%panel3.
    
    width=dlabels+dsliders+dedits+4*dxy+2*dxy;  %figure width
    height=hpanel1+hpanel2+hpanel3+4*dxy;       %figure height
        
    %**********************************************************************
    % Create GUI
    %**********************************************************************
    h.figures(1)=figure('Units','pixels','position',[200 200 width height],'Name','Control GUI');
    h.guistatepanel=uipanel('Title','Current GUI state','Units','pixels','Position',[dxy dxy width-2*dxy hpanel1],'parent',h.figures(1));
    h.aircraftstatepanel=uipanel('Title','Current aircraft state','Units','pixels','Position',[dxy hpanel1+2*dxy width-2*dxy hpanel2],'parent',h.figures(1));
    h.plotctrlpanel=uipanel('Title','Plot Control','Units','pixels','Position',[dxy hpanel1+hpanel2+3*dxy width-2*dxy hpanel3],'parent',h.figures(1));
    
    %%Control GUI-elements
    %Slider: Current time
    h.labels.CurTime=uicontrol(gcf,'style','text','Position',[dxy dxy dlabels hslider],'String','Current time t[s]:','parent',h.plotctrlpanel,'HorizontalAlignment','left');
    h.sliders.CurTime=uicontrol(gcf,'style','slider','units','pix','position',[2*dxy+dlabels dxy dsliders hslider],...
        'min',mintime,'max',maxtime,'value',mintime,'callback',@curtime_callback,'parent',h.plotctrlpanel);
    temp=get(h.sliders.CurTime,'Max')-get(h.sliders.CurTime,'Min');
    set(h.sliders.CurTime,'SliderStep',[1.0/temp 5.0/temp]);
    h.edits.CurTime=uicontrol(gcf,'style','edit','position',[3*dxy+dlabels+dsliders dxy dedits hslider],'String',get(h.sliders.CurTime,'value'),...
        'BackgroundColor','white','callback',@curtime_callback,'parent',h.plotctrlpanel);

    %Slider: MaxTime
    h.labels.MaxTime=uicontrol(gcf,'style','text','position',[dxy 2*dxy+hslider dlabels hslider],'String','Max. time t[s] to display:','parent',h.plotctrlpanel,'HorizontalAlignment','left');
    h.sliders.MaxTime=uicontrol(gcf,'style','slider','units','pix','position',[2*dxy+dlabels 2*dxy+hslider dsliders hslider],...
        'min',mintime_log,'max',maxtime_log,'value',maxtime,'callback',@minmaxtime_callback,'parent',h.plotctrlpanel);
    h.edits.MaxTime=uicontrol(gcf,'style','edit','position',[3*dxy+dlabels+dsliders 2*dxy+hslider dedits hslider],'String',get(h.sliders.MaxTime,'value'),...
        'BackgroundColor','white','callback',@minmaxtime_callback,'parent',h.plotctrlpanel);
    
    %Slider: MinTime
    h.labels.MinTime=uicontrol(gcf,'style','text','position',[dxy 3*dxy+2*hslider dlabels hslider],'String','Min. time t[s] to dispay :','parent',h.plotctrlpanel,'HorizontalAlignment','left');
    h.sliders.MinTime=uicontrol(gcf,'style','slider','units','pix','position',[2*dxy+dlabels 3*dxy+2*hslider dsliders hslider],...
        'min',mintime_log,'max',maxtime_log,'value',mintime,'callback',@minmaxtime_callback,'parent',h.plotctrlpanel);
    h.edits.MinTime=uicontrol(gcf,'style','edit','position',[3*dxy+dlabels+dsliders 3*dxy+2*hslider dedits hslider],'String',get(h.sliders.MinTime,'value'),...
        'BackgroundColor','white','callback',@minmaxtime_callback,'parent',h.plotctrlpanel);

    %%Current data/state GUI-elements (Multiline-edit-box)
    h.edits.AircraftState=uicontrol(gcf,'style','edit','Units','normalized','position',[.02 .02 0.96 0.96],'Min',1,'Max',10,'String','This shows the current aircraft state',...
                                    'HorizontalAlignment','left','parent',h.aircraftstatepanel);
    
    h.labels.GUIState=uicontrol(gcf,'style','text','Units','pixels','position',[dxy dxy width-4*dxy hslider],'String','Current state of this GUI',...
                                'HorizontalAlignment','left','parent',h.guistatepanel);
    
end

%% ************************************************************************
%  INITPLOTGUI (nested function)
%  ************************************************************************
function InitPlotGUI()
    
    % Setup handles to lines and text
    h.markertext=[];
    templinehandle=0.0;%line([0 1],[0 5]);   % Just a temporary handle to init array
    h.markerline(1:NrAxes)=templinehandle;   % the actual handle-array to the lines  - these are numbered consecutively
    h.markerline(1:NrAxes)=0.0;
        
    % Setup all other figures and axes for plotting
    %  PLOT WINDOW 1: GPS POSITION
    h.figures(2)=figure('units','normalized','Toolbar','figure', 'Name', 'GPS Position');
    h.axes(1)=axes();
    set(h.axes(1),'Parent',h.figures(2));

    %  PLOT WINDOW 2: IMU, baro altitude
    h.figures(3)=figure('Name', 'IMU / Baro Altitude');
    h.axes(2)=subplot(4,1,1);
    h.axes(3)=subplot(4,1,2);
    h.axes(4)=subplot(4,1,3);
    h.axes(5)=subplot(4,1,4);
    set(h.axes(2:5),'Parent',h.figures(3));
    
    %  PLOT WINDOW 3: ATTITUDE ESTIMATE, ACTUATORS/CONTROLS, AIRSPEEDS,...
    h.figures(4)=figure('Name', 'Attitude Estimate / Actuators / Airspeeds');
    h.axes(6)=subplot(4,1,1);
    h.axes(7)=subplot(4,1,2);
    h.axes(8)=subplot(4,1,3);
    h.axes(9)=subplot(4,1,4);
    set(h.axes(6:9),'Parent',h.figures(4));
    
    %  PLOT WINDOW 4: LOG STATS
    h.figures(5) = figure('Name', 'Log Statistics');
    h.axes(10)=subplot(1,1,1);
    set(h.axes(10:10),'Parent',h.figures(5));
    
end

%% ************************************************************************
%  DRAWRAWDATA (nested function)
%  ************************************************************************
%Draws the raw data from the sysvector, but does not add any
%marker-lines or so
function DrawRawData() 
    % ************************************************************************
    %  PLOT WINDOW 1: GPS POSITION & GUI
    %  ************************************************************************
    figure(h.figures(2));
    % Only plot GPS data if available
    if (sum(double(sysvector.GPS_Lat(imintime:imaxtime)))>0) && (bDisplayGPS)
        %Draw data
        plot3(h.axes(1),double(sysvector.GPS_Lat(imintime:imaxtime))*fconv_gpslatlong, ...
                        double(sysvector.GPS_Lon(imintime:imaxtime))*fconv_gpslatlong, ...
                        double(sysvector.GPS_Alt(imintime:imaxtime))*fconv_gpsalt,'r.');
        title(h.axes(1),'GPS Position Data(if available)');
        xlabel(h.axes(1),'Latitude [deg]');
        ylabel(h.axes(1),'Longitude [deg]');
        zlabel(h.axes(1),'Altitude above MSL [m]');
        grid on
        
        %Reset path
        h.pathpoints=0;
    end

    % ************************************************************************
    %  PLOT WINDOW 2: IMU, baro altitude
    %  ************************************************************************
    figure(h.figures(3));
    plot(h.axes(2),time(imintime:imaxtime),[sysvector.IMU_MagX(imintime:imaxtime), sysvector.IMU_MagY(imintime:imaxtime), sysvector.IMU_MagZ(imintime:imaxtime)]);
    title(h.axes(2),'Magnetometers [Gauss]');
    legend(h.axes(2),'x','y','z');
    plot(h.axes(3),time(imintime:imaxtime),[sysvector.IMU_AccX(imintime:imaxtime), sysvector.IMU_AccY(imintime:imaxtime), sysvector.IMU_AccZ(imintime:imaxtime)]);
    title(h.axes(3),'Accelerometers [m/s]');
    legend(h.axes(3),'x','y','z');
    plot(h.axes(4),time(imintime:imaxtime),[sysvector.IMU_GyroX(imintime:imaxtime), sysvector.IMU_GyroY(imintime:imaxtime), sysvector.IMU_GyroZ(imintime:imaxtime)]);
    title(h.axes(4),'Gyroscopes [rad/s]');
    legend(h.axes(4),'x','y','z');
    plot(h.axes(5),time(imintime:imaxtime),sysvector.SENS_BaroAlt(imintime:imaxtime),'color','blue');
    if(bDisplayGPS)
        hold on;
        plot(h.axes(5),time(imintime:imaxtime),double(sysvector.GPS_Alt(imintime:imaxtime)).*fconv_gpsalt,'color','red');
        hold off
        legend('Barometric Altitude [m]','GPS Altitude [m]');
    else
        legend('Barometric Altitude [m]');
    end
    title(h.axes(5),'Altitude above MSL [m]');

    % ************************************************************************
    %  PLOT WINDOW 3: ATTITUDE ESTIMATE, ACTUATORS/CONTROLS, AIRSPEEDS,...
    % ************************************************************************
    figure(h.figures(4));
    %Attitude Estimate
    plot(h.axes(6),time(imintime:imaxtime), [sysvector.ATT_Roll(imintime:imaxtime), sysvector.ATT_Pitch(imintime:imaxtime), sysvector.ATT_Yaw(imintime:imaxtime)] .*180./3.14159);
    title(h.axes(6),'Estimated attitude [deg]');
    legend(h.axes(6),'roll','pitch','yaw');
    %Actuator Controls
    plot(h.axes(7),time(imintime:imaxtime), [sysvector.ATTC_Roll(imintime:imaxtime), sysvector.ATTC_Pitch(imintime:imaxtime), sysvector.ATTC_Yaw(imintime:imaxtime), sysvector.ATTC_Thrust(imintime:imaxtime)]);
    title(h.axes(7),'Actuator control [-]');
    legend(h.axes(7),'ATT CTRL Roll [-1..+1]','ATT CTRL Pitch [-1..+1]','ATT CTRL Yaw [-1..+1]','ATT CTRL Thrust [0..+1]');
    %Actuator Controls
    plot(h.axes(8),time(imintime:imaxtime), [sysvector.OUT0_Out0(imintime:imaxtime), sysvector.OUT0_Out1(imintime:imaxtime), sysvector.OUT0_Out2(imintime:imaxtime), sysvector.OUT0_Out3(imintime:imaxtime), sysvector.OUT0_Out4(imintime:imaxtime), sysvector.OUT0_Out5(imintime:imaxtime), sysvector.OUT0_Out6(imintime:imaxtime), sysvector.OUT0_Out7(imintime:imaxtime)]);
    title(h.axes(8),'Actuator PWM (raw-)outputs [s]');
    legend(h.axes(8),'CH1','CH2','CH3','CH4','CH5','CH6','CH7','CH8');
    set(h.axes(8), 'YLim',[800 2200]);
    %Airspeeds
    plot(h.axes(9),time(imintime:imaxtime), sysvector.AIRS_IndSpeed(imintime:imaxtime));
    hold on
    plot(h.axes(9),time(imintime:imaxtime), sysvector.AIRS_TrueSpeed(imintime:imaxtime));
    hold off
    %add GPS total airspeed here
    title(h.axes(9),'Airspeed [m/s]');
    legend(h.axes(9),'Indicated Airspeed (IAS)','True Airspeed (TAS)','GPS Airspeed');
    %calculate time differences and plot them
    intervals = zeros(0,imaxtime - imintime);
    for k = imintime+1:imaxtime
        intervals(k) = time(k) - time(k-1);
    end
    plot(h.axes(10), time(imintime:imaxtime), intervals);

    %Set same timescale for all plots
    for i=2:NrAxes
        set(h.axes(i),'XLim',[mintime maxtime]);
    end
    
    set(h.labels.GUIState,'String','OK','BackgroundColor',[240/255 240/255 240/255]);
end

%% ************************************************************************
%  DRAWCURRENTAIRCRAFTSTATE(nested function)
%  ************************************************************************
function DrawCurrentAircraftState()
    %find current data index        
    i=find(time>=CurTime,1,'first');

    %**********************************************************************
    % Current aircraft state label update
    %**********************************************************************
    acstate{1,:}=[sprintf('%s \t\t','GPS Pos:'),'[lat=',num2str(double(sysvector.GPS_Lat(i))*fconv_gpslatlong),'�, ',...
                        'lon=',num2str(double(sysvector.GPS_Lon(i))*fconv_gpslatlong),'�, ',...
                        'alt=',num2str(double(sysvector.GPS_Alt(i))*fconv_gpsalt),'m]'];
    acstate{2,:}=[sprintf('%s \t\t','Mags[gauss]'),'[x=',num2str(sysvector.IMU_MagX(i)),...
                               ', y=',num2str(sysvector.IMU_MagY(i)),...
                               ', z=',num2str(sysvector.IMU_MagZ(i)),']'];
    acstate{3,:}=[sprintf('%s \t\t','Accels[m/s]'),'[x=',num2str(sysvector.IMU_AccX(i)),...
                               ', y=',num2str(sysvector.IMU_AccY(i)),...
                               ', z=',num2str(sysvector.IMU_AccZ(i)),']'];
    acstate{4,:}=[sprintf('%s \t\t','Gyros[rad/s]'),'[x=',num2str(sysvector.IMU_GyroX(i)),...
                               ', y=',num2str(sysvector.IMU_GyroY(i)),...
                               ', z=',num2str(sysvector.IMU_GyroZ(i)),']'];
    acstate{5,:}=[sprintf('%s \t\t','Altitude[m]'),'[Barometric: ',num2str(sysvector.SENS_BaroAlt(i)),'m, GPS: ',num2str(double(sysvector.GPS_Alt(i))*fconv_gpsalt),'m]'];
    acstate{6,:}=[sprintf('%s \t','Est. attitude[deg]:'),'[Roll=',num2str(sysvector.ATT_Roll(i).*180./3.14159),...
                               ', Pitch=',num2str(sysvector.ATT_Pitch(i).*180./3.14159),...
                               ', Yaw=',num2str(sysvector.ATT_Yaw(i).*180./3.14159),']'];
    acstate{7,:}=sprintf('%s \t[','Actuator Ctrls [-]:');
    %for j=1:4
    acstate{7,:}=[acstate{7,:},num2str(sysvector.ATTC_Roll(i)),','];
    acstate{7,:}=[acstate{7,:},num2str(sysvector.ATTC_Pitch(i)),','];
    acstate{7,:}=[acstate{7,:},num2str(sysvector.ATTC_Yaw(i)),','];
    acstate{7,:}=[acstate{7,:},num2str(sysvector.ATTC_Thrust(i)),','];
    %end
    acstate{7,:}=[acstate{7,:},']'];
    acstate{8,:}=sprintf('%s \t[','Actuator Outputs [PWM/s]:');
    %for j=1:8
    acstate{8,:}=[acstate{8,:},num2str(sysvector.OUT0_Out0(i)),','];
    acstate{8,:}=[acstate{8,:},num2str(sysvector.OUT0_Out1(i)),','];
    acstate{8,:}=[acstate{8,:},num2str(sysvector.OUT0_Out2(i)),','];
    acstate{8,:}=[acstate{8,:},num2str(sysvector.OUT0_Out3(i)),','];
    acstate{8,:}=[acstate{8,:},num2str(sysvector.OUT0_Out4(i)),','];
    acstate{8,:}=[acstate{8,:},num2str(sysvector.OUT0_Out5(i)),','];
    acstate{8,:}=[acstate{8,:},num2str(sysvector.OUT0_Out6(i)),','];
    acstate{8,:}=[acstate{8,:},num2str(sysvector.OUT0_Out7(i)),','];
    %end
    acstate{8,:}=[acstate{8,:},']'];
    acstate{9,:}=[sprintf('%s \t','Airspeed[m/s]:'),'[IAS: ',num2str(sysvector.AIRS_IndSpeed(i)),', TAS: ',num2str(sysvector.AIRS_TrueSpeed(i)),']'];
    
    set(h.edits.AircraftState,'String',acstate);
    
    %**********************************************************************
    % GPS Plot Update
    %**********************************************************************
    %Plot traveled path, and  and time.
    figure(h.figures(2));
    hold on;
    if(CurTime>mintime+1) %the +1 is only a small bugfix
        h.pathline=plot3(h.axes(1),double(sysvector.GPS_Lat(imintime:i))*fconv_gpslatlong, ...
                                    double(sysvector.GPS_Lon(imintime:i))*fconv_gpslatlong, ...
                                    double(sysvector.GPS_Alt(imintime:i))*fconv_gpsalt,'b','LineWidth',2); 
    end;
    hold off
    %Plot current position
    newpoint=[double(sysvector.GPS_Lat(i))*fconv_gpslatlong double(sysvector.GPS_Lat(i))*fconv_gpslatlong double(sysvector.GPS_Alt(i))*fconv_gpsalt];
    if(numel(h.pathpoints)<=3) %empty path
        h.pathpoints(1,1:3)=newpoint;
    else %Not empty, append new point 
        h.pathpoints(size(h.pathpoints,1)+1,:)=newpoint;
    end
    axes(h.axes(1));    
    line(h.pathpoints(:,1),h.pathpoints(:,2),h.pathpoints(:,3),'LineStyle','none','Marker','.','MarkerEdge','black','MarkerSize',20);
    
    
    % Plot current time (small label next to current gps position) 
    textdesc=strcat('  t=',num2str(time(i)),'s');
    if(isvalidhandle(h.markertext))
            delete(h.markertext); %delete old text
    end 
    h.markertext=text(double(sysvector.GPS_Lat(i))*fconv_gpslatlong,double(sysvector.GPS_Lon(i))*fconv_gpslatlong,...
                        double(sysvector.GPS_Alt(i))*fconv_gpsalt,textdesc);
    set(h.edits.CurTime,'String',CurTime);
        
    %**********************************************************************
    % Plot the lines showing the current time in the 2-d plots
    %**********************************************************************
    for i=2:NrAxes
        if(isvalidhandle(h.markerline(i))) delete(h.markerline(i)); end
        ylims=get(h.axes(i),'YLim');
        h.markerline(i)=line([CurTime CurTime] ,get(h.axes(i),'YLim'),'Color','black');
        set(h.markerline(i),'parent',h.axes(i));
    end
    
    set(h.labels.GUIState,'String','OK','BackgroundColor',[240/255 240/255 240/255]);
end

%% ************************************************************************
%  MINMAXTIME CALLBACK (nested function)
%  ************************************************************************
function minmaxtime_callback(hObj,event) %#ok<INUSL>
    new_mintime=get(h.sliders.MinTime,'Value');
    new_maxtime=get(h.sliders.MaxTime,'Value');

    %Safety checks:
    bErr=false;
    %1: mintime must be < maxtime
    if((new_mintime>maxtime) || (new_maxtime<mintime))
        set(h.labels.GUIState,'String','Error: Mintime cannot be bigger than maxtime! Values were not changed.','BackgroundColor','red');
        bErr=true;
    else
        %2: MinTime must be <=CurTime
        if(new_mintime>CurTime)
            set(h.labels.GUIState,'String','Error: Mintime cannot be bigger than CurTime! CurTime set to new mintime.','BackgroundColor','red');
            mintime=new_mintime;
            CurTime=mintime;
            bErr=true;
        end
        %3: MaxTime must be >CurTime
        if(new_maxtime<CurTime)
            set(h.labels.GUIState,'String','Error: Maxtime cannot be smaller than CurTime! CurTime set to new maxtime.','BackgroundColor','red');
            maxtime=new_maxtime;
            CurTime=maxtime;
            bErr=true;
        end
    end

    if(bErr==false)
        maxtime=new_maxtime;
        mintime=new_mintime;
    end

    %Needs to be done in case values were reset above
    set(h.sliders.MinTime,'Value',mintime);
    set(h.sliders.MaxTime,'Value',maxtime);

    %Update curtime-slider
    set(h.sliders.CurTime,'Value',CurTime);
    set(h.sliders.CurTime,'Max',maxtime);
    set(h.sliders.CurTime,'Min',mintime);
    temp=get(h.sliders.CurTime,'Max')-get(h.sliders.CurTime,'Min'); 
    set(h.sliders.CurTime,'SliderStep',[1.0/temp 5.0/temp]);  %Set Stepsize to constant [in seconds]

    %update edit fields
    set(h.edits.CurTime,'String',get(h.sliders.CurTime,'Value'));
    set(h.edits.MinTime,'String',get(h.sliders.MinTime,'Value'));
    set(h.edits.MaxTime,'String',get(h.sliders.MaxTime,'Value'));

    %Finally, we have to redraw. Update time indices first.
    [imintime,imaxtime]=FindMinMaxTimeIndices();
    DrawRawData();                  %Rawdata only
    DrawCurrentAircraftState();     %path info & markers
end


%% ************************************************************************
%  CURTIME CALLBACK (nested function)
%  ************************************************************************
function curtime_callback(hObj,event) %#ok<INUSL>
    %find current time
    if(hObj==h.sliders.CurTime)
        CurTime=get(h.sliders.CurTime,'Value');
    elseif (hObj==h.edits.CurTime)
        temp=str2num(get(h.edits.CurTime,'String'));
        if(temp<maxtime && temp>mintime)
            CurTime=temp;
        else
            %Error
            set(h.labels.GUIState,'String','Error: You tried to set an invalid current time! Previous value restored.','BackgroundColor','red');
        end
    else
        %Error
        set(h.labels.GUIState,'String','Error: curtime_callback','BackgroundColor','red');        
    end
    
    set(h.sliders.CurTime,'Value',CurTime);
    set(h.edits.CurTime,'String',num2str(CurTime));
    
    %Redraw time markers, but don't have to redraw the whole raw data
    DrawCurrentAircraftState();
end

%% ************************************************************************
%  FINDMINMAXINDICES (nested function)
%  ************************************************************************
function [idxmin,idxmax] = FindMinMaxTimeIndices()
    for i=1:size(sysvector.TIME_StartTime,1)
        if time(i)>=mintime; idxmin=i; break; end
    end
    for i=1:size(sysvector.TIME_StartTime,1)
        if maxtime==0; idxmax=size(sysvector.TIME_StartTime,1); break; end
        if time(i)>=maxtime; idxmax=i; break; end
    end
    mintime=time(idxmin); 
    maxtime=time(idxmax);
end

%% ************************************************************************
%  ISVALIDHANDLE (nested function)
%  ************************************************************************
function isvalid = isvalidhandle(handle)
   if(exist(varname(handle))>0 && length(ishandle(handle))>0) 
        if(ishandle(handle)>0)
            if(handle>0.0)
                isvalid=true;
                return;
            end
        end
   end
   isvalid=false;
end

%% ************************************************************************
%  JUST SOME SMALL HELPER FUNCTIONS (nested function)
%  ************************************************************************
function out = varname(var)
   out = inputname(1);
end

%This is the end of the matlab file / the main function
end