2016-05-17 124 views
2

假设我有一个系统将8820个值分配到96个值中,使用Banker's Round(称为他们的pulse)进行舍入。其计算公式为:如何检查范围内的值是否来自另一个范围的值的倍数?

pulse = BankerRound(8820 * i/96), with i[0,96[ 

因此,这是脉冲的列表:

0 
92 
184 
276 
368 
459 
551 
643 
735 
827 
919 
1011 
1102 
1194 
1286 
1378 
1470 
1562 
1654 
1746 
1838 
1929 
2021 
2113 
2205 
2297 
2389 
2481 
2572 
2664 
2756 
2848 
2940 
3032 
3124 
3216 
3308 
3399 
3491 
3583 
3675 
3767 
3859 
3951 
4042 
4134 
4226 
4318 
4410 
4502 
4594 
4686 
4778 
4869 
4961 
5053 
5145 
5237 
5329 
5421 
5512 
5604 
5696 
5788 
5880 
5972 
6064 
6156 
6248 
6339 
6431 
6523 
6615 
6707 
6799 
6891 
6982 
7074 
7166 
7258 
7350 
7442 
7534 
7626 
7718 
7809 
7901 
7993 
8085 
8177 
8269 
8361 
8452 
8544 
8636 
8728 

现在,假设系统不直接发送给我这些脉冲。相反,它发送的第八千八百二这些脉冲(称他们为tick):

tick = value * 1/8820 

蜱的名单我得到变成:

0 
0.010430839 
0.020861678 
0.031292517 
0.041723356 
0.052040816 
0.062471655 
0.072902494 
0.083333333 
0.093764172 
0.104195011 
0.11462585 
0.124943311 
0.13537415 
0.145804989 
0.156235828 
0.166666667 
0.177097506 
0.187528345 
0.197959184 
0.208390023 
0.218707483 
0.229138322 
0.239569161 
0.25 
0.260430839 
0.270861678 
0.281292517 
0.291609977 
0.302040816 
0.312471655 
0.322902494 
0.333333333 
0.343764172 
0.354195011 
0.36462585 
0.375056689 
0.38537415 
0.395804989 
0.406235828 
0.416666667 
0.427097506 
0.437528345 
0.447959184 
0.458276644 
0.468707483 
0.479138322 
0.489569161 
0.5 
0.510430839 
0.520861678 
0.531292517 
0.541723356 
0.552040816 
0.562471655 
0.572902494 
0.583333333 
0.593764172 
0.604195011 
0.61462585 
0.624943311 
0.63537415 
0.645804989 
0.656235828 
0.666666667 
0.677097506 
0.687528345 
0.697959184 
0.708390023 
0.718707483 
0.729138322 
0.739569161 
0.75 
0.760430839 
0.770861678 
0.781292517 
0.791609977 
0.802040816 
0.812471655 
0.822902494 
0.833333333 
0.843764172 
0.854195011 
0.86462585 
0.875056689 
0.88537415 
0.895804989 
0.906235828 
0.916666667 
0.927097506 
0.937528345 
0.947959184 
0.958276644 
0.968707483 
0.979138322 
0.989569161 

不幸的是,这些刻度之间发送给我也fake ticks,那不是原来的pulses的繁殖。比如0,029024943,它是256的倍数,不在脉冲列表中。

如何从此列表中找到哪些刻度是valid哪些是fake? 由于8820会在此期间发生变化,因此我没有要在此过程中进行比较的脉冲列表,因此我没有列表逐步比较。我需要在每次迭代时从滴答中推断出它。

什么是最好的数学方法呢?也许推理只是在嘀嗒声而不是脉搏。

我以为找到最近的整数脉冲和prev/next tick之间的近似误差。 Here在C++:

double pulse = tick * 96.; 
double prevpulse = (tick - 1/8820.) * 96.; 
double nextpulse = (tick + 1/8820.) * 96.; 

int pulseRounded=round(pulse); 
int buffer=lrint(tick * 8820.); 

double pulseABS = abs(pulse - pulseRounded); 
double prevpulseABS = abs(prevpulse - pulseRounded); 
double nextpulseABS = abs(nextpulse - pulseRounded); 

if (nextpulseABS > pulseABS && prevpulseABS > pulseABS) { 
    // is pulse 
} 

但例如蜱0.0417234(脉冲368)失败,因为先前误差蜱似乎比它更接近:prevpulseABS误差(0.00543795)比pulseABS误差(0.0054464)小。

这是因为这个比较并不关心我猜的四舍五入。

+0

为什么不只是将所有的脉冲值存储在列表中,并且系统在列表中向您发送值搜索时呢? – Dialecticus

+0

你能否简化这个例子来处理六个数值而不是96?另请注意,SO使用英语,小数点分隔符是“。”,而不是“,”。 –

+0

脉冲列出它不是我可以检查和比较的固定列表。 8820可能因时间而异,因此会产生蜱和脉冲。唯一真正的固定值是滴答。 – markzzz

回答

1

新的职位:

好吧。根据我现在了解的内容,这里是我修改后的答案。

你有你需要的信息来建立一个好值的列表。每次切换到新的轨道:

vector<double> good_list; 
good_list.reserve(96); 
for(int i = 0; i < 96; i++) 
    good_list.push_back(BankerRound(8820.0 * i/96.0)/8820.0); 

然后,每次要验证输入:

auto iter = find(good_list.begin(), good_list.end(), input); 
if(iter != good_list.end()) //It's a match! 
    cout << "Happy days! It's a match!" << endl; 
else 
    cout << "Oh bother. It's not a match." << endl; 

与数学上确定正确的脉冲的问题是BankerRound()函数,其将引入一个不断增长的错误,您输入的值越高。然后,你需要一个公式的公式,这是从我的驾驶室里走出来。或者,您可以跟踪连续值之间的差异。他们中的大多数将是相同的。你只需要检查两个可能的错误。但是,如果你能跳一首歌或者在一首歌中跳来跳去,那就会崩溃。

旧文章:

如果我没有理解这个问题吧,你得到的唯一信息,应在(P/V = Y)的形式来,你知道“Y”(这是每个元素在你从设备中获得的蜱列表中)并且你知道'p'是Pulse,'v'是每Beat值,但你不知道它们是什么。所以,拉一个数据点从你的文章,你可能有这样一个公式:

P/V = 0.010430839

“V”,在迄今为止你使用的所有例子,就是8820,但根据我的理解,这个价值不是一个有保证的常数。接下来的问题是:在开始获取所有这些十进制值之前,您是否有办法确定“v”是什么?如果你这样做,你可以用数学方法计算出最小误差是多少(1/v),然后把你的小数点信息乘以'v',四舍五入到最接近的整数,然后检查它的舍入形式和非圆的形式落在你的计算错误,像这样的界限:

double input; //let input be elements in your list of doubles, such as 0.010430839 
double allowed_error = 1.0/values_per_beat; 
double proposed = input * values_per_beat; 
double rounded = std::round(proposed); 
if(abs(rounded - proposed) < allowed_error){cout << "It's good!" << endl;} 

但是,如果你是能够提前确定values_per_beat,那么这将成为一个统计问题。您必须累积足够的数据样本,删除异常值(与标准不同的少数值)并使用该数据。但是这种方法并不是实时的,考虑到你使用的术语(每搏值,每分钟转数,值44100),这听起来像是实时可能是你在做什么。

+0

我可以在每次迭代时获得values_per_beat,所以我对此很满意。这就是那个害怕我的“圆”。 – markzzz

+0

使用你的8820作为values_per_beat,然后,这里是一个为什么这将起作用的例子。 1/8820是小数可以不同的数量,因为它被认为是不同的值(如93/8820 - 92/8820 = 1/8820)。 – Altainia

+0

不知道你的代码有什么问题:http://cpp.sh/2hlei但是这里没有一个值的作品:( – markzzz

0

我假设你在for循环中初始化你的脉冲,使用int i作为循环变量;那么问题是这一行:

BankerRound(8820 * i/96); 

8820 * i/96是一个全整数运算,结果是整数再次,切断其余(因此,实际上,总是朝着零已经四舍五入),并BankerRound实际上没有什么可圆任何更多。试试这个:

BankerRound(8820 * i/96.0); 

同样的问题适用,如果你想计算prev和next脉冲,因为你居然减去并添加0(再次,1/8820都是整数,结果为0)。

编辑:

从我从commments读取时,“系统”是不是–我认为以前–修改。实际上,它会以

n/96.0, n &#x220a [0, 96) in ℕ
的形式计算刻度,但其中包括某种内部舍入,显然与采样频率无关,因此与n/96.0的真实值存在一些差异,并且刻度乘以96不能完全提供积分值[0,96)(感谢KarstenKoop)。而一些交付的样品是简单无效的...

因此,任务是检测,如果滴答* 96足够接近一个整数值被接受为有效。

因此,我们需要检查:

double value = tick * 96.0; 
bool isValid 
    = value - floor(value) < threshold 
    || ceil(value) - value < threshold; 

一些适当定义的阈值。假设真的值计算为

double tick = round(8820*i/96.0)/8820.0; 

那么最大的偏差会比0.00544稍大(请参阅下面的一个更准确的值),阈值介于0.006,0.0055,0.00545,...可能大小是一个选择。

舍入可能是用于传感器值的比特(如果我们有可用的13位,蜱实际上可能与8192是1 << 13 & ndash的和地板会计为整数除法计算为floor(8192 * i/96.0)/8192.0的内部使用数的问题;只是一个猜测...)。

最大偏差的精确值,使用8820作为因素,确切为用双表示的,是:
0.00544217687075132516838493756949901580810546875

由96乘法实际上是没有必要的,您可以直接与划分的阈值进行比较96,具体做法是:
0.0000566893424036596371706764330156147480010986328125

+0

我什么也没有启动。阅读好问题:我没有脉冲列表。我从蜱中得出它。这是动态的(即在此期间8820变化)。所以我没有任何固定的脉冲列表。当然,我正在加倍,这只是一个例子。 – markzzz

+0

从你的问题来看,这是不清楚的,在我看来,就好像你在编程服务器一样,并且由于计算错误而导致错误值。 – Aconcagua

0

与Excel周围玩,我想你想乘达(应该是什么)的整数,而不是寻找最接近的脉冲。

Tick    Pulse     i Error       OK 
       Tick*8820  Pulse*96/8820 ABS(i - INT(i+0.05)) Error < 0.01 
------------ ------------ ------------- ------------------------ ------------ 
0.029024943  255.9999973  2.786394528  0.786394528     FALSE 
0.0417234  368.000388  4.0054464  0.0054464     TRUE 
0     0    0    0       TRUE 
0.010430839  91.99999998 1.001360544  0.001360544     TRUE 
0.020861678  184    2.002721088  0.002721088     TRUE 
0.031292517  275.9999999  3.004081632  0.004081632     TRUE 
0.041723356  367.9999999  4.005442176  0.005442176     TRUE 
0.052040816  458.9999971  4.995918336  0.004081664     TRUE 
0.062471655  550.9999971  5.99727888  0.00272112     TRUE 
0.072902494  642.9999971  6.998639424  0.001360576     TRUE 
0.083333333  734.9999971  7.999999968  3.2E-08      TRUE 

表显示你的两个“问题”的情况(真正的错误值256,和一个你的代码获取错误,368),其次是前几个“好”的价值观。

如果两个8820 s同时发生变化,那么很明显他们将取消,而i将只是Tick*96

Error术语是计算的i与最接近的整数之间的差值;如果这小于0.01,那么它是一个“很好”的价值。

注意:0.050.01的值有些随意选择(也可能是基于数字的第一次启发):如果需要调整。尽管我只显示了前几行,但您给出的所有96个“良好”值都显示为TRUE。

代码(完全未经测试)会是这样的:

double pulse = tick * 8820.0 ; 
double i = pulse * 96.0/8820.0 ; 
double error = abs(i - floor(i + 0.05)) ; 
if(error < 0.05) { 
    // is pulse 
} 
+0

问题是当你有“接近”的值时。假设我从系统中获得了“0.0418367”(脉冲369)。该错误较小,如368和0.0417234。但是这个价值需要被忽略。 – markzzz

+0

只需插入'0.0418367'并且它给出FALSE(其中'0.0417234'为真)。如果你有一个方便的电子表格,可能值得像我一样插入数字并且玩一玩。即使'0.05'和'0.01'不完美,技术应该是健全的。 – TripeHound

+0

它打勾“0.406349”(3584):http://cpp.sh/62rth失败。 3584不是脉冲,3583是 – markzzz

相关问题