Проблемы с кодом гитарного тюнера Mbed?

Я пытаюсь настроить гитару с помощью микроконтроллера mbed LPC. Ниже есть ссылка на пример проекта. https://developer.mbed.org/users/adurand/notebook/guitar-tuner/

Тем не менее, у меня есть некоторые проблемы с этим. Во-первых, я имитирую вход гитары с помощью генератора сигналов произвольной формы на требуемой частоте каждой струны. Схема усилителя построена так же. Я также изменил код, чтобы использовать ЖК-дисплей Mbed вместо Nokia. Я использовал осциллограф, чтобы убедиться, что выходной сигнал, поступающий на AnalogueIn p20 Mbed, усиливается и имеет правильную частоту. Вот тут у меня проблемы.

Вот код (с благодарностью Эндрю Дюранду):

#include "mbed.h"
#include "adc.h"
#include "C12832.h"
#include <math.h>
#define PI 3.1415
#define SAMPLE_RATE 24000

InterruptIn button1(p12);
C12832 lcd(p5, p7, p6, p8, p11);
DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);

//LCD and Other Random Variables
int string_select = 0;
float high, high1, in_tune, in_tune1, in_tune2, in_tune3,
low, low1, note, low_mod, high_mod;
char* key;
int Counter = 0;
int Buffer[6000];

float goertzelFilter(int samples[], float freq, int N) {
    float s_prev = 0.0;
    float s_prev2 = 0.0;
    float coeff,normalizedfreq,power,s;
    int i;
    normalizedfreq = freq / SAMPLE_RATE;
    coeff = 2*cos(2*PI*normalizedfreq);
    for (i=0; i<N; i++) {
        s = samples[i] + coeff * s_prev - s_prev2;
        s_prev2 = s_prev;
        s_prev = s;
    }
    power = s_prev2*s_prev2+s_prev*s_prev-coeff*s_prev*s_prev2;
    return power;
}

ADC adc(SAMPLE_RATE, 1);

void sample_audio(int chan, uint32_t value) {
    Buffer[Counter] = adc.read(p20);
    Counter += 1;
}

void button1_pressed() {
    string_select++;
    if (string_select > 5) string_select = 0;
}

int main() {
    //Interupt for Switching Strings
    button1.mode(PullDown);
    button1.rise(&button1_pressed);

    while (1) {

        switch (string_select) {
            case 0:
                note = 82;
                key= "E2";
                break;
            case 1:
                note = 110;
                key= "A2";
                break;
            case 2:
                note = 147;
                key= "D3";
                break;
            case 3:
                note = 196;
                key= "G3";
                break;
            case 4:
                note = 247;
                key= "B3";
                break;
            case 5:
                note = 330;
                key= "E4";
                break;
        }

        //Prepare for burst mode on all ADC pins and set up interrupt handler (using ADC library from Simon Blandford
        adc.append(sample_audio);
        adc.startmode(0,0);
        adc.burst(1);
        adc.setup(p20,1);

        //start the interrupt and wait for about 4096 samples
        adc.interrupt_state(p20,1);
        wait(.2);

        //Finsh up - Unset pin 20
        adc.interrupt_state(p20,0);
        adc.setup(p20,0);
        int actual_rate = adc.actual_sample_rate();

        //for debugging tell the terminal sample rate and how many samples we took
        printf("Requested max sample rate is %u, actual max sample rate is %u.\n",
               SAMPLE_RATE, actual_rate);
        printf("We did %i samples\n",Counter);

high = 0;
low = 0;
for (int i=3; i<46; i+=3) {
    high1 = goertzelFilter(Buffer, (note + i ), Counter);
    if (high1 > high) high=high1;
}
for (int i=3; i<46; i+=3) {
    low1 = goertzelFilter(Buffer, (note - i ), Counter);
    if (low1 > low) low=low1;
}
        in_tune1 =  goertzelFilter(Buffer, (note+1), Counter);
        in_tune2 =  goertzelFilter(Buffer, note, Counter);
        in_tune3 =  goertzelFilter(Buffer, (note-1), Counter);

        if ((in_tune1 > in_tune2) && (in_tune1 > in_tune3)) in_tune = in_tune1;
        else if ((in_tune2 > in_tune1) && (in_tune2 > in_tune3)) in_tune = in_tune2;
        else in_tune = in_tune3;
        printf("high = %.2f, low = %.2f, in_tune = %.2f", high, low, in_tune);
       high_mod = high/in_tune;
      low_mod = low/in_tune; 
        if ((high_mod > .8)&&(low_mod > .8)) {
            myled1 = 0;
            myled2 = 0;
            myled3 = 0; 
        }
                if ((high_mod < .8)&&(low_mod > .8)) {
            myled1 = 0;
            myled2 = 0;
            myled3 = 0;
        }
        if ((high > in_tune) && (low < in_tune)) {         //Guitar string is at correct frequency
            myled1 = 0;
            myled2 = 1;
            myled3 = 0;

        } else if (high > in_tune) {                     // String is higher than the desired frequency
            myled1 = 1;
            myled2 = 0;
            myled3 = 0;

        } else if (low < in_tune){                     // String is below that of the desired frequency
            myled1 = 0;
            myled2 = 0;
            myled3 = 1;

        } else {                                       // Else no input, display squiggles
            myled1 = 0;
            myled2 = 0;
            myled3 = 0;
        }

        // Display on the LCD
        lcd.cls();
        lcd.locate(0,0);
        lcd.printf("Tuning String: %i", (6-string_select));
        lcd.locate(0,11);
        lcd.printf("%s at %i Hz",key, (int) note);
        lcd.locate(0,23);
        if (myled2) lcd.printf("In Tune!");              // if myled2 is on, guitar is in tune
        else if (myled3) lcd.printf("Too Low ");         // if myled3 is on, guitar is lower than desired tone
        else if (myled1) lcd.printf("Too High");         // if myled1 is on, guitar is higher than desired tone
        else lcd.printf("No Input Detected");                     // corresponds to led case 4 - no guitar input present

        Counter = 0;

    }



}

Теперь, когда я компилирую программу, сообщения печатаются. Однако светодиоды чередуются между «Слишком высоко», «Слишком низко» и закорючками. Я буду первым, кто признает, что я не лучший кодер, над чем я действительно собираюсь поработать летом. Там может быть очень серьезная проблема с кодом, или это может быть что-то относительно простое. Все входы приветствуются.

Примечание. Я не подключал схему подавления дребезга на макетной плате — она подключена к ЖК-дисплею Nokia, который я не использовал. Я могу изменить нужную строку от 1 до 6, используя вместо этого джойстик на панели приложений mbed. Все хорошо? Или схема устранения дребезга имеет ключевое значение? Спасибо еще раз.


person jvnlendm    schedule 26.04.2016    source источник


Ответы (1)


Цикл, который находит low, (почти) такой же, как цикл, который находит high в этом коде:

high = 0;
low = 0;
for (int i=3; i<46; i+=3) {
    high1 = goertzelFilter(Buffer, (note + i ), Counter);
    if (high1 > high) high=high1;
}
for (int i=3; i<46; i+=3) {
    low1 = goertzelFilter(Buffer, (note - i ), Counter);
    if (low1 > low) low=low1;
}

Я предлагаю, чтобы часть low была такой

low = FLT_MAX;
for (int i=3; i<46; i+=3) {
    low1 = goertzelFilter(Buffer, (note - i ), Counter);
    if (low1 < low) low=low1;
}

... хотя я могу ошибаться в предполагаемом использовании low.

person Weather Vane    schedule 26.04.2016
comment
Как бы я определил FLT_MAX? - person jvnlendm; 27.04.2016
comment
#include <float.h> и, кстати, я вижу, что вы используете printf, так что #include <stdio.h> тоже. - person Weather Vane; 27.04.2016
comment
... или установите low на какое-то другое неоправданно высокое значение. - person Weather Vane; 27.04.2016
comment
Хорошо, я сделал вышеописанное. Дисплей теперь меняется между отображением In Tune! слишком низко!, и когда я приближаюсь к правильной частоте, это показывает In Tune! и стабилизирует. Однако увеличение частоты выше частоты струны не приводит к загоранию индикатора Too High! ВЕЛ. Я сделал еще несколько изменений в коде, чтобы добраться до этой точки, в основном возился с кодом светодиода. Он намного улучшился. Спасибо. Любые дополнительные предложения? - person jvnlendm; 27.04.2016
comment
Все, что я могу предложить, это посмотреть на состояние светодиодов. Возможно, else if (high > in_tune) никогда не будет удовлетворен из-за предыдущего условия. Предложите if(intune>high) {/*high*/} else if(intune<low) {/*low*/} else {/*in tune*/}, но я не совсем понял, что делает ваш код. - person Weather Vane; 27.04.2016