2015-07-29 1 views
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) { 

    } 
}; 

Я получил метр 43 высоты например, XXXXXXX на 09.AM.

И я проверил его снова в 09.PM, результат меняется. Он меняет 2 метра или больше.

Это потому, что давление изменилось луной или чем-нибудь еще?

И как это исправить?

Я прочитал следующую тему: Android: How to get accurate altitude?

Но я все равно получил confused.Could ты ведешь меня, как писать код? И для заметки, я хочу использовать его на основе барометрического датчика.

ответ

4

Изменение температуры между днем ​​и ночью приводит к разнице давлений воздуха, и по этой причине вы получаете разные показания высоты. Если вы можете учитывать влияние температуры, ошибка может быть исправлена.

7

Барометры обеспечивают показания давления, а не высотные.

Теперь, поскольку существует градиент давления, и в целом он уменьшается с высотой, вы теоретически можете определить разницу в высоте от разницы в давлении. Это все, что вы знаете, с некалиброванным альтиметром: вы не знаете свою текущую высоту, но вы будете знать, когда будете подниматься или спускаться и сколько.

Для вычисления высоты от текущего давления вам понадобится опорное давление. Например, вам нужно знать, какое давление находится на уровне моря. Поэтому, если на уровне моря давление составляет х гПа, а ваш барометр читает х + 3 гПа, и вы знаете, что давление увеличивается + 1hPa за метр, ваша высота будет на 3 м выше уровня моря.

Проблема заключается в том, что любое эталонное давление всегда будет меняться в связи с метеорологическими явлениями. Таким образом, это будет действовать только в течение определенного времени в определенной области. Аэропорты предоставляют эту информацию для самолетов, чтобы они могли устанавливать свои высотомеры с правильным опорным давлением (например, QNH). После того, как вы знаете, это опорное давление, нормированное к уровню моря (QNH нет, то лучше использовать QFF), вы можете передать его в качестве первого параметра этого метода:

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

И помните, что вы не можете жёстко ссылку давление. Он постоянно меняется, как температура. Вам нужно искать его в Интернете или использовать авиационные метеорологические службы.

+0

Может показать мне somr примера, что <опорного давления на уровне моря>? Есть ли способ получить текущую решетку? Самый точный я имею в виду –

+0

Вы могли бы выбрать метеорологическую станцию ​​рядом с вами и прочитать давление, а затем нормализовать ее до уровня моря, зная высоту станции. Или самый простой способ, просто выберите ближайший аэропорт, проконсультируйтесь с METAR (тип сообщения, который они транслируют) и найдите поле давления на уровне моря (SLP). Существуют приложения-декодеры METAR в Google Play и по всему Интернету. –

+0

Я читал из моего ближайшего метафора. У меня давление на уровне моря составляет 1012 гПа. Из чего я должен это делать? –

3

Датчик атмосферного давления измеряет давление от колонки воздух над датчиком - он не измеряет высоту над землей. К счастью, существует (в основном) прямая корреляция. Однако воздух сжимается и расширяется, а давление, оказываемое колонкой, равно . Корреляция между давлением и высотой должна быть , скорректированной для этого локального изменения плотности воздуха. Эта коррекция представляет большой интерес для пилотов самолетов, поэтому правительство гарантирует, что каждый аэропорт делает эту информацию свободно доступной.

Поскольку температура и барометрическое давление случайным образом меняется все время, так, чтобы быть наиболее точным вам нужно будет знать текущее стандартное давление в вашем регионе.

Вы можете сначала получить текущее значение барометра для ближайшего аэропорта , а затем использовать это значение вместо PRESSURE_STANDARD_ATMOSPHERE. Вам нужно знать идентификатор станции или указать прямоугольник lat/long. См. METAR station specifications.

BUT ... Если ваша текущая ошибка составляет всего 2 метра, то есть уже очень хорошо. Вы никогда не получите точную высоту от барометрического высотомера - вот почему были изобретены радарные альтиметры.

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

Это возвращает последнее METAR для KSFO (Сан-Франциско):

<?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_mb которое 1013,2.

Вот фрагмент, который отображает текущее барометрическое давление на карте вашего текущего местоположения .

Я начал писать «правильный» код для анализа XML, но потерял интерес , когда мне пришлось спуститься по узлам. Я оставил это как учебное упражнение и написал вместо него «взломанную» версию.

/***********************************************************************/ 
/** 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> 
+0

Где я должен поставить этот код? В веб-службе? –

+0

SLP изменяется постоянно, но медленно, поэтому я запускаю HTTP GET для METAR, когда приложение запускается и учитывает ответ, действительный около 15 минут или около того. Вы не хотите ждать веб-ответа каждый раз, когда вы проверяете датчик. – TeasingDart

+0

Я не понимал, что вы имеете в виду. Можете ли вы направить меня от шага к шагу? Я понимаю, что метаданные должны быть загружены часто. Я просто не смог получить его с сайта www.aviationweather.gov. –

Смежные вопросы