波形识别:
waveEncode: 字符转换成波形;
waveDecode:将波形转换成字符;
无线通信实现传输信息
完整源码:
waveEncode.c
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#include "waveRecog.h"
static signed char crc_8_ccitt(signed char* msg, int len)
{
int crc = 0xFF;
int polynomial = 0x07;
signed char bit, c7;
int b = 0, i = 0;
for (b = 0; b < len; b++)
{
for (i = 0; i < 8; i++)
{
bit = ((msg[b] >> (7 - i) & 1) == 1)?1:0;
c7 = ((crc >> 7 & 1) == 1)?1:0;
crc <<= 1;
if (c7 ^ bit)
crc ^= polynomial;
}
}
crc &= CRC_BIT;
return (signed char)crc;
}
// 浮点的正弦波转成整数
void float2Byte(double* sequence, int length, signed char* result)
{
int i = 0;
for(i=0; i < length; i++)
{
result[i] = (signed char)((sequence[i] * FLOAT_TO_BYTE_BASE));
}
}
// 两端磨平,降低两端的权值,凸出中间部分权重,提高准确率
void smoothBurst(double* input, int length)
{
int peaks = (int)(length /40);
int i = 0;
for (i=0; i<length; i++)
{
if (i < peaks)
{
input[i] = input[i] * i /peaks ;
}
else if ( i > length - peaks)
{
input[i] = input[i] * (length - i - 1)/peaks;
}
}
}
// 头部用于调相的正弦波
void phaseSequence(signed char* output)
{
double signal[SAMPLES_PER_BURST];
double innerMultiplier = (HEAD_SCH_FREQUENCY* 2 * M_PI)/ SAMPLING_RATE ;
int i = 0;
for(i = 0; i < SAMPLES_PER_BURST; i++){
signal[i] = cos(innerMultiplier * i);
}
smoothBurst(signal, SAMPLES_PER_BURST);
float2Byte(signal, SAMPLES_PER_BURST, output);
}
// 信号调制
void encodeBurst(char input, signed char* output)
{
double signal[SAMPLES_PER_BURST];
int k = 0;
int l = 0;
double innerMultiplier = 0.0;
memset(signal, 0, sizeof(double)*SAMPLES_PER_BURST);
// 8种频率的信号调制到一起, CA(载波聚合)?
for(k = 0; k < BITS_PER_BYTE; k++)
{
if( ((input >> k) & 0x1) == 0 )
{
continue;
}
innerMultiplier = (2 * M_PI) / g_iFrequencies[k];
for(l = 0; l < SAMPLES_PER_BURST; l++){
signal[l] = signal[l] + ((cos(innerMultiplier * l)/BITS_PER_BYTE));
}
}
smoothBurst(signal, SAMPLES_PER_BURST);
float2Byte(signal,SAMPLES_PER_BURST, output);
return ;
}
void encodeStream(char* input, int lengthOfInput, signed char* outputresult, int* lengthOfOutput)
{
int i=0;
int j=0;
int ioutPos = 0;
signed char crc;
signed char *output = outputresult;
#ifdef SUPPORT_NOISE
//用当前时间点初始化随机种子,防止每次运行的结果都相同, 可以用于产生噪声
time_t tm;
time(&tm);
unsigned int nSeed =(unsigned int)tm;
srand(nSeed);
#endif
memset(&output[ioutPos], 0, SAMPLES_PER_BURST); //初始化一段全0脉冲
ioutPos += SAMPLES_PER_BURST;
phaseSequence(&output[ioutPos]); //产生一个固定频率的正弦波, 用于解码调相的脉冲序列
ioutPos += SAMPLES_PER_BURST;
encodeBurst(HEAD_0, &output[ioutPos]); //头部脉冲
ioutPos += SAMPLES_PER_BURST;
encodeBurst(HEAD_1, &output[ioutPos]); // 头部脉冲
ioutPos += SAMPLES_PER_BURST;
for(i=0;i<lengthOfInput;i++)
{
encodeBurst(input[i], &output[ioutPos]); // 内容脉冲
ioutPos += SAMPLES_PER_BURST;
}
crc = crc_8_ccitt((signed char*)input, lengthOfInput);
encodeBurst(crc, &output[ioutPos]); // crc校验脉冲
ioutPos += SAMPLES_PER_BURST;
encodeBurst(0, &output[ioutPos]); // 尾部冗余量
ioutPos += SAMPLES_PER_BURST;
*lengthOfOutput = ioutPos;
return ;
}
int main()
{
FILE *fp = NULL;
char fileName[64] = "inputWave.pcm";
char input[] = "abcdefghijklmnopqrstuvwxyz 0123456789 ~!@#$%^&*()_+{}:";
int lengthOfInput = strlen(input);
int lengthOfOutput = 0;
int iWriteLen = 0;
char *output = (char *)malloc(SAMPLES_PER_BURST*(8+sizeof(input)));
if(NULL == output)
{
TRACE_ERROR("No Mem!");
return -1;
}
memset(output, 0 ,SAMPLES_PER_BURST*(8+sizeof(input)));
fp = fopen(fileName,"wb");
if(NULL == fp)
{
TRACE_ERROR("Create %s Failed!", fileName);
free(output);
return -2;
}
encodeStream(input,lengthOfInput,output,&lengthOfOutput);
if(lengthOfOutput > 0)
{
iWriteLen = fwrite(output,1,lengthOfOutput,fp);
if(iWriteLen != lengthOfOutput)
{
TRACE_WARN("File write error input length is %d, write length is %d",lengthOfOutput , iWriteLen);
}
}
else
{
TRACE_ERROR("Encode error!");
}
fclose(fp);
free(output);
TRACE_INFO("Encode %s ok...",input);
return 0;
}
waveDecode.c
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <math.h>
#include "waveRecog.h"
#define RECOG_THRESHOLD (0.53) //0.4
static signed char crc_8_ccitt(signed char* msg, int len)
{
int crc = 0xFF;
int polynomial = 0x07;
signed char bit, c7;
int b = 0, i = 0;
for (b = 0; b < len; b++)
{
for (i = 0; i < 8; i++)
{
bit = ((msg[b] >> (7 - i) & 1) == 1)?1:0;
c7 = ((crc >> 7 & 1) == 1)?1:0;
crc <<= 1;
if (c7 ^ bit)
crc ^= polynomial;
}
}
crc &= CRC_BIT;
return (signed char)crc;
}
double complexCalculate(signed char *signal, int lengthofsignal, double u)
{
int i = 0;
double realSum = 0;
double imaginarySum = 0;
double realUnit = 0;
double imaginaryUnit = 0;
// 滤波 积分
for(i = 0; i < lengthofsignal; i ++)
{
realUnit = cos(i * u) * signal[i] ;
imaginaryUnit = sin(i * u) * signal[i]; // 防止相位相差180
realSum = realSum + realUnit;
imaginarySum = imaginarySum + imaginaryUnit;
}
// 均衡
double realAve = realSum/lengthofsignal;
double imaginaryAve = imaginarySum/lengthofsignal;
return sqrt( (realAve * realAve) + (imaginaryAve * imaginaryAve) );
}
double complexDetect(signed char *signal, int lengthofsignal, int index)
{
// 特征频点
double innerMultiplier = (2 * M_PI) / g_iFrequencies[index];
// 滤波积分
return complexCalculate(signal, lengthofsignal, innerMultiplier);
}
double complexHead(signed char *signal, int lengthofsignal)
{
// 头部频点
double u = 2 * M_PI * HEAD_SCH_FREQUENCY / SAMPLING_RATE;
//滤波积分
return complexCalculate(signal, lengthofsignal, u);
}
int streamdecode(double *StartSignals, int lengthofStartSignals, signed char *pcm_buf8, int lengthofpcmbuf8, signed char *decoded, int lengthofDecoded)
{
int i = 0;
int j = 0;
int k = 0;
int kk = 0;
int durations = lengthofpcmbuf8/SAMPLES_PER_BURST;
double signal[BITS_PER_BYTE * BYTES_PER_BURST][durations];
// 该Burst所有信道的原始信号能量
for(i=0; i < durations; i++)
{
for( j = 0; j < BITS_PER_BYTE * BYTES_PER_BURST; j++)
{
signal[j][i] = complexDetect(pcm_buf8 + SAMPLES_PER_BURST*i, SAMPLES_PER_BURST, j);
}
}
//归一化信号
for( i = 0; i < (BITS_PER_BYTE * BYTES_PER_BURST); i++)
{
for( j = 0; j < durations; j++)
{
signal[i][j] = signal[i][j] / StartSignals[i];
}
}
int ivalue = 0;
for( i = 0; i < durations; i++)
{
for( k = 0; k < BYTES_PER_BURST; k++)
{
signed char value = 0;
for(j = 0; j < BITS_PER_BYTE; j++)
{
// 归一化后的能量大于RECOG_THRESHOLD(0.53 理论上是0.5) 就检测到该信道为1,否则为0
if(signal[(k * BITS_PER_BYTE) + j][i] > RECOG_THRESHOLD)
{
value = (signed char)(value | ( 1 << j));
}
// 信道噪声比较大, 信道能量在 RECOG_THRESHOLD 左右
/* TODO 信道差的处理
两种猜测,0和1, 后面做CRC的时候分别传入校验即可,但是质量差的点太多也无法恢复,如传输CRC的的信号质量差怎么办
*/
if((signal[(k * BITS_PER_BYTE) + j][i] > (RECOG_THRESHOLD - 0.1) && (signal[(k * BITS_PER_BYTE) + j][i] < (RECOG_THRESHOLD + 0.1))))
{
TRACE_WARN("Bad quality: %d:%f %d \n",j,signal[(k * BITS_PER_BYTE) + j][i],ivalue);
}
}
// 得出信号值
*(decoded+kk)=value;
kk++;
// 函数调用问题
if(kk > lengthofDecoded)
{
TRACE_ERROR("Decoded size is not enough\n");
return -1;
}
}
}
return 0;
}
static int findHead(char* signal, int lengthofsignal, int granularity)
{
int maxCorrelationIndex = -1;
double maxCorrelation = -1; // 如果噪声大,这个点可以调节,需要更多的噪声环境测量出一个合适的阈值
double acceptedSignal = 0.01;
int i=0;
for(i = 0; i <= lengthofsignal - SAMPLES_PER_BURST; i += granularity)
{
double corr = complexHead(signal+i,SAMPLES_PER_BURST);
if (corr > maxCorrelation)
{
// 如果频率匹配且相位正确,那从这一点开始的积分的结果最大
maxCorrelation = corr;
maxCorrelationIndex = i;
}
}
// 最大能量都小于可接受的能量
if (maxCorrelation < acceptedSignal && maxCorrelation > -1){
maxCorrelationIndex = -1;
}
return maxCorrelationIndex;
}
int main()
{
int headIndex = 0;
int i = 0;
int iNeedLen = 0, ireadLen = 0,iPos = 0;
int iGotHead = 0;
int iBufSize = SAMPLES_PER_BURST * HEAD_LEN;
int ioutIndex = 0;
int iFilePos = 0;
unsigned char outStream[128];
double startSignals[BITS_PER_BYTE] = {0,0,0,0,0,0,0,0};
signed char *pcm_buf8 = NULL;
FILE *fp = NULL;
char fileName[] = "inputWave.pcm";
fp = fopen(fileName,"rb");
if (NULL == fp)
{
TRACE_ERROR("Open %s failed!",fileName);
return -1;
}
pcm_buf8 = (signed char *)malloc(iBufSize);
if(NULL == pcm_buf8)
{
TRACE_ERROR("No Mem!");
fclose(fp);
return -2;
}
while(1)
{
iNeedLen = iBufSize - iPos;
if (iNeedLen)
{
ireadLen = fread(&pcm_buf8[iPos],1,iNeedLen,fp);
if((ireadLen != iNeedLen) && (0 == (iPos + ireadLen)))
{
TRACE_WARN("Read file, Can't get enough data, expert:%d read :%d \n",iNeedLen,ireadLen);
break ;
}
iFilePos += ireadLen;
iPos += ireadLen;
}
if(0 == iGotHead)
{
// 以20个样点为单位步进找到头部,步进越小查找的相位越精确
headIndex = findHead(pcm_buf8,iPos,20);
if(0 == headIndex) //检测到头
{
TRACE_INFO("Find head ");
// 头部信息的两个字节为0xAA(10101010) 0x55(01010101)
// 得到到所有物理信道,便于后面做归一化
for( i= 1; i < BITS_PER_BYTE ; i+=2)
{
startSignals[i] = complexDetect(pcm_buf8 + SAMPLES_PER_BURST, SAMPLES_PER_BURST, i);
}
for( i= 0; i < BITS_PER_BYTE; i+=2)
{
startSignals[i] = complexDetect(pcm_buf8 +(SAMPLES_PER_BURST*2), SAMPLES_PER_BURST, i);
}
// TODO 这里其实也可以把 头部两个字节(0xAA 和0x55)解析出来 ,头部解析出来就不需要 memmove
iGotHead = 1;
}
else if(0 < headIndex) //可能检测到头的位置,在某个位置有个能量极值点
{
TRACE_INFO("May Be Get Head ");
}
else //未检测到任何信息
{
TRACE_INFO("No any Data , Have Read:%d headIndex:%d",iFilePos,headIndex);
}
iPos -= SAMPLES_PER_BURST;
if (iPos > 0)
memmove(pcm_buf8, pcm_buf8 + SAMPLES_PER_BURST, iPos);
continue;
}
streamdecode(startSignals,BITS_PER_BYTE,pcm_buf8,SAMPLES_PER_BURST,&(outStream[ioutIndex]),1);
iPos -= SAMPLES_PER_BURST;
// 这里可以把buf里面的内容都解析出来就不用 memmove
if (iPos > 0)
memmove(pcm_buf8, pcm_buf8 + SAMPLES_PER_BURST, iPos);
TRACE_INFO("%d.Get 0x%x[%c] ",ioutIndex,outStream[ioutIndex],outStream[ioutIndex]);
if(outStream[ioutIndex])
{
ioutIndex += 1;
continue;
}
if(ioutIndex <= 1+HEAD_INFO_LEN)
{
TRACE_ERROR("Can't Get any info! File Pos:%d",iFilePos);
}
// TRACE_INFO("%x CRC:%x \n\n", outStream[ioutIndex - 1],(unsigned char)crc_8_ccitt(&outStream[HEAD_INFO_LEN], ioutIndex-1-HEAD_INFO_LEN));
if (outStream[ioutIndex - 1] == (unsigned char)crc_8_ccitt(&outStream[HEAD_INFO_LEN], ioutIndex-1-HEAD_INFO_LEN))
{
outStream[ioutIndex-1] = 0;
TRACE_INFO("outstring is %s ", &outStream[HEAD_INFO_LEN]);
}
else
{
TRACE_WARN("CRC error outstring is %s ", &outStream[HEAD_INFO_LEN]);
}
break;
}
fclose(fp);
free(pcm_buf8);
return (0);
}
TODO:
1. 增加载波数量 - 即增加物理通道数量
2. 提高载波频率 - 即提高负载
3. 跳频 - 提高抗干扰能力
4. 增加高能基波 - 相当于加入干扰因子