Форум Радиолюбителей

Авто нотч

43018 просмотров, 22 ответов

ra0ahc 11 октября 2020 г. в 09:30#1
Пока я не совсем понимаю как оно работает.


void arm_lms_norm_init_f32 ( arm_lms_norm_instance_f32 * S ,
uint16_t numTaps ,
float32_t * pCoeffs ,
float32_t * pState ,
float32_t му ,
uint32_t размер блока
)
Параметры
[в] S указывает на экземпляр структуры фильтра LMS с плавающей запятой
[в] numTaps количество коэффициентов фильтра
[в] pCoeffs указывает на буфер коэффициентов
[в] pState указывает на буфер состояния
[в] му размер шага, который управляет обновлениями коэффициентов фильтра
[в] размер блока количество образцов для обработки
Возврат
никто
Детали
pCoeffs указывает на массив коэффициентов фильтра, хранящихся в обратном во времени порядке:
{b [numTaps-1], b [numTaps-2], b [N-2], ..., b [1], b }
Начальные коэффициенты фильтра служат отправной точкой для адаптивного фильтра. pStateуказывает на массив numTaps+blockSize-1выборок длины , где blockSize- количество входных выборок, обработанных каждым вызовом arm_lms_norm_f32().


void arm_lms_norm_f32 ( arm_lms_norm_instance_f32 * S ,
const float32_t * pSrc ,
float32_t * pRef ,
float32_t * pOut ,
float32_t * pErr ,
uint32_t размер блока
)
Параметры
[в] S указывает на экземпляр структуры нормализованного фильтра LMS с плавающей запятой
[в] pSrc указывает на блок входных данных
[в] pRef указывает на блок справочных данных
[вне] pOut указывает на блок выходных данных
[вне] pErr указывает на блок данных об ошибке
[в] размер блока количество образцов для обработки
Relayer 11 октября 2020 г. в 09:59#2
А что в качестве референса использовать? Шум белый?
Нет никакого референса. Рассматривайте LMS как простой линейный предсказатель невысокого порядка. Даете ему на вход синус плюс чегото там еще - он адаптируется к самому простому сигналу - синусу. Вычитаете - остается все остальное (шум, речь и тп)
Relayer 11 октября 2020 г. в 10:02#3
Вот код для LMS. Семплрейт 24к. Параметры: Order=25, Delay=20, Leakage=1E-5, AdaptationRate=0.002
Может использоваться как шумодв если FMode = fmDeNoise, но хреново и надо другие параметры. С параметрами которые я написал хорошо работает как автонотч. В случае другого семплрейт параметры возможно придется менять. order так точно можно будет уменьшить
Код: [Выделить]procedure TDSPLMSFilter.ApplyFilter(bf: TBuffer);
var px: PFloat32;
i,j,idl,sz,mask,dl: integer;
sum,sum_sq,df: double;
begin
dl:=Delay;
mask:=Length(DelayLine)-1;
df:=1-Leakage*AdaptationRate;
bf_Write(bf);
px:=bf_Data(bf);
sz:=Length(taps)-1;
idl:=idelay;
for j:=1 to bf.Size do begin
DelayLine[idl]:=px^;
DelayLineSqr[idl]:=px^*px^;
sum:=0; sum_sq:=0;
for i:=0 to sz do begin
sum:=sum+DelayLine[(idl+i+1+dl) and mask]*taps[i];
sum_sq:=sum_sq+DelayLineSqr[(idl+i+1+dl) and mask];
end;
if FMode = fmDeNoise then begin
px^:=sum;
sum:=DelayLine[idl]-sum;
end else begin
sum:=DelayLine[idl]-sum;
px^:=sum;
end;
// LMS update
sum:=sum*AdaptationRate/(sum_sq+1E-10);
for i:=0 to sz do
taps[i]:=taps[i]*df+sum*DelayLine[(idl+i+1+dl) and mask];
//
Inc(px);
idl:=(idl-1) and mask;
end;
idelay:=idl;
end;

function TDSPLMSFilter.Redesign(SampleRate: integer; var DelayLen: integer): Boolean;
begin
taps:=nil;
Result:=False;
if Order > 0 then begin
SetLength(taps,Order);
FillChar(taps[0],Length(taps)*SizeOf(TFloat32),0);
DelayLen:=Order+Delay+10{Gap};
SetLength(DelayLineSqr,RoundToPower2(DelayLen)*2);
FillChar(DelayLineSqr[0],Length(DelayLineSqr)*SizeOf(TFloat32),0);
Result:=True;
end;
end;
Relayer 11 октября 2020 г. в 10:08#4
Млин, можно как-то запретить форматирование? Этож ппц какой-то - съедает квадратные скобки с индексами. Что за форумный движок такой кривой?!?!?
ra0ahc 12 октября 2020 г. в 01:54#5
начилась рабочая неделя....
zenit 12 октября 2020 г. в 08:03#6
Млин, можно как-то запретить форматирование?
Попробуйте вставлять текст как код.
Код: [Выделить]вот так для примера- смайлики в игноре


ra0ahc 12 октября 2020 г. в 09:00#7
Код: [Выделить]void DMA2_Stream5_IRQHandler(void) {
/* USER CODE BEGIN DMA2_Stream5_IRQn 0 */
//////////////////////////////////////////////////B-RX
// saiRxBankNowNumber++;

if ((DMA2->HISR & DMA_HISR_TCIF5) != 0) {

uint8_t b = (uint8_t) ((hdma_sai1_b.Instance->CR & DMA_SxCR_CT) != 0);
if (b != 0)
saiRxBankNowNumber = 0;
else
saiRxBankNowNumber = 1;

arm_fir_f32(&S_dsp, (float *) &saiRxBank[saiRxBankNowNumber], (float32_t *) pFirOutTemp, FRAME_SIZE);
uint16_t y = 0;
float32_t a;
if (tim > 0)tim--;
for (int i = 0; i < FRAME_SIZE; i++) {
a = (pFirOutTemp[i] < 0) ? -1.0f * (pFirOutTemp[i]) : pFirOutTemp[i];
nowAgc = 1 / a;
if (nowAgc <= agcLevel) {
agcLevel = nowAgc;
tim = 2;
} else {
if (tim == 0) agcLevel += 0.02f;
}
pFirOutTemp[i] *= agcLevel;
}


arm_fir_f32(&S_dsp_temp, (float *) pFirOutTemp, (float32_t *) pFirOut, FRAME_SIZE);

for (int i = 1; i < FRAME_SIZE; i += 2) {
pOutDac[dacTxBankNawNumber][y] = (uint32_t) (2048 + pFirOut[i - 1] * 300);
pOutDac[dacTxBankNawNumber][y] |= ((uint32_t) (2048 + pFirOut[i] * 300)) << 16;
y++;
}
mayk = 2;


}
/* USER CODE END DMA2_Stream5_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_sai1_b);
/* USER CODE BEGIN DMA2_Stream5_IRQn 1 */

/* USER CODE END DMA2_Stream5_IRQn 1 */
}
ra0ahc 12 октября 2020 г. в 09:02#8
Спасибо Андрею за код
Спасибо Зениту за совет
Relayer 12 октября 2020 г. в 09:07#9
Не могу поправить пост. Короче там съело taps [ i ] везде
GenaSPB 12 октября 2020 г. в 09:49#10
Посмотрел у UA3REO.
Там перед началом обработки очередного блока семплов просто проверяется на наличие НЕ ЧИСЕЛ в ранее накомленнвх коэффициентов
ra0ahc 13 октября 2020 г. в 05:17#11
Ну вот, что я сделал и не заработало. НЕ удивительно, в слепую делаю, то чего не понимаю .

и так
сперва делаю ini
Код: [Выделить]// arrays
__IO float32_t pOutLms[FRAME_SIZE];//out array
__IO float32_t lmsRef[FRAME_SIZE];// reference
__IO float32_t lmsErr[FRAME_SIZE];// error


ини и заполнение lmsRef синусом массива длиной FRAME_SIZE (1024)
LMS_FILTER_AP_NUM=40

Код: [Выделить]//lms
//https://www.keil.com/pack/doc/CMSIS/DSP/html/group__LMS__NORM.html
//LMS_FILTER_AP_NUM=40
arm_lms_norm_init_f32(&Slms, LMS_FILTER_AP_NUM, (float32_t *) firCoeff32, &firStateF32lms[0], 20, FRAME_SIZE);

float32_t phaseRef = 0;
float32_t pi2=2.0f * pi;
delta = (pi2 * 1000) / 24000;//1000Hz
//заполнение референсного массива синусом
for (int i = 0; i < FRAME_SIZE; i += 1) {
lmsRef[i] = arm_sin_f32(phaseRef);
phaseRef += delta;
if (phaseRef >= pi2) phaseRef -=pi2;
}


Теперь в прерывании:

Код: [Выделить]....
arm_lms_norm_f32(&Slms,(float32_t *)pFirOutTemp,(float32_t *)lmsRef,(float32_t *)pOutLms,(float32_t *)lmsErr,FRAME_SIZE);
....

Ну и на выходе фигня
ra0ahc 13 октября 2020 г. в 05:45#12
arm_lms_norm_init_f32

здесь есть
- размер шага, который управляет обновлениями коэффициентов фильтра
поставил 2 , что то там заплясало поработало сколько то и в аут улетело.

arm_lms_norm_init_f32(&Slms, LMS_FILTER_AP_NUM, (float32_t *) firCoeff32, &firStateF32lms[0], 2, FRAME_SIZE);


и еще, что делать с массивом Error?
Relayer 13 октября 2020 г. в 05:47#13
Так надо видеть и понимать что внутри arm_lms_norm_f32 делается. Не понимаю почему вы не хотите написать код "с нуля" - там не так сложно
ra0ahc 13 октября 2020 г. в 05:51#14
"с нуля" -
Потому-что не понимаю, нет опыта. Я даже на листе не смогу описать этот процесс
ra0ahc 13 октября 2020 г. в 05:58#15
Геннадий как вы запустили "это"?
GenaSPB 13 октября 2020 г. в 06:40#16
Мы срисовали откуда то...
ra0ahc 14 октября 2020 г. в 06:37#17
Исправил mu с 2 на 0.0001
Как то заработало. Каряво конечно, но хоть так пока. Шум теперь постоянно. Во времени артефакты всякие вылазят.

Сильно все во времени растянуто. Тон когда появляется то система его начинает гасить крайне медленно.
На фото лучший вариант.
Тональник у меня подается и исчезает по 1 сек, от него остается яма, когда его нет.
ra0ahc 14 октября 2020 г. в 07:32#18
Ну понятно, что я все не правильно делаю.
ra0ahc 14 октября 2020 г. в 09:01#19
Запустил. Надо было референс обновлять.

Красные точки это появление тональника.
ra0ahc 14 октября 2020 г. в 09:06#20
ra0ahc 14 октября 2020 г. в 09:15#21
У UA3REO не спрашивал разрешения, надеюсь он не обидится.

https://github.com/XGudron/UA3REO-DDC-Transceiver/tree/master/STM32/Src


Код: [Выделить]#include "auto_notch.h"
#include <arm_math.h>

// Private variables
static AN_Instance RX1_AN_instance = {0}; // filter instances for two receivers

// initialize the automatic notch filter
void InitAutoNotchReduction(void)
{
arm_lms_norm_init_f32(&RX1_AN_instance.lms2_Norm_instance, AUTO_NOTCH_TAPS,RX1_AN_instance.lms2_normCoeff_f32 , RX1_AN_instance.lms2_stateF32, AUTO_NOTCH_STEP, AUTO_NOTCH_BLOCK_SIZE);
AUTO_NOTCH_STEP, AUTO_NOTCH_BLOCK_SIZE);
arm_fill_f32(0.0f, RX1_AN_instance.lms2_reference, AUTO_NOTCH_REFERENCE_SIZE);
arm_fill_f32(0.0f, RX1_AN_instance.lms2_normCoeff_f32, AUTO_NOTCH_TAPS);
}

// start automatic notch filter
void processAutoNotchReduction(float32_t *buffer)
{
AN_Instance *instance = &RX1_AN_instance;

for (uint32_t i = 0; i < AUTO_NOTCH_REFERENCE_SIZE; i++)
if (isnanf(instance->lms2_reference[i]))
InitAutoNotchReduction();

arm_copy_f32(buffer, &instance->lms2_reference[instance->reference_index_new], AUTO_NOTCH_BLOCK_SIZE); // save the data to the reference buffer
arm_lms_norm_f32(&instance->lms2_Norm_instance, buffer, &instance->lms2_reference[instance->reference_index_old], instance->lms2_errsig2, buffer, AUTO_NOTCH_BLOCK_SIZE); // start LMS filter

instance->reference_index_old += AUTO_NOTCH_BLOCK_SIZE; // move along the reference buffer
if (instance->reference_index_old >= AUTO_NOTCH_REFERENCE_SIZE)
instance->reference_index_old = 0;

instance->reference_index_new = instance->reference_index_old + AUTO_NOTCH_BLOCK_SIZE;
if (instance->reference_index_new >= AUTO_NOTCH_REFERENCE_SIZE)
instance->reference_index_new = 0;
}

.h
от красного зависит качество фильтра
от зеленого скорость

#define AUTO_NOTCH_TAPS 40 // filter order
#define AUTO_NOTCH_STEP 0.0005f

Код: [Выделить]#define AUTO_NOTCH_BLOCK_SIZE 1024 // block size for processing
#define AUTO_NOTCH_TAPS 40 // filter order
#define AUTO_NOTCH_REFERENCE_SIZE (AUTO_NOTCH_BLOCK_SIZE * 2) // size of the reference buffer
#define AUTO_NOTCH_STEP 0.0005f // LMS algorithm step

typedef struct // filter instance
{
arm_lms_norm_instance_f32 lms2_Norm_instance;
float32_t lms2_stateF32[AUTO_NOTCH_TAPS + AUTO_NOTCH_BLOCK_SIZE - 1];
float32_t lms2_normCoeff_f32[AUTO_NOTCH_TAPS];
float32_t lms2_reference[AUTO_NOTCH_REFERENCE_SIZE];
float32_t lms2_errsig2[AUTO_NOTCH_BLOCK_SIZE];
uint_fast16_t reference_index_old;
uint_fast16_t reference_index_new;
} AN_Instance;

// Public methods
extern void InitAutoNotchReduction(void); // initialize the automatic notch filter
extern void processAutoNotchReduction(float32_t *buffer); // start automatic notch filter

ra0ahc 14 октября 2020 г. в 09:21#22
Морзянка взрывает мозг
Нужна задержка.