1 // simulates ridge lift
3 // Written by Patrice Poly
4 // Copyright (C) 2009 Patrice Poly - p.polypa@gmail.com
7 // Entirely based on the paper :
8 // http://carrier.csi.cam.ac.uk/forsterlewis/soaring/sim/fsx/dev/sim_probe/sim_probe_paper.html
9 // by Ian Forster-Lewis, University of Cambridge, 26th December 2007
12 // This program is free software; you can redistribute it and/or
13 // modify it under the terms of the GNU General Public License as
14 // published by the Free Software Foundation; either version 2 of the
15 // License, or (at your option) any later version.
17 // This program is distributed in the hope that it will be useful, but
18 // WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 // General Public License for more details.
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
33 #include <Main/fg_props.hxx>
34 #include <Main/globals.hxx>
35 #include <Scenery/scenery.hxx>
41 #include "ridge_lift.hxx"
44 FGRidgeLift::FGRidgeLift ()
46 dist_probe_m[0] = 0.0; // in meters
47 dist_probe_m[1] = 250.0;
48 dist_probe_m[2] = 750.0;
49 dist_probe_m[3] = 2000.0;
50 dist_probe_m[4] = -100.0;
52 BOUNDARY1_m = 40.0; // in meters
55 PI = 4.0*atan(1.0); // pi
62 earth_rad_ft=20899773.07;
66 FGRidgeLift::~FGRidgeLift()
71 void FGRidgeLift::init(void)
73 _ridge_lift_fps_node =
74 fgGetNode("/environment/ridge-lift-fps"
76 _surface_wind_from_deg_node =
77 fgGetNode("/environment/config/boundary/entry[0]/wind-from-heading-deg"
79 _surface_wind_speed_node =
80 fgGetNode("/environment/config/boundary/entry[0]/wind-speed-kt"
83 fgGetNode("/position/sea-level-radius-ft"
85 _user_longitude_node =
86 fgGetNode("/position/longitude-deg"
89 fgGetNode("/position/latitude-deg"
91 _user_altitude_ft_node =
92 fgGetNode("/position/altitude-ft"
94 _user_altitude_agl_ft_node =
95 fgGetNode("/position/altitude-agl-ft"
99 void FGRidgeLift::bind() {
101 fgTie("/environment/ridge-lift/probe-elev-m[0]", this,
102 &FGRidgeLift::get_probe_elev_m_0); // read-only
103 fgTie("/environment/ridge-lift/probe-elev-m[1]", this,
104 &FGRidgeLift::get_probe_elev_m_1); // read-only
105 fgTie("/environment/ridge-lift/probe-elev-m[2]", this,
106 &FGRidgeLift::get_probe_elev_m_2); // read-only
107 fgTie("/environment/ridge-lift/probe-elev-m[3]", this,
108 &FGRidgeLift::get_probe_elev_m_3); // read-only
109 fgTie("/environment/ridge-lift/probe-elev-m[4]", this,
110 &FGRidgeLift::get_probe_elev_m_4); // read-only
112 fgTie("/environment/ridge-lift/probe-lat-deg[0]", this,
113 &FGRidgeLift::get_probe_lat_0); // read-only
114 fgTie("/environment/ridge-lift/probe-lat-deg[1]", this,
115 &FGRidgeLift::get_probe_lat_1); // read-only
116 fgTie("/environment/ridge-lift/probe-lat-deg[2]", this,
117 &FGRidgeLift::get_probe_lat_2); // read-only
118 fgTie("/environment/ridge-lift/probe-lat-deg[3]", this,
119 &FGRidgeLift::get_probe_lat_3); // read-only
120 fgTie("/environment/ridge-lift/probe-lat-deg[4]", this,
121 &FGRidgeLift::get_probe_lat_4); // read-only
123 fgTie("/environment/ridge-lift/probe-lon-deg[0]", this,
124 &FGRidgeLift::get_probe_lon_0); // read-only
125 fgTie("/environment/ridge-lift/probe-lon-deg[1]", this,
126 &FGRidgeLift::get_probe_lon_1); // read-only
127 fgTie("/environment/ridge-lift/probe-lon-deg[2]", this,
128 &FGRidgeLift::get_probe_lon_2); // read-only
129 fgTie("/environment/ridge-lift/probe-lon-deg[3]", this,
130 &FGRidgeLift::get_probe_lon_3); // read-only
131 fgTie("/environment/ridge-lift/probe-lon-deg[4]", this,
132 &FGRidgeLift::get_probe_lon_4); // read-only
134 fgTie("/environment/ridge-lift/slope[0]", this,
135 &FGRidgeLift::get_slope_0); // read-only
136 fgTie("/environment/ridge-lift/slope[1]", this,
137 &FGRidgeLift::get_slope_1); // read-only
138 fgTie("/environment/ridge-lift/slope[2]", this,
139 &FGRidgeLift::get_slope_2); // read-only
140 fgTie("/environment/ridge-lift/slope[3]", this,
141 &FGRidgeLift::get_slope_3); // read-only
145 void FGRidgeLift::unbind() {
147 fgUntie("/environment/ridge-lift/probe-elev-m[0]");
148 fgUntie("/environment/ridge-lift/probe-elev-m[1]");
149 fgUntie("/environment/ridge-lift/probe-elev-m[2]");
150 fgUntie("/environment/ridge-lift/probe-elev-m[3]");
151 fgUntie("/environment/ridge-lift/probe-elev-m[4]");
153 fgUntie("/environment/ridge-lift/probe-lat-deg[0]");
154 fgUntie("/environment/ridge-lift/probe-lat-deg[1]");
155 fgUntie("/environment/ridge-lift/probe-lat-deg[2]");
156 fgUntie("/environment/ridge-lift/probe-lat-deg[3]");
157 fgUntie("/environment/ridge-lift/probe-lat-deg[4]");
159 fgUntie("/environment/ridge-lift/probe-lon-deg[0]");
160 fgUntie("/environment/ridge-lift/probe-lon-deg[1]");
161 fgUntie("/environment/ridge-lift/probe-lon-deg[2]");
162 fgUntie("/environment/ridge-lift/probe-lon-deg[3]");
163 fgUntie("/environment/ridge-lift/probe-lon-deg[4]");
165 fgUntie("/environment/ridge-lift/slope[0]");
166 fgUntie("/environment/ridge-lift/slope[1]");
167 fgUntie("/environment/ridge-lift/slope[2]");
168 fgUntie("/environment/ridge-lift/slope[3]");
172 void FGRidgeLift::update(double dt) {
176 double FGRidgeLift::sign(double x) {
183 void FGRidgeLift::Run(double dt) {
187 user_latitude_deg = _user_latitude_node->getDoubleValue();
188 user_longitude_deg = _user_longitude_node->getDoubleValue();
189 //user_altitude_ft = _user_altitude_ft_node->getDoubleValue();
191 if ( ( _earth_radius_node->getDoubleValue() ) > 1.0 ) {
192 earth_rad_ft =_earth_radius_node->getDoubleValue(); }
193 else { earth_rad_ft=20899773.07; }
195 //earth_rad_m = earth_rad_ft * 0.3048 ;
196 earth_rad_m = earth_rad_ft * SG_FEET_TO_METER ;
198 //get the windspeed at ground level
200 double ground_wind_from_deg = _surface_wind_from_deg_node->getDoubleValue();
201 double ground_wind_speed_kts = _surface_wind_speed_node->getDoubleValue();
202 //double ground_wind_speed_mps = ground_wind_speed_kts / SG_METER_TO_FEET;
203 double ground_wind_speed_mps = ground_wind_speed_kts / 3.2808399;
205 double ground_wind_from_rad = (user_longitude_deg < 0.0) ?
206 PI*( ground_wind_from_deg/180.0) +PI : PI*( ground_wind_from_deg/180.0);
208 // Placing the probes
210 for (int i = 0; i <= 4; i++)
212 probe_lat_rad[i] = asin(sin(deg2rad*user_latitude_deg)*cos(dist_probe_m[i]/earth_rad_m)
213 +cos(deg2rad*user_latitude_deg)*sin(dist_probe_m[i]/earth_rad_m)*cos(ground_wind_from_rad));
214 if (probe_lat_rad[i] == 0.0) {
215 probe_lon_rad[i] = (deg2rad*user_latitude_deg); // probe on a pole
218 probe_lon_rad[i] = fmod((deg2rad*user_longitude_deg+asin(sin(ground_wind_from_rad)
219 *sin(dist_probe_m[i]/earth_rad_m)/cos(probe_lon_rad[i]))+PI)
222 probe_lat_deg[i]= rad2deg*probe_lat_rad[i];
223 probe_lon_deg[i]= rad2deg*probe_lon_rad[i];
232 for (int i = 0; i <= 4; i++)
234 if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(
235 SGGeod::fromRad(probe_lon_rad[i],probe_lat_rad[i]), 20000), alt, 0));
237 probe_elev_m[i] = alt;
248 slope[0] = (probe_elev_m[0] - probe_elev_m[1]) / dist_probe_m[1];
249 slope[1] = (probe_elev_m[1] - probe_elev_m[2]) / dist_probe_m[2];
250 slope[2] = (probe_elev_m[2] - probe_elev_m[3]) / dist_probe_m[3];
251 slope[3] = (probe_elev_m[4] - probe_elev_m[0]) / -dist_probe_m[4];
253 for (int i = 0; i <= 4; i++)
255 adj_slope[i] = sin(atan(5.0 * pow ( (abs(slope[i])),1.7) ) ) *sign(slope[i]);
260 adj_slope[0] = 0.2 * adj_slope[0];
261 adj_slope[1] = 0.2 * adj_slope[1];
262 if ( adj_slope [2] < 0.0 )
264 adj_slope[2] = 0.5 * adj_slope[2];
271 if ( ( adj_slope [0] >= 0.0 ) && ( adj_slope [3] < 0.0 ) )
277 adj_slope[3] = 0.2 * adj_slope[3];
280 double lift_factor = adj_slope[0]+adj_slope[1]+adj_slope[2]+adj_slope[3];
282 //user altitude above ground
284 user_altitude_agl_ft = _user_altitude_agl_ft_node->getDoubleValue();
285 user_altitude_agl_m = ( user_altitude_agl_ft / SG_METER_TO_FEET );
290 if ( user_altitude_agl_m < BOUNDARY1_m )
292 agl_factor = 0.5+0.5*user_altitude_agl_m /BOUNDARY1_m ;
294 else if ( user_altitude_agl_m < BOUNDARY2_m )
300 agl_factor = exp(-(2 + 2 * probe_elev_m[0] / 4000) *
301 (user_altitude_agl_m - BOUNDARY2_m) / max(probe_elev_m[0],200.0));
304 double lift_mps = lift_factor* ground_wind_speed_mps * agl_factor;
306 //the updraft, finally, in ft per second
307 strength = lift_mps * SG_METER_TO_FEET ;
309 _ridge_lift_fps_node->setDoubleValue( strength );