Пользуюсь ALSA для записи звука с микрофона, работает вроде как все нормально почти, но 0 сдвинут вниз, т.е. когда нет сигнала это например -0.2 в значении амплитуды в конкретный момент. 0 мне нужен для отсечение сигнала от не сигнала, например считаем что все что по модулю меньше 0.05 это шум и не обрабатываем в дальнейшем, а этот сдвиг не дает так сделать.
Может кто знает где это смещение настраивается или подскажет на какие алгоритмы посмотреть для калибровки микрофона?
[Решено] ALSA смещен ноль
Модератор: Модераторы разделов
-
Warlornhor
- Сообщения: 428
- ОС: openSUSE 12.3
Re: [Решено] ALSA смещен ноль
Подумал и пришел к выводу что можно делать fft на буфере который был считан, рассматривать разницу минимального и максимального значения и если она меньше чем сколько-то, то это шум иначе начало сигнала. Но, этот вариант может оказаться слишком медленным. Так что я еще открыт для идей.
-
NickLion
- Сообщения: 3408
- Статус: аватар-невидимка
- ОС: openSUSE Tumbleweed x86_64
Re: [Решено] ALSA смещен ноль
Откуда значение -0.2? Амплитуда — абсолютная величина и не может быть меньше 0. Если измерение в dB, то абсолютная тишина — это минус бесконечность. В этом случае порог может быть любым, т.к. dB — относительная характеристика. Если имеется в виду, что сигнал равен -0.2, то в таком случае значение не может означать тишину, тишина — это отсутствие колебаний. Самый простой способ в данном случае — найти минимум и максимум за некоторый промежуток времени, если max-min < порога, то тишина.
-
Warlornhor
- Сообщения: 428
- ОС: openSUSE 12.3
Re: [Решено] ALSA смещен ноль
Да, с утверждением согласен на счет просто разницы max-min. Опять же основная задача в том что нужно определить начало полезного сигнала, ну и конец соответственно.
На счет почему именно -0.2 не знаю почему так, цифра взята из вывода преобразованных двух байт в double, она такая же, например, в audacity если ничего не говорить, то полоса идет ниже 0.
На счет почему именно -0.2 не знаю почему так, цифра взята из вывода преобразованных двух байт в double, она такая же, например, в audacity если ничего не говорить, то полоса идет ниже 0.
-
NickLion
- Сообщения: 3408
- Статус: аватар-невидимка
- ОС: openSUSE Tumbleweed x86_64
Re: [Решено] ALSA смещен ноль
Ну да, сам уровень не значит ничего. Стоит буфер держать даже, когда сигнала нет, и как только сигнал станет оличаться более порога, то взять с небольшим участком времени до этого.
Подробнее:
Длина буфера = T отсчётов, период достаточный, чтобы отличить тишину, от малого затишья.
С одной стороны данные попадают от источника аудио. С другой стороны идёт запись, если необходимо. Т.е. буфер представляет очередь, реальная запись идёт с некоторой задержкой.
Начинаем с тишины, запись отключена.
Если в буфере max-min > порога, то включаем запись и данные уже находящиеся в буфере начинают попадать на запись.
Если в буфере max-min < порога, то запись выключаем, пустой буфер уже не попадёт никуда.
Подробнее:
Длина буфера = T отсчётов, период достаточный, чтобы отличить тишину, от малого затишья.
С одной стороны данные попадают от источника аудио. С другой стороны идёт запись, если необходимо. Т.е. буфер представляет очередь, реальная запись идёт с некоторой задержкой.
Начинаем с тишины, запись отключена.
Если в буфере max-min > порога, то включаем запись и данные уже находящиеся в буфере начинают попадать на запись.
Если в буфере max-min < порога, то запись выключаем, пустой буфер уже не попадёт никуда.
-
Warlornhor
- Сообщения: 428
- ОС: openSUSE 12.3
Re: [Решено] ALSA смещен ноль
Не взлетит, например нет сигнала это числа типа
Есть сигнал
Очевидно, что разница max-min одинаковая. Если брать модуль, то в теории модно стремиться к нулю при некоторых обстоятельствах, но на практике я вчера пробовал получается не то что хотелось бы.
Код: Выделить всё
-0.1 -0.11 -0.09Есть сигнал
Код: Выделить всё
-0.8 -0.79 -0.81Очевидно, что разница max-min одинаковая. Если брать модуль, то в теории модно стремиться к нулю при некоторых обстоятельствах, но на практике я вчера пробовал получается не то что хотелось бы.
-
NickLion
- Сообщения: 3408
- Статус: аватар-невидимка
- ОС: openSUSE Tumbleweed x86_64
Re: [Решено] ALSA смещен ноль
Если постоянно идёт около -0.8 — это нет сигнала, поскольку колебания отсутствуют.
-
Warlornhor
- Сообщения: 428
- ОС: openSUSE 12.3
Re: [Решено] ALSA смещен ноль
Вот так вот по идее работает.
Нахождение времени начала и конца
Код который считает спектр и анализирует его, грубо, но должно работать, проверено только на wav файле, надеюсь с микрофоном будет аналогично работающе:
Если надо обрезать частоты то вот так:
Нахождение времени начала и конца
Код: Выделить всё
string fileName = argv[1];
int sampleSize = 64;
int samplesPerSecond = 8000;
double startTime = 0;
double endTime = 0;
int sampleCounter = 0;
bool startFound = false;
bool endFound = false;
double expSilenceTime = 0.1;
double silenceTime = 0;
vector<double> ampls = getAmplList(fileName, false, 0.05, 0.1, true);
for (int i = 0; i < ampls.size() - sampleSize; i += sampleSize) {
vector<double> samples;
for (int j = 0; j < sampleSize; j++) {
samples.push_back(ampls[i + j]);
}
vector<double> energyArr = createSpectr(samples);
bool signalFound = hasSignal(energyArr);
if (signalFound && !startFound) {
startTime = (double)sampleCounter * ((double)sampleSize / (double)samplesPerSecond);
startFound = true;
} else if (!endFound && startFound && !signalFound && silenceTime > expSilenceTime) {
endTime = (double)sampleCounter * ((double)sampleSize / (double)samplesPerSecond);
endFound = true;
} else if (startFound && !signalFound) {
silenceTime += ((double)sampleSize / (double)samplesPerSecond);
}
for (vector<double>::iterator eIt = energyArr.begin(); eIt != energyArr.end(); eIt++) {
printf("%f ", *eIt);
}
printf("\n");
samples.clear();
sampleCounter++;
}
printf("%f \n", startTime);
printf("%f \n", endTime);Код который считает спектр и анализирует его, грубо, но должно работать, проверено только на wav файле, надеюсь с микрофоном будет аналогично работающе:
Код: Выделить всё
bool hasSignal(vector<double> &energyArr) {
for (vector<double>::iterator eIt = energyArr.begin(); eIt != energyArr.end(); eIt++) {
if (*eIt > 1) return true;
}
return false;
}
vector<double> createSpectr(vector<double> &ls) {
int samplesAmount = ampls.size();
double *in = (double*)fftw_malloc(sizeof(double)*samplesAmount);
fftw_complex* out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*samplesAmount);
fftw_plan p = fftw_plan_dft_r2c_1d(samplesAmount, in, out, FFTW_MEASURE);
vector<double> energyArr;
for (int i = 0; i < samplesAmount; i++)
in[i] = ampls[i];
fftw_execute(p);
for (int i = 0; i < samplesAmount/2 ; i++)
energyArr.push_back(sqrt(out[i][1]*out[i][1] + out[i][0]*out[i][0]));
return energyArr;
}Если надо обрезать частоты то вот так:
Код: Выделить всё
void cutOffUnneededFreqs(vector<double> &energyArr, int minFreq, int maxFreq, int fRate) {
int max_freq = fRate/2;
int freq_step = max_freq/energyArr.size();
int hiBound = 0, loBound = 0;
if((max_freq - maxFreq) > 0)
hiBound = (max_freq - maxFreq)/freq_step;
loBound = minFreq/freq_step;
energyArr.resize(energyArr.size() - hiBound);
int i = 0;
while( i < loBound)
{
energyArr.erase(energyArr.begin());
i++;
}
}