第一步在arduino实现语音开关

1. 关于噪声过滤
arduino是在loop循环中不断的去读取adc的值,所以当你说出来语音的时候,采到值的幅度可能并不在顶峰,所以可以考虑采样10次,选取最大值和次大值来和前面一次的最大值和次大值进行对比,如果超过2倍,则可认为一次有效的呼唤。

2. 关于frame
当一次唤醒后,设置标志位为有效,然后当随后的唤醒在1.5s中之内则不会重复唤醒。而仅适用前0.5s用来频率分析。

ref:
http://arduino.cc/en/Reference/HomePage


#define SAMPLE_NUMBER    80
#define HALF_SAMPLE_NUMBER 40
#define LOWEST_THRESHOLD 0.3

boolean Triggered = false;
unsigned long Triggered_time = 0;

float previous_value[SAMPLE_NUMBER] = {0};

void update_previous_values(float current_value) {
    int i;
    for(i=SAMPLE_NUMBER-1; i>0; i--) {
        previous_value[i] = previous_value[i-1];
    }
    previous_value[0] = current_value;
}


boolean trigger(float current_value) {
    // when the latest samples are larger 2 times than previous half samples, we think it is meanful signal
    // step1: get the largest number and sub-largest number for latest samples
    // step2: get the largest number and sub-largest number for earlier samples
    
    float latest_largest = current_value;
    float latest_sublargest = current_value;
    for(int i=0; i<HALF_SAMPLE_NUMBER; i++) {
        if(latest_largest < previous_value[i]) latest_largest = previous_value[i];
        else if(latest_sublargest < previous_value[i]) latest_sublargest = previous_value[i];
    }
    
    float earlier_largest = previous_value[HALF_SAMPLE_NUMBER];
    float earlier_sublargest = previous_value[HALF_SAMPLE_NUMBER];
    for(int i=HALF_SAMPLE_NUMBER+1; i<SAMPLE_NUMBER; i++) {
        if(earlier_largest < previous_value[i]) earlier_largest = previous_value[i];
        else if(earlier_sublargest < previous_value[i]) earlier_sublargest = previous_value[i];
    }
    
    if(latest_largest < LOWEST_THRESHOLD) Triggered = false;
    
    if(latest_largest + latest_sublargest > 2*(earlier_largest + earlier_sublargest)
    && latest_largest > LOWEST_THRESHOLD
    && Triggered == false
    && (millis() - Triggered_time) >= 1500 ) return true;
    else return false;
}

void debug_prints() {
     Serial.print("Triggered at:");
     Serial.println(millis());
     //for(int i=SAMPLE_NUMBER-1; i>=0; i--) Serial.println(previous_value[i]);
}


// the setup routine runs once when you press reset:
void setup() {
    // initialize serial communication at 9600 bits per second:
    Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop() {
    // read the input on analog pin 0:
    int sensorValue = analogRead(A0);
    // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
    float voltage = sensorValue * (10.0 / 1023.0);
    update_previous_values(voltage);
    if(trigger(voltage)) {
        // print out the value you read:
        Triggered = true;
        debug_prints();
        Serial.println(voltage);
        Serial.println(millis() - Triggered_time);
        Triggered_time = millis();
    }
}