Пока я не совсем понимаю как оно работает.
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 указывает на блок данных об ошибке
[в] размер блока количество образцов для обработки
Авто нотч
43018 просмотров, 22 ответов
ra0ahc — 11 октября 2020 г. в 09:30#1
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;
Может использоваться как шумодв если 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 */
}
/* 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);
....
Ну и на выходе фигня
и так
сперва делаю 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?
здесь есть
- размер шага, который управляет обновлениями коэффициентов фильтра
поставил 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 сек, от него остается яма, когда его нет.
Как то заработало. Каряво конечно, но хоть так пока. Шум теперь постоянно. Во времени артефакты всякие вылазят.
Сильно все во времени растянуто. Тон когда появляется то система его начинает гасить крайне медленно.
На фото лучший вариант.
Тональник у меня подается и исчезает по 1 сек, от него остается яма, когда его нет.
ra0ahc — 14 октября 2020 г. в 07:32#18
Ну понятно, что я все не правильно делаю.
ra0ahc — 14 октября 2020 г. в 09:01#19
Запустил. Надо было референс обновлять.
Красные точки это появление тональника.
Красные точки это появление тональника.
ra0ahc — 14 октября 2020 г. в 09:06#20
Тест работы авто нотч
https://drive.google.com/file/d/1zLI6Nf6rTqPYlmVtQIBQwNlEY4gQ4s7Q/view?usp=sharing
https://drive.google.com/file/d/1zLI6Nf6rTqPYlmVtQIBQwNlEY4gQ4s7Q/view?usp=sharing
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
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
Морзянка взрывает мозг
Нужна задержка.
Нужна задержка.