海上自动识别系统(Marine AIS)中使用的接受算法(在IEC61193-2中指定)是
Rhumb Line算法。我已经成功地在目标上实现了这一点,使用了
Anthony Williams' fixed point maths library,该库使用
CORDIC算法,并且通常比软件浮点数提供约5倍的性能改进。
然而,该库是C ++而不是C,由于广泛的运算符重载,使其易于使用,但可能不是您要寻找的。然而,考虑为您的C代码使用C++编译,仅出于使用此库的好处。当然,问题在于Microchip的C31编译器奇怪地不支持C ++。
然而,一个警告是
log()
函数的查找表缺少一个值,并且需要在末尾添加一个额外的元素,其值为零。我发现这一点后,Anthony确认了这一点,但我不认为他已经更新了下载。
无论如何,答案可能是使用定点和CORDIC。
为了将经度或赤道弧分辨率设置为1m,您需要8位数字精度,因此单精度浮点数不足,使用双精度会显著减慢速度。检查MikroElectronica的C用户手册发现,编译器仅支持单精度-
float
,
double
和
long double
都是32位,因此在任何情况下都无法使用内置FP类型实现所需的精度。
如果有用的话,这是我的Rhumb Line代码,使用了Anthony的库:
头文件:
#if !defined cRhumbLine_INCLUDE
#define cRhumbLine_INCLUDE
#include "fixed.hpp"
class cRhumbLine
{
public:
cRhumbLine() : m_update_bearing(false), m_update_distance(false), m_distance(0), m_bearing(0) {}
cRhumbLine( fixed startLatDeg, fixed startLonDeg, fixed endLatDeg, fixed endLonDeg )
{
define( startLatDeg, startLonDeg, endLatDeg, endLonDeg ) ;
}
void define( fixed startLatDeg, fixed startLonDeg, fixed endLatDeg, fixed endLonDeg ) ;
fixed distanceNm() { return distanceMetres() / ONE_NM_IN_METRE ; }
fixed distanceMetres() ;
fixed bearingDeg() ;
private:
static const int ONE_NM_IN_METRE = 1852 ;
bool m_update_bearing ;
bool m_update_distance ;
fixed m_distance ;
fixed m_bearing ;
fixed m_delta_phi ;
fixed m_delta_lon ;
fixed m_delta_lat ;
fixed m_lat1_radians ;
} ;
#endif
身体:
#include "cRhumbLine.h"
void cRhumbLine::define( fixed startLatDeg, fixed startLonDeg, fixed endLatDeg, fixed endLonDeg )
{
fixed lat1 = startLatDeg / 180 * fixed_pi ;
fixed lon1 = startLonDeg / 180 * fixed_pi ;
fixed lat2 = endLatDeg / 180 * fixed_pi ;
fixed lon2 = endLonDeg / 180 * fixed_pi ;
m_update_bearing = true ;
m_update_distance = true ;
m_delta_phi = log( tan( lat2 / 2 + fixed_quarter_pi ) / tan( lat1 / 2 + fixed_quarter_pi ) ) ;
m_delta_lat = lat1 - lat2 ;
m_delta_lon = lon1 - lon2 ;
m_lat1_radians = lat1 ;
if( m_delta_lon.abs() > fixed_pi )
{
m_delta_lon = m_delta_lon > 0 ? -(fixed_two_pi - m_delta_lon) : (fixed_two_pi + m_delta_lon) ;
}
}
fixed cRhumbLine::distanceMetres()
{
if( m_update_distance )
{
static const fixed mean_radius = 6371009 ;
fixed q = m_delta_phi != 0 ? m_delta_lat / m_delta_phi : cos( m_lat1_radians ) ;
m_distance = sqrt( ( sqr(m_delta_lat) + sqr(q) * sqr(m_delta_lon) ) ) * mean_radius ;
m_update_distance = false ;
}
return m_distance ;
}
fixed cRhumbLine::bearingDeg()
{
if( m_update_bearing )
{
static const fixed mean_radius = 6371009 ;
m_bearing = atan2( m_delta_lon, m_delta_phi ) / fixed_pi * 180 ;
if( m_bearing == -180 )
{
m_bearing == 0 ;
}
else if( m_bearing < 0 )
{
m_bearing += 360 ;
}
m_update_bearing = false ;
}
return m_bearing ;
}