相关
相关部分比较简单,相关的意义和实现有需要可以参考下面两篇博文,
https://blog.csdn.net/jbb0523/article/details/6669883?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4
https://blog.csdn.net/LiuXF93/article/details/88956643?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-5&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-5
相关函数优化
将相关部分转化成代码
/*!
* @brief 互相关
*
* @param acor: 互相关结果
* @param x : 互相关数据 x
* @param y : 互相关数据 y
* @param len : 互相关数据长度
*
* @return 无
*
* @note 无
*
* @see
*
* @date 2020/4/28
*/
void xcorr(float *acor, int16_t *x, int16_t *y, uint16 len)
{
double sum = 0;
int delay, i, j;
for(delay = -len + 1; delay < 0; delay++)
{
sum = 0;
for(i = 0; i < len; i++)
{
j = i + delay;
if((j < 0))
{
sum += 0.00001f * x[j + len] * y[i]; //防止溢出,缩小一定倍数
}
else if(j >= len)
{
sum += 0.00001f * x[j - len] * y[i]; //防止溢出,缩小一定倍数
}
else
{
sum += 0.00001f * x[j] * y[i]; //防止溢出,缩小一定倍数
}
}
acor[delay + len - 1] = (float)sum;
}
}
运行时间巨慢,简直无法使用,但是这个和fft加速相比,占用内存比较小,TC264官方的FFT库需要输入输出都是float32的复数,在做相关的时候还需要把2048点的原始数据补零变成4096点的复数,两组数据进行相关就需要 4 x 2 x 4096 x 3 字节,也就是96KB。而TC264双核架构,CPU0的dsram只有72KB,CPU1的dsram只有120KB,嗯,也就是只可以用CPU1的内存了,但是这只是一个麦克风和FM做相关计算,一般确定位置最少也要三个麦克风,内存不够用了!怎么降低内存消耗?
1.可以降低采样率,以5KHz的频率进行采样,这样1024点就可以采集到一个周期,缺点就是原始数据粒度下降了,可能会影响相关结果,实测的时候发现相关峰值位置不会变,没有发现和原始结果有太大区别(也可能是测的不太久)。
2.可以使用TC264DA版芯片,DA芯片多了512K的EMEM内存,可以在CPU0中进行使用,缺点EMEM速度比常规的RAM要慢一些。
使用FFT加速相关运算的步骤比较简单
1.将ADC采集到FM信号1和9814信号2从2048点补零成4096点
2.对信号1和信号2进行FFT变换
3.对信号2求共轭
4.(信号1FFT结果)* (信号2FFT结果的共轭)
5.对上述结果进行IFFT变换
6.求出IFFT变换结果的幅值
7.找出最大幅值的下标
8.两个信号之间的时延 = 最大下标 * 1/采样频率
9.距离信息 = 时延 * 声速
那么是否必须使用FFT加速呢?
我们可以上述直接相关函数进行优化,直接相关函数一样可以得到最大下标(也就是FFT加速的第7个步骤),赛场大小是固定的,因此距离信息其实有最大值的,而距离信息 = 时延 * 声速,声速固定,因此时延其实有最大值,时延和最大下标又有关系,因此最大下标其实在一个范围内,我们直接进行相关的时候,可以只求最大下标范围内的相关值,因此相关函数可以改成如下
/*!
* @brief 互相关
*
* @param acor: 互相关结果
* @param x : 互相关数据 x
* @param y : 互相关数据 y
* @param len : 互相关数据长度
*
* @return 无
*
* @note 无
*
* @see
*
* @date 2020/4/28
*/
void xcorr(float *acor, int16_t *x, int16_t *y, uint16 len)
{
double sum = 0;
int delay, i, j;
for(delay = -300; delay < 0; delay++) //300 * 100us * 0.0346 cm/us (声速) 可以检测最远距离 10.38m
// for(delay = -len + 1; delay < len; delay++)
{
sum = 0;
for(i = 0; i < len; i++)
{
j = i + delay;
if((j < 0))
{
sum += 0.00001f * x[j + len] * y[i]; //防止溢出,缩小一定倍数
}
else if(j >= len)
{
sum += 0.00001f * x[j - len] * y[i]; //防止溢出,缩小一定倍数
}
else
{
sum += 0.00001f * x[j] * y[i]; //防止溢出,缩小一定倍数
}
}
acor[delay + 300] = (float)sum;
}
}
速度有所提升,将对应的变量全部放到运行CPU的dram中,大概需要50ms,50ms还是有点好长啊,是否可以接着优化?
分析这个函数,发现循环次数非常多,大部分资源都耗费在循环上了,按一般最少使用3个4468模块来算,一次循环做三组相关,是否可以提高效率?
void xcorr(float *acor1, float *acor2, float *acor3, int16_t *x, int16_t *y, int16_t *y1, int16_t *y2, uint16 len)
{
float sum3 = 0;
float sum1 = 0;
float sum2 = 0;
int delay, i, j;
for(delay = -300; delay < 0; delay++)
// for(delay = -len + 1; delay < len; delay++)
{
sum1 = 0;
sum2 = 0;
sum3 = 0;
for(i = 0; i < len; i++)
{
j = i + delay;
if((j < 0))
{
sum1 += 0.0001f * (float)x[j + len] * (float)y[i];
sum2 += 0.0001f * (float)x[j + len] * (float)y1[i];
sum3 += 0.0001f * (float)x[j + len] * (float)y2[i];
}
// else if ((j >= len))
// {
// sum1 += 0.0001f * (float)x[j - len] * (float)y[i];
// sum2 += 0.0001f * (float)x[j - len] * (float)y1[i];
// sum3 += 0.0001f * (float)x[j - len] * (float)y2[i];
// }
else
{
sum1 += 0.0001f * (float)x[j] * (float)y[i];
sum2 += 0.0001f * (float)x[j] * (float)y1[i];
sum3 += 0.0001f * (float)x[j] * (float)y2[i];
}
}
/* 相关结果存放在 300长度数组中 */
acor1[300 + delay] = (float)sum1;
acor2[300 + delay] = (float)sum2;
acor3[300 + delay] = (float)sum3;
}
}
实测发现,三组相关时间上大概需要70ms左右,这样子就和用FFT加速效果差不多,如果使用更多9814模块,速度上就可能超过FFT加速,而且内存消耗相比FFT减少的不要太多。
思考
小车在运动过程中采集数据是否会影响距离信息精确度?该如何减小该方面误差?
可以在灭灯后原地静止,当下一个信标灯响起,采集到一帧静止状态的数据,获取精确的距离信息,根据此距离信息和编码器信息,在空间位置上进行控制。不过这样有个问题,计算的距离信息必须准确,编码器距离积分必须精确(脉轮车估计不行)。
可以运动过程中进行采集计算,计算大概方位,然后横冲直撞莽过去,个人觉得这种比较靠谱。