Суть проблемы такова: есть фото-датчик (обычный фотодиод + резистор подтянутый на 3.3), используется как индикатор свечения флоурисцентной лампы. Поскольку лампа не просто светит а "мерцает" с частотой сети, то сигнал, снимаемый с датчика, образует сумму постоянной составляющей и переменной отдаленной похожей половину периода синуса, вдобавок разночастотные помехи, которые весело резвятся "поверх" сигнала. Первоначально я просто делал скользящее осреднение по периоду мерцания лампы, но нет-нет по неясной причине АЦП выдавал неприлично высокий уровень (как будто нет свечения вообще) и выскакивала ошибка свечения лампы. Тогда я решал эту проблему всякими неприличными алгоритмическими ветвлениями, но теперь решил попробовать цифровой фильтр. Вкратце ознакомился с общей теорией отсюда, воспользовался вот этой программой и сгенерил код со следеющими параметрами: iir-ФНЧ Батервотра 4-го порядка, частота выборок 103 герца, частота среза 13 Гц (по-правде говоря пробовал разные значения, просто здесь привожу последнее, 103 герца из соображений, что фильтр не борется с частотами кратными частоте найквиста, а 13 Гц потому что меньше 50 и время переходного процесса не слишком большое). Далее настроил высокоприритетную задачу которая опрашивала АЦП с частотой 103 Гц и данные отправляла в фильтр, возвращаемое значение выводилось мне. Вообщем никакой фильтрации я не увидел, не знаю как там с помехами, но 50 Гц точно не подавляет, показания "пляшут". Ниже привожу код фильтра и задачи которая вызывает фильтр. Может кто-нибудь подскажет, что я делаю не так, буду очень признателен.
Фильтр:
Код
#define NCoef 4
#define DCgain 16
int16_t iir(int16_t NewSample) {
int16_t ACoef[NCoef+1] = {
2763,
11052,
16578,
11052,
2763
};
int16_t BCoef[NCoef+1] = {
16384,
-31933,
28030,
-11648,
1929
};
static int32_t y[NCoef+1]; //output samples
//Warning!!!!!! This variable should be signed (input sample width + Coefs width + 4 )-bit width to avoid saturation.
static int16_t x[NCoef+1]; //input samples
int n;
//shift the old samples
for(n=NCoef; n>0; n--) {
x[n] = x[n-1];
y[n] = y[n-1];
}
//Calculate the new output
x[0] = NewSample;
y[0] = ACoef[0] * x[0];
for(n=1; n<=NCoef; n++)
y[0] += ACoef[n] * x[n] - BCoef[n] * y[n];
y[0] /= BCoef[0];
return y[0] / DCgain;
}
#define DCgain 16
int16_t iir(int16_t NewSample) {
int16_t ACoef[NCoef+1] = {
2763,
11052,
16578,
11052,
2763
};
int16_t BCoef[NCoef+1] = {
16384,
-31933,
28030,
-11648,
1929
};
static int32_t y[NCoef+1]; //output samples
//Warning!!!!!! This variable should be signed (input sample width + Coefs width + 4 )-bit width to avoid saturation.
static int16_t x[NCoef+1]; //input samples
int n;
//shift the old samples
for(n=NCoef; n>0; n--) {
x[n] = x[n-1];
y[n] = y[n-1];
}
//Calculate the new output
x[0] = NewSample;
y[0] = ACoef[0] * x[0];
for(n=1; n<=NCoef; n++)
y[0] += ACoef[n] * x[n] - BCoef[n] * y[n];
y[0] /= BCoef[0];
return y[0] / DCgain;
}
Задача вызывающая фильтр:
Код
uint16_t adc0MVal;
__task void getUfoSensorsDataTask (void)
{
for(;;)
{
os_dly_wait(39); //Это RTXовская задержка по времени равно 9.7 мс - частота 103 Гц
uint16_t tmpAdc = (~ADCRead( 0 ))&0x1FF;
adc0MVal = iir((int16_t)tmpAdc);//tmp0;
}
}
__task void getUfoSensorsDataTask (void)
{
for(;;)
{
os_dly_wait(39); //Это RTXовская задержка по времени равно 9.7 мс - частота 103 Гц
uint16_t tmpAdc = (~ADCRead( 0 ))&0x1FF;
adc0MVal = iir((int16_t)tmpAdc);//tmp0;
}
}
Спасибо!