Example #1
0
void TestZigZag(double V_wind, double theta_wind) {
  double t, V_tas, V_gps, theta_gps, theta_glider;

  int i;
  for (i=0; i<=NUM_SAMPLES; i++) {
    t = i;
    V_tas = 20.0;
    theta_glider = sin(t*M_PI*2.0/NUM_SAMPLES)*30*DEGTORAD;
    double V_gps_x = V_tas * sin(theta_glider) - V_wind*sin(theta_wind);
    double V_gps_y = V_tas * cos(theta_glider) - V_wind*cos(theta_wind);

    V_gps = sqrt(V_gps_x*V_gps_x+V_gps_y*V_gps_y);
    theta_gps = atan2(V_gps_x,V_gps_y);

    myzigzag.AddPoint(t, V_tas, V_gps, theta_gps);
  }

  // ok, ready to calculate
  if (myzigzag.CheckSpread(t+1, 0.0)) {
    // data is ok to make an estimate
    double V_wind_estimate=1;
    double theta_wind_estimate=0;
    double percent_error;
    percent_error = myzigzag.StartSearch(V_wind_estimate, theta_wind_estimate);
    myzigzag.Estimate(&V_wind_estimate, &theta_wind_estimate, &percent_error);

    DebugStore("%2.1f %2.1f %03.0f %03.0f %2.1f # test zigzag\n",
            V_wind,
            V_wind_estimate,
            theta_wind/DEGTORAD,
            theta_wind_estimate/DEGTORAD,
            percent_error
            );
  }
}
Example #2
0
void
WindStore::newWind(const NMEA_INFO *nmeaInfo, DERIVED_INFO *derivedInfo,
                   Vector &wind)
{
  //
  double mag = sqrt(wind.x*wind.x+wind.y*wind.y);
  double bearing;

  if (wind.y == 0 && wind.x == 0)
    bearing = 0;
  else
    bearing = atan2(wind.y, wind.x)*RAD_TO_DEG;

  if (mag<30) { // limit to reasonable values
    derivedInfo->WindSpeed = mag;
    if (bearing<0) {
      bearing += 360;
    }
    derivedInfo->WindBearing = bearing;
  } else {
    // TODO code: give warning, wind estimate bogus or very strong!
  }

#ifdef DEBUG_WIND
  DebugStore("%f %f 0 # wind estimate\n",wind.x,wind.y);
#endif

}
Example #3
0
static bool WindZigZagCheckAirData(NMEA_INFO* Basic, DERIVED_INFO* Calculated)
{
  static double tLast = -1;
  static double bearingLast=0;

  bool airdata_invalid = false;
  if (!Calculated->Flying) {
    airdata_invalid = true;
  } else if (fabs(Calculated->TurnRate)>20.0) {
    airdata_invalid = true;
#ifdef DEBUG_ZIGZAG_A
    DebugStore("zigzag airdata invalid - turn rate\n");
#endif
  } else if (fabs(Basic->TrueAirspeed)<GlidePolar::Vminsink*0.8) {
    airdata_invalid = true;
#ifdef DEBUG_ZIGZAG_A
    DebugStore("zigzag airdata invalid - true airspeed\n");
#endif
  } else if (fabs(Basic->Speed)<2.5) {
    airdata_invalid = true;
#ifdef DEBUG_ZIGZAG_A
    DebugStore("zigzag airdata invalid - ground speed\n");
#endif
  } else if (Basic->AccelerationAvailable && (fabs(Basic->AccelZ-1.0)>0.3)) {
    airdata_invalid = true;
#ifdef DEBUG_ZIGZAG_A
    DebugStore("zigzag airdata invalid - acceleration\n");
#endif
  }
  if (airdata_invalid) {
    tLast = Basic->Time; // blackout for SAMPLE_RATE seconds
    return false;
  }
  if ((Basic->Time<tLast+SAMPLE_RATE) &&
      (fabs(bearingLast-Basic->TrackBearing)<10.0)) {
    return false;
  } else {
    tLast = Basic->Time;
    bearingLast = Basic->TrackBearing;
  }
  return true;
}
Example #4
0
  bool CheckSpread(double time, double error) {
    double spread = CheckValidity(time);
    if (spread<0) {
#ifdef DEBUG_ZIGZAG_A
        DebugStore("zigzag time invalid\n");
#endif
        return false;
    }
    spread /= DEGTORAD;
    double minspread;

    minspread = 10.0+30.0/(1.0+error*error/30.0);
    // nominal spread required is 40 degrees, smaller if large
    // error is detected

    if ((spread>360.0)||(spread< minspread)) {
      // invalid if really circling or if not enough zig-zag
#ifdef DEBUG_ZIGZAG_A
      DebugStore("zigzag spread invalid %03.1f\n", spread);
#endif
      return false;
    }
    return true;
  }
Example #5
0
void CuSondeLevel::updateThermalIndex(unsigned short level,
				      bool newdata) {
  double hlevel = level*CUSONDE_HEIGHTSTEP;

  tempDry = DALR*(hlevel-CuSonde::hGround)+CuSonde::maxGroundTemperature;

  // thermal index is difference in dry temp and environmental temp
  thermalIndex = airTemp-tempDry;

#ifdef DEBUG_CUSONDE
  if (newdata) {
    DebugStore("%g %g %g %g # temp measurement \r\n",
	    hlevel, airTemp, dewpoint, thermalIndex);
  }
#endif

}
Example #6
0
/**
 * Calculates the ThermalIndex for the given height level
 *
 * ThermalIndex is the difference in dry temp and environmental temp
 * at the specified altitude.
 * @param level level = altitude / CUSONDE_HEIGHTSTEP
 * @param newdata Function logs data to debug file if true
 */
void CuSondeLevel::updateThermalIndex(unsigned short level,
				      bool newdata) {
  double hlevel = level*CUSONDE_HEIGHTSTEP;

  // Calculate the dry temperature at altitude = hlevel
  tempDry = DALR*(hlevel-CuSonde::hGround)+CuSonde::maxGroundTemperature;

  // Calculate ThermalIndex
  thermalIndex = airTemp-tempDry;

#ifdef DEBUG_CUSONDE
  if (newdata) {
    DebugStore("%g %g %g %g # temp measurement \r\n",
	    hlevel, airTemp, dewpoint, thermalIndex);
  }
#endif
}
Example #7
0
void WindAnalyser::slot_newEstimate(NMEA_INFO *nmeaInfo,
                                    DERIVED_INFO *derivedInfo,
                                    Vector a, int quality)
{

#ifdef DEBUG_WIND
  const char *type;

  if (quality>=6) {
    type = "external wind";
  } else {
    type = "wind circling";
  }
  DebugStore("%f %f %d # %s\n", a.x, a.y, quality, type);
#endif

  windstore.slot_measurement(nmeaInfo, derivedInfo, a, quality);
}
Example #8
0
void LastThermalStats(NMEA_INFO *Basic, DERIVED_INFO *Calculated)
{
  static int LastCircling = FALSE;

  if((Calculated->Circling == FALSE) && (LastCircling == TRUE)
     && (Calculated->ClimbStartTime>=0))
    {
      double ThermalTime = Calculated->CruiseStartTime 
        - Calculated->ClimbStartTime;
                                      
      if(ThermalTime >0)
        {
          double ThermalGain = Calculated->CruiseStartAlt + Calculated->EnergyHeight
            - Calculated->ClimbStartAlt;

          if (ThermalGain>0) {
            if (ThermalTime>THERMAL_TIME_MIN) {

	      Calculated->LastThermalAverage = ThermalGain/ThermalTime;
	      Calculated->LastThermalGain = ThermalGain;
	      Calculated->LastThermalTime = ThermalTime;

              flightstats.ThermalAverage.
                least_squares_update(Calculated->LastThermalAverage);

#ifdef DEBUG_STATS
              DebugStore("%f %f # thermal stats\n",
                      flightstats.ThermalAverage.m,
                      flightstats.ThermalAverage.b
                      );
#endif
              if (EnableThermalLocator) {
                ThermalSources(Basic, Calculated);
              }
            }
	  }
	}
    }
  LastCircling = Calculated->Circling;
}
Example #9
0
void CuSonde::findCloudBase(unsigned short level) {
  if (cslevels[level+1].nmeasurements==0) return;
  if (cslevels[level].nmeasurements==0) return;

  double dti = (cslevels[level+1].tempDry-cslevels[level+1].dewpoint)
              -(cslevels[level].tempDry-cslevels[level].dewpoint);

  cslevels[level].cloudBase = -1;

  if (fabs(dti)<1.0e-3) {
    return;
  }

  // ti = dlevel * dti + ti0;
  // (-3 - ti0)/dti = dlevel;

  LKASSERT(dti!=0);
  double dlevel = -(cslevels[level].tempDry-cslevels[level].dewpoint)/dti;
  double dcloudbase = (level+dlevel)*CUSONDE_HEIGHTSTEP;
  if (dlevel>0.0) {
    if (dlevel>1.0) {
      if ((level+2<CUSONDE_NUMLEVELS)
	  && (cslevels[level+2].nmeasurements>0)) {
	// estimated point should be in next level.
	return;
      }
    }
    cslevels[level].cloudBase = dcloudbase;

    // set the overall cloudbase to this value
    cloudBase = dcloudbase;

#ifdef DEBUG_CUSONDE
    DebugStore("%g # cloud base \r\n", cloudBase);
#endif

  }

}
Example #10
0
void CuSonde::findThermalHeight(unsigned short level) {
  if (cslevels[level+1].nmeasurements==0) return;
  if (cslevels[level].nmeasurements==0) return;

  double dti = cslevels[level+1].thermalIndex - cslevels[level].thermalIndex;

  cslevels[level].thermalHeight = -1;

  if (fabs(dti)<1.0e-3) {
    return;
  }

  // ti = dlevel * dti + ti0;
  // (-1.6 - ti0)/dti = dlevel;

  LKASSERT(dti!=0);
  double dlevel = (TITHRESHOLD-cslevels[level].thermalIndex)/dti;
  double dthermalheight = (level+dlevel)*CUSONDE_HEIGHTSTEP;
  if (dlevel>0.0) {
    if (dlevel>1.0) {
      if ((level+2<CUSONDE_NUMLEVELS)
	  && (cslevels[level+2].nmeasurements>0)) {
	// estimated point should be in next level.
	return;
      }

    }
    cslevels[level].thermalHeight = dthermalheight;

    // set the overall thermal height to this value
    thermalHeight = dthermalheight;

#ifdef DEBUG_CUSONDE
    DebugStore("%g # thermal height \r\n", thermalHeight);
#endif
  }

}
Example #11
0
// This is called at the end of slow calculation AirspaceWarning function, after tables have been filled up
void AirspaceWarnListProcess(NMEA_INFO *Basic, DERIVED_INFO *Calculated){

  if (!InitDone) return;

  LockList();
  __try{
    for (List<AirspaceInfo_c>::Node* it = AirspaceWarnings.begin(); it;){
      
      it->data.TimeOut--;                // age the entry
      
      if (it->data.TimeOut < 0){
	
        it->data.Predicted = false;
        it->data.Inside = false;
        it->data.WarnLevel = 0;

        int hDistance = 0;
        int vDistance = 0;
        int Bearing = 0;

        AirspaceWarnListCalcDistance(Basic, Calculated,
				     it->data.IsCircle, 
				     it->data.AirspaceIndex, 
				     &hDistance, &Bearing, &vDistance);

        it->data.hDistance = hDistance; // for all: update data
        it->data.vDistance = vDistance;
        it->data.Bearing = Bearing;
        it->data.TimeOut = OUTSIDE_CHECK_INTERVAL; // retrigger checktimeout


        if (calcWarnLevel(&it->data))
          AirspaceWarnListDoNotify(asaWarnLevelIncreased, &it->data);

        UpdateAirspaceAckBrush(&it->data, 0);

        if (it->data.Acknowledge == 4){ // whole day achnowledged
          if (it->data.SortKey > 25000) {
            it->data.TimeOut = 60; // JMW hardwired why?
          }
          continue;
        }

        if ((hDistance > 2500) || (abs(vDistance) > 250)){  
	  // far away remove from warning list
          AirspaceInfo_c asi = it->data;

          it = AirspaceWarnings.erase(it);
          UpdateAirspaceAckBrush(&asi, -1);
          AirspaceWarnListDoNotify(asaItemRemoved, &asi);

          continue;

        } else {
          if ((hDistance > 500) || (abs(vDistance) > 100)){   
	    // close clear inside ack and auto ACK til closer
            if (it->data.Acknowledge > 2)
              if (--(it->data.InsideAckTimeOut) < 0){      // timeout the
                it->data.Acknowledge = 1;
              }

          } else { // very close, just update ack timer
            it->data.InsideAckTimeOut = AcknowledgementTime / OUTSIDE_CHECK_INTERVAL;
	    // 20sec outside check interval prevent down ACK on circling
          }
        }

        AirspaceWarnListDoNotify(asaItemChanged, &it->data);

      }

      // SortTheList();

      /*

      // just for debugging

      TCHAR szMessageBuffer[1024];

      if (it->data.IsCircle){

        int i = it->data.AirspaceIndex;

        wsprintf(szMessageBuffer, TEXT("%20s %d %d %5d %5d"), AirspaceCircle[i].Name, it->data.Inside, it->data.Predicted, (int)it->data.hDistance, (int)it->data.vDistance);

      } else {

        int i = it->data.AirspaceIndex;

        wsprintf(szMessageBuffer, TEXT("%20s %d %d %5d %5d"), AirspaceArea[i].Name, it->data.Inside, it->data.Predicted, (int)it->data.hDistance, (int)it->data.vDistance);

      }

      devPutVoice(NULL, szMessageBuffer);
      */

      it = it->next;

    }


    AirspaceWarnListSort();

#ifdef DEBUG_AIRSPACE
    DebugStore("%d # airspace\n", AirspaceWarnGetItemCount());
#endif

    AirspaceWarnListDoNotify(asaProcessEnd, NULL);

  }__finally {
    UnLockList();
  }

}
Example #12
0
//
// This is called FORCED when changing multimap
//
void SetTopologyBounds(const RECT& rcin, const ScreenProjection& _Proj, const bool force) {
  static rectObj bounds_active;
  static double range_active = 1.0;
  bool unchanged=false;
  static double oldmapscale=0;
  static short runnext=0;
  
  rectObj bounds_screen = MapWindow::CalculateScreenBounds(1.0, rcin, _Proj);

  if (!force) {
	if (oldmapscale!=MapWindow::zoom.Scale()) {
		#if DEBUG_STB2
		StartupStore(_T("... scale changed to %f\n"),MapWindow::zoom.Scale());
		#endif
		oldmapscale=MapWindow::zoom.Scale();
	} else
		unchanged=true;
  }

  bool recompute = false;

  // only recalculate which shapes when bounds change significantly
  // need to have some trigger for this..

  // trigger if the border goes outside the stored area
  if (!RectangleIsInside(bounds_active, bounds_screen)) {
    #if DEBUG_STB
    StartupStore(_T("(recompute for out of rectangle)\n"));
    #endif
    recompute = true;
  }
  
  // also trigger if the scale has changed heaps
  double range_real = max((bounds_screen.maxx-bounds_screen.minx), 
			  (bounds_screen.maxy-bounds_screen.miny));
  double range = max(MINRANGE,range_real);

  double scale = range/range_active;

  if (max(scale, 1.0/scale)>2) {  // tighter threshold
	#if DEBUG_STB
	StartupStore(_T("(recompute for OUT OF SCALE)\n"),scale);
	#endif
	recompute = true;
  }

  if (recompute || force || LKSW_ForceNearestTopologyCalculation) {

    #if DEBUG_STB
    StartupStore(_T("..... Run Recompute, Force=%d LKSW=%d unchanged=%d\n"),force,LKSW_ForceNearestTopologyCalculation,unchanged);
    #endif

    #if 0 // 121208
    // make bounds bigger than screen
    if (range_real<MINRANGE) {
      scale = BORDERFACTOR*MINRANGE/range_real;
    } else {
      // 121208 this is creating problems after a low zoom
      // scale = BORDERFACTOR;
    }
    #endif

    bounds_active = MapWindow::CalculateScreenBounds(scale, rcin, _Proj);

    range_active = max((bounds_active.maxx-bounds_active.minx), 
		       (bounds_active.maxy-bounds_active.miny));
    
    for (int z=0; z<MAXTOPOLOGY; z++) {
      if (TopoStore[z]) {
	TopoStore[z]->triggerUpdateCache=true;          
      }
    }
    #if USETOPOMARKS
    if (topo_marks) {
      topo_marks->triggerUpdateCache = true;
    }
    #endif

    // now update visibility of objects in the map window
    MapWindow::ScanVisibility(&bounds_active);

    runnext=NUMRUNS;
    unchanged=false;

  } else {
	if (unchanged) { // nothing has changed, can we skip?
		#if DEBUG_STB2
		StartupStore(_T("... Nothing has changed\n"));
		#endif
		if (runnext<=0) {
			#if DEBUG_STB2
			StartupStore(_T("..... no runnext, skip\n"));
			#endif
			return;
		} else {
			#if DEBUG_STB2
			StartupStore(_T("..... ONE MORE run\n"));
			#endif
			runnext--;
		}
	} else
		runnext=NUMRUNS;
  }

  
  #if DEBUG_STB
  StartupStore(_T("------ Run full update --- \n"));
  #endif

  // check if things have come into or out of scale limit
  for (int z=0; z<MAXTOPOLOGY; z++) {
    if (TopoStore[z]) {
      TopoStore[z]->TriggerIfScaleNowVisible();          
    }
  }

  // ok, now update the caches
  #if USETOPOMARKS 
  if (topo_marks) {
    topo_marks->updateCache(bounds_active);
  }
  #endif

    // check if any needs to have cache updates because wasnt 
    // visible previously when bounds moved
    bool sneaked = false;
    bool rta;

    // we will make sure we update at least one cache per call
    // to make sure eventually everything gets refreshed

    int total_shapes_visible = 0;
    for (int z = 0; z < MAXTOPOLOGY; z++) {
        if (TopoStore[z]) {
            rta = MapWindow::RenderTimeAvailable() || force || !sneaked;
            if (TopoStore[z]->triggerUpdateCache) {
                sneaked = true;
            }
            TopoStore[z]->updateCache(bounds_active, !rta);
            total_shapes_visible += TopoStore[z]->shapes_visible_count;
        }
    }
#ifdef DEBUG_GRAPHICS
    DebugStore("%d # shapes\n", total_shapes_visible);
#endif
}
Example #13
0
int WindZigZagUpdate(NMEA_INFO* Basic, DERIVED_INFO* Calculated,
		      double *zzwindspeed, double *zzwindbearing) {
  static double tLastEstimate = -1;

  if (!Basic->AirspeedAvailable) {
    return 0;
  }

#if (WINDOWSPC>0)
#ifdef DEBUG_ZIGZAG
  TestZigZagLoop();
#endif
#endif  

  // TODO accuracy: correct TAS for vertical speed if dynamic pullup

  if ((Basic->Time<= tLastEstimate)||(tLastEstimate==-1)) {
    tLastEstimate = Basic->Time-UPDATE_RATE;
  }

  if (!WindZigZagCheckAirData(Basic, Calculated)) {
    return 0;
  }

  // ok to add a point

  myzigzag.AddPoint(Basic->Time, Basic->TrueAirspeed, 
		    Basic->Speed, Basic->TrackBearing*DEGTORAD);

#ifdef DEBUG_ZIGZAG_A
    DebugStore("%f %03.0f %03.0f %03.0f # zigpoint\n",
            Basic->Time,
            Basic->TrueAirspeed,
            Basic->Speed,
            Basic->TrackBearing);
#endif

  // don't update wind from zigzag more often than 
  // every UPDATE_RATE seconds, so it is balanced with respect
  // to circling
  if (Basic->Time<tLastEstimate+UPDATE_RATE) {
    return 0;
  } 

  double V_wind_estimate = Calculated->WindSpeed;
  double theta_wind_estimate = Calculated->WindBearing*DEGTORAD;
  double percent_error = 
    myzigzag.StartSearch(V_wind_estimate, theta_wind_estimate);

  // Check spread of zig-zag manoeuver
  if (!myzigzag.CheckSpread(Basic->Time, percent_error)) {
    return 0;
  }

  double v_error = percent_error*Basic->TrueAirspeed/100.0;

  if (v_error<0.5) {
    // don't refine search if error is small

#ifdef DEBUG_ZIGZAG
    DebugStore("zigzag error small %02.0f %03.1f\n",
            percent_error, v_error);
#endif
    return 0;
  }

  if (myzigzag.Estimate(&V_wind_estimate, 
                        &theta_wind_estimate, 
                        &percent_error)) {

    // ok, we have made an update
    tLastEstimate = Basic->Time;

    theta_wind_estimate /= DEGTORAD;
    
    *zzwindspeed = V_wind_estimate;
    *zzwindbearing = theta_wind_estimate;

    // calculate error quality
    int quality;
    //    double pes = v_error/(V_SCALE/NUM_V_POINTS);
    //quality = iround(0.5+4.5/(1.0+percent_error*percent_error/30.0));
    quality = max(1,5-iround(percent_error/2));
    if (Calculated->Circling) {
      quality = max(1,quality/2); // de-value updates in circling mode
    }

#ifdef DEBUG_ZIGZAG
    DebugStore("%f %3.1f %03.0f %3.1f %03.0f %f %d # zigzag\n",
            Basic->Time,
            V_wind_estimate,
            theta_wind_estimate,
            Calculated->WindSpeed, 
            Calculated->WindBearing,
            percent_error,
            quality);
#endif
    return quality;
  } else {
#ifdef DEBUG_ZIGZAG
    DebugStore("zigzag estimate failed to improve\n");
#endif
  }
  return 0;
}