Reputation: 735
I'm looking to implement the Normalised Least Mean Squares (NLMS) in C. My issue is in the weight update (I think) As I'm running it against a standard MATLAB library. This is the MATLAB code (That works):
function [e,w,y]=nlmsFunc(mu,M,u,d,a);
% Normalized LMS
% Call:
% [e,w]=nlms(mu,M,u,d,a);
%
% Input arguments:
% mu = step size, dim 1x1
% M = filter length, dim 1x1
% u = input signal, dim Nx1
% d = desired signal, dim Nx1
% a = constant, dim 1x1
%
% Output arguments:
% e = estimation error, dim Nx1
% w = final filter coefficients, dim Mx1
%intial value 0
w=zeros(M,1); %This is a vertical column
%input signal length
N=length(u);
%make sure that u and d are colon vectors
u=u(:);
d=d(:);
%NLMS
for n=M:N %Start at M (Filter Length) and Loop to N (Length of Sample)
uvec=u(n:-1:n-M+1); %Array, start at n, decrement to n-m+1
e(n)=d(n)-w'*uvec;
w=w+mu/(a+uvec'*uvec)*uvec*conj(e(n));
y(n) = w'*uvec; %In ALE, this will be the narrowband noise.
end
My issue is translating this to C, and this is what I have so far:
float mu = 0.05; //Set up mu
int a = 1; //Constant
int inputSigSize = numSamples;
float outputYSignal[inputSigSize];
float desiredSignal[inputSigSize];
float error[inputSigSize];
float inputSignal[inputSigSize];
//Initialise Weights to Zero
if (weights[0] == 0) {
for (int k = 0; k<=filterLength; k++) {
weights[k]=0;
}
}
float X[filterLength+1];
float Y = 0;
float E = 0;
//Start NLMS Loop
for (int t = 0; t<numSamples; t++) {
X[0] = inputSignal[t];
for (int i = 0; i<=filterLength; i++) {
Y += (weights[i]*X[i]);
}
E = desiredSignal[t] - Y;
for (int i = filterLength; i>=0; i--) {
weights[i] = weights[i] + (mu*E*X[i]);
if (i!=0) {
X[i]=X[i-1];
}
}
outputYSignal[t] = Y;
error[t] = E;
}
//END NLMS Loop
I have a feeling its a way I'm handling the weight updates.
Upvotes: 3
Views: 5671
Reputation: 4130
NLMS C Code Implementation:
#define inputSize 800
#define N 64 // filter size
double stepsize = 0.0; //Set up mu
double x[inputSize];
double d[inputSize];
double y[inputSize];
double h[N];
double e[inputSize];
int M = inputSize;
void nlmsFilter() {
//Initialise Weights to Zero
memset(y, 0, inputSize);
memset(e, 0, inputSize);
memset(h, 0, N);
double X1[N];
int t, j, i;
for (t = N; t <= M; t++) {
for (j = (t - 1); j >= (t - N); j--) {
X1[t-j-1] = x[j];
printf("%d %lf %lf \n", (t-j-1), X1[t-j-1], x[j]);
}
for (i = 0; i < N; i++) {
y[t-1] += (h[i] * X1[i]);
}
e[t-1] = d[t-1] - y[t-1];
for (i = 0; i < N; i++) {
stepsize += (X1[i] * X1[i]);
}
stepsize = 1/stepsize;
for (i = 0; i < N; i++) {
h[i] = h[i] + (stepsize * e[t-1] * X1[i]);
}
}
return;
}
Upvotes: 1
Reputation: 944
You seem to have forgotten the normalization of mu by the variance of the input.
Also, note that your filtering technique doesn't match the reference code: the coefficient weight[j] should multiply the input sample X[FilterLength - j]. The input array is reversed in uvec (keeping taps (not taps+1 as we would expect) samples).
In the original code they seem to add a small constant in case the variance is 0 (constant input for FilterLength+1 taps), but I think you could get more accurate results just by doing a check of the variance before.
Avoid moving data like that: X[i]=X[i-1] in the for loop.
Upvotes: 0