mirror of
https://github.com/paparazzi/paparazzi.git
synced 2026-05-09 22:49:53 +08:00
fix line endings, replace CRLF with LF
This commit is contained in:
@@ -127,29 +127,29 @@
|
||||
|
||||
</section>
|
||||
|
||||
<section name="VERTICAL CONTROL" prefix="V_CTL_">
|
||||
<define name="POWER_CTL_BAT_NOMINAL" value="7.6" unit="volt"/>
|
||||
<section name="VERTICAL CONTROL" prefix="V_CTL_">
|
||||
<define name="POWER_CTL_BAT_NOMINAL" value="7.6" unit="volt"/>
|
||||
|
||||
<!-- Vertical Outerloop
|
||||
v_ctl_climb_setpoint = ALTITUDE_PGAIN * altitude_error + altitude_pre_climb;
|
||||
BoundAbs(v_ctl_climb_setpoint, V_CTL_ALTITUDE_MAX_CLIMB);
|
||||
-->
|
||||
<!-- Vertical Outerloop
|
||||
v_ctl_climb_setpoint = ALTITUDE_PGAIN * altitude_error + altitude_pre_climb;
|
||||
BoundAbs(v_ctl_climb_setpoint, V_CTL_ALTITUDE_MAX_CLIMB);
|
||||
-->
|
||||
|
||||
<!-- outer loop proportional gain: alt error 5 climb m/s -->
|
||||
<define name="ALTITUDE_PGAIN" value="-0.0750000029802"/>
|
||||
<!-- outer loop saturation: m/s-->
|
||||
<define name="ALTITUDE_MAX_CLIMB" value="5.0"/>
|
||||
|
||||
<!-- auto throttle inner loop
|
||||
float controlled_throttle = v_ctl_auto_throttle_cruise_throttle
|
||||
+ v_ctl_auto_throttle_climb_throttle_increment * v_ctl_climb_setpoint
|
||||
+ v_ctl_auto_throttle_pgain *
|
||||
(err + v_ctl_auto_throttle_igain * v_ctl_auto_throttle_sum_err
|
||||
+ v_ctl_auto_throttle_dgain * d_err);
|
||||
|
||||
/* pitch pre-command */
|
||||
<!-- auto throttle inner loop
|
||||
float controlled_throttle = v_ctl_auto_throttle_cruise_throttle
|
||||
+ v_ctl_auto_throttle_climb_throttle_increment * v_ctl_climb_setpoint
|
||||
+ v_ctl_auto_throttle_pgain *
|
||||
(err + v_ctl_auto_throttle_igain * v_ctl_auto_throttle_sum_err
|
||||
+ v_ctl_auto_throttle_dgain * d_err);
|
||||
|
||||
/* pitch pre-command */
|
||||
float v_ctl_pitch_of_vz = (v_ctl_climb_setpoint + d_err * v_ctl_auto_throttle_pitch_of_vz_dgain)
|
||||
* v_ctl_auto_throttle_pitch_of_vz_pgain;
|
||||
* v_ctl_auto_throttle_pitch_of_vz_pgain;
|
||||
-->
|
||||
<define name="AUTO_THROTTLE_NOMINAL_CRUISE_THROTTLE" value="0.40000000596"/>
|
||||
<define name="AUTO_THROTTLE_MIN_CRUISE_THROTTLE" value="0.20"/>
|
||||
|
||||
@@ -132,29 +132,29 @@
|
||||
|
||||
</section>
|
||||
|
||||
<section name="VERTICAL CONTROL" prefix="V_CTL_">
|
||||
<define name="POWER_CTL_BAT_NOMINAL" value="7.6" unit="volt"/>
|
||||
<section name="VERTICAL CONTROL" prefix="V_CTL_">
|
||||
<define name="POWER_CTL_BAT_NOMINAL" value="7.6" unit="volt"/>
|
||||
|
||||
<!-- Vertical Outerloop
|
||||
v_ctl_climb_setpoint = ALTITUDE_PGAIN * altitude_error + altitude_pre_climb;
|
||||
BoundAbs(v_ctl_climb_setpoint, V_CTL_ALTITUDE_MAX_CLIMB);
|
||||
-->
|
||||
<!-- Vertical Outerloop
|
||||
v_ctl_climb_setpoint = ALTITUDE_PGAIN * altitude_error + altitude_pre_climb;
|
||||
BoundAbs(v_ctl_climb_setpoint, V_CTL_ALTITUDE_MAX_CLIMB);
|
||||
-->
|
||||
|
||||
<!-- outer loop proportional gain: alt error 5 climb m/s -->
|
||||
<define name="ALTITUDE_PGAIN" value="-0.0750000029802"/>
|
||||
<!-- outer loop saturation: m/s-->
|
||||
<define name="ALTITUDE_MAX_CLIMB" value="5.0"/>
|
||||
|
||||
<!-- auto throttle inner loop
|
||||
float controlled_throttle = v_ctl_auto_throttle_cruise_throttle
|
||||
+ v_ctl_auto_throttle_climb_throttle_increment * v_ctl_climb_setpoint
|
||||
+ v_ctl_auto_throttle_pgain *
|
||||
(err + v_ctl_auto_throttle_igain * v_ctl_auto_throttle_sum_err
|
||||
+ v_ctl_auto_throttle_dgain * d_err);
|
||||
|
||||
/* pitch pre-command */
|
||||
<!-- auto throttle inner loop
|
||||
float controlled_throttle = v_ctl_auto_throttle_cruise_throttle
|
||||
+ v_ctl_auto_throttle_climb_throttle_increment * v_ctl_climb_setpoint
|
||||
+ v_ctl_auto_throttle_pgain *
|
||||
(err + v_ctl_auto_throttle_igain * v_ctl_auto_throttle_sum_err
|
||||
+ v_ctl_auto_throttle_dgain * d_err);
|
||||
|
||||
/* pitch pre-command */
|
||||
float v_ctl_pitch_of_vz = (v_ctl_climb_setpoint + d_err * v_ctl_auto_throttle_pitch_of_vz_dgain)
|
||||
* v_ctl_auto_throttle_pitch_of_vz_pgain;
|
||||
* v_ctl_auto_throttle_pitch_of_vz_pgain;
|
||||
-->
|
||||
<define name="AUTO_THROTTLE_NOMINAL_CRUISE_THROTTLE" value="0.40000000596"/>
|
||||
<define name="AUTO_THROTTLE_MIN_CRUISE_THROTTLE" value="0.20"/>
|
||||
|
||||
+13
-13
@@ -1,13 +1,13 @@
|
||||
|
||||
|
||||
<!DOCTYPE radio SYSTEM "radio.dtd">
|
||||
<radio name="T9cap" data_min="900" data_max="2100" sync_min="5000" sync_max="15000" pulse_type="POSITIVE">
|
||||
<channel ctl="switch_E" function="MODE" min="966" neutral="1526" max="2079" average="10"/>
|
||||
<channel ctl="switch_G" function="DISABLE" min="2080" neutral="1525" max="969" average="10"/>
|
||||
<channel ctl="left_stick_horiz" function="YAW" min="1115" neutral="1520" max="1940" average="0"/>
|
||||
<channel ctl="right_stick_vert" function="PITCH" min="1937" neutral="1518" max="1112" average="0"/>
|
||||
<channel ctl="right_stick_horiz" function="ROLL" min="1114" neutral="1525" max="1939" average="0"/>
|
||||
<channel ctl="left_stick_vert" function="THROTTLE" min="1115" neutral="1115" max="1940" average="0"/>
|
||||
|
||||
</radio>
|
||||
|
||||
|
||||
|
||||
<!DOCTYPE radio SYSTEM "radio.dtd">
|
||||
<radio name="T9cap" data_min="900" data_max="2100" sync_min="5000" sync_max="15000" pulse_type="POSITIVE">
|
||||
<channel ctl="switch_E" function="MODE" min="966" neutral="1526" max="2079" average="10"/>
|
||||
<channel ctl="switch_G" function="DISABLE" min="2080" neutral="1525" max="969" average="10"/>
|
||||
<channel ctl="left_stick_horiz" function="YAW" min="1115" neutral="1520" max="1940" average="0"/>
|
||||
<channel ctl="right_stick_vert" function="PITCH" min="1937" neutral="1518" max="1112" average="0"/>
|
||||
<channel ctl="right_stick_horiz" function="ROLL" min="1114" neutral="1525" max="1939" average="0"/>
|
||||
<channel ctl="left_stick_vert" function="THROTTLE" min="1115" neutral="1115" max="1940" average="0"/>
|
||||
|
||||
</radio>
|
||||
|
||||
|
||||
@@ -37,9 +37,9 @@
|
||||
<dl_setting var="controller.c" min="0.001" step="0.01" max="10" module="beth/overo_twist_controller" shortname="c">
|
||||
</dl_setting>
|
||||
|
||||
<!--float ulim; 1
|
||||
float Vm; .1
|
||||
float VM; 300
|
||||
<!--float ulim; 1
|
||||
float Vm; .1
|
||||
float VM; 300
|
||||
float satval1; 0.4
|
||||
float satval2; 1
|
||||
const float c;.04-->
|
||||
|
||||
@@ -1,103 +1,103 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
************************************************************************
|
||||
Rascal 110 R/C airplane config. This files ties together all the components
|
||||
used by FGFS to represent the Rascal 110 (by Sig Mfg) including the flight
|
||||
dynamics model, and external 3D model.
|
||||
************************************************************************
|
||||
-->
|
||||
|
||||
<PropertyList>
|
||||
<sim>
|
||||
|
||||
<description>Malolo1(R/C)</description>
|
||||
<author>Innis Cunningham, Josh Wilson</author>
|
||||
<aircraft-version>0.0</aircraft-version>
|
||||
|
||||
<startup>
|
||||
<splash-texture>Aircraft/Malolo1/Malolo1-splash.rgb</splash-texture>
|
||||
</startup>
|
||||
|
||||
<flight-model>jsb</flight-model>
|
||||
<aero>Malolo1</aero>
|
||||
<fuel-fraction>0.8</fuel-fraction>
|
||||
<!--
|
||||
<systems>
|
||||
<autopilot>
|
||||
<path>Aircraft/Malolo1/Systems/110-autopilot.xml</path>
|
||||
</autopilot>
|
||||
<electrical>
|
||||
<path>Aircraft/Malolo1/Systems/electrical.xml</path>
|
||||
</electrical>
|
||||
</systems> -->
|
||||
|
||||
<sound>
|
||||
<path>Aircraft/Generic/generic-sound.xml</path>
|
||||
</sound>
|
||||
|
||||
<panel>
|
||||
<visibility archive="n">false</visibility>
|
||||
</panel>
|
||||
|
||||
<model>
|
||||
<path archive="y">Aircraft/Malolo1/Models/Malolo1.xml</path>
|
||||
</model>
|
||||
|
||||
<view>
|
||||
<internal archive="y">true</internal>
|
||||
<config>
|
||||
<x-offset-m archive="y">0.0</x-offset-m>
|
||||
<y-offset-m archive="y">0.26</y-offset-m>
|
||||
<z-offset-m archive="y">0.34</z-offset-m>
|
||||
<pitch-offset-deg>-8</pitch-offset-deg>
|
||||
</config>
|
||||
</view>
|
||||
|
||||
<chase-distance-m archive="y" type="double">-15.0</chase-distance-m>
|
||||
<help>
|
||||
<title>YardStik 110 (Sig Mfg)</title>
|
||||
<line>Cruise speed: 60 mph</line>
|
||||
<line>Never-exceed (Vne): 85 mph</line>
|
||||
<line>Best Glide (Vglide): 20 mph</line>
|
||||
<line>Maneuvering (Va): 50 mph</line>
|
||||
<line>Approach speed: 15-25 mph</line>
|
||||
<line>Stall speed (Vs): 10 mph</line>
|
||||
</help>
|
||||
|
||||
</sim>
|
||||
|
||||
<controls>
|
||||
<flight>
|
||||
<aileron-trim>-0.01</aileron-trim> <!-- fixed -->
|
||||
<elevator-trim>0.00</elevator-trim> <!-- controllable -->
|
||||
<rudder-trim>0.00</rudder-trim> <!-- fixed -->
|
||||
</flight>
|
||||
<engines>
|
||||
<engine n="0">
|
||||
<magnetos>3</magnetos>
|
||||
</engine>
|
||||
</engines>
|
||||
<door>1.0</door>
|
||||
</controls>
|
||||
|
||||
<engines>
|
||||
<engine>
|
||||
<rpm type="double">700</rpm>
|
||||
</engine>
|
||||
</engines>
|
||||
|
||||
<!-- An autopilot on a Cub??? -->
|
||||
<autopilot>
|
||||
<config>
|
||||
<min-climb-speed-kt type="float">48.0</min-climb-speed-kt>
|
||||
<best-climb-speed-kt type="float">56.0</best-climb-speed-kt>
|
||||
<target-climb-rate-fpm type="float">400.0</target-climb-rate-fpm>
|
||||
<target-descent-rate-fpm type="float">1000.0</target-descent-rate-fpm>
|
||||
<elevator-adj-factor type="float">6000.0</elevator-adj-factor>
|
||||
<integral-contribution type="float">0.008</integral-contribution>
|
||||
<zero-pitch-throttle type="float">0.35</zero-pitch-throttle>
|
||||
<zero-pitch-trim-full-throttle type="float">0.001</zero-pitch-trim-full-throttle>
|
||||
</config>
|
||||
</autopilot>
|
||||
|
||||
</PropertyList>
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
************************************************************************
|
||||
Rascal 110 R/C airplane config. This files ties together all the components
|
||||
used by FGFS to represent the Rascal 110 (by Sig Mfg) including the flight
|
||||
dynamics model, and external 3D model.
|
||||
************************************************************************
|
||||
-->
|
||||
|
||||
<PropertyList>
|
||||
<sim>
|
||||
|
||||
<description>Malolo1(R/C)</description>
|
||||
<author>Innis Cunningham, Josh Wilson</author>
|
||||
<aircraft-version>0.0</aircraft-version>
|
||||
|
||||
<startup>
|
||||
<splash-texture>Aircraft/Malolo1/Malolo1-splash.rgb</splash-texture>
|
||||
</startup>
|
||||
|
||||
<flight-model>jsb</flight-model>
|
||||
<aero>Malolo1</aero>
|
||||
<fuel-fraction>0.8</fuel-fraction>
|
||||
<!--
|
||||
<systems>
|
||||
<autopilot>
|
||||
<path>Aircraft/Malolo1/Systems/110-autopilot.xml</path>
|
||||
</autopilot>
|
||||
<electrical>
|
||||
<path>Aircraft/Malolo1/Systems/electrical.xml</path>
|
||||
</electrical>
|
||||
</systems> -->
|
||||
|
||||
<sound>
|
||||
<path>Aircraft/Generic/generic-sound.xml</path>
|
||||
</sound>
|
||||
|
||||
<panel>
|
||||
<visibility archive="n">false</visibility>
|
||||
</panel>
|
||||
|
||||
<model>
|
||||
<path archive="y">Aircraft/Malolo1/Models/Malolo1.xml</path>
|
||||
</model>
|
||||
|
||||
<view>
|
||||
<internal archive="y">true</internal>
|
||||
<config>
|
||||
<x-offset-m archive="y">0.0</x-offset-m>
|
||||
<y-offset-m archive="y">0.26</y-offset-m>
|
||||
<z-offset-m archive="y">0.34</z-offset-m>
|
||||
<pitch-offset-deg>-8</pitch-offset-deg>
|
||||
</config>
|
||||
</view>
|
||||
|
||||
<chase-distance-m archive="y" type="double">-15.0</chase-distance-m>
|
||||
<help>
|
||||
<title>YardStik 110 (Sig Mfg)</title>
|
||||
<line>Cruise speed: 60 mph</line>
|
||||
<line>Never-exceed (Vne): 85 mph</line>
|
||||
<line>Best Glide (Vglide): 20 mph</line>
|
||||
<line>Maneuvering (Va): 50 mph</line>
|
||||
<line>Approach speed: 15-25 mph</line>
|
||||
<line>Stall speed (Vs): 10 mph</line>
|
||||
</help>
|
||||
|
||||
</sim>
|
||||
|
||||
<controls>
|
||||
<flight>
|
||||
<aileron-trim>-0.01</aileron-trim> <!-- fixed -->
|
||||
<elevator-trim>0.00</elevator-trim> <!-- controllable -->
|
||||
<rudder-trim>0.00</rudder-trim> <!-- fixed -->
|
||||
</flight>
|
||||
<engines>
|
||||
<engine n="0">
|
||||
<magnetos>3</magnetos>
|
||||
</engine>
|
||||
</engines>
|
||||
<door>1.0</door>
|
||||
</controls>
|
||||
|
||||
<engines>
|
||||
<engine>
|
||||
<rpm type="double">700</rpm>
|
||||
</engine>
|
||||
</engines>
|
||||
|
||||
<!-- An autopilot on a Cub??? -->
|
||||
<autopilot>
|
||||
<config>
|
||||
<min-climb-speed-kt type="float">48.0</min-climb-speed-kt>
|
||||
<best-climb-speed-kt type="float">56.0</best-climb-speed-kt>
|
||||
<target-climb-rate-fpm type="float">400.0</target-climb-rate-fpm>
|
||||
<target-descent-rate-fpm type="float">1000.0</target-descent-rate-fpm>
|
||||
<elevator-adj-factor type="float">6000.0</elevator-adj-factor>
|
||||
<integral-contribution type="float">0.008</integral-contribution>
|
||||
<zero-pitch-throttle type="float">0.35</zero-pitch-throttle>
|
||||
<zero-pitch-trim-full-throttle type="float">0.001</zero-pitch-trim-full-throttle>
|
||||
</config>
|
||||
</autopilot>
|
||||
|
||||
</PropertyList>
|
||||
|
||||
+546
-546
File diff suppressed because it is too large
Load Diff
+4197
-4197
File diff suppressed because it is too large
Load Diff
@@ -1,103 +1,103 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<PropertyList>
|
||||
|
||||
<path>Malolo1.ac</path>
|
||||
<offsets>
|
||||
<z-m>-0.01</z-m>
|
||||
<pitch-deg>0.2</pitch-deg>
|
||||
</offsets>
|
||||
|
||||
<animation>
|
||||
<type>rotate</type>
|
||||
<object-name>rhelevon</object-name>
|
||||
<property>controls/flight/elevator</property>
|
||||
<factor>15</factor>
|
||||
<offset-deg>0</offset-deg>
|
||||
<center>
|
||||
<x-m>0.65</x-m>
|
||||
<y-m>1.4</y-m>
|
||||
<z-m>0.07</z-m>
|
||||
</center>
|
||||
<axis>
|
||||
<x>0.215</x>
|
||||
<y>1</y>
|
||||
<z>0.056</z>
|
||||
</axis>
|
||||
</animation>
|
||||
|
||||
<animation>
|
||||
<type>rotate</type>
|
||||
<object-name>rhelevon</object-name>
|
||||
<property>controls/flight/aileron</property>
|
||||
<factor>-15</factor>
|
||||
<offset-deg>0</offset-deg>
|
||||
<center>
|
||||
<x-m>0.65</x-m>
|
||||
<y-m>1.4</y-m>
|
||||
<z-m>0.07</z-m>
|
||||
</center>
|
||||
<axis>
|
||||
<x>0.215</x>
|
||||
<y>1</y>
|
||||
<z>0.056</z>
|
||||
</axis>
|
||||
</animation>
|
||||
|
||||
<animation>
|
||||
<type>rotate</type>
|
||||
<object-name>lhelevon</object-name>
|
||||
<property>controls/flight/elevator</property>
|
||||
<factor>15</factor>
|
||||
<offset-deg>0</offset-deg>
|
||||
<center>
|
||||
<x-m>0.65</x-m>
|
||||
<y-m>-1.4</y-m>
|
||||
<z-m>0.07</z-m>
|
||||
</center>
|
||||
<axis>
|
||||
<x>-0.215</x>
|
||||
<y>1</y>
|
||||
<z>-0.056</z>
|
||||
</axis>
|
||||
</animation>
|
||||
|
||||
<animation>
|
||||
<type>rotate</type>
|
||||
<object-name>lhelevon</object-name>
|
||||
<property>controls/flight/aileron</property>
|
||||
<factor>15</factor>
|
||||
<offset-deg>0</offset-deg>
|
||||
<center>
|
||||
<x-m>0.65</x-m>
|
||||
<y-m>-1.4</y-m>
|
||||
<z-m>0.07</z-m>
|
||||
</center>
|
||||
<axis>
|
||||
<x>-0.215</x>
|
||||
<y>1</y>
|
||||
<z>-0.056</z>
|
||||
</axis>
|
||||
</animation>
|
||||
|
||||
|
||||
<animation>
|
||||
<type>spin</type>
|
||||
<object-name>prop2</object-name>
|
||||
<property>engines/engine/rpm</property>
|
||||
<factor>-0.2</factor>
|
||||
<center>
|
||||
<x-m>0</x-m>
|
||||
<y-m>0</y-m>
|
||||
<z-m>0.0156</z-m>
|
||||
</center>
|
||||
<axis>
|
||||
<x>1</x>
|
||||
<y>0</y>
|
||||
<z>0</z>
|
||||
</axis>
|
||||
</animation>
|
||||
|
||||
|
||||
|
||||
</PropertyList>
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<PropertyList>
|
||||
|
||||
<path>Malolo1.ac</path>
|
||||
<offsets>
|
||||
<z-m>-0.01</z-m>
|
||||
<pitch-deg>0.2</pitch-deg>
|
||||
</offsets>
|
||||
|
||||
<animation>
|
||||
<type>rotate</type>
|
||||
<object-name>rhelevon</object-name>
|
||||
<property>controls/flight/elevator</property>
|
||||
<factor>15</factor>
|
||||
<offset-deg>0</offset-deg>
|
||||
<center>
|
||||
<x-m>0.65</x-m>
|
||||
<y-m>1.4</y-m>
|
||||
<z-m>0.07</z-m>
|
||||
</center>
|
||||
<axis>
|
||||
<x>0.215</x>
|
||||
<y>1</y>
|
||||
<z>0.056</z>
|
||||
</axis>
|
||||
</animation>
|
||||
|
||||
<animation>
|
||||
<type>rotate</type>
|
||||
<object-name>rhelevon</object-name>
|
||||
<property>controls/flight/aileron</property>
|
||||
<factor>-15</factor>
|
||||
<offset-deg>0</offset-deg>
|
||||
<center>
|
||||
<x-m>0.65</x-m>
|
||||
<y-m>1.4</y-m>
|
||||
<z-m>0.07</z-m>
|
||||
</center>
|
||||
<axis>
|
||||
<x>0.215</x>
|
||||
<y>1</y>
|
||||
<z>0.056</z>
|
||||
</axis>
|
||||
</animation>
|
||||
|
||||
<animation>
|
||||
<type>rotate</type>
|
||||
<object-name>lhelevon</object-name>
|
||||
<property>controls/flight/elevator</property>
|
||||
<factor>15</factor>
|
||||
<offset-deg>0</offset-deg>
|
||||
<center>
|
||||
<x-m>0.65</x-m>
|
||||
<y-m>-1.4</y-m>
|
||||
<z-m>0.07</z-m>
|
||||
</center>
|
||||
<axis>
|
||||
<x>-0.215</x>
|
||||
<y>1</y>
|
||||
<z>-0.056</z>
|
||||
</axis>
|
||||
</animation>
|
||||
|
||||
<animation>
|
||||
<type>rotate</type>
|
||||
<object-name>lhelevon</object-name>
|
||||
<property>controls/flight/aileron</property>
|
||||
<factor>15</factor>
|
||||
<offset-deg>0</offset-deg>
|
||||
<center>
|
||||
<x-m>0.65</x-m>
|
||||
<y-m>-1.4</y-m>
|
||||
<z-m>0.07</z-m>
|
||||
</center>
|
||||
<axis>
|
||||
<x>-0.215</x>
|
||||
<y>1</y>
|
||||
<z>-0.056</z>
|
||||
</axis>
|
||||
</animation>
|
||||
|
||||
|
||||
<animation>
|
||||
<type>spin</type>
|
||||
<object-name>prop2</object-name>
|
||||
<property>engines/engine/rpm</property>
|
||||
<factor>-0.2</factor>
|
||||
<center>
|
||||
<x-m>0</x-m>
|
||||
<y-m>0</y-m>
|
||||
<z-m>0.0156</z-m>
|
||||
</center>
|
||||
<axis>
|
||||
<x>1</x>
|
||||
<y>0</y>
|
||||
<z>0</z>
|
||||
</axis>
|
||||
</animation>
|
||||
|
||||
|
||||
|
||||
</PropertyList>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010",
|
||||
MODE="0666", GROUP="plugdev"
|
||||
|
||||
in the udev rules
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010",
|
||||
MODE="0666", GROUP="plugdev"
|
||||
|
||||
in the udev rules
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
/*#define HW_ENDPOINT_LINUX*/
|
||||
/*#define HW_ENDPOINT_ATMEGA128_SD*/
|
||||
/*#define HW_ENDPOINT_ATMEGA128_SD*/
|
||||
|
||||
|
||||
#define HW_ENDPOINT_LPC2000_SD
|
||||
|
||||
@@ -1,72 +1,72 @@
|
||||
/* based on LPC213x.h from Keil GmbH (keil.com/arm.com) */
|
||||
|
||||
#ifndef LPC2000_regs_h
|
||||
#define LPC2000_regs_h
|
||||
|
||||
/* Pin Connect Block */
|
||||
#define PINSEL0 (*((volatile unsigned long *) 0xE002C000))
|
||||
#define PINSEL1 (*((volatile unsigned long *) 0xE002C004))
|
||||
#define PINSEL2 (*((volatile unsigned long *) 0xE002C014))
|
||||
|
||||
/* General Purpose Input/Output (GPIO) */
|
||||
#define IOPIN0 (*((volatile unsigned long *) 0xE0028000))
|
||||
#define IOSET0 (*((volatile unsigned long *) 0xE0028004))
|
||||
#define IODIR0 (*((volatile unsigned long *) 0xE0028008))
|
||||
#define IOCLR0 (*((volatile unsigned long *) 0xE002800C))
|
||||
#define IOPIN1 (*((volatile unsigned long *) 0xE0028010))
|
||||
#define IOSET1 (*((volatile unsigned long *) 0xE0028014))
|
||||
#define IODIR1 (*((volatile unsigned long *) 0xE0028018))
|
||||
#define IOCLR1 (*((volatile unsigned long *) 0xE002801C))
|
||||
|
||||
/* SPI0 (Serial Peripheral Interface 0) */
|
||||
#define S0SPCR (*((volatile unsigned char *) 0xE0020000))
|
||||
#define S0SPSR (*((volatile unsigned char *) 0xE0020004))
|
||||
#define S0SPDR (*((volatile unsigned char *) 0xE0020008))
|
||||
#define S0SPCCR (*((volatile unsigned char *) 0xE002000C))
|
||||
#define S0SPTCR (*((volatile unsigned char *) 0xE0020010))
|
||||
#define S0SPTSR (*((volatile unsigned char *) 0xE0020014))
|
||||
#define S0SPTOR (*((volatile unsigned char *) 0xE0020018))
|
||||
#define S0SPINT (*((volatile unsigned char *) 0xE002001C))
|
||||
|
||||
/* SSP Controller */
|
||||
#define SSPCR0 (*((volatile unsigned short* ) 0xE0068000))
|
||||
#define SSPCR1 (*((volatile unsigned char * ) 0xE0068004))
|
||||
#define SSPDR (*((volatile unsigned short* ) 0xE0068008))
|
||||
#define SSPSR (*((volatile unsigned char * ) 0xE006800C))
|
||||
#define SSPCPSR (*((volatile unsigned char * ) 0xE0068010))
|
||||
#define SSPIMSC (*((volatile unsigned char * ) 0xE0068014))
|
||||
#define SSPRIS (*((volatile unsigned char * ) 0xE0068018))
|
||||
#define SSPMIS (*((volatile unsigned char * ) 0xE006801C))
|
||||
#define SSPICR (*((volatile unsigned char * ) 0xE0068020))
|
||||
#define SSPDMACR (*((volatile unsigned char * ) 0xE0068024))
|
||||
|
||||
/* Real Time Clock */
|
||||
/* maybe useful for the efsl time-handling : */
|
||||
#define ILR (*((volatile unsigned char *) 0xE0024000))
|
||||
#define CTC (*((volatile unsigned short*) 0xE0024004))
|
||||
#define CCR (*((volatile unsigned char *) 0xE0024008))
|
||||
#define CIIR (*((volatile unsigned char *) 0xE002400C))
|
||||
#define AMR (*((volatile unsigned char *) 0xE0024010))
|
||||
#define CTIME0 (*((volatile unsigned long *) 0xE0024014))
|
||||
#define CTIME1 (*((volatile unsigned long *) 0xE0024018))
|
||||
#define CTIME2 (*((volatile unsigned long *) 0xE002401C))
|
||||
#define SEC (*((volatile unsigned char *) 0xE0024020))
|
||||
#define MIN (*((volatile unsigned char *) 0xE0024024))
|
||||
#define HOUR (*((volatile unsigned char *) 0xE0024028))
|
||||
#define DOM (*((volatile unsigned char *) 0xE002402C))
|
||||
#define DOW (*((volatile unsigned char *) 0xE0024030))
|
||||
#define DOY (*((volatile unsigned short*) 0xE0024034))
|
||||
#define MONTH (*((volatile unsigned char *) 0xE0024038))
|
||||
#define YEAR (*((volatile unsigned short*) 0xE002403C))
|
||||
#define ALSEC (*((volatile unsigned char *) 0xE0024060))
|
||||
#define ALMIN (*((volatile unsigned char *) 0xE0024064))
|
||||
#define ALHOUR (*((volatile unsigned char *) 0xE0024068))
|
||||
#define ALDOM (*((volatile unsigned char *) 0xE002406C))
|
||||
#define ALDOW (*((volatile unsigned char *) 0xE0024070))
|
||||
#define ALDOY (*((volatile unsigned short*) 0xE0024074))
|
||||
#define ALMON (*((volatile unsigned char *) 0xE0024078))
|
||||
#define ALYEAR (*((volatile unsigned short*) 0xE002407C))
|
||||
#define PREINT (*((volatile unsigned short*) 0xE0024080))
|
||||
#define PREFRAC (*((volatile unsigned short*) 0xE0024084))
|
||||
|
||||
#endif
|
||||
/* based on LPC213x.h from Keil GmbH (keil.com/arm.com) */
|
||||
|
||||
#ifndef LPC2000_regs_h
|
||||
#define LPC2000_regs_h
|
||||
|
||||
/* Pin Connect Block */
|
||||
#define PINSEL0 (*((volatile unsigned long *) 0xE002C000))
|
||||
#define PINSEL1 (*((volatile unsigned long *) 0xE002C004))
|
||||
#define PINSEL2 (*((volatile unsigned long *) 0xE002C014))
|
||||
|
||||
/* General Purpose Input/Output (GPIO) */
|
||||
#define IOPIN0 (*((volatile unsigned long *) 0xE0028000))
|
||||
#define IOSET0 (*((volatile unsigned long *) 0xE0028004))
|
||||
#define IODIR0 (*((volatile unsigned long *) 0xE0028008))
|
||||
#define IOCLR0 (*((volatile unsigned long *) 0xE002800C))
|
||||
#define IOPIN1 (*((volatile unsigned long *) 0xE0028010))
|
||||
#define IOSET1 (*((volatile unsigned long *) 0xE0028014))
|
||||
#define IODIR1 (*((volatile unsigned long *) 0xE0028018))
|
||||
#define IOCLR1 (*((volatile unsigned long *) 0xE002801C))
|
||||
|
||||
/* SPI0 (Serial Peripheral Interface 0) */
|
||||
#define S0SPCR (*((volatile unsigned char *) 0xE0020000))
|
||||
#define S0SPSR (*((volatile unsigned char *) 0xE0020004))
|
||||
#define S0SPDR (*((volatile unsigned char *) 0xE0020008))
|
||||
#define S0SPCCR (*((volatile unsigned char *) 0xE002000C))
|
||||
#define S0SPTCR (*((volatile unsigned char *) 0xE0020010))
|
||||
#define S0SPTSR (*((volatile unsigned char *) 0xE0020014))
|
||||
#define S0SPTOR (*((volatile unsigned char *) 0xE0020018))
|
||||
#define S0SPINT (*((volatile unsigned char *) 0xE002001C))
|
||||
|
||||
/* SSP Controller */
|
||||
#define SSPCR0 (*((volatile unsigned short* ) 0xE0068000))
|
||||
#define SSPCR1 (*((volatile unsigned char * ) 0xE0068004))
|
||||
#define SSPDR (*((volatile unsigned short* ) 0xE0068008))
|
||||
#define SSPSR (*((volatile unsigned char * ) 0xE006800C))
|
||||
#define SSPCPSR (*((volatile unsigned char * ) 0xE0068010))
|
||||
#define SSPIMSC (*((volatile unsigned char * ) 0xE0068014))
|
||||
#define SSPRIS (*((volatile unsigned char * ) 0xE0068018))
|
||||
#define SSPMIS (*((volatile unsigned char * ) 0xE006801C))
|
||||
#define SSPICR (*((volatile unsigned char * ) 0xE0068020))
|
||||
#define SSPDMACR (*((volatile unsigned char * ) 0xE0068024))
|
||||
|
||||
/* Real Time Clock */
|
||||
/* maybe useful for the efsl time-handling : */
|
||||
#define ILR (*((volatile unsigned char *) 0xE0024000))
|
||||
#define CTC (*((volatile unsigned short*) 0xE0024004))
|
||||
#define CCR (*((volatile unsigned char *) 0xE0024008))
|
||||
#define CIIR (*((volatile unsigned char *) 0xE002400C))
|
||||
#define AMR (*((volatile unsigned char *) 0xE0024010))
|
||||
#define CTIME0 (*((volatile unsigned long *) 0xE0024014))
|
||||
#define CTIME1 (*((volatile unsigned long *) 0xE0024018))
|
||||
#define CTIME2 (*((volatile unsigned long *) 0xE002401C))
|
||||
#define SEC (*((volatile unsigned char *) 0xE0024020))
|
||||
#define MIN (*((volatile unsigned char *) 0xE0024024))
|
||||
#define HOUR (*((volatile unsigned char *) 0xE0024028))
|
||||
#define DOM (*((volatile unsigned char *) 0xE002402C))
|
||||
#define DOW (*((volatile unsigned char *) 0xE0024030))
|
||||
#define DOY (*((volatile unsigned short*) 0xE0024034))
|
||||
#define MONTH (*((volatile unsigned char *) 0xE0024038))
|
||||
#define YEAR (*((volatile unsigned short*) 0xE002403C))
|
||||
#define ALSEC (*((volatile unsigned char *) 0xE0024060))
|
||||
#define ALMIN (*((volatile unsigned char *) 0xE0024064))
|
||||
#define ALHOUR (*((volatile unsigned char *) 0xE0024068))
|
||||
#define ALDOM (*((volatile unsigned char *) 0xE002406C))
|
||||
#define ALDOW (*((volatile unsigned char *) 0xE0024070))
|
||||
#define ALDOY (*((volatile unsigned short*) 0xE0024074))
|
||||
#define ALMON (*((volatile unsigned char *) 0xE0024078))
|
||||
#define ALYEAR (*((volatile unsigned short*) 0xE002407C))
|
||||
#define PREINT (*((volatile unsigned short*) 0xE0024080))
|
||||
#define PREFRAC (*((volatile unsigned short*) 0xE0024084))
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,66 +1,66 @@
|
||||
/*****************************************************************************\
|
||||
* efs - General purpose Embedded Filesystem library *
|
||||
* --------------------------------------------------------- *
|
||||
* *
|
||||
* Filename : sd.h *
|
||||
* Revision : Initial developement *
|
||||
* Description : Headerfile for sd.c *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; version 2 *
|
||||
* of the License. *
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* As a special exception, if other files instantiate templates or *
|
||||
* use macros or inline functions from this file, or you compile this *
|
||||
* file and link it with other works to produce a work based on this file, *
|
||||
* this file does not by itself cause the resulting work to be covered *
|
||||
* by the GNU General Public License. However the source code for this *
|
||||
* file must still be made available in accordance with section (3) of *
|
||||
* the GNU General Public License. *
|
||||
* *
|
||||
* This exception does not invalidate any other reasons why a work based *
|
||||
* on this file might be covered by the GNU General Public License. *
|
||||
* *
|
||||
* (c)2006 Lennart Yseboodt *
|
||||
* (c)2006 Michael De Nil *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef __SD_H_
|
||||
#define __SD_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "../debug.h"
|
||||
|
||||
#ifdef HW_ENDPOINT_ATMEGA128_SD
|
||||
#include "interfaces/atmega128.h"
|
||||
#endif
|
||||
#ifdef HW_ENDPOINT_DSP_TI6713_SD
|
||||
#include "interfaces/dsp67xx.h"
|
||||
#endif
|
||||
#ifdef HW_ENDPOINT_LPC2000_SD
|
||||
#include "interfaces/lpc2000_spi.h"
|
||||
#endif
|
||||
|
||||
#define CMDREAD 17
|
||||
#define CMDWRITE 24
|
||||
#define CMDREADCSD 9
|
||||
|
||||
esint8 sd_Init(hwInterface *iface);
|
||||
void sd_Command(hwInterface *iface,euint8 cmd, euint16 paramx, euint16 paramy);
|
||||
euint8 sd_Resp8b(hwInterface *iface);
|
||||
void sd_Resp8bError(hwInterface *iface,euint8 value);
|
||||
euint16 sd_Resp16b(hwInterface *iface);
|
||||
esint8 sd_State(hwInterface *iface);
|
||||
|
||||
esint8 sd_readSector(hwInterface *iface,euint32 address,euint8* buf, euint16 len);
|
||||
esint8 sd_writeSector(hwInterface *iface,euint32 address, euint8* buf);
|
||||
esint8 sd_getDriveSize(hwInterface *iface, euint32* drive_size );
|
||||
|
||||
#endif
|
||||
/*****************************************************************************\
|
||||
* efs - General purpose Embedded Filesystem library *
|
||||
* --------------------------------------------------------- *
|
||||
* *
|
||||
* Filename : sd.h *
|
||||
* Revision : Initial developement *
|
||||
* Description : Headerfile for sd.c *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; version 2 *
|
||||
* of the License. *
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* As a special exception, if other files instantiate templates or *
|
||||
* use macros or inline functions from this file, or you compile this *
|
||||
* file and link it with other works to produce a work based on this file, *
|
||||
* this file does not by itself cause the resulting work to be covered *
|
||||
* by the GNU General Public License. However the source code for this *
|
||||
* file must still be made available in accordance with section (3) of *
|
||||
* the GNU General Public License. *
|
||||
* *
|
||||
* This exception does not invalidate any other reasons why a work based *
|
||||
* on this file might be covered by the GNU General Public License. *
|
||||
* *
|
||||
* (c)2006 Lennart Yseboodt *
|
||||
* (c)2006 Michael De Nil *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef __SD_H_
|
||||
#define __SD_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "../debug.h"
|
||||
|
||||
#ifdef HW_ENDPOINT_ATMEGA128_SD
|
||||
#include "interfaces/atmega128.h"
|
||||
#endif
|
||||
#ifdef HW_ENDPOINT_DSP_TI6713_SD
|
||||
#include "interfaces/dsp67xx.h"
|
||||
#endif
|
||||
#ifdef HW_ENDPOINT_LPC2000_SD
|
||||
#include "interfaces/lpc2000_spi.h"
|
||||
#endif
|
||||
|
||||
#define CMDREAD 17
|
||||
#define CMDWRITE 24
|
||||
#define CMDREADCSD 9
|
||||
|
||||
esint8 sd_Init(hwInterface *iface);
|
||||
void sd_Command(hwInterface *iface,euint8 cmd, euint16 paramx, euint16 paramy);
|
||||
euint8 sd_Resp8b(hwInterface *iface);
|
||||
void sd_Resp8bError(hwInterface *iface,euint8 value);
|
||||
euint16 sd_Resp16b(hwInterface *iface);
|
||||
esint8 sd_State(hwInterface *iface);
|
||||
|
||||
esint8 sd_readSector(hwInterface *iface,euint32 address,euint8* buf, euint16 len);
|
||||
esint8 sd_writeSector(hwInterface *iface,euint32 address, euint8* buf);
|
||||
esint8 sd_getDriveSize(hwInterface *iface, euint32* drive_size );
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -92,4 +92,4 @@ ISR(ADC_vect)
|
||||
ADMUX = (analog_reference << 6) | MuxSel;
|
||||
// start the conversion
|
||||
ADCSRA|= (1<<ADSC);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,4 +71,4 @@ void Compass_Heading()
|
||||
MAG_Y = magnetom_y*cos_roll-magnetom_z*sin_roll;
|
||||
// Magnetic Heading
|
||||
MAG_Heading = atan2(-MAG_Y,MAG_X);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,4 +277,4 @@ void Euler_angles(void)
|
||||
yaw = atan2(DCM_Matrix[1][0],DCM_Matrix[0][0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -201,4 +201,4 @@ Serial.begin(38400); //Universal Synchronous Asynchronous Recieving Transmiting
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -289,4 +289,4 @@ void decode_gps(void)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -408,4 +408,4 @@ long convert_to_dec(float x)
|
||||
{
|
||||
return x*10000000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -37,4 +37,4 @@ void Vector_Add(float vectorOut[3],float vectorIn1[3], float vectorIn2[3])
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -727,4 +727,4 @@ EEPROM memory map
|
||||
21 0x15 ..
|
||||
22 0x16 Ground Altitude
|
||||
23 0x17 ..
|
||||
*/
|
||||
*/
|
||||
|
||||
@@ -19,4 +19,4 @@ void Matrix_Multiply(float a[3][3], float b[3][3],float mat[3][3])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -241,4 +241,4 @@ void TWIdocmd(unsigned char *msg)
|
||||
STOP;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,65 +1,65 @@
|
||||
/*
|
||||
* assertions.hpp
|
||||
*
|
||||
* Created on: Aug 6, 2009
|
||||
* Author: Jonathan Brandmeyer
|
||||
*
|
||||
* This file is part of libeknav.
|
||||
*
|
||||
* Libeknav is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* Libeknav is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with libeknav. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AHRS_ASSERTIONS_HPP
|
||||
#define AHRS_ASSERTIONS_HPP
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <cmath>
|
||||
|
||||
template<typename MatrixBase>
|
||||
bool hasNaN(const MatrixBase& expr);
|
||||
|
||||
template<typename MatrixBase>
|
||||
bool hasInf(const MatrixBase& expr);
|
||||
|
||||
template<typename MatrixBase>
|
||||
bool hasNaN(const MatrixBase& expr)
|
||||
{
|
||||
for (int j = 0; j != expr.cols(); ++j) {
|
||||
for (int i = 0; i != expr.rows(); ++i) {
|
||||
if (std::isnan(expr.coeff(i, j)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename MatrixBase>
|
||||
bool hasInf(const MatrixBase& expr)
|
||||
{
|
||||
for (int i = 0; i != expr.cols(); ++i) {
|
||||
for (int j = 0; j != expr.rows(); ++j) {
|
||||
if (std::isinf(expr.coeff(j, i)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename MatrixBase>
|
||||
bool isReal(const MatrixBase& exp)
|
||||
{
|
||||
return !hasNaN(exp) && ! hasInf(exp);
|
||||
}
|
||||
|
||||
#endif /* ASSERTIONS_HPP_ */
|
||||
/*
|
||||
* assertions.hpp
|
||||
*
|
||||
* Created on: Aug 6, 2009
|
||||
* Author: Jonathan Brandmeyer
|
||||
*
|
||||
* This file is part of libeknav.
|
||||
*
|
||||
* Libeknav is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* Libeknav is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with libeknav. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AHRS_ASSERTIONS_HPP
|
||||
#define AHRS_ASSERTIONS_HPP
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <cmath>
|
||||
|
||||
template<typename MatrixBase>
|
||||
bool hasNaN(const MatrixBase& expr);
|
||||
|
||||
template<typename MatrixBase>
|
||||
bool hasInf(const MatrixBase& expr);
|
||||
|
||||
template<typename MatrixBase>
|
||||
bool hasNaN(const MatrixBase& expr)
|
||||
{
|
||||
for (int j = 0; j != expr.cols(); ++j) {
|
||||
for (int i = 0; i != expr.rows(); ++i) {
|
||||
if (std::isnan(expr.coeff(i, j)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename MatrixBase>
|
||||
bool hasInf(const MatrixBase& expr)
|
||||
{
|
||||
for (int i = 0; i != expr.cols(); ++i) {
|
||||
for (int j = 0; j != expr.rows(); ++j) {
|
||||
if (std::isinf(expr.coeff(j, i)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename MatrixBase>
|
||||
bool isReal(const MatrixBase& exp)
|
||||
{
|
||||
return !hasNaN(exp) && ! hasInf(exp);
|
||||
}
|
||||
|
||||
#endif /* ASSERTIONS_HPP_ */
|
||||
|
||||
@@ -1,154 +1,154 @@
|
||||
/*
|
||||
* basic_ins_qkf.cpp
|
||||
*
|
||||
* Created on: Aug 11, 2009
|
||||
* Author: Jonathan Brandmeyer
|
||||
* This file is part of libeknav.
|
||||
*
|
||||
* Libeknav is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* Libeknav is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with libeknav. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ins_qkf.hpp"
|
||||
#include "assertions.hpp"
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
basic_ins_qkf::basic_ins_qkf(
|
||||
const Vector3d& estimate,
|
||||
double pos_error, double bias_error, double v_error,
|
||||
const Vector3d& gyro_white_noise,
|
||||
const Vector3d& gyro_stability_noise,
|
||||
const Vector3d& accel_white_noise,
|
||||
Quaterniond initial_orientation, // this is new
|
||||
const Vector3d& vel_estimate)
|
||||
: gyro_stability_noise(gyro_stability_noise)
|
||||
, gyro_white_noise(gyro_white_noise)
|
||||
, accel_white_noise(accel_white_noise)
|
||||
{
|
||||
avg_state.position = estimate;
|
||||
avg_state.gyro_bias = Vector3d::Zero();
|
||||
//avg_state.orientation = Quaterniond::Identity();
|
||||
avg_state.orientation = initial_orientation;
|
||||
avg_state.velocity = vel_estimate;
|
||||
|
||||
cov << Matrix3d::Identity()*bias_error*bias_error, Matrix<double, 3, 9>::Zero(),
|
||||
Matrix3d::Zero(), Matrix3d::Identity()*M_PI*M_PI*0.5, Matrix<double, 3, 6>::Zero(),
|
||||
Matrix<double, 3, 6>::Zero(), Matrix3d::Identity()*pos_error*pos_error, Matrix3d::Zero(),
|
||||
Matrix<double, 3, 9>::Zero(), Matrix3d::Identity()*v_error*v_error;
|
||||
assert(is_real());
|
||||
}
|
||||
|
||||
void
|
||||
basic_ins_qkf::counter_rotate_cov(const Quaterniond&)
|
||||
{
|
||||
// Rotate the principle axes of the angular error covariance by the
|
||||
// mean update.
|
||||
|
||||
// TODO: This is only required in the case that the system covariance is
|
||||
// right-multiplied by the mean. The current design left-multiplies the
|
||||
// covariance by the mean.
|
||||
return;
|
||||
|
||||
// TODO: There should be an expression that makes both this matrix's
|
||||
// construction and multiplication much more efficient.
|
||||
// Matrix<double, 12, 12> counter_rot = Matrix<double, 12, 12>::Identity();
|
||||
// counter_rot.block<3, 3>(3, 3) = update.cast<double>().conjugate().toRotationMatrix();
|
||||
// cov = (counter_rot * cov.cast<double>() * counter_rot.transpose()).cast<float>();
|
||||
}
|
||||
#if 0
|
||||
basic_ins_qkf::state
|
||||
basic_ins_qkf::average_sigma_points(const std::vector<state, aligned_allocator<state> >& points)
|
||||
{
|
||||
state ret;
|
||||
Vector3d sum;
|
||||
#define avg_vector_field(field) \
|
||||
sum = Vector3d::Zero(); \
|
||||
for (auto i = points.begin(), end = points.end(); i != end; ++i) { \
|
||||
sum += i->field; \
|
||||
} \
|
||||
ret.field = sum / points.size()
|
||||
|
||||
avg_vector_field(gyro_bias);
|
||||
avg_vector_field(velocity);
|
||||
|
||||
Vector3d p_sum = Vector3d::Zero();
|
||||
for (auto i = points.begin(), end = points.end(); i != end; ++i) {
|
||||
p_sum += i->position;
|
||||
}
|
||||
ret.position = p_sum / (double)points.size();
|
||||
|
||||
std::vector<Quaterniond> quat_points;
|
||||
quat_points.reserve(points.size());
|
||||
for (auto i = points.begin(), end = points.end(); i != end; ++i) {
|
||||
quat_points.push_back(i->orientation);
|
||||
}
|
||||
ret.orientation = quaternion_avg_johnson(quat_points).normalized();
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
basic_ins_qkf::is_real(void) const
|
||||
{
|
||||
return !(hasNaN(cov) || hasInf(cov)) && avg_state.is_real();
|
||||
}
|
||||
|
||||
Quaterniond
|
||||
basic_ins_qkf::state::apply_kalman_vec_update(const Matrix<double, 12, 1> update)
|
||||
{
|
||||
// std::cout << "***update available***\n"
|
||||
// << "\tstate: "; print(std::cout);
|
||||
// std::cout << "\n\tupdate: " << update.transpose() << "\n";
|
||||
gyro_bias += update.segment<3>(0);
|
||||
Quaterniond posterior_update = exp<double>(update.segment<3>(3));
|
||||
orientation = (orientation * posterior_update).normalized();
|
||||
position += update.segment<3>(6);
|
||||
velocity += update.segment<3>(9);
|
||||
assert(is_real());
|
||||
return posterior_update;
|
||||
}
|
||||
|
||||
#if 0
|
||||
Quaterniond
|
||||
basic_ins_qkf::state::apply_left_kalman_vec_update(const Matrix<double, 12, 1> update)
|
||||
{
|
||||
// std::cout << "***update available***\n"
|
||||
// << "\tstate: "; print(std::cout);
|
||||
// std::cout << "\n\tupdate: " << update.transpose() << "\n";
|
||||
gyro_bias += update.segment<3>(0);
|
||||
Quaterniond posterior_update = exp<double>(update.segment<3>(3));
|
||||
orientation = (posterior_update * orientation).normalized();
|
||||
position += update.segment<3>(6);
|
||||
velocity += update.segment<3>(9);
|
||||
assert(is_real());
|
||||
return posterior_update;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
basic_ins_qkf::state::has_nan(void)const
|
||||
{
|
||||
return hasNaN(gyro_bias) || hasNaN(orientation.coeffs())
|
||||
|| hasNaN(position) || hasNaN(velocity);
|
||||
}
|
||||
|
||||
bool
|
||||
basic_ins_qkf::state::is_real(void) const
|
||||
{
|
||||
return !(hasNaN(gyro_bias) || hasNaN(orientation.coeffs())
|
||||
|| hasNaN(position) || hasNaN(velocity))
|
||||
&& !(hasInf(gyro_bias) || hasInf(orientation.coeffs())
|
||||
|| hasInf(position) || hasInf(velocity));
|
||||
}
|
||||
|
||||
/*
|
||||
* basic_ins_qkf.cpp
|
||||
*
|
||||
* Created on: Aug 11, 2009
|
||||
* Author: Jonathan Brandmeyer
|
||||
* This file is part of libeknav.
|
||||
*
|
||||
* Libeknav is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* Libeknav is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with libeknav. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ins_qkf.hpp"
|
||||
#include "assertions.hpp"
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
basic_ins_qkf::basic_ins_qkf(
|
||||
const Vector3d& estimate,
|
||||
double pos_error, double bias_error, double v_error,
|
||||
const Vector3d& gyro_white_noise,
|
||||
const Vector3d& gyro_stability_noise,
|
||||
const Vector3d& accel_white_noise,
|
||||
Quaterniond initial_orientation, // this is new
|
||||
const Vector3d& vel_estimate)
|
||||
: gyro_stability_noise(gyro_stability_noise)
|
||||
, gyro_white_noise(gyro_white_noise)
|
||||
, accel_white_noise(accel_white_noise)
|
||||
{
|
||||
avg_state.position = estimate;
|
||||
avg_state.gyro_bias = Vector3d::Zero();
|
||||
//avg_state.orientation = Quaterniond::Identity();
|
||||
avg_state.orientation = initial_orientation;
|
||||
avg_state.velocity = vel_estimate;
|
||||
|
||||
cov << Matrix3d::Identity()*bias_error*bias_error, Matrix<double, 3, 9>::Zero(),
|
||||
Matrix3d::Zero(), Matrix3d::Identity()*M_PI*M_PI*0.5, Matrix<double, 3, 6>::Zero(),
|
||||
Matrix<double, 3, 6>::Zero(), Matrix3d::Identity()*pos_error*pos_error, Matrix3d::Zero(),
|
||||
Matrix<double, 3, 9>::Zero(), Matrix3d::Identity()*v_error*v_error;
|
||||
assert(is_real());
|
||||
}
|
||||
|
||||
void
|
||||
basic_ins_qkf::counter_rotate_cov(const Quaterniond&)
|
||||
{
|
||||
// Rotate the principle axes of the angular error covariance by the
|
||||
// mean update.
|
||||
|
||||
// TODO: This is only required in the case that the system covariance is
|
||||
// right-multiplied by the mean. The current design left-multiplies the
|
||||
// covariance by the mean.
|
||||
return;
|
||||
|
||||
// TODO: There should be an expression that makes both this matrix's
|
||||
// construction and multiplication much more efficient.
|
||||
// Matrix<double, 12, 12> counter_rot = Matrix<double, 12, 12>::Identity();
|
||||
// counter_rot.block<3, 3>(3, 3) = update.cast<double>().conjugate().toRotationMatrix();
|
||||
// cov = (counter_rot * cov.cast<double>() * counter_rot.transpose()).cast<float>();
|
||||
}
|
||||
#if 0
|
||||
basic_ins_qkf::state
|
||||
basic_ins_qkf::average_sigma_points(const std::vector<state, aligned_allocator<state> >& points)
|
||||
{
|
||||
state ret;
|
||||
Vector3d sum;
|
||||
#define avg_vector_field(field) \
|
||||
sum = Vector3d::Zero(); \
|
||||
for (auto i = points.begin(), end = points.end(); i != end; ++i) { \
|
||||
sum += i->field; \
|
||||
} \
|
||||
ret.field = sum / points.size()
|
||||
|
||||
avg_vector_field(gyro_bias);
|
||||
avg_vector_field(velocity);
|
||||
|
||||
Vector3d p_sum = Vector3d::Zero();
|
||||
for (auto i = points.begin(), end = points.end(); i != end; ++i) {
|
||||
p_sum += i->position;
|
||||
}
|
||||
ret.position = p_sum / (double)points.size();
|
||||
|
||||
std::vector<Quaterniond> quat_points;
|
||||
quat_points.reserve(points.size());
|
||||
for (auto i = points.begin(), end = points.end(); i != end; ++i) {
|
||||
quat_points.push_back(i->orientation);
|
||||
}
|
||||
ret.orientation = quaternion_avg_johnson(quat_points).normalized();
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
basic_ins_qkf::is_real(void) const
|
||||
{
|
||||
return !(hasNaN(cov) || hasInf(cov)) && avg_state.is_real();
|
||||
}
|
||||
|
||||
Quaterniond
|
||||
basic_ins_qkf::state::apply_kalman_vec_update(const Matrix<double, 12, 1> update)
|
||||
{
|
||||
// std::cout << "***update available***\n"
|
||||
// << "\tstate: "; print(std::cout);
|
||||
// std::cout << "\n\tupdate: " << update.transpose() << "\n";
|
||||
gyro_bias += update.segment<3>(0);
|
||||
Quaterniond posterior_update = exp<double>(update.segment<3>(3));
|
||||
orientation = (orientation * posterior_update).normalized();
|
||||
position += update.segment<3>(6);
|
||||
velocity += update.segment<3>(9);
|
||||
assert(is_real());
|
||||
return posterior_update;
|
||||
}
|
||||
|
||||
#if 0
|
||||
Quaterniond
|
||||
basic_ins_qkf::state::apply_left_kalman_vec_update(const Matrix<double, 12, 1> update)
|
||||
{
|
||||
// std::cout << "***update available***\n"
|
||||
// << "\tstate: "; print(std::cout);
|
||||
// std::cout << "\n\tupdate: " << update.transpose() << "\n";
|
||||
gyro_bias += update.segment<3>(0);
|
||||
Quaterniond posterior_update = exp<double>(update.segment<3>(3));
|
||||
orientation = (posterior_update * orientation).normalized();
|
||||
position += update.segment<3>(6);
|
||||
velocity += update.segment<3>(9);
|
||||
assert(is_real());
|
||||
return posterior_update;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
basic_ins_qkf::state::has_nan(void)const
|
||||
{
|
||||
return hasNaN(gyro_bias) || hasNaN(orientation.coeffs())
|
||||
|| hasNaN(position) || hasNaN(velocity);
|
||||
}
|
||||
|
||||
bool
|
||||
basic_ins_qkf::state::is_real(void) const
|
||||
{
|
||||
return !(hasNaN(gyro_bias) || hasNaN(orientation.coeffs())
|
||||
|| hasNaN(position) || hasNaN(velocity))
|
||||
&& !(hasInf(gyro_bias) || hasInf(orientation.coeffs())
|
||||
|| hasInf(position) || hasInf(velocity));
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,121 +1,121 @@
|
||||
/*
|
||||
* ins_qkf_observe_gps_pvt.cpp
|
||||
*
|
||||
* Created on: Sep 2, 2009
|
||||
* Author: Jonathan Brandmeyer
|
||||
*
|
||||
* This file is part of libeknav.
|
||||
*
|
||||
* Libeknav is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* Libeknav is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with libeknav. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ins_qkf.hpp"
|
||||
#include "assertions.hpp"
|
||||
#include <Eigen/LU>
|
||||
|
||||
#ifdef TIME_OPS
|
||||
#include "timer.hpp"
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
#define RANK_ONE_UPDATES
|
||||
|
||||
void
|
||||
basic_ins_qkf::obs_gps_v_report(const Vector3d& vel, const Vector3d& v_error)
|
||||
{
|
||||
Vector3d residual = vel - avg_state.velocity;
|
||||
//std::cout << "diff_v(" <<residual(0) << ", " << residual(1) << ", " << residual(2) <<")\n";
|
||||
|
||||
#ifdef RANK_ONE_UPDATES
|
||||
Matrix<double, 12, 1> update = Matrix<double, 12, 1>::Zero();
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
double innovation_cov_inv = 1.0/(cov(9+i, 9+i) + v_error[i]);
|
||||
Matrix<double, 12, 1> gain = cov.block<12, 1>(0, 9+i) * innovation_cov_inv;
|
||||
update += gain * (residual[i] - update[9+i]);
|
||||
cov -= gain * cov.block<1, 12>(9+i, 0);
|
||||
}
|
||||
#else
|
||||
Matrix<double, 3, 3> innovation_cov = cov.block<3, 3>(9, 9);
|
||||
innovation_cov += v_error.asDiagonal();
|
||||
Matrix<double, 3, 12> kalman_gain_t;
|
||||
innovation_cov.qr().solve(cov.block<3, 12>(9, 0), &kalman_gain_t);
|
||||
cov.part<Eigen::SelfAdjoint>() -= cov.block<12, 3>(0, 9) * kalman_gain_t; // .transpose() * cov.block<3, 12>(9, 0);
|
||||
Matrix<double, 12, 1> update = kalman_gain_t.transpose() * residual;
|
||||
#endif
|
||||
//std::cout << "update(" << update.segment<6>(0).transpose()*180/M_PI << "\t" << update.segment<6>(6).transpose() << ")\n";
|
||||
|
||||
//update.segment<6>(0) = Matrix<double, 6, 1>::Zero(); // only for debugging
|
||||
//std::cout << "update(" << update.segment<6>(0).transpose()*180/M_PI << "\t" << update.segment<6>(6).transpose() << ")\n";
|
||||
Quaterniond rotor = avg_state.apply_kalman_vec_update(update);
|
||||
counter_rotate_cov(rotor);
|
||||
assert(is_real());
|
||||
}
|
||||
|
||||
void
|
||||
basic_ins_qkf::obs_gps_pv_report(
|
||||
const Vector3d& pos, const Vector3d& vel,
|
||||
const Vector3d& p_error, const Vector3d v_error)
|
||||
{
|
||||
#ifdef TIME_OPS
|
||||
timer clock;
|
||||
clock.start();
|
||||
#endif
|
||||
#if 1
|
||||
//std::cout<<"position"<<std::endl;
|
||||
obs_gps_p_report(pos, p_error);
|
||||
//std::cout<<"velocity"<<std::endl;
|
||||
obs_gps_v_report(vel, v_error);
|
||||
#else
|
||||
|
||||
// The observation model is strictly linear here, so use the linear
|
||||
// form of the kalman gain and update
|
||||
Matrix<double, 6, 12> obs_matrix;
|
||||
obs_matrix << Matrix<double, 6, 6>::Zero(), Matrix<double, 6, 6>::Identity();
|
||||
|
||||
Matrix<double, 6, 1> residual;
|
||||
residual.segment<3>(0) = (pos - avg_state.position);
|
||||
residual.segment<3>(3) = vel - avg_state.velocity;
|
||||
|
||||
Matrix<double, 6, 6> innovation_cov = cov.corner<6, 6>(Eigen::BottomRight);
|
||||
//innovation_cov = obs_matrix * cov * obs_matrix.transpose();
|
||||
innovation_cov.corner<3, 3>(Eigen::TopLeft) += p_error.asDiagonal();
|
||||
innovation_cov.corner<3, 3>(Eigen::BottomRight) += v_error.asDiagonal();
|
||||
#if 1
|
||||
// Perform matrix inverse by LU decomposition instead of cofactor expansion.
|
||||
// K = P*transpose(H)*inverse(S)
|
||||
// K = P*transpose(transpose(transpose(H)*inverse(S)))
|
||||
// K = P*transpose(transpose(inverse(S))*H)
|
||||
// K = P*transpose(inverse(transpose(S))*H)
|
||||
// S == transpose(S)
|
||||
// K = P*transpose(inverse(S)*H)
|
||||
// obs_matrx <- inverse(S)*H
|
||||
Matrix<double, 6, 12> inv_s_h;
|
||||
innovation_cov.qr().solve(obs_matrix, &inv_s_h);
|
||||
Matrix<double, 12, 6> kalman_gain = cov * inv_s_h.transpose();
|
||||
#else
|
||||
Matrix<double, 12, 6> kalman_gain = cov.block<12, 6>(0, 6) * innovation_cov.inverse();
|
||||
#endif
|
||||
Quaterniond rotor = avg_state.apply_kalman_vec_update(kalman_gain * residual);
|
||||
cov.part<Eigen::SelfAdjoint>() -= kalman_gain * obs_matrix * cov;
|
||||
counter_rotate_cov(rotor);
|
||||
assert(is_real());
|
||||
#endif
|
||||
|
||||
#ifdef TIME_OPS
|
||||
double time = clock.stop() * 1e6;
|
||||
std::cout << "obs_gps_pvt time: " << time << "\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* ins_qkf_observe_gps_pvt.cpp
|
||||
*
|
||||
* Created on: Sep 2, 2009
|
||||
* Author: Jonathan Brandmeyer
|
||||
*
|
||||
* This file is part of libeknav.
|
||||
*
|
||||
* Libeknav is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* Libeknav is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with libeknav. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ins_qkf.hpp"
|
||||
#include "assertions.hpp"
|
||||
#include <Eigen/LU>
|
||||
|
||||
#ifdef TIME_OPS
|
||||
#include "timer.hpp"
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
#define RANK_ONE_UPDATES
|
||||
|
||||
void
|
||||
basic_ins_qkf::obs_gps_v_report(const Vector3d& vel, const Vector3d& v_error)
|
||||
{
|
||||
Vector3d residual = vel - avg_state.velocity;
|
||||
//std::cout << "diff_v(" <<residual(0) << ", " << residual(1) << ", " << residual(2) <<")\n";
|
||||
|
||||
#ifdef RANK_ONE_UPDATES
|
||||
Matrix<double, 12, 1> update = Matrix<double, 12, 1>::Zero();
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
double innovation_cov_inv = 1.0/(cov(9+i, 9+i) + v_error[i]);
|
||||
Matrix<double, 12, 1> gain = cov.block<12, 1>(0, 9+i) * innovation_cov_inv;
|
||||
update += gain * (residual[i] - update[9+i]);
|
||||
cov -= gain * cov.block<1, 12>(9+i, 0);
|
||||
}
|
||||
#else
|
||||
Matrix<double, 3, 3> innovation_cov = cov.block<3, 3>(9, 9);
|
||||
innovation_cov += v_error.asDiagonal();
|
||||
Matrix<double, 3, 12> kalman_gain_t;
|
||||
innovation_cov.qr().solve(cov.block<3, 12>(9, 0), &kalman_gain_t);
|
||||
cov.part<Eigen::SelfAdjoint>() -= cov.block<12, 3>(0, 9) * kalman_gain_t; // .transpose() * cov.block<3, 12>(9, 0);
|
||||
Matrix<double, 12, 1> update = kalman_gain_t.transpose() * residual;
|
||||
#endif
|
||||
//std::cout << "update(" << update.segment<6>(0).transpose()*180/M_PI << "\t" << update.segment<6>(6).transpose() << ")\n";
|
||||
|
||||
//update.segment<6>(0) = Matrix<double, 6, 1>::Zero(); // only for debugging
|
||||
//std::cout << "update(" << update.segment<6>(0).transpose()*180/M_PI << "\t" << update.segment<6>(6).transpose() << ")\n";
|
||||
Quaterniond rotor = avg_state.apply_kalman_vec_update(update);
|
||||
counter_rotate_cov(rotor);
|
||||
assert(is_real());
|
||||
}
|
||||
|
||||
void
|
||||
basic_ins_qkf::obs_gps_pv_report(
|
||||
const Vector3d& pos, const Vector3d& vel,
|
||||
const Vector3d& p_error, const Vector3d v_error)
|
||||
{
|
||||
#ifdef TIME_OPS
|
||||
timer clock;
|
||||
clock.start();
|
||||
#endif
|
||||
#if 1
|
||||
//std::cout<<"position"<<std::endl;
|
||||
obs_gps_p_report(pos, p_error);
|
||||
//std::cout<<"velocity"<<std::endl;
|
||||
obs_gps_v_report(vel, v_error);
|
||||
#else
|
||||
|
||||
// The observation model is strictly linear here, so use the linear
|
||||
// form of the kalman gain and update
|
||||
Matrix<double, 6, 12> obs_matrix;
|
||||
obs_matrix << Matrix<double, 6, 6>::Zero(), Matrix<double, 6, 6>::Identity();
|
||||
|
||||
Matrix<double, 6, 1> residual;
|
||||
residual.segment<3>(0) = (pos - avg_state.position);
|
||||
residual.segment<3>(3) = vel - avg_state.velocity;
|
||||
|
||||
Matrix<double, 6, 6> innovation_cov = cov.corner<6, 6>(Eigen::BottomRight);
|
||||
//innovation_cov = obs_matrix * cov * obs_matrix.transpose();
|
||||
innovation_cov.corner<3, 3>(Eigen::TopLeft) += p_error.asDiagonal();
|
||||
innovation_cov.corner<3, 3>(Eigen::BottomRight) += v_error.asDiagonal();
|
||||
#if 1
|
||||
// Perform matrix inverse by LU decomposition instead of cofactor expansion.
|
||||
// K = P*transpose(H)*inverse(S)
|
||||
// K = P*transpose(transpose(transpose(H)*inverse(S)))
|
||||
// K = P*transpose(transpose(inverse(S))*H)
|
||||
// K = P*transpose(inverse(transpose(S))*H)
|
||||
// S == transpose(S)
|
||||
// K = P*transpose(inverse(S)*H)
|
||||
// obs_matrx <- inverse(S)*H
|
||||
Matrix<double, 6, 12> inv_s_h;
|
||||
innovation_cov.qr().solve(obs_matrix, &inv_s_h);
|
||||
Matrix<double, 12, 6> kalman_gain = cov * inv_s_h.transpose();
|
||||
#else
|
||||
Matrix<double, 12, 6> kalman_gain = cov.block<12, 6>(0, 6) * innovation_cov.inverse();
|
||||
#endif
|
||||
Quaterniond rotor = avg_state.apply_kalman_vec_update(kalman_gain * residual);
|
||||
cov.part<Eigen::SelfAdjoint>() -= kalman_gain * obs_matrix * cov;
|
||||
counter_rotate_cov(rotor);
|
||||
assert(is_real());
|
||||
#endif
|
||||
|
||||
#ifdef TIME_OPS
|
||||
double time = clock.stop() * 1e6;
|
||||
std::cout << "obs_gps_pvt time: " << time << "\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1,193 +1,193 @@
|
||||
/*
|
||||
* ins_qkf_observe_vector.cpp
|
||||
*
|
||||
* Created on: Sep 2, 2009
|
||||
* Author: Jonathan Brandmeyer
|
||||
|
||||
* This file is part of libeknav.
|
||||
*
|
||||
* Libeknav is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* Libeknav is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with libeknav. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ins_qkf.hpp"
|
||||
#include "assertions.hpp"
|
||||
|
||||
#ifdef TIME_OPS
|
||||
#include "timer.hpp"
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
using namespace Eigen;
|
||||
#define RANK_ONE_UPDATES
|
||||
|
||||
#include <Eigen/LU>
|
||||
|
||||
void
|
||||
basic_ins_qkf::obs_gyro_bias(const Vector3d& bias, const Vector3d& bias_error)
|
||||
{
|
||||
Matrix<double, 12, 3> kalman_gain = cov.block<12, 3>(0, 0)
|
||||
* (cov.block<3, 3>(0, 0) + bias_error.asDiagonal()).inverse();
|
||||
cov -= kalman_gain * cov.block<3, 12>(0, 0);
|
||||
Vector3d innovation = bias - avg_state.gyro_bias;
|
||||
|
||||
// Apply the Kalman gain to obtain the posterior state and error estimates.
|
||||
avg_state.apply_kalman_vec_update(kalman_gain * innovation);
|
||||
}
|
||||
|
||||
void
|
||||
basic_ins_qkf::obs_vector(const Vector3d& ref, const Vector3d& obs, double error)
|
||||
{
|
||||
#ifdef TIME_OPS
|
||||
timer clock;
|
||||
clock.start();
|
||||
#endif
|
||||
#define DEBUG_VECTOR_OBS 0
|
||||
// Optimization opportunity: re-use sigma points from the state prediction
|
||||
#if 0
|
||||
std::vector<vector_obs_state, aligned_allocator<vector_obs_state> > points;
|
||||
Matrix<double, 15, 30> state_errors;
|
||||
decompose_sigma_points(points, state_errors, error);
|
||||
|
||||
std::vector<Quaterniond> projected_points;
|
||||
projected_points.reserve(points.size());
|
||||
for (auto i = points.begin(), end = points.end(); i != end; ++i) {
|
||||
projected_points.push_back(observe_vector(*i, ref));
|
||||
}
|
||||
|
||||
Vector3d expected_obs = avg_state.orientation * ref;
|
||||
Quaterniond expected_observation_prediction = Quaterniond().setFromTwoVectors(ref, expected_obs);
|
||||
// Compute the observation error matrix and its self-covariance
|
||||
Quaterniond mean_observation_pred = quaternion_avg_johnson(projected_points);
|
||||
|
||||
|
||||
// assert(obs_projection.transpose().isUnitary());
|
||||
#if DEBUG_VECTOR_OBS
|
||||
std::cout << "\n\nref: " << ref.transpose();
|
||||
std::cout << "\nobs: " << obs.transpose();
|
||||
std::cout << "\nexpected observation: " << expected_observation_prediction.coeffs().transpose();
|
||||
std::cout << "\nUKF observation: " << mean_observation_pred.coeffs().transpose();
|
||||
std::cout << "\nexpected innovation: " << log<double>(Quaterniond().setFromTwoVectors(
|
||||
expected_obs, obs)).transpose();
|
||||
std::cout << "\ntangent space innovation: " << log<double>(avg_state.orientation.conjugate() *
|
||||
Quaterniond().setFromTwoVectors(expected_obs, obs) * avg_state.orientation) << "\n";
|
||||
#endif
|
||||
Matrix<double, 3, Dynamic> obs_errors(3, projected_points.size());
|
||||
for (unsigned i = 0; i != projected_points.size(); ++i) {
|
||||
if (projected_points[i].coeffs().dot(mean_observation_pred.coeffs()) < 0) {
|
||||
// Choose the point on the same hemisphere as the mean. otherwise, the error vectors
|
||||
// get screwed up.
|
||||
projected_points[i].coeffs() *= -1;
|
||||
}
|
||||
obs_errors.col(i) = log<double>(mean_observation_pred.conjugate() * projected_points[i]);
|
||||
}
|
||||
|
||||
// Construct an observation matrix composed of the two unit vectors
|
||||
// orthogonal to the direction that pivots about the expected observation
|
||||
// Vector3d obs = obs.normalized();
|
||||
Matrix<double, 2, 3> obs_projection;
|
||||
#if 1
|
||||
SelfAdjointEigenSolver<Matrix<double, 3, 3> > obs_cov((obs_errors * obs_errors.transpose())*0.5);
|
||||
obs_projection = obs_cov.eigenvectors().block<3, 2>(0, 1).transpose();
|
||||
#else
|
||||
typedef Vector3d vector_t;
|
||||
obs_projection.row(0) = expected_obs.cross((expected_obs.dot(vector_t::UnitX()) < 0.707)
|
||||
? vector_t::UnitX() : vector_t::UnitY()).normalized();
|
||||
obs_projection.row(1) = expected_obs.cross(obs_projection.row(0));
|
||||
#endif
|
||||
assert(!hasNaN(obs_projection));
|
||||
#if DEBUG_VECTOR_OBS
|
||||
std::cout << "predicted obs: " << expected_obs.transpose() << "\n";
|
||||
std::cout << "actual obs: " << obs.transpose() << "\n";
|
||||
std::cout << "reference obs: " << ref.transpose() << "\n";
|
||||
std::cout << "obs cov eigenvalues: " << obs_cov.eigenvalues().transpose() << "\n";
|
||||
std::cout << "obs cov eigenvectors:\n" << obs_cov.eigenvectors() << "\n";
|
||||
std::cout << "measurement subspace:\n" << obs_projection.transpose() << "\n";
|
||||
#endif
|
||||
|
||||
Matrix<double, 2, Dynamic> projected_obs_errors = obs_projection*obs_errors;
|
||||
Matrix<double, 2, 2> obs_pred_cov = (projected_obs_errors * projected_obs_errors.transpose())*0.5;
|
||||
#if DEBUG_VECTOR_OBS
|
||||
std::cout << "obs errors: " << obs_errors << "\n";
|
||||
std::cout << "S: " << obs_pred_cov << "\n";
|
||||
std::cout << "expected S: " << cov.block<3, 3>(3, 3) << "\n";
|
||||
#endif
|
||||
|
||||
Matrix<double, 12, 2> state_meas_cross_cov =
|
||||
(state_errors.block<12, 30>(0,0) * projected_obs_errors.transpose())*0.5;
|
||||
Matrix<double, 12, 2> kalman_gain = state_meas_cross_cov * obs_pred_cov.inverse();
|
||||
// Innovation rotation in the tangent space at the mean
|
||||
Vector2d innovation = obs_projection*log<double>(
|
||||
Quaterniond().setFromTwoVectors((mean_observation_pred * ref), obs));
|
||||
#if DEBUG_VECTOR_OBS
|
||||
std::cout << "inverse(S): " << obs_pred_cov.inverse() << "\n";
|
||||
std::cout << "used innovation: " << log<double>(Quaterniond().setFromTwoVectors(
|
||||
mean_observation_pred * ref, obs)).transpose() << "\n";
|
||||
std::cout << "projected innovation: " << innovation.transpose() << "\n";
|
||||
std::cout << "deprojected innovation: " << (obs_projection.transpose() * innovation).transpose() << "\n";
|
||||
#endif
|
||||
// actually, cov -= K*S*K^T, but this saves a multiplication.
|
||||
cov -= (kalman_gain * obs_pred_cov * kalman_gain.transpose());
|
||||
#else
|
||||
// BIG optimization opportunity: Use a pseudo-linear measurement model.
|
||||
|
||||
Vector3d obs_ref = avg_state.orientation.conjugate()*obs;
|
||||
Vector3d v_residual = log<double>(Quaterniond().setFromTwoVectors(ref, obs_ref));
|
||||
|
||||
Matrix<double, 3, 2> h_trans;
|
||||
h_trans.col(0) = ref.cross(
|
||||
(abs(ref.dot(obs_ref)) < 0.9994) ? obs_ref :
|
||||
(abs(ref.dot(Vector3d::UnitX())) < 0.707)
|
||||
? Vector3d::UnitX() : Vector3d::UnitY()).normalized();
|
||||
|
||||
h_trans.col(1) = -ref.cross(h_trans.col(0));
|
||||
assert(!hasNaN(h_trans));
|
||||
assert(h_trans.isUnitary());
|
||||
Vector2d innovation = h_trans.transpose() * v_residual;
|
||||
#ifdef RANK_ONE_UPDATES
|
||||
// Running a rank-one update here is a strict win.
|
||||
Matrix<double, 12, 1> update = Matrix<double, 12, 1>::Zero();
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
double obs_error = error;
|
||||
double obs_cov = (h_trans.col(i).transpose() * cov.block<3, 3>(3, 3) * h_trans.col(i))[0];
|
||||
Matrix<double, 12, 1> gain = cov.block<12, 3>(0, 3) * h_trans.col(i) / (obs_error + obs_cov);
|
||||
update += gain * h_trans.col(i).transpose() * v_residual;
|
||||
cov -= gain * h_trans.col(i).transpose() * cov.block<3, 12>(3, 0);
|
||||
}
|
||||
#else
|
||||
Matrix<double, 12, 2> kalman_gain = cov.block<12, 3>(0, 3) * h_trans
|
||||
* (h_trans.transpose() * cov.block<3, 3>(3, 3) * h_trans
|
||||
+ (Vector2d() << error, error).finished().asDiagonal()).inverse();
|
||||
cov -= kalman_gain * h_trans.transpose() * cov.block<3, 12>(3, 0);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// Apply the Kalman gain to obtain the posterior state and error estimates.
|
||||
#ifndef RANK_ONE_UPDATES
|
||||
Matrix<double, 12, 1> update = (kalman_gain * innovation);
|
||||
#endif
|
||||
|
||||
#if DEBUG_VECTOR_OBS
|
||||
// std::cout << "projected update: " << (obs_projection * update.segment<3>(3)).transpose() << "\n";
|
||||
std::cout << "deprojected update: " << update.segment<3>(3).transpose() << "\n";
|
||||
#endif
|
||||
Quaterniond posterior_update = avg_state.apply_kalman_vec_update(update);
|
||||
counter_rotate_cov(posterior_update);
|
||||
|
||||
assert(is_real());
|
||||
#ifdef TIME_OPS
|
||||
double time = clock.stop() * 1e6;
|
||||
std::cout << "observe_vector(): " << time << "\n";
|
||||
#endif
|
||||
|
||||
}
|
||||
/*
|
||||
* ins_qkf_observe_vector.cpp
|
||||
*
|
||||
* Created on: Sep 2, 2009
|
||||
* Author: Jonathan Brandmeyer
|
||||
|
||||
* This file is part of libeknav.
|
||||
*
|
||||
* Libeknav is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* Libeknav is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with libeknav. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ins_qkf.hpp"
|
||||
#include "assertions.hpp"
|
||||
|
||||
#ifdef TIME_OPS
|
||||
#include "timer.hpp"
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
using namespace Eigen;
|
||||
#define RANK_ONE_UPDATES
|
||||
|
||||
#include <Eigen/LU>
|
||||
|
||||
void
|
||||
basic_ins_qkf::obs_gyro_bias(const Vector3d& bias, const Vector3d& bias_error)
|
||||
{
|
||||
Matrix<double, 12, 3> kalman_gain = cov.block<12, 3>(0, 0)
|
||||
* (cov.block<3, 3>(0, 0) + bias_error.asDiagonal()).inverse();
|
||||
cov -= kalman_gain * cov.block<3, 12>(0, 0);
|
||||
Vector3d innovation = bias - avg_state.gyro_bias;
|
||||
|
||||
// Apply the Kalman gain to obtain the posterior state and error estimates.
|
||||
avg_state.apply_kalman_vec_update(kalman_gain * innovation);
|
||||
}
|
||||
|
||||
void
|
||||
basic_ins_qkf::obs_vector(const Vector3d& ref, const Vector3d& obs, double error)
|
||||
{
|
||||
#ifdef TIME_OPS
|
||||
timer clock;
|
||||
clock.start();
|
||||
#endif
|
||||
#define DEBUG_VECTOR_OBS 0
|
||||
// Optimization opportunity: re-use sigma points from the state prediction
|
||||
#if 0
|
||||
std::vector<vector_obs_state, aligned_allocator<vector_obs_state> > points;
|
||||
Matrix<double, 15, 30> state_errors;
|
||||
decompose_sigma_points(points, state_errors, error);
|
||||
|
||||
std::vector<Quaterniond> projected_points;
|
||||
projected_points.reserve(points.size());
|
||||
for (auto i = points.begin(), end = points.end(); i != end; ++i) {
|
||||
projected_points.push_back(observe_vector(*i, ref));
|
||||
}
|
||||
|
||||
Vector3d expected_obs = avg_state.orientation * ref;
|
||||
Quaterniond expected_observation_prediction = Quaterniond().setFromTwoVectors(ref, expected_obs);
|
||||
// Compute the observation error matrix and its self-covariance
|
||||
Quaterniond mean_observation_pred = quaternion_avg_johnson(projected_points);
|
||||
|
||||
|
||||
// assert(obs_projection.transpose().isUnitary());
|
||||
#if DEBUG_VECTOR_OBS
|
||||
std::cout << "\n\nref: " << ref.transpose();
|
||||
std::cout << "\nobs: " << obs.transpose();
|
||||
std::cout << "\nexpected observation: " << expected_observation_prediction.coeffs().transpose();
|
||||
std::cout << "\nUKF observation: " << mean_observation_pred.coeffs().transpose();
|
||||
std::cout << "\nexpected innovation: " << log<double>(Quaterniond().setFromTwoVectors(
|
||||
expected_obs, obs)).transpose();
|
||||
std::cout << "\ntangent space innovation: " << log<double>(avg_state.orientation.conjugate() *
|
||||
Quaterniond().setFromTwoVectors(expected_obs, obs) * avg_state.orientation) << "\n";
|
||||
#endif
|
||||
Matrix<double, 3, Dynamic> obs_errors(3, projected_points.size());
|
||||
for (unsigned i = 0; i != projected_points.size(); ++i) {
|
||||
if (projected_points[i].coeffs().dot(mean_observation_pred.coeffs()) < 0) {
|
||||
// Choose the point on the same hemisphere as the mean. otherwise, the error vectors
|
||||
// get screwed up.
|
||||
projected_points[i].coeffs() *= -1;
|
||||
}
|
||||
obs_errors.col(i) = log<double>(mean_observation_pred.conjugate() * projected_points[i]);
|
||||
}
|
||||
|
||||
// Construct an observation matrix composed of the two unit vectors
|
||||
// orthogonal to the direction that pivots about the expected observation
|
||||
// Vector3d obs = obs.normalized();
|
||||
Matrix<double, 2, 3> obs_projection;
|
||||
#if 1
|
||||
SelfAdjointEigenSolver<Matrix<double, 3, 3> > obs_cov((obs_errors * obs_errors.transpose())*0.5);
|
||||
obs_projection = obs_cov.eigenvectors().block<3, 2>(0, 1).transpose();
|
||||
#else
|
||||
typedef Vector3d vector_t;
|
||||
obs_projection.row(0) = expected_obs.cross((expected_obs.dot(vector_t::UnitX()) < 0.707)
|
||||
? vector_t::UnitX() : vector_t::UnitY()).normalized();
|
||||
obs_projection.row(1) = expected_obs.cross(obs_projection.row(0));
|
||||
#endif
|
||||
assert(!hasNaN(obs_projection));
|
||||
#if DEBUG_VECTOR_OBS
|
||||
std::cout << "predicted obs: " << expected_obs.transpose() << "\n";
|
||||
std::cout << "actual obs: " << obs.transpose() << "\n";
|
||||
std::cout << "reference obs: " << ref.transpose() << "\n";
|
||||
std::cout << "obs cov eigenvalues: " << obs_cov.eigenvalues().transpose() << "\n";
|
||||
std::cout << "obs cov eigenvectors:\n" << obs_cov.eigenvectors() << "\n";
|
||||
std::cout << "measurement subspace:\n" << obs_projection.transpose() << "\n";
|
||||
#endif
|
||||
|
||||
Matrix<double, 2, Dynamic> projected_obs_errors = obs_projection*obs_errors;
|
||||
Matrix<double, 2, 2> obs_pred_cov = (projected_obs_errors * projected_obs_errors.transpose())*0.5;
|
||||
#if DEBUG_VECTOR_OBS
|
||||
std::cout << "obs errors: " << obs_errors << "\n";
|
||||
std::cout << "S: " << obs_pred_cov << "\n";
|
||||
std::cout << "expected S: " << cov.block<3, 3>(3, 3) << "\n";
|
||||
#endif
|
||||
|
||||
Matrix<double, 12, 2> state_meas_cross_cov =
|
||||
(state_errors.block<12, 30>(0,0) * projected_obs_errors.transpose())*0.5;
|
||||
Matrix<double, 12, 2> kalman_gain = state_meas_cross_cov * obs_pred_cov.inverse();
|
||||
// Innovation rotation in the tangent space at the mean
|
||||
Vector2d innovation = obs_projection*log<double>(
|
||||
Quaterniond().setFromTwoVectors((mean_observation_pred * ref), obs));
|
||||
#if DEBUG_VECTOR_OBS
|
||||
std::cout << "inverse(S): " << obs_pred_cov.inverse() << "\n";
|
||||
std::cout << "used innovation: " << log<double>(Quaterniond().setFromTwoVectors(
|
||||
mean_observation_pred * ref, obs)).transpose() << "\n";
|
||||
std::cout << "projected innovation: " << innovation.transpose() << "\n";
|
||||
std::cout << "deprojected innovation: " << (obs_projection.transpose() * innovation).transpose() << "\n";
|
||||
#endif
|
||||
// actually, cov -= K*S*K^T, but this saves a multiplication.
|
||||
cov -= (kalman_gain * obs_pred_cov * kalman_gain.transpose());
|
||||
#else
|
||||
// BIG optimization opportunity: Use a pseudo-linear measurement model.
|
||||
|
||||
Vector3d obs_ref = avg_state.orientation.conjugate()*obs;
|
||||
Vector3d v_residual = log<double>(Quaterniond().setFromTwoVectors(ref, obs_ref));
|
||||
|
||||
Matrix<double, 3, 2> h_trans;
|
||||
h_trans.col(0) = ref.cross(
|
||||
(abs(ref.dot(obs_ref)) < 0.9994) ? obs_ref :
|
||||
(abs(ref.dot(Vector3d::UnitX())) < 0.707)
|
||||
? Vector3d::UnitX() : Vector3d::UnitY()).normalized();
|
||||
|
||||
h_trans.col(1) = -ref.cross(h_trans.col(0));
|
||||
assert(!hasNaN(h_trans));
|
||||
assert(h_trans.isUnitary());
|
||||
Vector2d innovation = h_trans.transpose() * v_residual;
|
||||
#ifdef RANK_ONE_UPDATES
|
||||
// Running a rank-one update here is a strict win.
|
||||
Matrix<double, 12, 1> update = Matrix<double, 12, 1>::Zero();
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
double obs_error = error;
|
||||
double obs_cov = (h_trans.col(i).transpose() * cov.block<3, 3>(3, 3) * h_trans.col(i))[0];
|
||||
Matrix<double, 12, 1> gain = cov.block<12, 3>(0, 3) * h_trans.col(i) / (obs_error + obs_cov);
|
||||
update += gain * h_trans.col(i).transpose() * v_residual;
|
||||
cov -= gain * h_trans.col(i).transpose() * cov.block<3, 12>(3, 0);
|
||||
}
|
||||
#else
|
||||
Matrix<double, 12, 2> kalman_gain = cov.block<12, 3>(0, 3) * h_trans
|
||||
* (h_trans.transpose() * cov.block<3, 3>(3, 3) * h_trans
|
||||
+ (Vector2d() << error, error).finished().asDiagonal()).inverse();
|
||||
cov -= kalman_gain * h_trans.transpose() * cov.block<3, 12>(3, 0);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// Apply the Kalman gain to obtain the posterior state and error estimates.
|
||||
#ifndef RANK_ONE_UPDATES
|
||||
Matrix<double, 12, 1> update = (kalman_gain * innovation);
|
||||
#endif
|
||||
|
||||
#if DEBUG_VECTOR_OBS
|
||||
// std::cout << "projected update: " << (obs_projection * update.segment<3>(3)).transpose() << "\n";
|
||||
std::cout << "deprojected update: " << update.segment<3>(3).transpose() << "\n";
|
||||
#endif
|
||||
Quaterniond posterior_update = avg_state.apply_kalman_vec_update(update);
|
||||
counter_rotate_cov(posterior_update);
|
||||
|
||||
assert(is_real());
|
||||
#ifdef TIME_OPS
|
||||
double time = clock.stop() * 1e6;
|
||||
std::cout << "observe_vector(): " << time << "\n";
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -1,184 +1,184 @@
|
||||
/*
|
||||
* ins_qkf_predict.cpp
|
||||
*
|
||||
* Created on: Sep 2, 2009
|
||||
* Author: Jonathan Brandmeyer
|
||||
|
||||
* This file is part of libeknav.
|
||||
*
|
||||
* Libeknav is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* Libeknav is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with libeknav. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is a modified version by Martin Dieblich
|
||||
* The general changes are a more consequent naming
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "ins_qkf.hpp"
|
||||
#include "assertions.hpp"
|
||||
#ifdef TIME_OPS
|
||||
//#include "timer.hpp"
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
namespace {
|
||||
|
||||
Matrix<double, 3, 3>
|
||||
axis_scale(const Vector3d& axis, double scale)
|
||||
{
|
||||
return (scale - 1) * axis * axis.transpose() + Matrix3d::Identity();
|
||||
}
|
||||
|
||||
void
|
||||
linear_predict(basic_ins_qkf& _this, const Vector3d& gyro_meas, const Vector3d& accel_meas, double dt)
|
||||
{
|
||||
// The two components of rotation that do not spin about the gravity vector
|
||||
// have an influence on the position and velocity of the vehicle.
|
||||
// Let r be an error axis of rotation, and z be the gravity vector.
|
||||
// Increasing r creates increasing error in the direction _|_ to r and z.
|
||||
// By the small angle theorem, the amount of error is ~ abs(r)*abs(z).
|
||||
// Increasing r also creates increasing error in the direction || to -z.
|
||||
// By the small angle theorem, the amount of error is ~ zero.
|
||||
// Therefore, rotate the error block about the z axis by -90 degrees, and
|
||||
// zero out the error vector in the z direction.
|
||||
// accel_cov is the relationship between error vectors in the tangent space
|
||||
// of the vehicle orientation and the translational reference frame.
|
||||
|
||||
|
||||
Matrix3d rot = _this.avg_state.orientation.conjugate().toRotationMatrix();
|
||||
|
||||
Vector3d accel_ecef = rot*accel_meas; // a_e = (q_e2b)^* x a_b = q_b2e x a_b
|
||||
Vector3d accel_gravity = _this.avg_state.position.normalized()*(-9.81);
|
||||
Vector3d accel_resid = accel_ecef + accel_gravity; // a = (xdd-g)+g = xdd;
|
||||
|
||||
#if 0
|
||||
printf("==================================================\n");
|
||||
printf("Quaternion: % 1.4f % 1.4f % 1.4f % 1.4f\n",
|
||||
_this.avg_state.orientation.w(),
|
||||
_this.avg_state.orientation.x(),
|
||||
_this.avg_state.orientation.y(),
|
||||
_this.avg_state.orientation.z());
|
||||
printf("Accel_meas: % 1.4f % 1.4f % 1.4f\n", accel_meas(0), accel_meas(1), accel_meas(2));
|
||||
printf("Accel_ecef: % 1.4f % 1.4f % 1.4f\n", accel_ecef(0), accel_ecef(1), accel_ecef(2));
|
||||
printf("Accel_grav: % 1.4f % 1.4f % 1.4f\n", accel_gravity(0), accel_gravity(1), accel_gravity(2));
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// This form works well with zero static acceleration.
|
||||
Matrix<double, 3, 3> accel_cov =
|
||||
Eigen::AngleAxisd(-M_PI*0.5, _this.avg_state.position.normalized())
|
||||
* axis_scale(_this.avg_state.position.normalized(), 0) * 9.81;
|
||||
#elif 1
|
||||
Matrix<double, 3, 3> accel_cov =
|
||||
Eigen::AngleAxisd(-M_PI*0.5, accel_ecef.normalized())
|
||||
* axis_scale(accel_ecef.normalized(), 0) * accel_meas.norm();
|
||||
#else
|
||||
// The following form ends up being identical to the simpler one
|
||||
// above
|
||||
Matrix<double, 3, 3> accel_cov =
|
||||
Eigen::AngleAxisd(-M_PI*0.5, _this.avg_state.position.normalized())
|
||||
* axis_scale(_this.avg_state.position.normalized(), 0) * 9.81
|
||||
+ Eigen::AngleAxisd(-M_PI*0.5, accel_resid.normalized())
|
||||
* axis_scale(accel_resid.normalized(), 0)*accel_resid.norm();
|
||||
#endif
|
||||
// TODO: Optimization opportunity: the accel_cov doesn't change much over
|
||||
// the life of a mission. Precompute it once and then retain the original.
|
||||
// Then, only one 3x3 block ever gets updated in the A matrix below.
|
||||
|
||||
// The linearized Kalman state projection matrix.
|
||||
#if 0
|
||||
Matrix<double, 12, 12> A;
|
||||
// gyro bias row
|
||||
A << Matrix<double, 3, 3>::Identity(), Matrix<double, 3, 9>::Zero(),
|
||||
// Orientation row
|
||||
_this.avg_state.orientation.conjugate().toRotationMatrix()*-dt,
|
||||
Matrix<double, 3, 3>::Identity(), Matrix<double, 3, 6>::Zero(),
|
||||
// Position row
|
||||
Matrix<double, 3, 3>::Zero(), -accel_cov*0.5*dt*dt,
|
||||
Matrix<double, 3, 3>::Identity(), Matrix<double, 3, 3>::Identity()*dt,
|
||||
// Velocity row
|
||||
Matrix<double, 3, 3>::Zero(), -accel_cov * dt,
|
||||
Matrix<double, 3, 3>::Zero(), Matrix<double, 3, 3>::Identity();
|
||||
|
||||
// 800x realtime, with vectorization
|
||||
_this.cov.part<Eigen::SelfAdjoint>() = A * _this.cov * A.transpose();
|
||||
#else
|
||||
// 1500x realtime, without vectorization, on 2.2 GHz Athlon X2
|
||||
const Matrix<double, 12, 12> cov = _this.cov;
|
||||
const Matrix3d dtR = dt * _this.avg_state.orientation.conjugate().toRotationMatrix();
|
||||
const Matrix3d dtQ = accel_cov * dt;
|
||||
|
||||
_this.cov.block<3, 3>(0, 3) -= cov.block<3,3>(0, 0)*dtR.transpose();
|
||||
_this.cov.block<3, 3>(0, 6) += dt * cov.block<3, 3>(0, 9);
|
||||
_this.cov.block<3, 3>(0, 9) -= cov.block<3, 3>(0, 3) * dtQ.transpose();
|
||||
_this.cov.block<3, 3>(3, 3).part<Eigen::SelfAdjoint>() += dtR*cov.block<3, 3>(0, 0)*dtR.transpose()
|
||||
- dtR*cov.block<3, 3>(0, 3) - cov.block<3, 3>(3, 0)*dtR.transpose();
|
||||
_this.cov.block<3, 3>(3, 6) += -dtR * (cov.block<3, 3>(0, 6) + dt*cov.block<3, 3>(0, 9))
|
||||
+ dt*cov.block<3, 3>(3, 9);
|
||||
_this.cov.block<3, 3>(3, 9) += -dtR*( -cov.block<3, 3>(0, 3)*dtQ.transpose() + cov.block<3, 3>(0, 9))
|
||||
- cov.block<3, 3>(3, 3)*dtQ.transpose();
|
||||
_this.cov.block<3, 3>(6, 6).part<Eigen::SelfAdjoint>() += dt*cov.block<3, 3>(6, 9) + dt*dt*cov.block<3, 3>(9, 9)
|
||||
+ dt*cov.block<3, 3>(9, 6);
|
||||
_this.cov.block<3, 3>(6, 9) += -cov.block<3, 3>(6, 3)*dtQ.transpose() + dt*cov.block<3, 3>(9, 9)
|
||||
- dt*cov.block<3, 3>(9, 3)*dtQ.transpose();
|
||||
_this.cov.block<3, 3>(9, 9).part<Eigen::SelfAdjoint>() += dtQ*cov.block<3, 3>(3, 3)*dtQ.transpose()
|
||||
- dtQ*cov.block<3, 3>(3, 9) - cov.block<3, 3>(9, 3)*dtQ.transpose();
|
||||
|
||||
_this.cov.block<3, 3>(3, 0) = _this.cov.block<3, 3>(0, 3).transpose();
|
||||
_this.cov.block<3, 3>(6, 0) = _this.cov.block<3, 3>(0, 6).transpose();
|
||||
_this.cov.block<3, 3>(6, 3) = _this.cov.block<3, 3>(3, 6).transpose();
|
||||
_this.cov.block<3, 3>(9, 0) = _this.cov.block<3, 3>(0, 9).transpose();
|
||||
_this.cov.block<3, 3>(9, 3) = _this.cov.block<3, 3>(3, 9).transpose();
|
||||
_this.cov.block<3, 3>(9, 6) = _this.cov.block<3, 3>(6, 9).transpose();
|
||||
#endif
|
||||
|
||||
_this.cov.block<3, 3>(0, 0) += _this.gyro_stability_noise.asDiagonal() * dt;
|
||||
_this.cov.block<3, 3>(3, 3) += _this.gyro_white_noise.asDiagonal() * dt;
|
||||
_this.cov.block<3, 3>(6, 6) += _this.accel_white_noise.asDiagonal() * 0.5*dt*dt;
|
||||
_this.cov.block<3, 3>(9, 9) += _this.accel_white_noise.asDiagonal() * dt;
|
||||
|
||||
Quaterniond orientation = exp<double>((gyro_meas - _this.avg_state.gyro_bias) * dt)
|
||||
* _this.avg_state.orientation;
|
||||
//Vector3d accel = accel_ecef - _this.avg_state.position.normalized() * 9.81;
|
||||
//std::cout << " ACCEL______(" << accel.transpose() << ")\n";
|
||||
Vector3d position = _this.avg_state.position + _this.avg_state.velocity * dt + 0.5*accel_resid*dt*dt;
|
||||
Vector3d velocity = _this.avg_state.velocity + accel_resid*dt;
|
||||
|
||||
_this.avg_state.position = position;
|
||||
_this.avg_state.velocity = velocity;
|
||||
_this.avg_state.orientation = orientation;
|
||||
}
|
||||
|
||||
} // !namespace (anon)
|
||||
|
||||
void
|
||||
basic_ins_qkf::predict(const Vector3d& gyro_meas, const Vector3d& accel_meas, double dt)
|
||||
{
|
||||
#ifdef TIME_OPS
|
||||
timer clock;
|
||||
clock.start();
|
||||
#endif
|
||||
|
||||
// Always use linearized prediction
|
||||
linear_predict(*this, gyro_meas, accel_meas, dt);
|
||||
|
||||
#ifdef TIME_OPS
|
||||
double time = clock.stop()*1e6;
|
||||
std::cout << "unscented predict time: " << time << "\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* ins_qkf_predict.cpp
|
||||
*
|
||||
* Created on: Sep 2, 2009
|
||||
* Author: Jonathan Brandmeyer
|
||||
|
||||
* This file is part of libeknav.
|
||||
*
|
||||
* Libeknav is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* Libeknav is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with libeknav. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is a modified version by Martin Dieblich
|
||||
* The general changes are a more consequent naming
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "ins_qkf.hpp"
|
||||
#include "assertions.hpp"
|
||||
#ifdef TIME_OPS
|
||||
//#include "timer.hpp"
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
namespace {
|
||||
|
||||
Matrix<double, 3, 3>
|
||||
axis_scale(const Vector3d& axis, double scale)
|
||||
{
|
||||
return (scale - 1) * axis * axis.transpose() + Matrix3d::Identity();
|
||||
}
|
||||
|
||||
void
|
||||
linear_predict(basic_ins_qkf& _this, const Vector3d& gyro_meas, const Vector3d& accel_meas, double dt)
|
||||
{
|
||||
// The two components of rotation that do not spin about the gravity vector
|
||||
// have an influence on the position and velocity of the vehicle.
|
||||
// Let r be an error axis of rotation, and z be the gravity vector.
|
||||
// Increasing r creates increasing error in the direction _|_ to r and z.
|
||||
// By the small angle theorem, the amount of error is ~ abs(r)*abs(z).
|
||||
// Increasing r also creates increasing error in the direction || to -z.
|
||||
// By the small angle theorem, the amount of error is ~ zero.
|
||||
// Therefore, rotate the error block about the z axis by -90 degrees, and
|
||||
// zero out the error vector in the z direction.
|
||||
// accel_cov is the relationship between error vectors in the tangent space
|
||||
// of the vehicle orientation and the translational reference frame.
|
||||
|
||||
|
||||
Matrix3d rot = _this.avg_state.orientation.conjugate().toRotationMatrix();
|
||||
|
||||
Vector3d accel_ecef = rot*accel_meas; // a_e = (q_e2b)^* x a_b = q_b2e x a_b
|
||||
Vector3d accel_gravity = _this.avg_state.position.normalized()*(-9.81);
|
||||
Vector3d accel_resid = accel_ecef + accel_gravity; // a = (xdd-g)+g = xdd;
|
||||
|
||||
#if 0
|
||||
printf("==================================================\n");
|
||||
printf("Quaternion: % 1.4f % 1.4f % 1.4f % 1.4f\n",
|
||||
_this.avg_state.orientation.w(),
|
||||
_this.avg_state.orientation.x(),
|
||||
_this.avg_state.orientation.y(),
|
||||
_this.avg_state.orientation.z());
|
||||
printf("Accel_meas: % 1.4f % 1.4f % 1.4f\n", accel_meas(0), accel_meas(1), accel_meas(2));
|
||||
printf("Accel_ecef: % 1.4f % 1.4f % 1.4f\n", accel_ecef(0), accel_ecef(1), accel_ecef(2));
|
||||
printf("Accel_grav: % 1.4f % 1.4f % 1.4f\n", accel_gravity(0), accel_gravity(1), accel_gravity(2));
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// This form works well with zero static acceleration.
|
||||
Matrix<double, 3, 3> accel_cov =
|
||||
Eigen::AngleAxisd(-M_PI*0.5, _this.avg_state.position.normalized())
|
||||
* axis_scale(_this.avg_state.position.normalized(), 0) * 9.81;
|
||||
#elif 1
|
||||
Matrix<double, 3, 3> accel_cov =
|
||||
Eigen::AngleAxisd(-M_PI*0.5, accel_ecef.normalized())
|
||||
* axis_scale(accel_ecef.normalized(), 0) * accel_meas.norm();
|
||||
#else
|
||||
// The following form ends up being identical to the simpler one
|
||||
// above
|
||||
Matrix<double, 3, 3> accel_cov =
|
||||
Eigen::AngleAxisd(-M_PI*0.5, _this.avg_state.position.normalized())
|
||||
* axis_scale(_this.avg_state.position.normalized(), 0) * 9.81
|
||||
+ Eigen::AngleAxisd(-M_PI*0.5, accel_resid.normalized())
|
||||
* axis_scale(accel_resid.normalized(), 0)*accel_resid.norm();
|
||||
#endif
|
||||
// TODO: Optimization opportunity: the accel_cov doesn't change much over
|
||||
// the life of a mission. Precompute it once and then retain the original.
|
||||
// Then, only one 3x3 block ever gets updated in the A matrix below.
|
||||
|
||||
// The linearized Kalman state projection matrix.
|
||||
#if 0
|
||||
Matrix<double, 12, 12> A;
|
||||
// gyro bias row
|
||||
A << Matrix<double, 3, 3>::Identity(), Matrix<double, 3, 9>::Zero(),
|
||||
// Orientation row
|
||||
_this.avg_state.orientation.conjugate().toRotationMatrix()*-dt,
|
||||
Matrix<double, 3, 3>::Identity(), Matrix<double, 3, 6>::Zero(),
|
||||
// Position row
|
||||
Matrix<double, 3, 3>::Zero(), -accel_cov*0.5*dt*dt,
|
||||
Matrix<double, 3, 3>::Identity(), Matrix<double, 3, 3>::Identity()*dt,
|
||||
// Velocity row
|
||||
Matrix<double, 3, 3>::Zero(), -accel_cov * dt,
|
||||
Matrix<double, 3, 3>::Zero(), Matrix<double, 3, 3>::Identity();
|
||||
|
||||
// 800x realtime, with vectorization
|
||||
_this.cov.part<Eigen::SelfAdjoint>() = A * _this.cov * A.transpose();
|
||||
#else
|
||||
// 1500x realtime, without vectorization, on 2.2 GHz Athlon X2
|
||||
const Matrix<double, 12, 12> cov = _this.cov;
|
||||
const Matrix3d dtR = dt * _this.avg_state.orientation.conjugate().toRotationMatrix();
|
||||
const Matrix3d dtQ = accel_cov * dt;
|
||||
|
||||
_this.cov.block<3, 3>(0, 3) -= cov.block<3,3>(0, 0)*dtR.transpose();
|
||||
_this.cov.block<3, 3>(0, 6) += dt * cov.block<3, 3>(0, 9);
|
||||
_this.cov.block<3, 3>(0, 9) -= cov.block<3, 3>(0, 3) * dtQ.transpose();
|
||||
_this.cov.block<3, 3>(3, 3).part<Eigen::SelfAdjoint>() += dtR*cov.block<3, 3>(0, 0)*dtR.transpose()
|
||||
- dtR*cov.block<3, 3>(0, 3) - cov.block<3, 3>(3, 0)*dtR.transpose();
|
||||
_this.cov.block<3, 3>(3, 6) += -dtR * (cov.block<3, 3>(0, 6) + dt*cov.block<3, 3>(0, 9))
|
||||
+ dt*cov.block<3, 3>(3, 9);
|
||||
_this.cov.block<3, 3>(3, 9) += -dtR*( -cov.block<3, 3>(0, 3)*dtQ.transpose() + cov.block<3, 3>(0, 9))
|
||||
- cov.block<3, 3>(3, 3)*dtQ.transpose();
|
||||
_this.cov.block<3, 3>(6, 6).part<Eigen::SelfAdjoint>() += dt*cov.block<3, 3>(6, 9) + dt*dt*cov.block<3, 3>(9, 9)
|
||||
+ dt*cov.block<3, 3>(9, 6);
|
||||
_this.cov.block<3, 3>(6, 9) += -cov.block<3, 3>(6, 3)*dtQ.transpose() + dt*cov.block<3, 3>(9, 9)
|
||||
- dt*cov.block<3, 3>(9, 3)*dtQ.transpose();
|
||||
_this.cov.block<3, 3>(9, 9).part<Eigen::SelfAdjoint>() += dtQ*cov.block<3, 3>(3, 3)*dtQ.transpose()
|
||||
- dtQ*cov.block<3, 3>(3, 9) - cov.block<3, 3>(9, 3)*dtQ.transpose();
|
||||
|
||||
_this.cov.block<3, 3>(3, 0) = _this.cov.block<3, 3>(0, 3).transpose();
|
||||
_this.cov.block<3, 3>(6, 0) = _this.cov.block<3, 3>(0, 6).transpose();
|
||||
_this.cov.block<3, 3>(6, 3) = _this.cov.block<3, 3>(3, 6).transpose();
|
||||
_this.cov.block<3, 3>(9, 0) = _this.cov.block<3, 3>(0, 9).transpose();
|
||||
_this.cov.block<3, 3>(9, 3) = _this.cov.block<3, 3>(3, 9).transpose();
|
||||
_this.cov.block<3, 3>(9, 6) = _this.cov.block<3, 3>(6, 9).transpose();
|
||||
#endif
|
||||
|
||||
_this.cov.block<3, 3>(0, 0) += _this.gyro_stability_noise.asDiagonal() * dt;
|
||||
_this.cov.block<3, 3>(3, 3) += _this.gyro_white_noise.asDiagonal() * dt;
|
||||
_this.cov.block<3, 3>(6, 6) += _this.accel_white_noise.asDiagonal() * 0.5*dt*dt;
|
||||
_this.cov.block<3, 3>(9, 9) += _this.accel_white_noise.asDiagonal() * dt;
|
||||
|
||||
Quaterniond orientation = exp<double>((gyro_meas - _this.avg_state.gyro_bias) * dt)
|
||||
* _this.avg_state.orientation;
|
||||
//Vector3d accel = accel_ecef - _this.avg_state.position.normalized() * 9.81;
|
||||
//std::cout << " ACCEL______(" << accel.transpose() << ")\n";
|
||||
Vector3d position = _this.avg_state.position + _this.avg_state.velocity * dt + 0.5*accel_resid*dt*dt;
|
||||
Vector3d velocity = _this.avg_state.velocity + accel_resid*dt;
|
||||
|
||||
_this.avg_state.position = position;
|
||||
_this.avg_state.velocity = velocity;
|
||||
_this.avg_state.orientation = orientation;
|
||||
}
|
||||
|
||||
} // !namespace (anon)
|
||||
|
||||
void
|
||||
basic_ins_qkf::predict(const Vector3d& gyro_meas, const Vector3d& accel_meas, double dt)
|
||||
{
|
||||
#ifdef TIME_OPS
|
||||
timer clock;
|
||||
clock.start();
|
||||
#endif
|
||||
|
||||
// Always use linearized prediction
|
||||
linear_predict(*this, gyro_meas, accel_meas, dt);
|
||||
|
||||
#ifdef TIME_OPS
|
||||
double time = clock.stop()*1e6;
|
||||
std::cout << "unscented predict time: " << time << "\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1,143 +1,143 @@
|
||||
#ifndef AHRS_QUATERNIONS_HPP
|
||||
#define AHRS_QUATERNIONS_HPP
|
||||
|
||||
/*
|
||||
* quaternions.cpp
|
||||
*
|
||||
* Author: Jonathan Brandmeyer
|
||||
*
|
||||
* This file is part of libeknav.
|
||||
*
|
||||
* Libeknav is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* Libeknav is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with libeknav. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
using Eigen::Quaternion;
|
||||
|
||||
template<typename FloatT>
|
||||
Quaternion<FloatT> operator-(const Quaternion<FloatT>& q)
|
||||
{
|
||||
return Quaternion<FloatT>(-q.w(), -q.x(), -q.y(), -q.z());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a rotation from modified Rodrigues parameters to a quaternion.
|
||||
* @param v The multiplication of the rotation angle by the tangent of the angle/4
|
||||
* @return The quaternion corresponding to that rotation.
|
||||
*/
|
||||
template<typename FloatT>
|
||||
Quaternion<FloatT> exp_r(const Eigen::Matrix<FloatT, 3, 1>& v)
|
||||
{
|
||||
// a2 = tan^2(theta/4)
|
||||
FloatT a2 = v.squaredNorm();
|
||||
Quaternion<FloatT> ret;
|
||||
// sin(theta/2) = 2*tan(theta/4) / (1 + tan^2(theta/4))
|
||||
// v == v.normalized() * tan^2(theta/4)
|
||||
ret.vec() = v*(2/(1+a2));
|
||||
// cos(theta/2) = (1 - tan^2(theta/4)) / (1 + tan^2(theta/4))
|
||||
ret.w() = (1-a2)/(1+a2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename FloatT>
|
||||
Eigen::Matrix<FloatT, 3, 1> log_r(const Quaternion<FloatT>& q)
|
||||
{
|
||||
// Note: This algorithm is reasonably safe when using double
|
||||
// precision (to within 1e-10 of precision), but not float.
|
||||
/*
|
||||
* q.w() == cos(theta/2)
|
||||
* q.vec() == sin(theta/2)*v_hat
|
||||
*
|
||||
*
|
||||
* Normal rodrigues params:
|
||||
* v*tan(theta/2) = v*sin(theta/2) / cos(theta/2)
|
||||
* v*tan(theta/2) = q.vec() / q.w()
|
||||
*
|
||||
* Modified rodrigues params (pulls away from infinity at theta=pi)
|
||||
* tan(theta/2) == sin(theta) / (1 + cos(theta))
|
||||
* therefore, tan(theta/4)*v_hat = sin(theta/2)*v_hat / (1 + cos(theta/2))
|
||||
*/
|
||||
return q.vec() / (1.0+q.w());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an angle/axis 3-vector to a unit quaternion
|
||||
* @param v A 3-vector whose length is between 0 and 2*pi
|
||||
* @return The quaternion that represents the same rotation.
|
||||
*/
|
||||
template<typename FloatT>
|
||||
Quaternion<FloatT> exp(Eigen::Matrix<FloatT, 3, 1> v);
|
||||
|
||||
template<typename FloatT>
|
||||
Quaternion<FloatT> exp(Eigen::Matrix<FloatT, 3, 1> v)
|
||||
{
|
||||
FloatT angle = v.norm();
|
||||
if (angle <= Eigen::machine_epsilon<FloatT>()) {
|
||||
// std::cerr << "Warning: tiny quaternion flushed to zero\n";
|
||||
return Quaternion<FloatT>::Identity();
|
||||
}
|
||||
else {
|
||||
Quaternion<FloatT> ret;
|
||||
#if 0
|
||||
if (angle > 1.999*M_PI) {
|
||||
// TODO: I really, really don't like this hack. It should
|
||||
// be impossible to compute an angular measurement update
|
||||
// with a rotation angle greater than this number...
|
||||
v *= 1.999*M_PI / angle;
|
||||
angle = 1.999*M_PI;
|
||||
}
|
||||
#endif
|
||||
assert(angle <= FloatT(2.0*M_PI));
|
||||
#if 0
|
||||
// Oddly enough, this attempt to make the formula faster by reducing
|
||||
// the number of trig calls actually runs slower.
|
||||
FloatT tan_x = std::tan(angle * 0.25);
|
||||
FloatT cos_angle = (1 - tan_x*tan_x)/(1+tan_x*tan_x);
|
||||
FloatT sin_angle = 2*tan_x/(1+tan_x*tan_x);
|
||||
ret.w() = cos_angle;
|
||||
ret.vec() = (sin_angle/angle)*v;
|
||||
#else
|
||||
ret.w() = std::cos(angle*0.5);
|
||||
ret.vec() = (std::sin(angle*0.5)/angle)*v;
|
||||
#endif
|
||||
return ret;
|
||||
// return Quaternion<FloatT>(Eigen::AngleAxis<FloatT>(angle, v / angle));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a unit quaternion to multiplied angle/axis form.
|
||||
* @param q A unit quaternion. The quaternion's norm should be close to unity,
|
||||
* but may be slightly too large or small.
|
||||
* @return The 3-vector in the tangent space of the quaternion q.
|
||||
*/
|
||||
template<typename FloatT>
|
||||
Eigen::Matrix<FloatT, 3, 1> log(const Quaternion<FloatT>& q) __attribute__((noinline));
|
||||
|
||||
template<typename FloatT>
|
||||
Eigen::Matrix<FloatT, 3, 1> log(const Quaternion<FloatT>& q)
|
||||
{
|
||||
FloatT mag = q.vec().norm();
|
||||
if (mag <= Eigen::machine_epsilon<FloatT>()) {
|
||||
// Flush to zero for very small angles. This avoids division by zero.
|
||||
return Eigen::Matrix<FloatT, 3, 1>::Zero();
|
||||
}
|
||||
FloatT angle = 2.0*std::atan2(mag, q.w());
|
||||
return q.vec() * (angle/mag);
|
||||
// Eigen::AngleAxis<FloatT> res(q /*mag <= 1.0) ? q : q.normalized() */);
|
||||
// return res.axis() * res.angle();
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifndef AHRS_QUATERNIONS_HPP
|
||||
#define AHRS_QUATERNIONS_HPP
|
||||
|
||||
/*
|
||||
* quaternions.cpp
|
||||
*
|
||||
* Author: Jonathan Brandmeyer
|
||||
*
|
||||
* This file is part of libeknav.
|
||||
*
|
||||
* Libeknav is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* Libeknav is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with libeknav. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
using Eigen::Quaternion;
|
||||
|
||||
template<typename FloatT>
|
||||
Quaternion<FloatT> operator-(const Quaternion<FloatT>& q)
|
||||
{
|
||||
return Quaternion<FloatT>(-q.w(), -q.x(), -q.y(), -q.z());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a rotation from modified Rodrigues parameters to a quaternion.
|
||||
* @param v The multiplication of the rotation angle by the tangent of the angle/4
|
||||
* @return The quaternion corresponding to that rotation.
|
||||
*/
|
||||
template<typename FloatT>
|
||||
Quaternion<FloatT> exp_r(const Eigen::Matrix<FloatT, 3, 1>& v)
|
||||
{
|
||||
// a2 = tan^2(theta/4)
|
||||
FloatT a2 = v.squaredNorm();
|
||||
Quaternion<FloatT> ret;
|
||||
// sin(theta/2) = 2*tan(theta/4) / (1 + tan^2(theta/4))
|
||||
// v == v.normalized() * tan^2(theta/4)
|
||||
ret.vec() = v*(2/(1+a2));
|
||||
// cos(theta/2) = (1 - tan^2(theta/4)) / (1 + tan^2(theta/4))
|
||||
ret.w() = (1-a2)/(1+a2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename FloatT>
|
||||
Eigen::Matrix<FloatT, 3, 1> log_r(const Quaternion<FloatT>& q)
|
||||
{
|
||||
// Note: This algorithm is reasonably safe when using double
|
||||
// precision (to within 1e-10 of precision), but not float.
|
||||
/*
|
||||
* q.w() == cos(theta/2)
|
||||
* q.vec() == sin(theta/2)*v_hat
|
||||
*
|
||||
*
|
||||
* Normal rodrigues params:
|
||||
* v*tan(theta/2) = v*sin(theta/2) / cos(theta/2)
|
||||
* v*tan(theta/2) = q.vec() / q.w()
|
||||
*
|
||||
* Modified rodrigues params (pulls away from infinity at theta=pi)
|
||||
* tan(theta/2) == sin(theta) / (1 + cos(theta))
|
||||
* therefore, tan(theta/4)*v_hat = sin(theta/2)*v_hat / (1 + cos(theta/2))
|
||||
*/
|
||||
return q.vec() / (1.0+q.w());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an angle/axis 3-vector to a unit quaternion
|
||||
* @param v A 3-vector whose length is between 0 and 2*pi
|
||||
* @return The quaternion that represents the same rotation.
|
||||
*/
|
||||
template<typename FloatT>
|
||||
Quaternion<FloatT> exp(Eigen::Matrix<FloatT, 3, 1> v);
|
||||
|
||||
template<typename FloatT>
|
||||
Quaternion<FloatT> exp(Eigen::Matrix<FloatT, 3, 1> v)
|
||||
{
|
||||
FloatT angle = v.norm();
|
||||
if (angle <= Eigen::machine_epsilon<FloatT>()) {
|
||||
// std::cerr << "Warning: tiny quaternion flushed to zero\n";
|
||||
return Quaternion<FloatT>::Identity();
|
||||
}
|
||||
else {
|
||||
Quaternion<FloatT> ret;
|
||||
#if 0
|
||||
if (angle > 1.999*M_PI) {
|
||||
// TODO: I really, really don't like this hack. It should
|
||||
// be impossible to compute an angular measurement update
|
||||
// with a rotation angle greater than this number...
|
||||
v *= 1.999*M_PI / angle;
|
||||
angle = 1.999*M_PI;
|
||||
}
|
||||
#endif
|
||||
assert(angle <= FloatT(2.0*M_PI));
|
||||
#if 0
|
||||
// Oddly enough, this attempt to make the formula faster by reducing
|
||||
// the number of trig calls actually runs slower.
|
||||
FloatT tan_x = std::tan(angle * 0.25);
|
||||
FloatT cos_angle = (1 - tan_x*tan_x)/(1+tan_x*tan_x);
|
||||
FloatT sin_angle = 2*tan_x/(1+tan_x*tan_x);
|
||||
ret.w() = cos_angle;
|
||||
ret.vec() = (sin_angle/angle)*v;
|
||||
#else
|
||||
ret.w() = std::cos(angle*0.5);
|
||||
ret.vec() = (std::sin(angle*0.5)/angle)*v;
|
||||
#endif
|
||||
return ret;
|
||||
// return Quaternion<FloatT>(Eigen::AngleAxis<FloatT>(angle, v / angle));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a unit quaternion to multiplied angle/axis form.
|
||||
* @param q A unit quaternion. The quaternion's norm should be close to unity,
|
||||
* but may be slightly too large or small.
|
||||
* @return The 3-vector in the tangent space of the quaternion q.
|
||||
*/
|
||||
template<typename FloatT>
|
||||
Eigen::Matrix<FloatT, 3, 1> log(const Quaternion<FloatT>& q) __attribute__((noinline));
|
||||
|
||||
template<typename FloatT>
|
||||
Eigen::Matrix<FloatT, 3, 1> log(const Quaternion<FloatT>& q)
|
||||
{
|
||||
FloatT mag = q.vec().norm();
|
||||
if (mag <= Eigen::machine_epsilon<FloatT>()) {
|
||||
// Flush to zero for very small angles. This avoids division by zero.
|
||||
return Eigen::Matrix<FloatT, 3, 1>::Zero();
|
||||
}
|
||||
FloatT angle = 2.0*std::atan2(mag, q.w());
|
||||
return q.vec() * (angle/mag);
|
||||
// Eigen::AngleAxis<FloatT> res(q /*mag <= 1.0) ? q : q.normalized() */);
|
||||
// return res.axis() * res.angle();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
clear
|
||||
close all
|
||||
|
||||
% DATA
|
||||
t=1:200;
|
||||
orig = sin(t./3)+sin(t./100.*2.*pi);
|
||||
echo = [orig(4:end) 0 0 0]./1.2 + 0.5;
|
||||
echo = echo + randn(size(orig))./10;
|
||||
x = echo;
|
||||
d = orig;
|
||||
|
||||
% RLS
|
||||
rls_p = 5;
|
||||
rls_delta = 1;
|
||||
rls_lambda = 0.95;
|
||||
rls_x = ones(rls_p+1, 1).* x(1);
|
||||
rls_w = ones(rls_p+1, 1)./(rls_p+1);
|
||||
rls_P = eye(rls_p+1) .* rls_delta;
|
||||
|
||||
filt = x;
|
||||
|
||||
for i=t
|
||||
rls_x = [ x(i); rls_x(1:end-2); 1];
|
||||
filt(i) = rls_w' * rls_x;
|
||||
rls_alpha = d(i) - filt(i);
|
||||
rls_g = rls_P * rls_x / (rls_lambda + rls_x' * rls_P * rls_x);
|
||||
rls_P = rls_P / rls_lambda - rls_g*rls_x'* rls_P / rls_lambda;
|
||||
rls_w = rls_w + rls_alpha * rls_g;
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
close all;
|
||||
figure;
|
||||
plot(orig,'r');
|
||||
hold on;
|
||||
plot(echo,'b');
|
||||
plot(filt,'g');
|
||||
|
||||
clear
|
||||
close all
|
||||
|
||||
% DATA
|
||||
t=1:200;
|
||||
orig = sin(t./3)+sin(t./100.*2.*pi);
|
||||
echo = [orig(4:end) 0 0 0]./1.2 + 0.5;
|
||||
echo = echo + randn(size(orig))./10;
|
||||
x = echo;
|
||||
d = orig;
|
||||
|
||||
% RLS
|
||||
rls_p = 5;
|
||||
rls_delta = 1;
|
||||
rls_lambda = 0.95;
|
||||
rls_x = ones(rls_p+1, 1).* x(1);
|
||||
rls_w = ones(rls_p+1, 1)./(rls_p+1);
|
||||
rls_P = eye(rls_p+1) .* rls_delta;
|
||||
|
||||
filt = x;
|
||||
|
||||
for i=t
|
||||
rls_x = [ x(i); rls_x(1:end-2); 1];
|
||||
filt(i) = rls_w' * rls_x;
|
||||
rls_alpha = d(i) - filt(i);
|
||||
rls_g = rls_P * rls_x / (rls_lambda + rls_x' * rls_P * rls_x);
|
||||
rls_P = rls_P / rls_lambda - rls_g*rls_x'* rls_P / rls_lambda;
|
||||
rls_w = rls_w + rls_alpha * rls_g;
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
close all;
|
||||
figure;
|
||||
plot(orig,'r');
|
||||
hold on;
|
||||
plot(echo,'b');
|
||||
plot(filt,'g');
|
||||
|
||||
|
||||
@@ -1,99 +1,99 @@
|
||||
clear
|
||||
close all
|
||||
|
||||
% DATA
|
||||
tmax = 200;
|
||||
t=1:tmax;
|
||||
command = zeros(1,tmax);
|
||||
command(50:150) = 1;
|
||||
|
||||
% reference model
|
||||
vref = zeros(1,tmax);
|
||||
vrefdot = 0;
|
||||
|
||||
sysx = 0.2;
|
||||
sysvx = 0;
|
||||
plotsys = zeros(1,tmax);
|
||||
|
||||
integrator = 0;
|
||||
plotint =zeros(1,tmax);
|
||||
|
||||
x = zeros(1,1:tmax);
|
||||
d = zeros(1,1:tmax);
|
||||
filt = zeros(1,1:tmax);
|
||||
|
||||
% RLS
|
||||
rls_p = 5;
|
||||
rls_delta = 1;
|
||||
rls_lambda = 0.95;
|
||||
rls_x = ones(rls_p+1, 1).* x(1);
|
||||
rls_w = ones(rls_p+1, 1)./(rls_p+1);
|
||||
rls_P = eye(rls_p+1) .* rls_delta;
|
||||
|
||||
for i=2:tmax
|
||||
acc = (command(i) - vref(i-1)) / 8 - vrefdot * 0.7 ;
|
||||
if (acc > 0.02)
|
||||
acc = 0.02;
|
||||
elseif (acc<-0.02)
|
||||
acc = -0.02;
|
||||
end
|
||||
vrefdot = vrefdot + acc;
|
||||
if vrefdot > 0.5
|
||||
vrefdot = 0.5
|
||||
elseif vrefdot < -0.5
|
||||
vrefdot = 0.5
|
||||
end
|
||||
vref(i) = vref(i-1) + vrefdot;
|
||||
|
||||
% Control with Integrator
|
||||
error = vref(i) - sysx + rand(1,1) / 20.0;
|
||||
integrator = integrator + error / 2;
|
||||
syscomm = error * 4 + integrator;
|
||||
|
||||
sysacc = (syscomm - (sysx-0.2)*0.75) / 5 - sysvx*0.6;
|
||||
if (sysacc > 0.04)
|
||||
sysacc = 0.04;
|
||||
elseif (sysacc<-0.04)
|
||||
sysacc = -0.04;
|
||||
end
|
||||
sysvx = sysvx + sysacc;
|
||||
if sysvx > 0.6
|
||||
sysvx = 0.6
|
||||
elseif sysvx < -0.7
|
||||
sysvx = 0.7
|
||||
end
|
||||
sysx = sysx + sysvx;
|
||||
|
||||
plotsys(i) = sysx;
|
||||
plotint(i) = integrator;
|
||||
end
|
||||
|
||||
close all
|
||||
figure
|
||||
plot(command , 'r');
|
||||
hold on
|
||||
plot(vref,'g');
|
||||
plot(plotsys,'b')
|
||||
plot(plotint,'k');
|
||||
|
||||
%% Rest
|
||||
|
||||
|
||||
for i=t
|
||||
rls_x = [ x(i); rls_x(1:end-1)];
|
||||
filt(i) = rls_w' * rls_x;
|
||||
rls_alpha = d(i) - filt(i);
|
||||
rls_g = rls_P * rls_x / (rls_lambda + rls_x' * rls_P * rls_x);
|
||||
rls_P = rls_P / rls_lambda - rls_g*rls_x'* rls_P / rls_lambda;
|
||||
rls_w = rls_w + rls_alpha * rls_g;
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
figure;
|
||||
plot(orig,'r');
|
||||
hold on;
|
||||
plot(echo,'b');
|
||||
plot(filt,'g');
|
||||
|
||||
clear
|
||||
close all
|
||||
|
||||
% DATA
|
||||
tmax = 200;
|
||||
t=1:tmax;
|
||||
command = zeros(1,tmax);
|
||||
command(50:150) = 1;
|
||||
|
||||
% reference model
|
||||
vref = zeros(1,tmax);
|
||||
vrefdot = 0;
|
||||
|
||||
sysx = 0.2;
|
||||
sysvx = 0;
|
||||
plotsys = zeros(1,tmax);
|
||||
|
||||
integrator = 0;
|
||||
plotint =zeros(1,tmax);
|
||||
|
||||
x = zeros(1,1:tmax);
|
||||
d = zeros(1,1:tmax);
|
||||
filt = zeros(1,1:tmax);
|
||||
|
||||
% RLS
|
||||
rls_p = 5;
|
||||
rls_delta = 1;
|
||||
rls_lambda = 0.95;
|
||||
rls_x = ones(rls_p+1, 1).* x(1);
|
||||
rls_w = ones(rls_p+1, 1)./(rls_p+1);
|
||||
rls_P = eye(rls_p+1) .* rls_delta;
|
||||
|
||||
for i=2:tmax
|
||||
acc = (command(i) - vref(i-1)) / 8 - vrefdot * 0.7 ;
|
||||
if (acc > 0.02)
|
||||
acc = 0.02;
|
||||
elseif (acc<-0.02)
|
||||
acc = -0.02;
|
||||
end
|
||||
vrefdot = vrefdot + acc;
|
||||
if vrefdot > 0.5
|
||||
vrefdot = 0.5
|
||||
elseif vrefdot < -0.5
|
||||
vrefdot = 0.5
|
||||
end
|
||||
vref(i) = vref(i-1) + vrefdot;
|
||||
|
||||
% Control with Integrator
|
||||
error = vref(i) - sysx + rand(1,1) / 20.0;
|
||||
integrator = integrator + error / 2;
|
||||
syscomm = error * 4 + integrator;
|
||||
|
||||
sysacc = (syscomm - (sysx-0.2)*0.75) / 5 - sysvx*0.6;
|
||||
if (sysacc > 0.04)
|
||||
sysacc = 0.04;
|
||||
elseif (sysacc<-0.04)
|
||||
sysacc = -0.04;
|
||||
end
|
||||
sysvx = sysvx + sysacc;
|
||||
if sysvx > 0.6
|
||||
sysvx = 0.6
|
||||
elseif sysvx < -0.7
|
||||
sysvx = 0.7
|
||||
end
|
||||
sysx = sysx + sysvx;
|
||||
|
||||
plotsys(i) = sysx;
|
||||
plotint(i) = integrator;
|
||||
end
|
||||
|
||||
close all
|
||||
figure
|
||||
plot(command , 'r');
|
||||
hold on
|
||||
plot(vref,'g');
|
||||
plot(plotsys,'b')
|
||||
plot(plotint,'k');
|
||||
|
||||
%% Rest
|
||||
|
||||
|
||||
for i=t
|
||||
rls_x = [ x(i); rls_x(1:end-1)];
|
||||
filt(i) = rls_w' * rls_x;
|
||||
rls_alpha = d(i) - filt(i);
|
||||
rls_g = rls_P * rls_x / (rls_lambda + rls_x' * rls_P * rls_x);
|
||||
rls_P = rls_P / rls_lambda - rls_g*rls_x'* rls_P / rls_lambda;
|
||||
rls_w = rls_w + rls_alpha * rls_g;
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
figure;
|
||||
plot(orig,'r');
|
||||
hold on;
|
||||
plot(echo,'b');
|
||||
plot(filt,'g');
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,75 +1,75 @@
|
||||
|
||||
close all
|
||||
|
||||
%% Read Data
|
||||
|
||||
% AIR = load('airspeed.txt');
|
||||
% air = AIR(:,5);
|
||||
% desired = AIR(:,6);
|
||||
% climb = AIR(:,7)./100;
|
||||
% speed = AIR(:,8)./100;
|
||||
% alt = AIR(:,9)./100;
|
||||
% course = AIR(:,10)./10;
|
||||
%
|
||||
% airspeed_bias = 64.5;
|
||||
% airspeed_scale = 3.5;
|
||||
|
||||
%% Read data
|
||||
|
||||
AIR = load('airspeed_amp.txt');
|
||||
AIR = AIR(1000:end,:);
|
||||
air = AIR(:,6);
|
||||
desired = AIR(:,9)./100;
|
||||
climb = AIR(:,7)./100;
|
||||
speed = AIR(:,8)./100;
|
||||
alt = AIR(:,9)./100;
|
||||
course = AIR(:,10)./10;
|
||||
|
||||
airspeed_bias = 370;
|
||||
airspeed_scale = 3.5 / 5.7 * 2.4;
|
||||
|
||||
%% Altitude
|
||||
|
||||
figure
|
||||
hold on
|
||||
plot (alt);
|
||||
plot(desired,'r');
|
||||
grid on;
|
||||
|
||||
%% Wind
|
||||
|
||||
windx = 7;
|
||||
windy = 0;
|
||||
|
||||
figure;
|
||||
vx = speed .* cosd(course) + windx;
|
||||
vy = speed .* sind(course) + windy;
|
||||
vz = climb;
|
||||
plot(vx,vy,'bx');
|
||||
grid on;
|
||||
axis equal;
|
||||
|
||||
%% Airspeed Calibration
|
||||
|
||||
gpsairspeed = sqrt(vx.^2 + vy .^2 + vz.^2);
|
||||
|
||||
airsp = air - airspeed_bias;
|
||||
airsp = airsp - airsp .* (airsp < 0);
|
||||
airsp = sqrt(airsp) * airspeed_scale;
|
||||
|
||||
% [b,a] = butter(2,0.1);
|
||||
% airsp = filter(b,a,airsp);
|
||||
% gpsairspeed = filter(b,a,gpsairspeed);
|
||||
|
||||
figure
|
||||
plot(airsp,'b');
|
||||
hold on;
|
||||
plot(gpsairspeed,'r');
|
||||
grid on;
|
||||
legend('air','gps');
|
||||
%plot(climb,'g');
|
||||
|
||||
%% Total Energy
|
||||
|
||||
%Ekin = airsp .*
|
||||
|
||||
|
||||
close all
|
||||
|
||||
%% Read Data
|
||||
|
||||
% AIR = load('airspeed.txt');
|
||||
% air = AIR(:,5);
|
||||
% desired = AIR(:,6);
|
||||
% climb = AIR(:,7)./100;
|
||||
% speed = AIR(:,8)./100;
|
||||
% alt = AIR(:,9)./100;
|
||||
% course = AIR(:,10)./10;
|
||||
%
|
||||
% airspeed_bias = 64.5;
|
||||
% airspeed_scale = 3.5;
|
||||
|
||||
%% Read data
|
||||
|
||||
AIR = load('airspeed_amp.txt');
|
||||
AIR = AIR(1000:end,:);
|
||||
air = AIR(:,6);
|
||||
desired = AIR(:,9)./100;
|
||||
climb = AIR(:,7)./100;
|
||||
speed = AIR(:,8)./100;
|
||||
alt = AIR(:,9)./100;
|
||||
course = AIR(:,10)./10;
|
||||
|
||||
airspeed_bias = 370;
|
||||
airspeed_scale = 3.5 / 5.7 * 2.4;
|
||||
|
||||
%% Altitude
|
||||
|
||||
figure
|
||||
hold on
|
||||
plot (alt);
|
||||
plot(desired,'r');
|
||||
grid on;
|
||||
|
||||
%% Wind
|
||||
|
||||
windx = 7;
|
||||
windy = 0;
|
||||
|
||||
figure;
|
||||
vx = speed .* cosd(course) + windx;
|
||||
vy = speed .* sind(course) + windy;
|
||||
vz = climb;
|
||||
plot(vx,vy,'bx');
|
||||
grid on;
|
||||
axis equal;
|
||||
|
||||
%% Airspeed Calibration
|
||||
|
||||
gpsairspeed = sqrt(vx.^2 + vy .^2 + vz.^2);
|
||||
|
||||
airsp = air - airspeed_bias;
|
||||
airsp = airsp - airsp .* (airsp < 0);
|
||||
airsp = sqrt(airsp) * airspeed_scale;
|
||||
|
||||
% [b,a] = butter(2,0.1);
|
||||
% airsp = filter(b,a,airsp);
|
||||
% gpsairspeed = filter(b,a,gpsairspeed);
|
||||
|
||||
figure
|
||||
plot(airsp,'b');
|
||||
hold on;
|
||||
plot(gpsairspeed,'r');
|
||||
grid on;
|
||||
legend('air','gps');
|
||||
%plot(climb,'g');
|
||||
|
||||
%% Total Energy
|
||||
|
||||
%Ekin = airsp .*
|
||||
|
||||
|
||||
Reference in New Issue
Block a user