6

我有以下代码:

public SensorEventListener sensorEventListener = new SensorEventListener() {
    @Override
    public void onSensorChanged(SensorEvent event) {
        float pressure_value = 0.0f;
        float height = 0.0f;
        if (Sensor.TYPE_PRESSURE == event.sensor.getType())
        {
            pressure_value = event.values[0];
            height = SensorManager.getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, pressure_value);
        }
        value = String.valueOf(height);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }
};

我有高度计,例如上午 9 点的 43,xxxxxxx。

我已经在 09.PM 再次检查它,结果正在改变。它改变2米或更多。

是因为月亮改变了压力还是其他什么?

以及如何解决这个问题?

我已阅读以下主题:Android:如何获得准确的高度?

但我还是很困惑。你能指导我如何编写代码吗?请注意,我想基于气压传感器使用它。

4

3 回答 3

7

气压计提供压力读数,而不是高度读数。

现在因为存在压力梯度,并且通常它随着高度而减小,所以理论上您可以从压力差中推断出高度差。这就是您使用非校准高度计所知道的一切:您不知道您当前的高度,但您会知道何时爬升或下降以及多少。

要根据您当前的压力计算海拔高度,您需要一个参考压力。例如,您需要知道海平面的压力是多少。因此,如果在海平面上压力为 x hPa,并且您的气压计读数为 x+3 hPa,并且您知道压力每米增加 +1hPa,那么您的海拔高度将是海平面以上 3m。

问题是任何参考压力总是会由于气象现象而变化。所以它只会在特定区域内的一段时间内有效。机场为飞机提供此信息,以便他们可以将高度计设置为正确的参考压力(例如QNH)。一旦你知道这个参考压力归一化到海平面( QNH 不是,你最好使用QFF),你可以将它作为第一个参数传递给这个方法:

SensorManager.getAltitude(<reference pressure at sea level>, pressure_value);

请记住,您不能对参考压力进行硬编码。它在不断变化,就像温度一样。您需要在互联网上查找它,或者使用航空气象服务。

于 2015-08-03T23:03:04.653 回答
4

白天和黑夜之间的温度变化会导致气压不同,这就是您获得不同高度读数的原因。如果您可以考虑温度的影响,则可以纠正错误。

于 2015-07-29T04:52:16.740 回答
3

气压传感器测量传感器上方空气柱的压力——它不测量地面以上的高度。幸运的是,存在(大部分)直接相关性。然而,空气压缩和膨胀,柱施加的压力不是恒定的。需要针对空气密度的这种局部变化来校正压力和高度之间的相关性。这种修正引起了飞机飞行员的极大兴趣,因此政府确保每个机场都免费提供这些信息。

因为温度和大气压力一直在随机变化,所以为了最准确,您需要知道您所在地区的 当前标准压力。

您可以先获取最近机场的当前气压计值,然后使用该值代替 PRESSURE_STANDARD_ATMOSPHERE。您将需要知道车站 ID,或指定一个纬度/经度矩形。请参阅METAR 站规范

但是...如果您当前的误差只有2米,那已经很好了。您永远无法从气压高度计获得准确的高度——这就是发明雷达高度计的原因。

http://www.aviationweather.gov/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=xml&stationString=KSFO&hoursBeforeNow=1&mostRecent=true

这将返回 KSFO(旧金山)的最新 METAR:

<?xml version="1.0" encoding="UTF-8"?>
<response xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XML-Schema-instance" version="1.2" xsi:noNamespaceSchemaLocation="http://aviationweather.gov/adds/schema/metar1_2.xsd">
  <request_index>34600121</request_index>
  <data_source name="metars" />
  <request type="retrieve" />
  <errors />
  <warnings />
  <time_taken_ms>1</time_taken_ms>
  <data num_results="1">
    <METAR>
      <raw_text>KSFO 061756Z 30011KT 10SM FEW008 BKN160 19/13 A2992 RMK AO2 SLP132 T01890133 10189 20150 51006</raw_text>
      <station_id>KSFO</station_id>
      <observation_time>2015-08-06T17:56:00Z</observation_time>
      <latitude>37.62</latitude>
      <longitude>-122.37</longitude>
      <temp_c>18.9</temp_c>
      <dewpoint_c>13.3</dewpoint_c>
      <wind_dir_degrees>300</wind_dir_degrees>
      <wind_speed_kt>11</wind_speed_kt>
      <visibility_statute_mi>10.0</visibility_statute_mi>
      <altim_in_hg>29.920275</altim_in_hg>
      <sea_level_pressure_mb>1013.2</sea_level_pressure_mb>
      <quality_control_flags>
        <auto_station>TRUE</auto_station>
      </quality_control_flags>
      <sky_condition sky_cover="FEW" cloud_base_ft_agl="800" />
      <sky_condition sky_cover="BKN" cloud_base_ft_agl="16000" />
      <flight_category>VFR</flight_category>
      <three_hr_pressure_tendency_mb>0.6</three_hr_pressure_tendency_mb>
      <maxT_c>18.9</maxT_c>
      <minT_c>15.0</minT_c>
      <metar_type>SPECI</metar_type>
      <elevation_m>3.0</elevation_m>
    </METAR>
  </data>
</response>

您想要提取sea_level_pressure_mb1013.2 的值。

这是在您当前位置的地图上显示当前气压的片段。

我开始编写“正确”的代码来解析 XML,但是当我不得不遍历节点时失去了兴趣。我把它作为一个学习练习,而是写了“hack”版本。

/***********************************************************************/
/** Page2: Simple example of using Google Map.                        **/
/** TeasingDart                                                       **/
/***********************************************************************/
package com.nlited.twopages;

import android.app.Activity;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

import org.w3c.dom.Document;
import org.xml.sax.InputSource;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

public class Page2 extends MapFragment implements LocationListener {
  private static Page2 mObj;
  private Activity mActivity;
  private View mView;
  private MapView mMapView;
  private GoogleMap mMap;
  private LocationManager mLocMgr;
  private String mLocProvider;
  private Location mLoc;
  private LatLng mLatLng= new LatLng(43,-122);
  private boolean mSlpFound= false;
  private float mSLP= 1012;
  private String mStationID;
  private long mNextSlpCheck= 0;

  static public Page2 getInstance() {
    if(mObj==null)
      mObj= new Page2();
    return(mObj);
  }

  public Page2() {
    Debug("constructor %s", this.toString());
    mObj= this;
  }

  @Override public void onAttach(Activity activity) {
    Debug("onAttach()");
    mActivity= (Main)activity;
    super.onAttach(activity);
    startLocation();
    new Thread(new GetSLP(),"GetSLP").start();
  }

  @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) {
    mActivity= (Main)getActivity();
    Debug("onCreateView()");
    super.onCreateView(inflater, container, state);
    mView= inflater.inflate(R.layout.frag_page2, container, false);
    mMapView= (MapView)mView.findViewById(R.id.map);
    mMapView.onCreate(state);
    mMapView.onResume();
    mMap= mMapView.getMap();
    mapUpdate();
    return(mView);
  }

  /***********************************************************************/
  /** Update the map using my GPS location and current SLP.             **/
  /***********************************************************************/
  private void mapUpdate() {
    MarkerOptions opt = new MarkerOptions();
    if(mMap!=null) {
      String status= mSlpFound ? String.format("%.1f %s",mSLP,mStationID) : "????";
      mMap.clear();
      mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(mLatLng, 15));
      mMap.addMarker(opt.position(mLatLng).title(status));
    }
  }

  /***********************************************************************/
  /** Retrieve my current GPS location.                                 **/
  /***********************************************************************/
  private void startLocation() {
    mLocMgr= (LocationManager)mActivity.getSystemService(Activity.LOCATION_SERVICE);
    if(mLocMgr==null) {
      Debug("Location services are not available.");
    } else if(!mLocMgr.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
      Debug("GPS is not enabled.");
    } else {
      mLocProvider= mLocMgr.getBestProvider(new Criteria(),false);
      if(mLocProvider==null) {
        Debug("No GPS providers available.");
      } else {
        mLoc = mLocMgr.getLastKnownLocation(mLocProvider);
        mLocMgr.requestLocationUpdates(mLocProvider,30000,1,this);
      }
    }
  }

  @Override public void onLocationChanged(Location loc) {
    Debug("Updated location: %f %f",loc.getLatitude(),loc.getLongitude());
    mLoc= loc;
    mLatLng= new LatLng(mLoc.getLatitude(), mLoc.getLongitude());
    if(System.currentTimeMillis() >= mNextSlpCheck)
      new Thread(new GetSLP(),"GetSLP").start();
    mapUpdate();
  }

  @Override public void onStatusChanged(String provider, int status, Bundle state) {
    Debug("Location %s state is now %d.",provider,status);
    if(status>0)
      mapUpdate();
  }

  @Override public void onProviderEnabled(String provider) {
    Debug("Location %s is now enabled.",provider);
  }

  @Override public void onProviderDisabled(String provider) {
    Debug("Location %s is now disabled.",provider);
  }

  /***********************************************************************/
  /** Background task to request the sea level pressure (SLP) from      **/
  /** the closest reporting station.                                    **/
  /***********************************************************************/
  private class GetSLP implements Runnable {
    public void run() {
      int range;
      boolean found= false;
      //Next check in 15 minutes from now.
      mNextSlpCheck= System.currentTimeMillis()+15*60*1000;
      for(range=10;range<100;range+=10) {
        URL url = buildUrl(range);
        if(url!=null) {
          String xml = fetch(url);
          if(xml!=null) {
            //found= parse(xml);
            String slp= hack("sea_level_pressure_mb",xml);
            if(slp!=null) {
              mSLP= Float.parseFloat(slp);
              mStationID= hack("station_id", xml);
              found = true;
              break;
            }
          }
        }
      }
      if(found) {
        Debug("Station found within %dkm.", range);
        mSlpFound = true;
        mActivity.runOnUiThread(new Runnable(){ public void run() { mapUpdate(); } });
      } else {
        Debug("No stations found within 100km!");
      }
    }

    //Build the request URL using a radial range from the current (longitude,latitude)
    private URL buildUrl(int range) {
      URL url= null;
      String protocol= "http";
      String host= "www.aviationweather.gov";
      String page= "adds/dataserver_current/httpparam";
      String parms= "dataSource=metars&requestType=retrieve&format=xml&hoursBeforeNow=1&mostRecent=true";
      parms+= String.format("&radialDistance=%d;%f,%f",range,mLatLng.longitude,mLatLng.latitude);
      String urlStr= String.format("%s://%s/%s?%s",protocol,host,page,parms);
      try {
        url = new URL(urlStr);
      } catch(Exception ex) {
        Debug("buildUrl(%s) blew up.", urlStr);
      }
      return(url);
    }

    //Fetch the most current METARS report as an xml document.
    private String fetch(URL url) {
      String text= null;
      try {
        HttpURLConnection connect = (HttpURLConnection)url.openConnection();
        InputStream strm= connect.getInputStream();
        BufferedReader reader= new BufferedReader(new InputStreamReader(strm));
        StringBuilder xml= new StringBuilder();
        String line;
        while((line= reader.readLine())!=null) {
          xml.append(line);
        }
        reader.close();
        text= xml.toString();
      } catch(Exception ex) {
        Debug("GetSLP.fetch() blew up.");
      }
      return(text);
    }

    //Quick hack version to extract a value from the xml string.
    private String hack(String name, String xml) {
      String value= null;
      String tag= String.format("<%s>",name);
      int nStart= xml.indexOf(tag);
      if(nStart>=0) {
        int nEnd = xml.indexOf("</", nStart+tag.length());
        if(nEnd>nStart) {
          value = xml.substring(nStart+tag.length(), nEnd);
        }
      }
      return(value);
    }

    //The proper (but incomplete) method to parse the xml document.
    private boolean parse(String xml) {
      boolean found= false;
      Float slp= 0.0f;
      try {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        InputSource src= new InputSource();
        src.setCharacterStream(new StringReader(xml));
        Document doc = builder.parse(src);
        //TODO: Walk the nodes down to "sea_level_pressure_mb"
        //slp= Float.parseFloat(value);
        //found= true;
      } catch(Exception ex) {
        Debug("GetSLP.parse() blew up.");
      }
      return(found);
    }
  }

  private void Debug(String fmt, Object... args) { Log.w("2Page:Page2", String.format(fmt, args)); }
}
//EOF: PAGE2.JAVA

布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  android:paddingBottom="@dimen/activity_vertical_margin"
  android:background="@color/ForestGreen"
  tools:context=".Page2"
>
  <TextView
    android:id="@+id/Page2_Title"
    android:text="This is Page Two"
    android:textSize="24pt"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:gravity="center"
  />
  <com.google.android.gms.maps.MapView
    android:id="@+id/map"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_below="@+id/Page2_Title"
  />
</RelativeLayout>
于 2015-08-06T19:20:25.380 回答