Floating point 是否有适合GPS航路点压缩的算法?

Floating point 是否有适合GPS航路点压缩的算法?,floating-point,gps,compression,coordinates,gpx,Floating Point,Gps,Compression,Coordinates,Gpx,我正在寻找任何GPS轨道航路点有损压缩算法,其坐标位于EPSG:4326 CRS(通常的度数如(75.223423,-10.123123)) 简言之,在用Ramer–Douglas–Peucker算法删除元信息和简化后,我得到了一个有序的航路点坐标序列,每个航路点占用16个字节(2 x 8字节双) 利用航路点是有序的,并且在大多数情况下航路点之间的距离小于0.01°(赤道处约1km),我做出了一个假设,这类序列可能存在某种有损压缩算法 你能帮我查一下吗 UPD:根据实际轨迹(~800分析),点之

我正在寻找任何GPS轨道航路点有损压缩算法,其坐标位于
EPSG:4326 CRS
(通常的度数如(75.223423,-10.123123))

简言之,在用Ramer–Douglas–Peucker算法删除元信息和简化后,我得到了一个有序的航路点坐标序列,每个航路点占用16个字节(2 x 8字节

利用航路点是有序的,并且在大多数情况下航路点之间的距离小于0.01°(赤道处约1km),我做出了一个假设,这类序列可能存在某种有损压缩算法

你能帮我查一下吗

UPD:根据实际轨迹(~800分析),点之间的距离(度)如下所示。P95是所有距离的第95个百分位

LON    
    avg: 0,000334560520818109
    p95: 0,001239999999999240 # ~138 meters
    max: 0,307273900000000000
LAT    
    avg: 0,000221987685948093
    p95: 0,000839999999996621
    max: 0,309625799999999000

对于预期的有效数字数和有限的可能值范围,不需要八字节浮点格式。首先,我将把数据转换成一个长度合适的整数序列,它可以表示值的准确性和范围。看起来两个四字节整数就足够了。这里有两个压缩因子

然后用该点与上一点的差值替换每个点,第一个点除外。现在,整数应该更小,允许任何通用无损压缩机进一步减少。如果差值仅在0.1°左右,则可以得到另一个系数2

这是一个简单的例子,对这一点的预测是最后一点。如果你的点序列代表了一条路径,你可以做一些更复杂的事情,比如你模拟一个速度。在这种情况下,使用上次建模的速度传播最后一个点,并从当前点减去该点

修正案


我发现WGS84参考框架本身的精度仅为2-5米。使用三字节整数,您可以在赤道处获得2.4米的分辨率。在差分和压缩之前,这将减少62.5%。它还提供了一个纬度的自由位,因为它有经度的一半范围。该位可用于标记这是绝对坐标还是从上一个坐标预测的坐标。

如果您需要自己编写代码,这里有一个简单的“增量”编码方案的技巧,可以避免不必要地丢失准确性


其思想是压缩器不应该计算当前数据点和最后一个数据点之间的增量,而是计算当前数据点和解压器将为最后一个数据点计算的增量。这意味着量化误差不会累加

作为一个简单的示例,您可能希望仔细阅读/试验以下c代码,该代码将双精度压缩为一个(起始双精度)和一系列浮点:

typedef struct
{   double  start;
    int n;
    float*  delta;
} compT;

compT   compress( int n, const double* data)
{
compT   c = (compT){ data[0], n-1, malloc( (n-1)*sizeof *c.delta)};
double  r = c.start;
    for( int i=1; i<n; ++i)
    {
    float   d = (float)(data[i]-r);
        c.delta[i-1] = d;
        r += d;
    }
    return c;
}

static  double* uncompress( compT c)
{
double* d = malloc( (c.n+1)*sizeof *d);
double  r = c.start;
    d[0] = r;
    for( int i=1; i<=c.n; ++i)
    {   r += c.delta[i-1];
        d[i] = r;
    }
    return d;
}
compT   bad_compress( int n, const double* data)
{
compT   c = (compT){ data[0], n-1, malloc( (n-1)*sizeof *c.delta)};
    for( int i=1; i<n; ++i)
    {
    float   d = (float)(data[i]-data[i-1]);
        c.delta[i-1] = d;
    }
    return c;
}
typedef结构
{双重启动;
int n;
浮动*三角洲;
}compT;
compT compress(整数n,常数双*数据)
{
compT c=(compT){data[0],n-1,malloc((n-1)*sizeof*c.delta)};
双r=c.启动;

对于(int i=1;i我找到了一个现有的解决方案:有适合我需要的数据格式。

  • 它存储几何图元(它支持我当前的需要)。
  • 它使用增量存储数据。
  • 它支持浮点的精度(+2到-2)。
  • 它支持几何图形的ID数据。
  • 它可以使用.Net模块编写

TinyWKB是从
WKT->WKB->TWKB
发展而来的,用于存储几何图元(点、线串、多边形、多点、多线串、多多边形、几何集合)

首先尝试在数据集上使用通用无损压缩工具,以评估潜在的压缩因子。@chux,我认为常用的压缩方法针对重复序列和词汇使用进行了优化。在我的例子中,没有二进制形式的词汇或重复序列,因此压缩太小资源使用率太高(cpu和ram)。“在我的情况下,没有二进制形式的词汇表或重复序列”与“在大多数情况下,航路点之间的距离小于0.01°”——>数据存在模式。“资源使用率太高”不是文章的一部分。如果你有限制,最好在文章中说明。“压缩率太小”-->这个比率是多少?只有在
Optimal
GZip和Deflate时才是35%。最好是
Optimal
Brotli(平均21.5%).测量了5000个真实的GPX文件。我认为它仍然相当大并且没有损失。我将尝试将浮点放大与整数相结合的实验(有损)用默认算法压缩它。***
Optimal
是.net的术语。我认为10m对于我的需求来说是相当好的精度。这个想法很有用,但我害怕重新发明轮子。我希望这种压缩已经被发明和测试过。比如,基于两个三角形,或者基于两个三角形之间的角度和距离o点,对于非标准情况,使用
关键帧
,并采用点之间的实际增量等。我不知道现有的实现。转换和减法非常简单,仅适用于lat-lat和long-long,压缩部分可以依赖现成的软件。注意交叉180E->180W。路径点可以相距几米,但经度约为360度!@dmuir除非路径正好挂在那条线上,来回穿过它,否则交叉对压缩的影响很小。“这意味着量化误差不会累积。”-->好主意。在我的具体案例中,我是通过按顺序添加两种类型的帧来找到它的-关键帧和增量帧。如果计算点和实际点之间的距离离原始点太远,则关键帧帧
typedef struct
{   float   scale;
    double  start;
    int n;
    int16_t*    delta;
} compiT;

compiT  compressi( int n, const double* data, float scale)
{
compiT  c = (compiT){ scale, data[0], n-1, malloc( (n-1)*sizeof *c.delta)};
double  r = c.start;
    for( int i=1; i<n; ++i)
    {
    int16_t d = (int16_t)round(c.scale*(data[i]-r));
        c.delta[i-1] = d;
        r += ((double)d)/c.scale;
    }
    return c;
}

compiT  bad_compressi( int n, const double* data, float scale)
{
compiT  c = (compiT){ scale, data[0], n-1, malloc( (n-1)*sizeof *c.delta)};
    for( int i=1; i<n; ++i)
    {
    int16_t d = (int16_t)round(c.scale*(data[i]-data[i-1]));
        c.delta[i-1] = d;
    }
    return c;
}

static  double* uncompressi( compiT c)
{
double* d = malloc( (c.n+1)*sizeof *d);
double  r = c.start;
    d[0] = r;
    for( int i=1; i<=c.n; ++i)
    {
    double  delta = ((double)c.delta[i-1])/c.scale;
        r += delta;
        d[i] = r;
    }
    return d;
}