Игорь 2
Трансиверы, передатчики, РПУ => Software Defined Radio (SDR) => Тема начата: ra0ahc от Октябрь 11, 2020, 09:30:28 pm
-
Пока я не совсем понимаю как оно работает.
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 указывает на блок данных об ошибке
[в] размер блока количество образцов для обработки
-
А что в качестве референса использовать? Шум белый?
Нет никакого референса. Рассматривайте LMS как простой линейный предсказатель невысокого порядка. Даете ему на вход синус плюс чегото там еще - он адаптируется к самому простому сигналу - синусу. Вычитаете - остается все остальное (шум, речь и тп)
-
Вот код для 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;
-
Млин, можно как-то запретить форматирование? Этож ппц какой-то - съедает квадратные скобки с индексами. Что за форумный движок такой кривой?!?!?
-
Млин, можно как-то запретить форматирование?
Попробуйте вставлять текст как код.
вот так для примера- смайлики в игноре :) ;) :D
-
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 */
}
-
Спасибо Андрею за код
Спасибо Зениту за совет
lol22
-
Не могу поправить пост. Короче там съело taps [ i ] везде
-
начилась рабочая неделя.... dontt44
-
Посмотрел у UA3REO.
Там перед началом обработки очередного блока семплов просто проверяется на наличие НЕ ЧИСЕЛ в ранее накомленнвх коэффициентов
-
Ну вот, что я сделал и не заработало. НЕ удивительно, в слепую делаю, то чего не понимаю .
и так
сперва делаю 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);
....
Ну и на выходе фигня
-
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?
-
Так надо видеть и понимать что внутри arm_lms_norm_f32 делается. Не понимаю почему вы не хотите написать код "с нуля" - там не так сложно
-
"с нуля" -
Потому-что не понимаю, нет опыта. Я даже на листе не смогу описать этот процесс
-
Геннадий как вы запустили "это"?
-
Мы срисовали откуда то...
-
Исправил mu с 2 на 0.0001
Как то заработало. Каряво конечно, но хоть так пока. Шум теперь постоянно. Во времени артефакты всякие вылазят.
Сильно все во времени растянуто. Тон когда появляется то система его начинает гасить крайне медленно.
На фото лучший вариант.
Тональник у меня подается и исчезает по 1 сек, от него остается яма, когда его нет.
-
Ну понятно, что я все не правильно делаю.
-
Запустил. Надо было референс обновлять.
Красные точки это появление тональника.
-
Тест работы авто нотч
https://drive.google.com/file/d/1zLI6Nf6rTqPYlmVtQIBQwNlEY4gQ4s7Q/view?usp=sharing
-
У 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
-
Морзянка взрывает мозг
Нужна задержка.