Εξερευνώντας τη μηχανή VoIP Mediastreamer2. Μέρος 4

Το υλικό του άρθρου είναι παρμένο από το δικό μου κανάλι ζεν.

Δημιουργία μετρητή στάθμης σήματος

Στο παρελθόν άρθρο Διευκρινίσαμε τον σωστό τερματισμό προγραμμάτων χρησιμοποιώντας τη ροή πολυμέσων.

Σε αυτό το άρθρο θα συναρμολογήσουμε ένα κύκλωμα μετρητή στάθμης σήματος και θα μάθουμε πώς να διαβάζουμε το αποτέλεσμα μέτρησης από το φίλτρο. Ας αξιολογήσουμε την ακρίβεια της μέτρησης.

Το σύνολο φίλτρων που παρέχεται από τη ροή πολυμέσων περιλαμβάνει ένα φίλτρο, MS_VOLUME, το οποίο είναι ικανό να μετρήσει το επίπεδο RMS του σήματος που διέρχεται από αυτό, να εξασθενίσει το σήμα και να εκτελέσει πολλές χρήσιμες και απροσδόκητες λειτουργίες. Θα αφιερώσουμε ένα ολόκληρο άρθρο σε αυτό το φίλτρο αργότερα. Αλλά προς το παρόν θα το χρησιμοποιήσουμε ως μετρητή.

Ως πηγή σήματος θα χρησιμοποιήσουμε μια γεννήτρια τόνου, από την οποία το σήμα θα σταλεί στο φίλτρο MS_VOLUME, στην έξοδο του οποίου είναι συνδεδεμένη η κάρτα ήχου.

Σε αυτό το παράδειγμα, θα χρησιμοποιήσουμε το φίλτρο της γεννήτριας σε μια ελαφρώς διαφορετική λειτουργία - θα δημιουργήσει ένα μονοτονικό σήμα για εμάς, δηλ. ένα σήμα που περιέχει μόνο μία ημιτονοειδή ταλάντωση.

Εκτός από τη συχνότητα και το πλάτος, θα χρειαστεί να ρυθμίσουμε το χρόνο κατά τον οποίο θα δημιουργηθεί το σήμα· πρέπει να είναι επαρκής ώστε να διέρχεται επαρκής αριθμός δειγμάτων από το φίλτρο MS_VOLUME για μέτρηση. Για τη μεταφορά ρυθμίσεων στη γεννήτρια, χρησιμοποιείται η δομή MSDtmfGenCustomTone:

struct _MSDtmfGenCustomTone{
    char tone_name[8];     /* Текстовое название сигнала из 8 букв.*/
    int duration;          /* Длительность сигнала в миллисекундах.*/
    int frequencies[2];    /* Пара частот из которых должен состоять выходной сигнал. */
    float amplitude;       /* Амплитуда тонов, 1.0 соответствует уровню 0 дБ от милливатта на нагрузке 600 Ом.*/
    int interval;          /* Пауза в миллисекундах перед началом повторного проигрывания сигнала.*/
    int repeat_count;      /* Количество повторов.*/
};
typedef struct _MSDtmfGenCustomTone MSDtmfGenCustomTone;

Για να ξεκινήσουμε τη γεννήτρια, θα χρησιμοποιήσουμε τη μέθοδο MS_DTMF_GEN_PLAY_CUSTOM.

Μπλοκ διάγραμμα επεξεργασίας σήματος:

Εξερευνώντας τη μηχανή VoIP Mediastreamer2. Μέρος 4

Ο κώδικας προγράμματος που υλοποιεί αυτό το σχήμα φαίνεται παρακάτω.

/* Файл mstest3.c */

#include <mediastreamer2/msfilter.h>
#include <mediastreamer2/msticker.h>
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/mssndcard.h>
#include <mediastreamer2/msvolume.h>

int main()
{
    ms_init();
    /* Создаем экземпляры фильтров. */
    MSFilter  *voidsource=ms_filter_new(MS_VOID_SOURCE_ID);
    MSFilter  *dtmfgen=ms_filter_new(MS_DTMF_GEN_ID);
    MSFilter  *volume=ms_filter_new(MS_VOLUME_ID);
    MSSndCard *card_playback=ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());
    MSFilter  *snd_card_write=ms_snd_card_create_writer(card_playback);

    /* Создаем тикер. */
    MSTicker *ticker=ms_ticker_new();

    /* Соединяем фильтры в цепочку. */
    ms_filter_link(voidsource, 0, dtmfgen, 0);
    ms_filter_link(dtmfgen, 0, volume, 0);
    ms_filter_link(volume, 0, snd_card_write, 0);

    /* Подключаем источник тактов. */
    ms_ticker_attach(ticker,voidsource);

    MSDtmfGenCustomTone dtmf_cfg;

   /* Устанавливаем имя нашего сигнала, помня о том, что в массиве мы должны
    оставить место для нуля, который обозначает конец строки. */
    strncpy(dtmf_cfg.tone_name, "busy", sizeof(dtmf_cfg.tone_name));
    dtmf_cfg.duration=1000;
    dtmf_cfg.frequencies[0]=440; /* Будем генерировать один тон, частоту второго тона установим в 0.*/
    dtmf_cfg.frequencies[1]=0;
    dtmf_cfg.amplitude=1.0; /* Такой амплитуде синуса должен соответствовать результат измерения 0.707.*/
    dtmf_cfg.interval=0.;
    dtmf_cfg.repeat_count=0.;

   /* Включаем звуковой генератор. */
   ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY_CUSTOM, (void*)&dtmf_cfg);

   /* Даем, время половину секунды, чтобы измеритель накопил данные. */
   ms_usleep(500000);

   /* Читаем результат измерения. */
  float level=0;
   ms_filter_call_method(volume, MS_VOLUME_GET_LINEAR,&level);
   printf("Амплитуде синуса %f вольт  соответствует среднеквадратическое значение %f вольт.n", dtmf_cfg.amplitude, level);
}

Μεταγλωττίζουμε το παράδειγμά μας, όπως κάναμε πριν, χρησιμοποιώντας μόνο το όνομα του αρχείου mstest3. Ας το τρέξουμε και πάρουμε το αποτέλεσμα:

Амплитуде синуса 1.000000 вольт  соответствует среднеквадратическое значение 0.707733 вольт.

Όπως μπορείτε να δείτε, το αποτέλεσμα της μέτρησης συνέπεσε στο τρίτο δεκαδικό ψηφίο με τη θεωρητική τιμή ίση με την τετραγωνική ρίζα δύο διαιρεμένων στο μισό: sqr(2)/2=0,7071067811865475

Η σχετική απόκλιση του αποτελέσματος από την πραγματική τιμή ήταν 0.1%. Αξιολογήσαμε το σφάλμα μέτρησης στο μέγιστο επίπεδο σήματος. Αντίστοιχα, καθώς μειώνεται το επίπεδο, το σφάλμα θα πρέπει να αυξάνεται. Σας προτείνω να το αξιολογήσετε μόνοι σας για χαμηλά επίπεδα σήματος.

Στο επόμενο άρθρο θα συναρμολογήσουμε ένα κύκλωμα που ανιχνεύει την παρουσία ενός σήματος τόνου μιας δεδομένης συχνότητας στην είσοδο χρησιμοποιώντας έναν ανιχνευτή τόνου. Θα μάθουμε επίσης πώς να επεξεργαζόμαστε συμβάντα που δημιουργούνται από φίλτρα.

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο