forked from WilliamCooper/KalmanFilter
-
Notifications
You must be signed in to change notification settings - Fork 2
/
WorkflowKalmanFilter.Rnw
1653 lines (1446 loc) · 80.9 KB
/
WorkflowKalmanFilter.Rnw
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
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
%% LyX 2.2.2 created this file. For more info, see http://www.lyx.org/.
%% Do not edit unless you really know what you are doing.
\documentclass[12pt,british,english]{article}
\usepackage{mathptmx}
\usepackage[T1]{fontenc}
\usepackage[letterpaper]{geometry}
\geometry{verbose,tmargin=3.54cm,bmargin=2.54cm,lmargin=2.54cm,rmargin=2.54cm,headheight=1cm,headsep=2cm,footskip=0.5cm}
\usepackage{fancyhdr}
\pagestyle{fancy}
\setcounter{secnumdepth}{2}
\setcounter{tocdepth}{2}
\setlength{\parskip}{\medskipamount}
\setlength{\parindent}{0pt}
\usepackage{color}
\usepackage{babel}
\usepackage{varioref}
\usepackage{calc}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{graphicx}
\usepackage[authoryear]{natbib}
\PassOptionsToPackage{normalem}{ulem}
\usepackage{ulem}
\usepackage[unicode=true]
{hyperref}
\usepackage{breakurl}
\makeatletter
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LyX specific LaTeX commands.
\providecommand{\LyX}{\texorpdfstring%
{L\kern-.1667em\lower.25em\hbox{Y}\kern-.125emX\@}
{LyX}}
%% Because html converters don't know tabularnewline
\providecommand{\tabularnewline}{\\}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands.
\newenvironment{lyxcode}
{\par\begin{list}{}{
\setlength{\rightmargin}{\leftmargin}
\setlength{\listparindent}{0pt}% needed for AMS classes
\raggedright
\setlength{\itemsep}{0pt}
\setlength{\parsep}{0pt}
\normalfont\ttfamily}%
\item[]}
{\end{list}}
\newenvironment{lyxlist}[1]
{\begin{list}{}
{\settowidth{\labelwidth}{#1}
\setlength{\leftmargin}{\labelwidth}
\addtolength{\leftmargin}{\labelsep}
\renewcommand{\makelabel}[1]{##1\hfil}}}
{\end{list}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands.
\input colordvi
\usepackage{color}
\fancyhead{}
\fancyfoot[CE,CO]{}
\newtoks{\addressee} \global\addressee={}
\newdimen\longindent \longindent=3.5truein
\fancyhead[L]{Memo to: \the\addressee \\ \datetoday \\ Page \thepage \hfill}
\renewcommand{\headrulewidth}{0.0pt}
\newenvironment{lylist}[1]
{\begin{list}{}
{\settowidth{\labelwidth}{#1}
\setlength{\leftmargin}{\labelwidth}
\addtolength{\leftmargin}{\labelsep}
\renewcommand{\makelabel}[1]{##1\hfil}}}
{\end{list}}
\newcommand{\datetoday}{\number\day\space
\ifcase\month\or January\or February\or March\or April\or May\or
June\or July\or August\or September\or October\or November\or
December\fi
\space\number\year}
\newcommand{\EOLmemo}{\null \vskip-1.5truein
{\raggedright \textsf{\textsc{\large \textcolor{blue}{Earth Observing Laboratory}}}}\par
{\raggedright \textsf{\textsl{\textcolor{blue}{Memorandum:}}}} \par \vskip6pt
{\color{blue}{\hrule}}\par
\vskip0.3truein \leftline{\hskip \longindent \datetoday} \vskip0.2truein
\thispagestyle{empty}}
\newcommand{\attachm}[1]{\begin{lylist}{Attachments:00}
\item [Attachments:] {#1}
\end{lylist}}
\newcommand{\cc}[1]{\begin{lylist}{Attachments:00}
\item [cc:] {#1}
\end{lylist}}
\newcommand{\attach}[1]{\begin{lylist}{Attachments:00}
\item [Attachment:] {#1}
\end{lylist}}
%usage: \encl{A\\B\\C} or \cc{ma,e1\\name2\\name3}
\makeatother
\begin{document}
\EOLmemo
\global\addressee={KalmanFilter archive: workflow document} % >>change "File" to the "To:" name desired
\begin{tabular}{ll}
\textsf{\textsc{\textcolor{blue}{To:}}} & \the\addressee\tabularnewline
\textsf{\textsc{\textcolor{blue}{From:}}} & William Cooper\tabularnewline
\textsf{\textsc{\textcolor{blue}{Subject:}}} & workflow for generating the Kalman filter Tech. Note\tabularnewline
\end{tabular}
\bigskip
<<initialization,echo=FALSE,include=FALSE>>=
library(knitr)
opts_chunk$set(echo=FALSE, include=FALSE, fig.lp="fig:")
opts_chunk$set(fig.width=6, fig.height=5, fig.pos="center", digits=4)
thisFileName <- "WorkflowAttitudeAngleNote"
require(Ranadu, quietly = TRUE, warn.conflicts=FALSE)
require(ggplot2)
require(grid)
require(ggthemes)
Directory <- DataDirectory ()
Flight <- "rf01" # XXX change this
Project = "DEEPWAVE" # XXX change this
ProjectDir <- "DEEPWAVE"
fname = sprintf("%s%s/%s%s.nc", Directory,ProjectDir,Project,Flight)
Data <- getNetCDF (fname, standardVariables()) #XXX set variables needed here
SaveRData <- sprintf("%s.Rdata", thisFileName)
@
\section{Purpose}
This workflow description documents the steps leading to the code
in ``KalmanFilterTechNote.Rnw'' and provides additional detail not
in the report ``KalmanFilterTechNote.pdf.'' KalmanFilterTechNote.Rnw
contains both text (in \LaTeX{} format) and R processing script for
the analyses in the resulting report on the development of a Kalman
filter for use with measurements from the NSF/NCAR Gulfstream V research
aircraft. The description of workflow provided here includes the process
of collecting the observations and processing them to data files,
the data archives used, the steps required to generate the plots and
other results including the instances where manual intervention is
required to identify appropriate subsets of the data, the relevant
R code and \LaTeX{} documents, and all the steps leading to the generation
of the text in the technical note. \textquotedbl{}KalmanFilterTechNote.Rnw\textquotedbl{}
is the definitive reference, but this overview and these diagrams
will help explain the workflow at a general level and so should substitute
for reading the R and \LaTeX{} code in most cases. The intent is
to describe the workflow in sufficient detail to support replication
of the analysis and figures presented in the report, to facilitate
changes based on new data or new analysis approaches, and to make
it practical to apply the proposed algorithms to data collected by
research aircraft used in atmospheric studies.
The document is intended for publication as an NCAR Technical Note.
Some parts may be suitable to accompany a separate journal article
that describes alternate and simpler methods for correcting attitude
angles. Both this document and that proposed publication augment the
material presented in the NCAR Technical Note ``Uncertainty in Measurements
of Wind from the NSF/NCAR Gulfstream Aircraft'' \citet{Cooper2016ncartn}.
\section{Acquisition of the primary data}
The measurements used in this report were collected using the NSF/NCAR
GV research aircraft during the DEEPWAVE project of 2014. The onboard
data-acquisition program 'aeros' recorded the data in digital format,
and those data files were then processed by the program 'nimbus' to
produce an archive in NetCDF format. The software management group
of NCAR/EOL maintains a version-controlled archive of these programs,
so if they are of interest they can be obtained by contacting the
data-management group of EOL (\href{mailto:[email protected]}{at this }
or \href{mailto:[email protected]}{this} address). The data files
available from NCAR/EOL can be found at links on \href{https://www.eol.ucar.edu/all-field-projects-and-deployments}{this URL}.
The details of the processing algorithms including those for the calculation
of wind are documented in this report on \href{https://drive.google.com/open?id=0B1kIUH45ca5Ab2Z6cld1M1cydjA}{Processing Algorithms}
and in \citet{Bulletin23}. These procedures as they pertain to the
measurement of wind are also documented in \citet{Cooper2016ncartn}.
The resulting data files contain measurements in scientific units
and brief descriptions of each measurement, included as netCDF attributes
for the files and for each variable.
One special file was generated and used in KalmanFilterTechNote.Rnw,
a netCDF file named DWIRUrf15HR.nc. It was generated by the program
nimbus (version of January 2016) by specifying a 25-Hz data rate and
by including the variables needed for the ``mechanization'' described
in this report. That file is not part of the standard project archives
and so must be obtained separately, as described in the ``Reproducibility''
appendix to the report, but as used it is also saved as KalmanFilterTechNote.Rdata
and can be used in that condensed form in the reference program.
\section{The KalmanFilterTechNote.Rnw file}
The .Rnw file is basically \LaTeX{} text, generated for simplicity
using \LyX{} and exported to .Rnw format and then processed in RStudio
(\citet{RStudio2012}). The .lyx file (KalmanFilterTechNote.lyx) will
run equivalently and produce a PDF-format version of the manuscript.
Within the .Rnw file or within the .lyx file there are ``chunks''
of R code (\citet{Rlanguage}), delineated by a header having this
format:
\begin{lyxcode}
\fbox{\begin{minipage}[t]{1\columnwidth - 2\fboxsep - 2\fboxrule}%
\begin{lyxcode}
<\textcompwordmark{}<title,~var=setting,~...>\textcompwordmark{}>=
...R~code...
@
\end{lyxcode}
%
\end{minipage}}
\end{lyxcode}
These chunks generate plots and other results of analyses that are
incorporated into the manuscript using 'knitr' (\citet{Xie2014a,Xie2014b}).
In RStudio, the chunks appear as gray sections in the file when it
is edited. Where tasks involve execution of R code, the chunk containing
the code is referenced in the discussion below. Any results from the
processing can be incorporated into the \LaTeX{} text via ``\textbackslash{}Sexpr\{\}''
calls embedded in the \LaTeX{} portion of the file.
Two ``switches'' serve to speed execution of the code: (1) ``ReloadData,''
which when TRUE causes the original archive data files to be read;
and the option ``CACHE'' which, when true, causes previously generated
subsets of the results to be re-used as saved in a subdirectory ``cache.''
Both are provided to speed execution in cases where small changes
are made. When ReloadData is FALSE subsets of data files previously
saved as ``Rdata'' files are restored to R data.frames, a process
that is much faster than re-reading the original archive data file.
If cache is FALSE all calculations are performed, but using ``cache=TRUE''
is usually much faster after the first run. To ensure a clean run,
set CACHE to be FALSE and remove all entries from the ``cache''
subdirectory.
After an introductory section, the program and the report are organized
into three main sections: (1) calculation of the derivative of the
state vector (position, aircraft velocity, and aircraft attitude angles)
from the measured accelerations and rotation rates, leading to a trial
``mechanization'' for validation by comparison to the INS-provided
solution; (2) a set of special topics that deal with component studies
like improvement in the variables used for rate of climb and angle
of attack and retrieval of the original measurements from data archives
where they are missing; and (3) a description of the Kalman filter
itself, with illustrative results. These sections are discussed in
detail in this workflow document, which is in turn generated by a
\LyX{} file (``WorkflowKalmanFilter.lyx''). There is additional
material and code at the end that adds the new variables to the data
archive after correction by the Kalman filter.
A top-level workflow diagram for the Kalman filter technical is presented
in Fig.~\ref{fig:Kalman-filter-workflow}. The Table of Contents
in the technical note provides an overview of the structure of the
document, while Fig.~\ref{fig:Kalman-filter-workflow} focuses more
on the logical flow of the routine that generates both the technical
note and a new data file containing the measurements as corrected
by the Kalman filter.
\begin{figure}
\begin{centering}
\includegraphics[width=0.9\textwidth]{FlowDiagrams/FlowChartKalmanFilterTN}
\par\end{centering}
\caption{Top-level workflow diagram for the Kalman filter technical note. Some
items (e.g., ``run the main Kalman-filter loop'') are described
in additional workflow diagrams below. \label{fig:Kalman-filter-workflow}}
\end{figure}
Some sections (mechanization, retrieval of IRU-provided measurements,
simplified correction functions, and the Kalman-filter loop) have
their own workflow diagrams in the sections where they are discussed.
\section{Required R packages including Ranadu}
The R code used for analysis reported in this paper relies heavily
on a package of routines for R called ``Ranadu.'' This is a set
of R scripts for working with the NetCDF archive data files produced
by NCAR/EOL/RAF, and it includes some convenience routines for generating
plots and performing other data-analysis tasks with the archived data.
The Ranadu package is available at this \href{https://github.com/WilliamCooper/Ranadu.git}{GitHub address}.
To run the R code referenced here, that package should be included
in the R installation. The KalmanFilterTechNote.Rnw routine requires
that package and also some others referenced in the file, including
``knitr'', ``ggplot2'', ``grid'', ``ggthemes'', ``zoo'',
``signal'' and ``numDeriv''. In addition, Ranadu requires ``ncdf4'',
``tcltk'' and ``stats''. Some parts of ``Ranadu'' reference
additional packages as needed, but they are not used in KalmanFilter.Rnw
so do not need to be available for this routine to run.
The data processing for this manuscript involved revising some parts
of the Ranadu package, as listed below. The relative timing among
measurements is particularly important in this study, so some development
of utilities to aid in studies of timing was useful. The netCDF files
sometimes have mixed rates, e.g., 5\_Hz for GPS-provided measurements
and 25~Hz for some others including interpolation to 25~Hz from
13~Hz for IRS-provided measurements. In ``Ranadu'', this is handled
appropriately in the ``getNetCDF()'' routine, sometimes with the
``ShiftInTime()'' routine to adjust for delays among the variables
and the ``SmoothInterp()'' routine to interpolate for missing values
and smooth the variables. Most of the plots are generated using ``ggplotWAC()''
or ``plotWAC()'', which are simple convenience routines that set
various options preferred by the author before calling the R ``ggplot()''
or ``plot()'' routines.
\subsection{Ranadu::getNetCDF () modifications}
To handle data files with mixed-rate variables (e.g., 5-Hz GPS but
25-Hz IRS and others at 1 Hz), this script for reading the netCDF
data files incorporates code to produce a single-rate R data.frame.
For this purpose, there is a function ``IntFilter()'' in that script
that interpolates and filters variables. The RAF data archives follow
the convention that each sample is tagged with a time that is the
\emph{beginning} of the time interval, not the center. For example,
for 50-Hz samples averaged to one second, the recorded variable represents
the average of 50 samples beginning at the specified time and so should
be interpreted as a sample average at 0.5~s past that specified time.
The ``IntFilter()'' routine observes this convention by interpolating
a low-rate sample to the specified higher rate and then shifting the
resulting time series forward in time by half the original time interval,
with duplication of the first measurement to fill the initial 1/2-period
slots and also replication of the trailing 1/2-period slots that are
not filled by the linear interpolation routine. Tests verified that
this provided an appropriate representation of the measurement as
interpolated to the higher rate and shifted forward to match other
higher-rate measurements.
\subsection{Ranadu::ShiftInTime ()\label{subsec:ShiftInTime}}
To shift time series variables forward or backward, this new function
was added to the ``Ranadu'' package. The function interpolates the
supplied time series to a higher rate (125~Hz), uses the R function
``stats::approx()'' for linear interpolation, shifts the interpolated
series an appropriate number of bins forward or backward (duplicating
or truncating the end values as necessary), optionally applies a Savitzgky-Golay
smoothing filter, and then returns an appropriate subset to represent
the shifted time series at the original sample rate.
\subsection{Ranadu::XformLA ()\label{subsec:XformLA}}
At many places the mechanization and Kalman-filter algorithms require
transformation from the aircraft or $a$-frame reference coordinates
to a local-level Earth-relative frame or $l$-frame in which the \{x,
y, z\} coordinates are respectively east, north, and up. This transformation
was coded as a new ``Ranadu'' function. This function takes as input
a data.frame containing the attitude angles measured by the INS in
variables named PITCH, ROLL, and THDG (true heading), all in units
of degrees. It transforms an $a$-frame vector to an $l$-frame vector
and returns the result. It would be preferable to do this in vectorized
form, but such a representation hasn't yet been found, so the function
uses a loop. As noted in the routine, the approach using R 'apply()'
functions was slower than the loop, but that is because the specific
approach tried here is likely unnecessarily convoluted. This is an
area of needed improvement, but the loop as coded is practical and
adequate for this study. The routine also accepts an ``inverse''
argument with default value FALSE; when true, the transformation is
from the \emph{l-}frame to the \emph{a-}frame instead.
The transformation coded in this routine was obtained in standard
ways using rotations $\phi$ about the roll axis, then $\theta$ about
the pitch axis, and then $\psi$ about the heading axis. The text
lists sources for this transformation, but they differ from the matrix
used here in that this transformation starts from what is called here
the $a$-frame or aircraft reference frame with $x$ forward, $y$
starboard, and $z$ downward and transforms to the local frame or
$l$-frame with $x$ east, $y$ north, and $z$ upward. The transformation
matrix $\mathbf{R}_{a}^{l}$ is obtained as follows, where the first
matrix changes the axis definitions:\\
\[
\mathbf{R}_{a}^{l}=\left(\begin{array}{ccc}
0 & 1 & 0\\
1 & 0 & 0\\
0 & 0 & -1
\end{array}\right)\left(\begin{array}{ccc}
\cos\psi & -\sin\psi & 0\\
\sin\psi & \cos\psi & 0\\
0 & 0 & 1
\end{array}\right)\left(\begin{array}{ccc}
\cos\theta & 0 & -\sin\theta\\
0 & 1 & 0\\
\sin\theta & 0 & \cos\theta
\end{array}\right)\left(\begin{array}{ccc}
1 & 0 & 0\\
0 & \cos\phi & \sin\phi\\
0 & -\sin\phi & \cos\phi
\end{array}\right)
\]
\\
\begin{equation}
R_{a}^{l}=\begin{bmatrix}\sin\psi\cos\theta & \sin\psi\sin\theta\sin\phi+\cos\psi\cos\phi & \cos\psi\sin\phi-\sin\psi\sin\theta\cos\phi\\
\cos\psi\cos\theta & \cos\psi\sin\theta\sin\phi-\sin\psi\cos\phi & -\cos\psi\sin\theta\cos\phi-\sin\psi\sin\phi\\
-\sin\theta & \cos\theta\sin\phi & -\cos\theta\cos\phi
\end{bmatrix}\label{eq:XformLA}
\end{equation}
Two references for this transformation are listed in the manuscript.
As checks, the transformations given in those two references (Eq.~2.6
in \citet{Bulletin23} and Eq.~2-82 in \citet{noureldin2013fundamentals})
were further transformed to give directly the $a$-frame-to-$l$-frame
transformation, with signs of rotation angles as required, and each
led to (\ref{eq:XformLA}).
It seemed useful to check that this transformation gives $l$-frame
accelerations in reasonable agreement with those measured by GPS,
so several checks were performed. One, reported in the manuscript,
used a circle maneuver flown during DEEPWAVE research flight 15. The
circle maneuvers are discussed in considerable detail in Sect.~7.1
of \citet{Cooper2016ncartn}, where plots of the flight track in a
coordinate frame drifting with the wind show that the Lagrangian tracks
are close approximations to circles. They were flown under control
of the flight management system of the aircraft, which was able to
maintain constant roll angle to a tolerance of a fraction of a degree.
Two circles were flown in left turns, then two additional circles
were flown in right turns. The ground-speed components measured by
GPS were differentiated to obtain reference measurements of the corresponding
acceleration components, again using the approach of replacing missing
values by interpolation and then using fitted Savitzgy-Golay polynomials
to find the derivatives. In this case, because the conditions changed
too rapidly for the long extents used in the pitch-correction algorithm,
the length of the polynomials was reduced to 21 1-Hz measurements
for the horizontal components and 7 1-Hz measurements for the vertical
component of acceleration. The results are shown in Fig.~1 of the
technical note. The agreement through several maneuvers supports the
validity of the transformation used to determing \emph{l-}frame transformations
from the measured accelerations in the \emph{a-}frame.
Several other checks were performed also but have not been described
in the manuscript. One important case was to consider a pitch maneuver
in which the pitch was varied cyclically with about a 20-s period,
with wings level but with airspeed and altitude varying. The maneuver
flown on DEEPWAVE flight 15, 4:25:00\textendash 4:28:30 UTC, showed
strong oscillations in the vertical acceleration, and again the body
accelerations transformed to the $l$-frame matched will the accelerations
deduced from the changes in vertical speed measured by the GPS receiver.
\section{Comments on ``The components of the derivatives''}
The calculations are explained in the document, but it may be useful
to elaborate on some of the choices that were made in regard to corrections
for inertial effects. Such corrections enter during calculation of
the accelerations and again during calculations of the rate of change
in attitude angles.
\subsection{Position derivative}
The position state variables are latitude, longitude, and altitude.
Their derivatives are related to the velocity state variable as follows
(cf.~\citet[pages 47--48 and 175]{noureldin2013fundamentals}):
\begin{enumerate}
\item $d\lambda/dt=v_{n}/(R_{m}+z)$ where $\lambda$ is the latitude, $v_{n}$
is the northward ground speed of the aircraft, $z$ the altitude,
and $R_{m}$ the radius of the Earth about a meridional circle, taken
to be\\
\begin{equation}
R_{m}=R_{e}\frac{(1-\epsilon^{2})}{(1-\epsilon^{2}\sin^{2}\lambda)^{3/2}}\label{eq:Rm}
\end{equation}
with the equatorial radius $R_{e}=6378137\,$m and the Earth's eccentricity
$\epsilon=0.08181919.$
\begin{enumerate}
\item $d\Psi/dt=v_{e}/((R_{n}+z)\cos\lambda)$ where $\Psi$ is the longitude,
$v_{e}$ is the eastward ground speed of the aircraft, and $R_{n}$
the normal radius of the Earth's ellipsoid, taken to be\\
\begin{equation}
R_{n}=R_{e}\frac{1}{(1-\epsilon^{2}\sin^{2}\lambda)^{1/2}}\,\,\,\,\,.\label{eq:Rn}
\end{equation}
\item $dz/dt=v_{u}$ where $v_{u}$ is the vertical component of the aircraft
motion. For the Kalman filter, the new variable ``ROC'' will be
used for $v_{u}$; for the trial mechanization to duplicate the INS
integration, the INS-provided variable VSPD was used.
\end{enumerate}
\end{enumerate}
\subsection{Velocity derivative (acceleration)}
There are two corrections needed if the accelerations measured in
the a-frame are to be used in the l-frame. First, a correction must
be made for the Coriolis acceleration that arises from motion relative
to a spherical Earch. In addition, a correction is needed because
the l-frame itself moves and remains oriented to match the local-level
orientation. Evaluation of the typical magnitudes arising from the
inertial terms indicates that the corrections are minor but not negligible,
and their omission leads to significant accumulated errors during
mechanization.
The Coriolis acceleration is\\
\begin{equation}
\boldsymbol{C}_{c}=-2\boldsymbol{\Omega}_{e}\times\boldsymbol{V}\label{eq:Coriolis}
\end{equation}
where $\boldsymbol{\Omega_{e}}$ is the angular rotation rate of the
Earch and $\boldsymbol{V}$ is the velocity of the aircraft relative
to the Earth.
In the R code, this equation and others involving vector cross products
are represented by skew-symmetric matrices, so this choice merits
some explanation. Strangely, core R mathematical functions do not
include the cross product needed by (\ref{eq:Coriolis}). Instead,
in R, the ``cross product'' has a different meaning. Of course,
there are many solutions that contributors have produced that could
be used, but it seemed awkward to use a non-standard package for such
a basic function and it seemed appropriate to select a solution that
ensured reproducibility in the future. The representation of the cross
product via a skew-symmetric matrix provides such a solution, but
it is likely to be unfamiliar to many readers so an elaboration is
provided here: If an angular-rotation vector has coordinates $\boldsymbol{{\bf \omega}}=(\omega_{1},\,\omega_{2},\,\omega_{3})$
then the skew-symmetric representation is \\
\begin{equation}
\boldsymbol{S}=\left(\begin{array}{ccc}
0 & -\omega_{3} & \omega_{2}\\
\omega_{3} & 0 & -\omega_{1}\\
-\omega_{2} & \omega_{1} & 0
\end{array}\right)\label{eq:skew-symmetric}
\end{equation}
Then the cross produce $\boldsymbol{\omega}\times\boldsymbol{\mathbf{V}}$
can be found by matrix multiplication via $\boldsymbol{S\thinspace V}$
with $\boldsymbol{V}$ the column matrix representing the velocity.
This equality can be verified by comparing the result of the matrix
multiplication to the standard formula for the vector product. In
particular, the vector representing the rotation of the Earth ($\omega_{ie}^{l}$,
where the notation denotes the rotation rate of the Earth relative
to an inertial frame, as observed in the l-frame) has components (0,
$\omega_{e}\cos\lambda,$ $\omega_{e}\sin\lambda$) where $\omega_{e}$
is the rotation rate and $\lambda$ is the latitude, so the Coriolis
acceleration can be represented by\\
\begin{equation}
\boldsymbol{C}_{c}=-2\omega_{e}\left(\begin{array}{ccc}
0 & -\sin\lambda & \cos\lambda\\
\sin\lambda & 0 & 0\\
-\cos\lambda & 0 & 0
\end{array}\right)\left(\begin{array}{c}
V_{1}\\
V_{2}\\
V_{3}
\end{array}\right)\label{eq:Cor-matrix}
\end{equation}
This is the form chosen to represent the Coriolis acceleration in
the derivative function.
\citet{noureldin2013fundamentals}, p.~179, give the components of
the rotation rate of the l-frame relative to the Earth, as expressed
in the l-frame, as $\omega_{el}^{l}=(-V_{2}/(R_{m}+h),\,V_{1}/(R_{n}+h),\,V_{1}\tan\lambda/(R_{n}+h)$
where $R_{m}$ and $R_{n}$ are respectively the meridional and normal
radii of the earth, and $h$ is the altitude above the Earth. Expressed
as a skew-symmetric matrix, this is the other component used to correct
the measured accelerations when transforming from the a-frame to the
l-frame. The resulting equation for the required correction can be
expressed as follows:\\
\begin{equation}
\mathbf{\Delta\boldsymbol{\dot{\mathbf{v}}}=}-(2\boldsymbol{\Omega}_{ie}^{l}+\boldsymbol{\Omega}_{el}^{l})\mathbf{v}^{(l)}\label{eq:rotation-correction}
\end{equation}
where the rotation matrices, respectively representing the Earth's
rotation and the $l$-frame rotation, are\\
\begin{equation}
\boldsymbol{\Omega}_{ie}^{l}=\left[\begin{array}{ccc}
0 & -\omega^{e}\sin\lambda & \omega^{e}\cos\lambda\\
\omega^{e}\sin\lambda & 0 & 0\\
-\omega^{e}\cos\lambda & 0 & 0
\end{array}\right]\label{eq:first-omega-eq}
\end{equation}
\begin{equation}
\boldsymbol{\Omega}_{el}^{l}=\left[\begin{array}{ccc}
0 & \frac{-v_{e}\tan\lambda}{R_{N}+z} & \frac{v_{e}}{R_{N}+z}\\
\frac{v_{e}\tan\lambda}{R_{N}+z} & 0 & \frac{v_{n}}{R_{M}+z}\\
\frac{-v_{e}}{R_{N}+z} & \frac{-v_{n}}{R_{M}+z} & 0
\end{array}\right]\label{eq:second-omega-equation}
\end{equation}
with $\omega^{e}=7.292\times10^{-5}$ the angular rate of rotation
of the Earth.
Without some feedback, the vertical component is unstable, so the
INS uses feedback based on the pressure altitude to control the third
component of aircraft velocity. To obtain an analogous variable for
comparison, a similar feedback loop was used for the third component
arising from this new mechanization. A conventional feedback loop
uses three coefficients specified in terms of a parameter $\zeta$
as \{$C_{0},\,C_{1},\,C_{2})=\{3$$\zeta$, 4$\zeta^{2}$, 2$\zeta^{3}$).
In an attempt to duplicate the INS reference source, the reference
altitude was calculated as the pressure altitude corresponding to
the avionics-supplied value of the pressure, but this still gave a
small offset from the INS values so it appears that a different pressure
source must be used by the INS. The loop was implemented in the conventional
way according to the algorithm in the next box:\\
\fbox{\begin{minipage}[t]{1\columnwidth - 2\fboxsep - 2\fboxrule}%
\texttt{initialize:}
~~~~wp3F=0; hxF=0; hxxF=0; hi3F=PALT{[}1{]};
for each ith time step of time change dt:
~~~~wp3F += (sv{[}6{]} - C1{*}hxF - C2{*}hxxF) {*} dt; \#\# sv
is the state vector; sv{[}6{]} is vertical speed
~~~~hi3F += (wp3F - C0{*}hxF) {*} dt;
~~~~hxF = HI3F-PALT{[}i{]};
~~~~hxxF += hxF{*}dt;
~~~~sv{[}6{]} = (sv{[}6{]} + wp3F)/2;
~~~~sv{[}3{]} = hi3F; \#\# sv{[}3{]} is then the altitude of the
aircraft
~~~~{[}save sv{[}3{]} and sv{[}6{]} as the values of the aircraft-state
vector vs time{]}%
\end{minipage}}
\subsection{Attitude angles}
The approach to finding the derivatives of the attitude angles is
to find the derivative ($\dot{R_{a}^{l}})$ of the transformation
matrix from the a-frame to the l-frame and then find the attitude-angle
derivatives from the definition of the transformation matrix.\footnote{This material relies heavily on the development in \citet{noureldin2013fundamentals},
pp.~178\textendash 180.} The steps are these:
\begin{enumerate}
\item The IRU measures the rotation rate $\omega_{ia}^{a}$ of the a-frame
relative to an inertial frame, as observed in the a-frame. In the
a-frame, the roll axis is the x-axis forward along the longitudinal
axis of the aircraft, the pitch axis is the y-axis to starboard, and
the yaw axis is the downward z-axis but with a sign reversal arising
from the inverse relationship between yaw angle and heading angle,
so $\omega_{ia}^{a}=(\dot{\theta},\dot{\phi},\dot{\Psi})=(\mathrm{BROLLR},\,\mathrm{BPITCHR},\,-\mathrm{BYAWR)}$
where the latter are the variables as recorded in the data file. As
a skew-symmetric matrix such as discussed above, this rotation rate
is represented as\\
\begin{equation}
\Omega_{ia}^{a}=\left[\begin{array}{ccc}
0 & -\dot{\Psi} & -\dot{\theta}\\
\dot{\Psi} & 0 & \dot{\phi}\\
\dot{\theta} & -\dot{\phi} & 0
\end{array}\right]\label{eq:Oiaa}
\end{equation}
\item The rotation rate needed to find the derivative of the transformation
matrix ($\dot{R_{a}^{l}})$ is instead the rotation rate $\omega_{la}^{a}$of
the a-frame relative to the l-frame, as observed in the a-frame. This
differs from $\omega_{ia}^{a}$ by the rotation rate of the l-frame
relative to the a-frame, as observed in an inertial frame ($\omega_{il}^{a}$):
$\omega_{la}^{a}=\omega_{ia}^{a}-\omega_{il}^{a}$. Transforming $\omega_{la}^{a}$
from the a-frame to the l-frame then gives the desired derivative
$\dot{R_{a}^{l}}$.
\item As for velocity, the term $\omega_{il}^{a}$ contains two contributions,
one from the rotation of the Earth ($\omega_{ie}^{a}$) and the second
from the rotation of the l-frame relative to an inertial frame ($\omega_{el}^{a}$).
These can be obtained by transforming $\omega_{ie}^{l}$ and $\omega_{el}^{l}$
as defined in the previous subsection to the a-frame. The appropriate
transformation is the inverse of $R_{a}^{l}$, denoted $R_{l}^{a}=t(R_{a}^{l}$)
where ``$t()"$ denotes the matrix transpose operator: $\omega_{ie}^{a}=R_{l}^{a}\omega_{ie}^{l}$
and $\omega_{el}^{a}=R_{l}^{a}\omega_{el}^{l}$. In the code, this
is replaced by the skew-symmetric equivalent: If $\boldsymbol{\Omega}^{l}$
is the skew-symmetric representation of $\omega_{ie}^{l}+\omega_{el}^{l}$,
with skew-symmetric representations given by (\ref{eq:first-omega-eq})
and (\ref{eq:second-omega-equation}) above. The skew-symmetric representation
in the a-frame, following the model for transformation of skew-symmetric
matrices, is then $\boldsymbol{\Omega}^{a}=R_{l}^{a}\boldsymbol{\Omega}^{l}R_{a}^{l}$.
\item Expressing $\omega_{ia}^{a}$ also as a skew-symmetric matrix, following
(\ref{eq:skew-symmetric}), and subtracting $\boldsymbol{\Omega}^{a}$
from it, gives a skew-symmetric matrix that, when multiplied by $R_{a}^{l}$,
gives the desired derivative $\dot{\boldsymbol{R}_{a}^{l}}=\mathbf{R}_{a}^{l}(\boldsymbol{\Omega}_{ia}^{a}-\boldsymbol{\Omega}^{a})$.
(See \citet{noureldin2013fundamentals}, p.~180.)
\item The attitude angles can be found from the definitions of the transformation
matrix, as specified by (\ref{eq:XformLA}):
\begin{eqnarray}
\theta & = & \arcsin(-R_{l}^{a}[3,1])\nonumber \\
\phi & = & \arctan2(R_{l}^{a}[3,2],\,-R_{l}^{a}[3,3])\label{eq:aa-from-R}\\
\Psi & = & \arctan2(R_{l}^{a}[1,1],\,R_{l}^{a}[2,1])\nonumber
\end{eqnarray}
The derivatives of the attitude angles are then given by the derivatives
of the arcsin and arctan functions:\\
\begin{eqnarray}
\frac{d(\arcsin(x))}{dx} & = & \frac{1}{\sqrt{1-x^{2}}}\nonumber \\
\frac{d(\arctan(x))}{dx} & = & \frac{1}{1+x^{2}}\nonumber \\
\dot{\theta} & = & \frac{-1}{\sqrt{1-R_{l}^{a}[3,1]^{2}}}\dot{R}_{l}^{a}[3,1]\label{eq:pdot}\\
\dot{\phi} & = & \frac{1}{1+\left(R_{l}^{a}[3,2]/R_{l}^{a}[3.3]\right)^{2}}\frac{R_{l}^{a}[3,2]}{R_{l}^{a}[3,3]}\left(\frac{\dot{R}_{l}^{a}[3,3]}{R_{l}^{a}[3,3]}-\frac{\dot{R}_{l}^{a}[3,2]}{R_{l}^{a}[3,2]}\right)\label{eq:rdot}\\
\dot{\psi} & = & \frac{1}{1+\left(R_{l}^{a}[1,1]/R_{l}^{a}[2,1]\right)^{2}}\frac{R_{l}^{a}[1,1]}{R_{l}^{a}[2,1]}\left(\frac{\dot{R}_{l}^{a}[1,1]}{R_{l}^{a}[1,1]}-\frac{\dot{R}_{l}^{a}[2,1]}{R_{l}^{a}[2,1]}\right)\nonumber \\
& = & \frac{1}{1+\left(R_{l}^{a}[1,1]/R_{l}^{a}[2,1]\right)^{2}}\left(\frac{\dot{R}_{l}^{a}[1,1]}{R_{l}^{a}[2,1]}-\frac{\dot{R}_{l}^{a}[2,1]R_{l}^{a}[1,1]}{R_{l}^{a}[2,1]^{2}}\right)\label{eq:hdot}
\end{eqnarray}
Because $R_{l}^{1}[2,1]$ (equal to $\cos\psi\cos\theta$) can pass
through zero for heading of 90 or 270$^{\circ},$ some numerical problems
arise when the last equation is used. (Avoiding similar problems at
the zero for $R_{l}^{a}[1,1]$ is the justification for using the
second form of the last equation.) For small $R_{l}^{a}[2,1]$, the
last equation becomes\\
\begin{equation}
\dot{\psi}\approx\left(\frac{R_{l}^{a}[2,1]\dot{R}_{l}^{a}[1,1]}{R_{l}^{a}[1,1]^{2}}-\frac{\dot{R}_{l}^{a}[2,1]}{R_{l}^{a}[1,1]}\right)\label{eq:hdot-approx}
\end{equation}
which avoids the singularity, so this form is used when the absolute
value of $R_{l}^{a}[2,1]$ is smaller than $R_{l}^{a}[1,1]/10$.
\end{enumerate}
\subsection{The function ``STMFV()''}
To standardize calculation of the derivatives of the state vector
for both mechanization and the Kalman filter, the code was incorporated
into a function \texttt{STMFV(D, .components, .aaframe)}. The first
argument is either a data.frame, vector, or matrix containing the
nine components of the state vector and the six a-frame measurements
from the IRU. If multiple rows are included, all are processed and
a matrix of derivatives is returned that has the original number of
rows and\texttt{ .components} components; this is included to accommodate
either the mechanization section that uses a nine-component state
vector or the Kalman-filter section that uses a 15-component error-state
vector. The argument \texttt{.aaframe} defaults to 'a' and attitude
angles are assumed to be in the a-frame. The other option 'l' is not
used; this was a provision for calculating all derivatives in terms
of a state vector with all components in the l-frame, which was used
during testing but not in the final program. As coded, STMFV () assumes
that the measurements from the IRU (accelerations and rotation rates)
have been added to the aircraft-state vector for convenience. This
function is called for each time step during mechanization, and it
then serves as the function argument to the Jacobian calculation that
finds the error-state transition matrix used by the Kalman filter.
The code is in the R chunk called ``chunks/STMFV.R'' to make it
available to the processing program for the Technical Note and also
for subsequent use in the data processing script ``KalmanFilter.R''
that applies the Kalman filter to other data files.
\subsection{Discussion of the ``Tests of the derivatives'' section}
\subsubsection{Time shifts}
An important part of the work that is background to this section was
determining the time shifts to apply to various measurements from
the INS. The ``initialization'' chunk of R code applies these time
shifts, using the ``Ranadu::ShiftInTime()'' function. The time shifts
quoted in the text were determined by varying the shifts specified
in that section and observing the result by plotting the plot generated
in the ``plot-acc'' chunk but modified to display only the pitch
maneuver (3::16:00 to 3:18:00) and observing the difference between
the measured values and the values determined from the derivatives
of the velocity measurements. This was not done systematically but
rather by trial-and-error to find a combination of time shifts that
showed small fluctuations during the maneuver. These results are sensitive
to pitch and roll as well because, in the case of pitch, gravity is
resolved into a longitudinal component of acceleration that affects
the comparison to BLONGA, and in the case of roll small roll angles
created similar contributions to the lateral acceleration represented
by BLATA. In the exploration of time shifts, the measured accelerations
were assumed to have the same time delays, and similar assumptions
were made about the pitch-roll pair and the set of velocities. With
the listed shifts, the residual errors (shown in Tables 1 and 2 of
the Technical Note) were so small that further refinement did not
seem warranted.
\subsubsection{Tables 1 and 2}
These tables show results from regression fits obtained using the
R function ``lm()''. Fit results including the coefficients, the
standard deviation of residuals from the fit, and the square of the
correlation coefficient are entered directly into the tables from
the results of the fits, via the ``\textbackslash{}Sexpr()'' function.
The values included in the tables are calculated in the R-code chunk
named ``check-accelerations''. The details for obtaining the entries
in Table 2, which are used as calibrations of the accelerometers,
are as follows:
\begin{enumerate}
\item Differentiate the GPS-provided velocity components (GGVEW, GGVNS,
GGVSPD) via the R routine signal::sgolayfilt() with appropriate argument
that returns the first derivative of the filtered function. Cubic
Savitzky-Golay polynomials spanning 11 25-Hz measurements were used,
which effectively imposes a high-pass cutoff of about 8~Hz and so
applies only minor smoothing while retaining high temporal resolution
in the derivatives.
\item Apply an appropriate rotation correction as discussed above, but with
reversed sign, to these accelerations.
\item Transform the resulting accelerations to the \emph{a-}frame using
the same function XformLA() discussed above but with the argument
``.inverse'' set TRUE to give the transformation from the \emph{l-}frame
to the \emph{a-}frame instead.
\item Use the R routine ``lm()'' to find the linear-model fit relating
the IRU-measured accelerations to the GPS-derived accelerations. The
coefficients from that fit are those quoted in the document.
\item One subtle circularity needs mention here: The coefficients obtained
are obtained from the original measurements as stored in the data.frame
Data, but the resulting calibration was already applied earlier and
saved in the data.frame SP that is used for the mechanization loop.
These calibrations were inserted manually into the statements near
the end of R-code chunk ``INS-data'', in the section following the
comment ``adjustments''. As mentioned in the main report, no calibration
was applied to the measurements ``BLATA'' because the IRU-provided
and GPS-derived lateral accelerations were consistently small and
the calibration did not appear sufficiently reliable to trust, especially
because the result was significantly different from the identity calibration
that reasonably characterized the other two components of measured
acceleration.\marginpar{check this}
\end{enumerate}
\subsubsection{Generation of Figure 1\label{subsec:Generation-of-Figure}}
Many of the figures in the Technical Note were generated following
the same model, so that model is described here. The plot is generated
by a call to the Ranadu function \texttt{Ranadu::ggplotWAC()}, which
uses the faceting capability of the R package ggplot2 to construct
multiple plots with the same time scale. The code is in R chunk ``plot-acc''.
Many of the plots were generated in multiple-panel displays. This
was straightforward in standard R graphics, using the ``layout()''
and ``par()'' functions, so the standard R plot function was used
in first drafts. However, plotting with ggplot2 produced plots with
better appearance. The construction of multiple-panel figures was
tried in two ways, first using viewports and then using facets. With
viewports, it was difficult to get the panels to align vertically
without much tailoring of margins, but facets handled this automatically
so that was the method used in the final version. The procedure is
worth documenting here because it took some exploration. This was
built into a revision of the function ``Ranadu::ggplotWAC(),'' which
is used as follows:
\begin{enumerate}
\item Construct a new data.frame that contains only the variables that will
appear on the plot, along with the ``Time'' variable (which should
be first). Variables should be in lines/panel format, i.e., all variables
for the top panel, all for the next-to-top, etc.
\item Call ggplotWAC() with these new arguments:
\begin{enumerate}
\item panels: the number of panels or facets, aligned vertically.
\item labelL: the names to appear in the legend for the lines. Only one
legend appears for all panels. Example: c(``IRU'', ``GPS'').
\item labelP: the names to appear at the right of each panel. Example: c(``longitudinal'',
``lateral'', ``upward'').
\item theme.version: 1 to use a theme with minor adaptations for the faceted
plots.
\end{enumerate}
\item The procedure that ggplotWAC() uses is as follows:
\begin{enumerate}
\item Define two groups, VarGroup and PanelGroup, to describe the structure
specified by the new arguments.
\item ``melt'' the data.frame to a long-format data.frame, with ``Time''
as the id.var, and include the two new groups in the data.frame definition.
\item Use the ggplotWAC() arguments for cols, lwd, and lty in groups for
each panel, with replication as needed. Each panel must be the same.
\item Construct the initial plot definition using ggplot, using x=Time,
y=value, colour=VarGroup, linetype=VarGroup in the aesthetic specification.
\item Add ``geom\_line(aes(size=VarGroup))'' to this definition to plot
the lines.
\item Use appropriate manual scale definitions to set the desired colors,
line types, and line widths in order to get consistent plot lines
and legend.
\item Add ``facet\_grid()'' with first argument ``PanelGroup'' as included
in the data.frame definition.
\item Tailor desired aspects of the plotting theme.
\end{enumerate}
\end{enumerate}
The routine then returns a plot definition, and that definition can
be tailored further using ``theme()'' elements if desired or printed
without further modification.
An example is this code that generates the plot of attitude angles
(generating Fig.~2 that appears in Sect.~2.4):
\begin{lyxcode}
d~<-~with(Data{[}setRange(Data,~32000,~35500),~{]},~
~~~~~~~~~~data.frame(Time,~PITCH,~PITCHX,~10{*}DPITCH,~ROLL,~ROLLX,~10{*}DROLL,
~~~~~~~~~~~~~~~~~~~~~THDG,~THDGX,~10{*}DTHDG))
ggplotWAC~(d,~col=c('blue',~'red',~'forestgreen'),~
~~~~~~~~~~ylab=expression~(paste~('attitude~angles~{[}',~degree,~'{]}')),
~~~~~~~~~~lwd=c(1.4,~0.8,~1),~lty=c(1,~42,~1),~panels=3,
~~~~~~~~~~labelL=c('original',~'new',~'10{*}diff'),
~~~~~~~~~~labelP=c('pitch',~'roll',~'heading'),
~~~~~~~~~~legend.position=c(0.8,~0.97),~theme.version=1)
\end{lyxcode}
\subsection{Discussion of the ``Mechanization'' section}
\subsubsection{The algorithm}
The following box contains an algorithmic flow chart describing the
mechanization scheme, which is also diagrammed in Fig.~\ref{fig:mechanization-workflow}:
\begin{lyxcode}
\fbox{\begin{minipage}[t]{1\columnwidth - 2\fboxsep - 2\fboxrule}%
\begin{lyxcode}
Initialize~a~time-series~matrix~of~aircraft-state~vectors;
\begin{lyxcode}
\#\#~Each~row:~three~position~coordinates,~
\#\#~~~~~~~~~~~three~velocity~coordinates,~
\#\#~~~~~~~~~~~three~attitude-angle~coordinates~
\end{lyxcode}
Add~the~measured~accelerations,~rotations~(M)~to~the~same~matrix;
Define~(STMFV(sv,M))~that~returns~the~matrix~of~derivatives~D;
\begin{lyxcode}
\#\#~each~row~D$_{i}$~is~the~derivative~of~sv$_{i}$~
\#\#~~~~~~~~~~~~with~respect~to~time,~given~M$_{i}$
\end{lyxcode}
For~each~time~(index~i)~in~the~data~set,~at~intervals~$\Delta$t:
\begin{lyxcode}
Propagate~the~state~vector~forward~one~time~step,~~\\
~~~~~~~~~~via~sv{[}i+1{]}$\leftarrow$sv{[}i{]}+D{[}i{]}$\Delta$t;
Save~the~resulting~new~state~vector~sv{[}i+1{]}
\end{lyxcode}
\end{lyxcode}
%
\end{minipage}}
\end{lyxcode}
\begin{figure}
\begin{centering}
\includegraphics[width=0.9\textwidth]{FlowDiagrams/FlowChartMechanization}
\par\end{centering}
\caption{Workflow diagram for the mechanization test in the technical note.
Some items (e.g., ``run the main Kalman-filter loop'') are described
in additional workflow diagrams below. \label{fig:mechanization-workflow}}
\end{figure}
The core of the mechanization is the function STMFV() discussed in
Sect.~5.3 above. Various references have provided ``cookbook''
equations for the required derivatives. In particular, the approach
followed was that described by \citet{noureldin2013fundamentals},
but with some differences arising primarily from use of the aircraft-coordinate
frame or \emph{a-}frame instead of the \emph{b-}frame (body frame)
used in that source. In addition, the derivatives of the attitude-angle
components were calculated differently, so some detail regarding this
function is appropriate.
\subsubsection{Time shifts}
Before the step-wise integration, some adjustments were made to the
measurements. To ensure against missing values, interpolation was
used to fill in a very small number of missing values in the measurements
from the IRU. In addition, some of the measurements were shifted in
time to compensate for delays in recording of the variables. This
shifting is a part of normal processing, but the mechanization is
very sensitive to timing errors so some fine tuning was used. The
procedure was discussed in connection with the Ranadu::ShiftInTime()
function discussed above. In addition, a few errors in interpolation
were introduced to the heading variable by this process, so a special
loop searched for these errors (four in the data set used) and corrected
them. The problem arose from a deficiency in the ShiftInTime() function
that still needs to be corrected.
\subsubsection{The integration}
After initializing the aircraft-state vector to match that from the
INS at a point near the start of the flight, the mechanization proceeded
by taking time steps where the changes in the aircraft-state vector
were determined by the preceding derivative function. The Technical
Note describes the initialization and the sequence of time steps.
For convenience, the measurements of acceleration and rotation rate
from the IRU were added to the state vector with each time step so
that those measurements were transferred to the function \texttt{STMFV()}
when it was called. The integration was done either by simple Euler
integration or via a fourth order Runge-Kutta scheme, with indistinguishable
results. A special test and correction were used to ensure that the
heading remained in the range from 0 to $2\pi$.
\subsubsection{The results}
Like Fig.~1, Figs.~2 and 3 showing results of the mechanization
were also generated using the ``Ranadu::ggplotWAC()'' convenience
function, which calls functions that are part of ggplot2 with some
assigned settings. Details are presented above (\vpageref{subsec:Generation-of-Figure}).
All three of these figures were generated during the same processing
step that produced the text document, and they were incorporated into
that document using the R package ``knitr'' to place the figures
appropriately in the resulting LaTeX file. During the mechanization,
the aircraft-state vector was saved in variables in an R data.frame
called SP, and at the end these variables were added back to the original
data.frame (called Data) as new variables with names like LATX, LONX,
ALTX, ... that correspond to the original INS-produced variables LAT,
LON, ALT. These variables were then used in plot commands to generate
the figures in the subsections that compare the results for attitude
angles, velocity components, and position.
\section{Elaboration on the ancillary functions}
\subsection{Rate of climb}
This is discussed fully in the Techical Note and the memo referenced
there.
\subsection{Retrieving IRU measurements}
\begin{figure}
\begin{centering}
\includegraphics[width=0.9\textwidth]{FlowDiagrams/FlowChartRetrieval}
\par\end{centering}
\caption{Workflow diagram for the retrieval of the measurements originally
provided by the IRU. If these are missing from the data file being
used, they are added by this procedure.\label{fig:retrieval-workflow}}
\end{figure}
A workflow diagram for this section is presented as Fig.~\ref{fig:retrieval-workflow}.
The two parts shown in this figure are independent and are discussed
separately below. The yellow box is an expanded description of the
box leading into it, to show how that derivative is found. The R implementation
of the code in the technical note (``KalmanFilter.R'') include a
branch that constructs these retrieved values when the IRU-provided
measurements (BLATA, BLONGA, BNORMA, BPITCHR, BROLLR, BYAWR) are not
present in the original data file.
\subsubsection{Rotation rates}
Item 1 in this subsection of the Technical Note prescribes starting
with analytical expressions for the derivative of the transformation
matrix. Those analytical expressions are developed in this Workflow
Document, as follows:
The rotation rates and accelerations measured by the IRU \{BPITCHR,
BROLLR, BYAWR, BLATA, BLONGA, BNORMA\} are the rotation rates and
accelerations of the a-frame relative to an inertial frame. Without