Duobinary Encoder and Decoder
function [c,b_r]=Duobinary_EncDec(b)
// Precoded Duobinary coder and decoder
//b = input binary sequence:precoder input
//c = duobinary coder output
//b_r = duobinary decoder output
a(1) = xor(1,b(1));
if(a(1)==1)
a_volts(1) = 1;
end
for k =2:length(b)
a(k) = xor(a(k-1),b(k));
if(a(k)==1)
a_volts(k)=1;
else
a_volts(k)=-1;
end
end
a = a';
a_volts = a_volts';
disp(a,'Precoder output in binary form:')
disp(a_volts,'Precoder output in volts:')
//Duobinary coder output in volts
c(1) = 1+ a_volts(1);
for k =2:length(a)
c(k) = a_volts(k-1)+a_volts(k);
end
c = c';
disp(c,'Duobinary coder output in volts:')
//Duobinary decoder output by applying decision rule
for k =1:length(c)
if(abs(c(k))>1)
b_r(k) = 0;
else
b_r(k) = 1;
end
end
b_r = b_r';
disp(b_r,'Recovered original sequence at detector oupupt:')
endfunction
//Result
//Precoder output in binary form:
//
// 1. 1. 0. 0. 1. 0. 0.
//
// Precoder output in volts:
//
// 1. 1. - 1. - 1. 1. - 1. - 1.
//
// Duobinary coder output in volts:
//
// 2. 2. 0. - 2. 0. 0. - 2.
//
// Recovered original sequence at detector oupupt:
//
// 0. 0. 1. 0. 1. 1. 0.
WCDMA channelization code generator
% WCDMA channelization codes
% source:
% 3GPP TS 25.213 V10.0.0 section 4.3.1.1
%
% parameters:
% sf: spreading factor
% k: code number
%
% The returned code is a column vector with length sf
%
% this code has not been tested extensively. Please verify
% independently that it does what it promises.
function code=UTRA_FDD_chanCode(sf, k)
persistent flag;
persistent codes;
% * ********************************************
% * Build codebook
% * ********************************************
if isempty(flag)
codes={};
flag=1;
% start of recursion: Identity code for sf=1
codes{1, 1}=1;
for sfi=1:8
sfg=2 ^ sfi;
for kgDest=0:2:sfg-2
kgSrc=kgDest/2;
prev=codes{sfg/2, kgSrc+1};
% generation method:
% - duplicate a lower-sf code
% - duplicate and change sign
codes{sfg, kgDest+1}=[prev prev];
codes{sfg, kgDest+2}=[prev -prev];
end
end
end
% * ********************************************
% * look up the requested code from codebook
% * ********************************************
code=transpose(codes{sf, k+1});
% ################## CUT HERE #########################
% Example use (put this into a separate file)
sf=128; codenum=3;
chanCode=UTRA_FDD_chanCode(sf, codenum);
sig=[1 0 0 1 0 0 ]; % signal, row vector
len=size(sig, 2),
% convolve:
s=chanCode * sig; % now matrix, one row per repetition
len=len*sf;
s=reshape(s, 1, len);
% plot
stem(s);
Farrow resampler
% **************************************************************
% Vectorized Farrow resampler
% M. Nentwig, 2011
% Note: Uses cyclic signals (wraps around)
% **************************************************************
close all; clear all;
% inData contains input to the resampling process (instead of function arguments)
inData = struct();
% **************************************************************
% example coefficients.
% Each column [c0; c1; c2; c3] describes a polynomial for one tap coefficent in fractional time ft [0, 1]:
% tapCoeff = c0 + c1 * ft + c2 * ft ^ 2 + c3 * ft ^ 3
% Each column corresponds to one tap.
% the matrix size may be changed arbitrarily.
%
% The example filter is based on a 6th order Chebyshev Laplace-domain prototype.
% **************************************************************
inData.cMatrix =[ -8.57738278e-3 7.82989032e-1 7.19303539e+000 6.90955718e+000 -2.62377450e+000 -6.85327127e-1 1.44681608e+000 -8.79147907e-1 7.82633997e-2 1.91318985e-1 -1.88573400e-1 6.91790782e-2 3.07723786e-3 -6.74800912e-3
2.32448021e-1 2.52624309e+000 7.67543936e+000 -8.83951796e+000 -5.49838636e+000 6.07298348e+000 -2.16053205e+000 -7.59142947e-1 1.41269409e+000 -8.17735712e-1 1.98119464e-1 9.15904145e-2 -9.18092030e-2 2.74136108e-2
-1.14183319e+000 6.86126458e+000 -6.86015957e+000 -6.35135894e+000 1.10745051e+001 -3.34847578e+000 -2.22405694e+000 3.14374725e+000 -1.68249886e+000 2.54083065e-1 3.22275037e-1 -3.04794927e-1 1.29393976e-1 -3.32026332e-2
1.67363115e+000 -2.93090391e+000 -1.13549165e+000 5.65274939e+000 -3.60291782e+000 -6.20715544e-1 2.06619782e+000 -1.42159644e+000 3.75075865e-1 1.88433333e-1 -2.64135123e-1 1.47117661e-1 -4.71871047e-2 1.24921920e-2
] / 12.28;
% **************************************************************
% Create example signal
% **************************************************************
nIn = 50; % used for test signal generation only
if true
% complex signal
inData.signal = cos(2*pi*(0:(nIn-1)) / nIn) + cos(2*2*pi*(0:(nIn-1)) / nIn) + 1.5;
else
% impulse response
inData.signal = zeros(1, nIn); inData.signal(1) = 1; %
% inData.cMatrix = 0 * inData.cMatrix; inData.cMatrix(1, 1) = 1; % enable to show constant c in first tap
% inData.cMatrix = 0 * inData.cMatrix; inData.cMatrix(2, 1) = 1; % enable to show linear c in first tap
% inData.cMatrix = 0 * inData.cMatrix; inData.cMatrix(3, 1) = 1; % enable to show quadratic c in first tap
% inData.cMatrix = 0 * inData.cMatrix; inData.cMatrix(1, 2) = 1; % enable to show constant c in second tap
end
% **************************************************************
% Resample to the following number of output samples
% must be integer, otherwise arbitrary
% **************************************************************
inData.nSamplesOut = floor(nIn * 6.28);
% **************************************************************
% Set up Farrow resampling
% **************************************************************
nSamplesIn = size(inData.signal, 2);
nSamplesOut = inData.nSamplesOut;
order = size(inData.cMatrix, 1) - 1; % polynomial order
nTaps = size(inData.cMatrix, 2); % number of input samples that contribute to one output sample (FIR size)
% pointer to the position in the input stream for each output sample (row vector, real numbers), starting at 0
inputIndex = (0:nSamplesOut-1) / nSamplesOut * nSamplesIn;
% split into integer part (0..nSamplesIn - 1) ...
inputIndexIntegerPart = floor(inputIndex);
% ... and fractional part [0, 1[
inputIndexFractionalPart = inputIndex - inputIndexIntegerPart;
% **************************************************************
% Calculate output stream
% First constant term (conventional FIR), then linear, quadratic, cubic, ...
% **************************************************************
outStream = zeros(1, inData.nSamplesOut);
for ixOrder = 0 : order
x = inputIndexFractionalPart .^ ixOrder;
% **************************************************************
% Add the contribution of each tap one-by-one
% **************************************************************
for ixTap = 0 : nTaps - 1
c = inData.cMatrix(ixOrder+1, ixTap+1);
% index of input sample that contributes to output via the current tap
% higher tap index => longer delay => older input sample => smaller data index
dataIx = inputIndexIntegerPart - ixTap;
% wrap around
dataIx = mod(dataIx, nSamplesIn);
% array indexing starts at 1
dataIx = dataIx + 1;
delayed = inData.signal(dataIx);
% for each individual output sample (index in row vector),
% - evaluate f = c(order, tapindex) * fracPart .^ order
% - scale the delayed input sample with f
% - accumulate the contribution of all taps
% this implementation performs the operation for all output samples in parallel (row vector)
outStream = outStream + c * delayed .* x;
end % for ixTap
end % for ixOrder
% **************************************************************
% plot
% **************************************************************
xIn = linspace(0, 1, nSamplesIn + 1); xIn = xIn(1:end-1);
xOut = linspace(0, 1, nSamplesOut + 1); xOut = xOut(1:end-1);
figure(); grid on; hold on;
stem(xIn, inData.signal, 'k+-');
plot(xOut, outStream, 'b+-');
legend('input', 'output');
title('Farrow resampling. Signals are cyclic');
2-D Ping Pong Game.
%By vkc
function RunGame
hMainWindow = figure(...
'Color', [1 1 1],...
'Name', 'Game Window',...
'Units', 'pixels',...
'Position',[100 100 800 500]);
img = imread('ball.bmp','bmp');
[m,n,c] = size(img);
hBall = axes(...
'parent', hMainWindow,...
'color', [1 1 1],...
'visible', 'off',...
'units', 'pixels',...
'position', [345, 280, n, m] );
hBallImage = imshow( img );
set(hBallImage, 'parent', hBall, 'visible', 'off' );
ballSpeed = 3;
ballDirection = 0;
hTempBall = axes( ...
'parent', hMainWindow,...
'units', 'pixels',...
'color', 'none',...
'visible', 'off',...
'position', get(hBall, 'position' ) );
img = imread('paddle.bmp','bmp');
[m,n,c] = size(img);
hRightPaddle = axes(...
'parent', hMainWindow,...
'color', 'none',...
'visible', 'off',...
'units', 'pixels',...
'position', [650 - 10, 250 - 50, n, m] );
hRightPaddleImage = imshow( img );
set(hRightPaddleImage, 'parent', hRightPaddle, 'visible', 'off' );
targetY = 200;
t = timer( 'TimerFcn', @UpdateRightPaddleAI,...
'StartDelay', 10 );
start(t)
hLeftPaddle = axes(...
'parent', hMainWindow,...
'color', 'none',...
'visible', 'off',...
'units', 'pixels',...
'position', [50, 250 - 50, n, m] );
hLeftPaddleImage = imshow( img );
set(hLeftPaddleImage, 'parent', hLeftPaddle, 'visible', 'off' );
hBottomWall = axes(...
'parent', hMainWindow,...
'color', [1 1 1],...
'units', 'pixels',...
'visible', 'off',...
'position', [0 40 700 10] );
patch( [0 700 700 0], [0 0 10 10], 'b' );
hTopWall = axes(...
'parent', hMainWindow,...
'color', [1 1 1],...
'units', 'pixels',...
'visible', 'off',...
'position', [0 450 700 10] );
patch( [0 700 700 0], [0 0 10 10], 'b' );
rightScore = 0;
leftScore = 0;
hRightScore = axes(...
'parent', hMainWindow,...
'color', 'none',...
'visible', 'off',...
'units', 'pixels',...
'position', [650 485 50 10] );
hLeftScore = axes(...
'parent', hMainWindow,...
'color', 'none',...
'visible', 'off',...
'units', 'pixels',...
'position', [30 485 50 10] );
hRightScoreText = text( 0, 0, '0', 'parent', hRightScore,...
'visible', 'on', 'color', [1 1 1] );
hLeftScoreText = text( 0, 0, '0', 'parent', hLeftScore,...
'visible', 'on', 'color', [1 1 1] );
hQuitButton = uicontrol(...
'string', 'Quit',...
'position', [325 475 50 20],...
'Callback', @QuitButton_CallBack );
hStartButton = uicontrol(...
'string', 'Start',...
'position', [325 240 50 20],...
'Callback',@StartButton_CallBack );
playing = true;
while playing == true
UpdateBall()
UpdateLeftPaddle()
UpdateRightPaddle()
CheckForScore()
pause( 0.01 )
end
stop(t)
close( hMainWindow )
function UpdateBall
pos = get( hBall, 'position' );
ballX = pos(1,1);
ballY = pos(1,2);
ballDirection = NormalizeAngle( ballDirection );
% check for collisions with the walls
if ( ballY > 450 - 10 ) && ( ballDirection > 0 ) && ( ballDirection < 180 )
if ( ballDirection > 90 )
ballDirection = ballDirection + 2 * ( 180 - ballDirection );
else
ballDirection = ballDirection - 2 * ballDirection;
end
elseif ( ballY < 50 ) && ( ballDirection > 180 ) && ( ballDirection < 360 )
if ( ballDirection > 270 )
ballDirection = ballDirection + 2 * ( 360 - ballDirection );
else
ballDirection = ballDirection - 2 * ( ballDirection - 180 );
end
end
% check for collisions with the paddles
if ( ballDirection > 90 && ballDirection < 270 )
leftPaddlePos = get( hLeftPaddle, 'position' );
leftX = leftPaddlePos(1,1);
leftY = leftPaddlePos(1,2);
if( (ballX < leftX + 10)...
&& (ballX > leftX + 5)...
&& (ballY + 10 > leftY)...
&& (ballY < leftY + 100) )
if ( ballDirection < 180 )
ballDirection = 180 - ballDirection;
elseif( ballDirection > 180 )
ballDirection = 180 - ballDirection;
end
end
else
rightPaddlePos = get( hRightPaddle, 'position' );
rightX = rightPaddlePos(1,1);
rightY = rightPaddlePos(1,2);
if( (ballX + 10 > rightX)...
&& (ballX + 10 < rightX + 5)...
&& (ballY > rightY)...
&& (ballY < rightY + 100) )
if ( ballDirection < 90 )
ballDirection = 180 - ballDirection;
elseif( ballDirection > 270 )
ballDirection = 180 - ballDirection;
end
end
end
MoveObject( hBall, ballSpeed, ballDirection );
end
function UpdateRightPaddle()
speed = 5;
pos = get( hRightPaddle, 'position' );
rightY = pos(1,2);
if( rightY + 5 < targetY - 50 && rightY < 400 - 50 )
MoveObject( hRightPaddle, speed, 90 )
elseif( rightY - 5 > targetY - 50 && rightY > 50 )
MoveObject( hRightPaddle, speed, 270 )
end
pos = get( hRightPaddle, 'position' );
rightY = pos( 1,2);
if( rightY > 400 - 50 )
rightY = 350;
elseif( rightY < 50 )
rightY = 50;
end
if( strcmp( get( t, 'Running' ), 'off' ) )
start(t)
end
end
function UpdateRightPaddleAI( ob, data )
% calculate where the ball will colide.
tempBallDirection = NormalizeAngle( ballDirection );
if( tempBallDirection < 90 || tempBallDirection > 270 && ballSpeed > 0 )
ballPos = get( hBall, 'position' );
set( hTempBall, 'position', ballPos );
ballX = ballPos(1,1);
while( ballX < 650 - 10 )
ballPos = get( hTempBall, 'position' );
ballX = ballPos(1,1);
ballY = ballPos(1,2);
MoveObject( hTempBall, 20, tempBallDirection )
% check for temp ball collision with walls.
if ( ballY > 450 - 10 )
if ( tempBallDirection > 0 )
if ( tempBallDirection < 180 )
tempBallDirection = 360 - tempBallDirection;
end
end
elseif ( ballY < 60 )
if( tempBallDirection > 180 )
if( tempBallDirection < 360 )
tempBallDirection = 360 - tempBallDirection;
end
end
end
% line( 0, 0, 'marker', '*', 'parent', hTempBall )
% pause( 0.0005 )
end
pos = get( hTempBall, 'position' );
ballY = pos(1,2);
targetY = ballY + ( rand * 150 ) - 75;
end
end
function UpdateLeftPaddle()
scr = get( hMainWindow, 'position' );
screenX = scr(1,1);
screenY = scr(1,2);
screenH = scr(1,4);
mouse = get(0, 'PointerLocation' );
y = mouse(1,2) - screenY;
if( y > 100 && y < 400 )
paddlePos = get( hLeftPaddle, 'position' );
paddlePos(1,2) = y - 50;
set( hLeftPaddle, 'position', paddlePos );
elseif( y > 400 )
paddlePos = get( hLeftPaddle, 'position' );
paddlePos(1,2) = 400 - 50;
set( hLeftPaddle, 'position', paddlePos );
elseif( y < 100 )
paddlePos = get( hLeftPaddle, 'position' );
paddlePos(1,2) = 100 - 50;
set( hLeftPaddle, 'position', paddlePos );
end
end
function CheckForScore()
pos = get( hBall, 'position' );
xpos = pos(1,1);
ypos = pos(1,2);
if ( xpos < 5 )
set( hBallImage, 'visible', 'off' )
rightScore = rightScore + 1;
set ( hRightScoreText, 'string', num2str( rightScore ) )
pause( .5 )
ResetBall()
elseif ( xpos + 10 > 695 )
set( hBallImage, 'visible', 'off' )
leftScore = leftScore + 1;
set ( hLeftScoreText, 'string', num2str( leftScore ) )
pause( .5 )
ResetBall()
end
end
function ResetBall
pos = get( hBall, 'position' );
pos(1,1) = 345;
pos(1,2) = 255 + floor( rand*100 ) - 50;
set( hBall, 'position', pos )
ballSpeed = 4;
ballDirection = ( (rand(1) < 0.5) * 180 ) ... % 0 or 180
+ ( 45 + (rand(1) < 0.5) * -90 ) ... % + 45 or - 45
+ ( floor( rand * 40 ) - 20 ); % + -20 to 20
set( hBallImage, 'visible', 'on' )
pause(1)
end
function MoveObject( hInstance, speed, direction )
p = get( hInstance, 'position' );
x = p( 1, 1 );
y = p( 1, 2 );
x = x + cosd( direction ) * speed;
y = y + sind( direction ) * speed;
p( 1, 1 ) = x;
p( 1, 2 ) = y;
set( hInstance, 'position', p )
end
function SetObjectPosition( hObject, x, y )
pos = get( hObject, 'position' );
pos(1,1) = x;
pos(1,2) = y;
set( hObject, 'position', pos )
end
function a = NormalizeAngle( angle )
while angle > 360
angle = angle - 360;
end
while angle < 0
angle = angle + 360;
end
a = angle;
end
function QuitButton_CallBack( hObject, eventData )
playing = false;
end
function StartButton_CallBack( hObject, eventData )
set( hObject, 'visible', 'off' );
set( hLeftPaddleImage, 'visible', 'on' )
set( hRightPaddleImage, 'visible', 'on' )
ResetBall();
end
end
Flat-Top Windowing Function for the Accurate Measurement of a Sinusoid's Peak Amplitude Based on FFT Data
function [Windowed_Spec] = Wind_Flattop(Spec)
% Given an input spectral sequence 'Spec', that is the
% FFT of some time sequence 'x', Wind_Flattop(Spec)
% returns a spectral sequence that is equivalent
% to the FFT of a flat-top windowed version of time
% sequence 'x'. The peak magnitude values of output
% sequence 'Windowed_Spec' can be used to accurately
% estimate the peak amplitudes of sinusoidal components
% in time sequence 'x'.
% Input: 'Spec' (a sequence of complex FFT sample values)
%
% Output: 'Windowed_Spec' (a sequence of complex flat-top
% windowed FFT sample values)
%
% Based on Lyons': "Reducing FFT Scalloping Loss Errors
% Without Multiplication", IEEE Signal Processing Magazine,
% DSP Tips & Tricks column, March, 2011, pp. 112-116.
%
% Richard Lyons [December, 2011]
N = length(Spec);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Perform freq-domain convolution
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
g_Coeffs = [1, -0.94247, 0.44247];
% Compute first two convolved spec samples using spectral 'wrap-around'
Windowed_Spec(1) = g_Coeffs(3)*Spec(N-1) ...
+g_Coeffs(2)*Spec(N) + Spec(1) ...
+g_Coeffs(2)*Spec(2) + g_Coeffs(3)*Spec(3);
Windowed_Spec(2) = g_Coeffs(3)*Spec(N) ...
+g_Coeffs(2)*Spec(1) + Spec(2) ...
+g_Coeffs(2)*Spec(3) + g_Coeffs(3)*Spec(4);
% Compute last two convolved spec samples using spectral 'wrap-around'
Windowed_Spec(N-1) = g_Coeffs(3)*Spec(N-3) ...
+g_Coeffs(2)*Spec(N-2) + Spec(N-1) ...
+g_Coeffs(2)*Spec(N) + g_Coeffs(3)*Spec(1);
Windowed_Spec(N) = g_Coeffs(3)*Spec(N-2) ...
+g_Coeffs(2)*Spec(N-1) + Spec(N) ...
+g_Coeffs(2)*Spec(1) + g_Coeffs(3)*Spec(2);
% Compute convolved spec samples for the middle of the spectrum
for K = 3:N-2
Windowed_Spec(K) = g_Coeffs(3)*Spec(K-2) ...
+g_Coeffs(2)*Spec(K-1) + Spec(K) ...
+g_Coeffs(2)*Spec(K+1) + g_Coeffs(3)*Spec(K+2);
end % % End of 'Wind_Flattop(Spec)' function
Resampling by Lagrange-polynomial interpolation
% Lagrange interpolation for resampling
% References:
% [1] A digital signal processing approach to Interpolation
% Ronald W. Schafer and Lawrence R. Rabiner
% Proc. IEEE vol 61, pp.692-702, June 1973
% [2] https://ccrma.stanford.edu/~jos/Interpolation/Lagrange_Interpolation.html
% [3] Splitting the Unit delay: Tools for fractional delay filter design
% T. I. Laakso, V. Valimaki, M. Karjalainen, and U. K. Laine
% IEEE Signal Processing Magazine, vol. 13, no. 1, pp. 30..60, January 1996
function lagrangeResamplingDemo()
originDefinition = 0; % see comment for LagrangeBasisPolynomial() below
% Regarding order: From [1]
% "Indeed, it is easy to show that whenever Q is odd, none of the
% impulse responses corresponding to Lagrange interpolation can have
% linear phase"
% Here, order = Q+1 => odd orders are preferable
order = 3;
% *******************************************************************
% Set up signals
% *******************************************************************
nIn = order + 1;
nOut = nIn * 5 * 20;
% Reference data: from [1] fig. 8, linear-phase type
ref = [-0.032, -0.056, -0.064, -0.048, 0, ...
0.216, 0.448, 0.672, 0.864, 1, ...
0.864, 0.672, 0.448, 0.216, 0, ...
-0.048, -0.064, -0.056, -0.032, 0];
tRef = (1:size(ref, 2)) / size(ref, 2);
% impulse input to obtain impulse response
inData = zeros(1, nIn);
inData(1) = 1;
outData = zeros(1, nOut);
outTime = 0:(nOut-1);
outTimeAtInput = outTime / nOut * nIn;
outTimeAtInputInteger = floor(outTimeAtInput);
outTimeAtInputFractional = outTimeAtInput - outTimeAtInputInteger;
evalFracTime = outTimeAtInputFractional - 0.5 + originDefinition;
% odd-order modification
if mod(order, 2) == 0
% Continuity of the impulse response is achieved when support points are located at
% the intersections between adjacent segments "at +/- 0.5"
% For an even order polynomial (odd number of points), this is only possible with
% an asymmetric impulse response
offset = 0.5;
%offset = -0.5; % alternatively, its mirror image
else
offset = 0;
end
% *******************************************************************
% Apply Lagrange interpolation to input data
% *******************************************************************
for ixTap = 0:order
% ixInSample is the input sample that appears at FIR tap 'ixTap' to contribute
% to the output sample
% Row vector, for all output samples in parallel
ixInSample = mod(outTimeAtInputInteger + ixTap - order, nIn) + 1;
% the value of said input sample, for all output samples in parallel
d = inData(ixInSample);
% Get Lagrange polynomial coefficients of this tap
c = lagrangeBasisPolynomial(order, ixTap, originDefinition + offset);
% Evaluate the Lagrange polynomial, resulting in the time-varying FIR tap weight
cTap = polyval(c, evalFracTime);
% FIR operation: multiply FIR tap weight with input sample and add to
% output sample (all outputs in parallel)
outData = outData + d .* cTap;
end
% *******************************************************************
% Plot
% *******************************************************************
figure(); hold on;
h = plot((0:nOut-1) / nOut, outData, 'b-'); set(h, 'lineWidth', 3);
stem(tRef, ref, 'r'); set(h, 'lineWidth', 3);
legend('impulse response', 'reference result');
title('Lagrange interpolation, impulse response');
end
% Returns the coefficients of a Lagrange basis polynomial
% 1 <= order: Polynomial order
% 0 <= evalIx <= order: index of basis function.
%
% At the set of support points, the basis polynomials evaluate as follows:
% evalIx = 1: [1 0 0 ...]
% evalIx = 2: [0 1 0 ...]
% evalIx = 3: [0 0 1 ...]
%
% The support point are equally spaced.
% Example, using originDefinition=0:
% order = 1: [-0.5 0.5]
% order = 2: [-1 0 1]
% order = 3: [-1.5 -0.5 0.5 1.5]
%
% The area around the mid-point corresponds to -0.5 <= x <= 0.5.
% If a resampler implementation uses by convention 0 <= x <= 1 instead, set
% originDefinition=0.5 to offset
% the polynomial.
function polyCoeff = lagrangeBasisPolynomial(order, evalIx, originDefinition)
assert(evalIx >= 0);
assert(evalIx <= order);
tapLocations = -0.5*(order) + (0:order) + originDefinition;
polyCoeff = [1];
for loopIx = 0:order
if loopIx ~= evalIx
% numerator: places a zero in the polynomial via (x-xTap(k)), with k != evalIx
% denominator: scales to 1 amplitude at x=xTap(evalIx)
term = [1 -tapLocations(loopIx+1)] / (tapLocations(evalIx+1)-tapLocations(loopIx+1));
% multiply polynomials => convolve coefficients
polyCoeff = conv(polyCoeff, term);
end
end
% TEST:
% The Lagrange polynomial evaluates to 1 at the location of the tap
% corresponding to evalIx
thisTapLocation = tapLocations(evalIx+1);
pEval = polyval(polyCoeff, thisTapLocation);
assert(max(abs(pEval) - 1) < 1e6*eps);
% The Lagrange polynomial evaluates to 0 at all other tap locations
tapLocations(evalIx+1) = [];
pEval = polyval(polyCoeff, tapLocations);
assert(max(abs(pEval)) < 1e6*eps);
end
Halfband Filter Design with Python/Scipy
# The following is a Python/scipy snippet to generate the
# coefficients for a halfband filter. A halfband filter
# is a filter where the cutoff frequency is Fs/4 and every
# other coeffecient is zero except the cetner tap.
# Note: every other (even except 0) is 0, most of the coefficients
# will be close to zero, force to zero actual
import numpy
from numpy import log10, abs, pi
import scipy
from scipy import signal
import matplotlib
import matplotlib.pyplot
import matplotlib as mpl
# ~~[Filter Design with Parks-McClellan Remez]~~
N = 32 # Filter order
# Filter symetric around 0.25 (where .5 is pi or Fs/2)
bands = numpy.array([0., .22, .28, .5])
h = signal.remez(N+1, bands, [1,0], [1,1])
h[abs(h) <= 1e-4] = 0.
(w,H) = signal.freqz(h)
# ~~[Filter Design with Windowed freq]~~
b = signal.firwin(N+1, 0.5)
b[abs(h) <= 1e-4] = 0.
(wb, Hb) = signal.freqz(b)
# Dump the coefficients for comparison and verification
print(' remez firwin')
print('------------------------------------')
for ii in range(N+1):
print(' tap %2d %-3.6f %-3.6f' % (ii, h[ii], b[ii]))
## ~~[Plotting]~~
# Note: the pylab functions can be used to create plots,
# and these might be easier for beginners or more familiar
# for Matlab users. pylab is a wrapper around lower-level
# MPL artist (pyplot) functions.
fig = mpl.pyplot.figure()
ax0 = fig.add_subplot(211)
ax0.stem(numpy.arange(len(h)), h)
ax0.grid(True)
ax0.set_title('Parks-McClellan (remez) Impulse Response')
ax1 = fig.add_subplot(212)
ax1.stem(numpy.arange(len(b)), b)
ax1.set_title('Windowed Frequency Sampling (firwin) Impulse Response')
ax1.grid(True)
fig.savefig('hb_imp.png')
fig = mpl.pyplot.figure()
ax1 = fig.add_subplot(111)
ax1.plot(w, 20*log10(abs(H)))
ax1.plot(w, 20*log10(abs(Hb)))
ax1.legend(['remez', 'firwin'])
bx = bands*2*pi
ax1.axvspan(bx[1], bx[2], facecolor='0.5', alpha='0.33')
ax1.plot(pi/2, -6, 'go')
ax1.axvline(pi/2, color='g', linestyle='--')
ax1.axis([0,pi,-64,3])
ax1.grid('on')
ax1.set_ylabel('Magnitude (dB)')
ax1.set_xlabel('Normalized Frequency (radians)')
ax1.set_title('Half Band Filter Frequency Response')
fig.savefig('hb_rsp.png')
Frequency Estimate using FFT
%For a real-valued, single tone sine or cosine wave, estimate the frequency
%using an fft. Resolution will be limited by the sampling rate of the tone
%and the number of points in the fft.
%Procedure:
%1. Generate the test tone with a given Fs and N
%2. Take the fft and keep the first half
%3. Detect the maximum peak and its index
%4. Equate this index to a frequency
%Error Estimate:
% (Fs/N)= Hz/bin
%Things to keep in mind:
%Adding noise to the input will skew the results
%windowing will help with the fft
%% Clear and close everything
clc;
close all;
clear all; %remove this line if you are trying to use breakpoints
%% Just copy into m file, save and run
Fs = 1e6; %1MHz
fi = 1.333e3; %1kHz
t = 0:1/Fs:.5;
y = sin(2*pi*fi*t);
%Plot the time and frequency domain. Be sure to zoom in to see the waveform
%and spectrum
figure;
subplot(2,1,1);
temp = (2/fi)*Fs;
plot(y);
xlabel('time (s)');
subplot(2,1,2);
sX=fft(y);
N=length(sX);
sXM = abs(sX(1:floor(end/2))).^2; %take the magnitude and only keep 0:Fs/2
plot(0:Fs/N:(Fs/2)-1,sXM);
xlabel('Frequency')
ylabel('Magnitude')
[vv, ii]=max(sXM); %find the index of the largest value in the spectrum
freqEst = (ii-1)*Fs/N; %units are Hz
resMin = Fs/N; %units are Hz
display(freqEst);%display to the command window the results
display(resMin);
NLMS Adaptive filter
%Normalized Least Mean Square Adaptive Filter
%for Echo Cancellation
function [e,h,t] = adapt_filt_nlms(x,B,h,delta,l,l1)
%x = the signal from the speaker
%B = signal through echo path
%h = impulse response of adaptive filter
%l = length of the signal x
%l1 = length of the adaptive filter
%delta = step size
%e = error
%h = adaptive filter impulse response
tic;
for k = 1:150
for n= 1:l
xcap = x((n+l1-1):-1:(n+l1-1)-l1+1);
yout(n) = h*xcap';
e(n) = B(n) - yout(n);
xnorm = 0.000001+(xcap*xcap');
h = h+((delta*e(n))*(xcap/xnorm));
end
eold = 0.0;
for i = 1:l
mesquare = eold+(e(i)^2);
eold = mesquare;
end
if mesquare <=0.0001
break;
end
end
t = toc; %to get the time elapsed
u -Law and Inverse u-Law
function [Cx,Xmax] = mulaw(x,mu)
//Non-linear Quantization
//mulaw: mulaw nonlinear quantization
//x = input vector
//Cx = mulaw compressor output
//Xmax = maximum of input vector x
Xmax = max(abs(x));
if(log(1+mu)~=0)
Cx = (log(1+mu*abs(x/Xmax))./log(1+mu));
else
Cx = x/Xmax;
end
Cx = Cx/Xmax; //normalization of output vector
endfunction
////////////////////////////////////////////////////
function x = invmulaw(y,mu)
//Non-linear Quantization
//invmulaw: inverse mulaw nonlinear quantization
//x = output vector
//y = input vector (using mulaw nonlinear comression)
x = (((1+mu).^(abs(y))-1)./mu)
endfunction
Power Computation of a Digital Stream
clear all;
%example vector having ac & dc power
x = complex(randn(1,2048)+.2,randn(1,2048)-.1);
%total power, three equivalent methods
pwr1_total = mean(abs(x).^2); %mean of squared values
pwr2_total = mean(real(x).^2 + imag(x).^2);
pwr3_total = mean(x .* conj(x));
%total expressed as rms
rms_total = sqrt(pwr1_total);
%dc power
pwr1_dc = mean(real(x))^2 + mean(imag(x))^2; %square of mean of values
%ac power
pwr1_ac = pwr1_total - pwr1_dc; %mean of squares - square of mean
%relation of ac power to statistical variance
pwr2_ac = var(x); %approximately
%ac expressed as rms
rms1_ac = sqrt(pwr1_ac);
%ac relation to standard of deviation, std = sqrt(var)
rms2_ac = std(x); %approximately
%dc relation to variance
pwr2_dc = pwr1_total - var(x); %approximately
fprintf('----------------------------------------------------\r');
fprintf('power(total), : %1.5f, %1.5f, %1.5f\r',pwr1_total,pwr2_total,pwr3_total);
fprintf('rms(total) : %1.5f\r',rms_total);
fprintf('power(ac), variance : %1.5f, %1.5f\r',pwr1_ac,pwr2_ac);
fprintf('rms(ac), std : %1.5f, %1.5f\r',rms1_ac,rms2_ac);
fprintf('power(dc), (total-var) : %1.5f, %1.5f\r',pwr1_dc,pwr2_dc);
Halfband Filter Design with Python/Scipy
# The following is a Python/scipy snippet to generate the
# coefficients for a halfband filter. A halfband filter
# is a filter where the cutoff frequency is Fs/4 and every
# other coeffecient is zero except the cetner tap.
# Note: every other (even except 0) is 0, most of the coefficients
# will be close to zero, force to zero actual
import numpy
from numpy import log10, abs, pi
import scipy
from scipy import signal
import matplotlib
import matplotlib.pyplot
import matplotlib as mpl
# ~~[Filter Design with Parks-McClellan Remez]~~
N = 32 # Filter order
# Filter symetric around 0.25 (where .5 is pi or Fs/2)
bands = numpy.array([0., .22, .28, .5])
h = signal.remez(N+1, bands, [1,0], [1,1])
h[abs(h) <= 1e-4] = 0.
(w,H) = signal.freqz(h)
# ~~[Filter Design with Windowed freq]~~
b = signal.firwin(N+1, 0.5)
b[abs(h) <= 1e-4] = 0.
(wb, Hb) = signal.freqz(b)
# Dump the coefficients for comparison and verification
print(' remez firwin')
print('------------------------------------')
for ii in range(N+1):
print(' tap %2d %-3.6f %-3.6f' % (ii, h[ii], b[ii]))
## ~~[Plotting]~~
# Note: the pylab functions can be used to create plots,
# and these might be easier for beginners or more familiar
# for Matlab users. pylab is a wrapper around lower-level
# MPL artist (pyplot) functions.
fig = mpl.pyplot.figure()
ax0 = fig.add_subplot(211)
ax0.stem(numpy.arange(len(h)), h)
ax0.grid(True)
ax0.set_title('Parks-McClellan (remez) Impulse Response')
ax1 = fig.add_subplot(212)
ax1.stem(numpy.arange(len(b)), b)
ax1.set_title('Windowed Frequency Sampling (firwin) Impulse Response')
ax1.grid(True)
fig.savefig('hb_imp.png')
fig = mpl.pyplot.figure()
ax1 = fig.add_subplot(111)
ax1.plot(w, 20*log10(abs(H)))
ax1.plot(w, 20*log10(abs(Hb)))
ax1.legend(['remez', 'firwin'])
bx = bands*2*pi
ax1.axvspan(bx[1], bx[2], facecolor='0.5', alpha='0.33')
ax1.plot(pi/2, -6, 'go')
ax1.axvline(pi/2, color='g', linestyle='--')
ax1.axis([0,pi,-64,3])
ax1.grid('on')
ax1.set_ylabel('Magnitude (dB)')
ax1.set_xlabel('Normalized Frequency (radians)')
ax1.set_title('Half Band Filter Frequency Response')
fig.savefig('hb_rsp.png')
Computing CIC Filter Register Pruning Using Matlab [Updated]
% Filename: CIC_Word_Truncation.m
%
% Computes CIC decimation filter accumulator register
% truncation in each filter stage based on Hogenauer's
% 'accumulator register pruning' technique.
%
% Inputs:
% N = number of decimation CIC filter stages (filter order).
% R = CIC filter rate change factor (decimation factor).
% M = differential delay.
% Bin = number of bits in an input data word.
% Bout = number of bits in the filter's final output data word.
% Outputs:
% Stage number (ranges from 1 -to- 2*N+1).
% Bj = number of least significant bits that can be truncated
% at the input of a filter stage.
% Accumulator widths = number of a stage's necessary accumulator
% bits accounting for truncation.
% Richard Lyons Feb., 2012
clear, clc
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Define CIC filter parameters
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%N = 4; R = 25; M = 1; Bin = 16; Bout = 16; % Hogenauer paper, pp. 159
%N = 3; R = 32; M = 2; Bin = 8; Bout = 10; % Meyer Baese book, pp. 268
%N = 3; R = 16; M = 1; Bin = 16; Bout = 16; % Thorwartl's PDF file
N = 3; R = 8; M = 1; Bin = 12; Bout = 12; % Lyons' blog Figure 2 example
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Find h_sub_j and "F_sub_j" values for (N-1) cascaded integrators
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
disp(' ')
for j = N-1:-1:1
h_sub_j = [];
h_sub_j((R*M-1)*N + j -1 + 1) = 0;
for k = 0:(R*M-1)*N + j -1
for L = 0:floor(k/(R*M)) % Use uppercase "L" for loop variable
Change_to_Result = (-1)^L*nchoosek(N, L)...
*nchoosek(N-j+k-R*M*L,k-R*M*L);
h_sub_j(k+1) = h_sub_j(k+1) + Change_to_Result;
end % End "L" loop
end % End "k" loop
F_sub_j(j) = sqrt(sum(h_sub_j.^2));
end % End "j" loop
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Define "F_sub_j" values for up to seven cascaded combs
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
F_sub_j_for_many_combs = sqrt([2, 6, 20, 70, 252, 924, 3432]);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Compute F_sub_j for last integrator stage
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
F_sub_j(N) = F_sub_j_for_many_combs(N-1)*sqrt(R*M); % Last integrator
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Compute F_sub_j for N cascaded filter's comb stages
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for j = 2*N:-1:N+1
F_sub_j(j) = F_sub_j_for_many_combs(2*N -j + 1);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Define "F_sub_j" values for the final output register truncation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
F_sub_j(2*N+1) = 1; % Final output register truncation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Compute column vector of minus log base 2 of "F_sub_j" values
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Minus_log2_of_F_sub_j = -log2(F_sub_j)';
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Compute total "Output_Truncation_Noise_Variance" terms
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CIC_Filter_Gain = (R*M)^N;
Num_of_Bits_Growth = ceil(log2(CIC_Filter_Gain));
% The following is from Hogenauer's Eq. (11)
%Num_Output_Bits_With_No_Truncation = Num_of_Bits_Growth +Bin -1;
Num_Output_Bits_With_No_Truncation = Num_of_Bits_Growth +Bin;
Num_of_Output_Bits_Truncated = Num_Output_Bits_With_No_Truncation -Bout;
Output_Truncation_Noise_Variance = (2^Num_of_Output_Bits_Truncated)^2/12;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Compute log base 2 of "Output_Truncation_Noise_Standard_Deviation" terms
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Output_Truncation_Noise_Standard_Deviation = ...
sqrt(Output_Truncation_Noise_Variance);
Log_base2_of_Output_Truncation_Noise_Standard_Deviation = ...
log2(Output_Truncation_Noise_Standard_Deviation);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Compute column vector of "half log base 2 of 6/N" terms
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Half_Log_Base2_of_6_over_N = 0.5*log2(6/N);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Compute desired "B_sub_j" vector
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
B_sub_j = floor(Minus_log2_of_F_sub_j ...
+ Log_base2_of_Output_Truncation_Noise_Standard_Deviation ...
+ Half_Log_Base2_of_6_over_N);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
disp(' '), disp(' ')
disp(['N = ',num2str(N),', R = ',num2str(R),', M = ',num2str(M),...
', Bin = ', num2str(Bin),', Bout = ',num2str(Bout)])
disp(['Num of Bits Growth Due To CIC Filter Gain = ', ...
num2str(Num_of_Bits_Growth)])
disp(['Num of Accumulator Bits With No Truncation = ', ...
num2str(Num_Output_Bits_With_No_Truncation)])
% disp(['Output Truncation Noise Variance = ', ...
% num2str(Output_Truncation_Noise_Variance)])
% disp(['Log Base2 of Output Truncation Noise Standard Deviation = ',...
% num2str(Log_base2_of_Output_Truncation_Noise_Standard_Deviation)])
% disp(['Half Log Base2 of 6/N = ', num2str(Half_Log_Base2_of_6_over_N)])
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Create and display "Results" matrix
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for Stage = 1:2*N
Results(Stage,1) = Stage;
Results(Stage,2) = F_sub_j(Stage);
Results(Stage,3) = Minus_log2_of_F_sub_j(Stage);
Results(Stage,4) = B_sub_j(Stage);
Results(Stage,5) = Num_Output_Bits_With_No_Truncation -B_sub_j(Stage);
end
% Include final output stage truncation in "Results" matrix
Results(2*N+1,1) = 2*N+1; % Output stage number
Results(2*N+1,2) = 1;
Results(2*N+1,4) = Num_of_Output_Bits_Truncated;
Results(2*N+1,5) = Bout;
%Results % Display "Results" matrix in raw float-pt.form
% % Display "F_sub_j" values if you wish
% disp(' ')
% disp(' Stage Fj -log2(Fj) Bj Accum width')
% for Stage = 1:2*N+1
% disp([' ',sprintf('%2.2g',Results(Stage,1)),sprintf('\t'),sprintf('%12.3g',Results(Stage,2)),...
% sprintf('\t'),sprintf('%7.5g',Results(Stage,3)),sprintf('\t'),...
% sprintf('%7.5g',Results(Stage,4)),sprintf('\t'),sprintf('%7.5g',Results(Stage,5))])
% end
% Display Stage number, # of truncated input bits, & Accumulator word widths
disp(' ')
disp(' Stage(j) Bj Accum (adder) width')
for Stage = 1:2*N
disp([' ',sprintf('%2.0f',Results(Stage,1)),...
sprintf('\t'),...
sprintf('%5.5g',Results(Stage,4)),sprintf('\t'),...
sprintf('%7.5g',Results(Stage,5))])
end
disp([' ',sprintf('%2.0f',Results(2*N+1,1)),...
sprintf('\t'),...
sprintf('%5.5g',Results(2*N+1,4)),sprintf('\t'),...
sprintf('%7.5g',Results(2*N+1,5)),' (final truncation)'])
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Reading text files in Matlab
clear all;
% create test file
data = [1 5 2 4 3 3 4 2 5 1];
filename = 'test_file.txt';
fid = fopen(filename, 'w');
fprintf(fid, '%d %d\n', data);
fclose(fid);
% (1) read file using fscanf
fid = fopen(filename, 'r');
y1 = fscanf(fid, '%d\n'); %interleaves columns
fclose(fid);
% (2) read file using textread (or textscan)
[ya,yb] = textread(filename,'%d%d');
y2 = [ya yb];
% (3) read file using importdata
y3 = importdata(filename);
% (4) read file using load
y4 = load(filename);
disp('-------------------------------------------------------------')
disp(' original vector data')
disp(data)
disp(' file content using fprintf')
disp(y2)
disp(' vector created by fscanf')
disp(y1)
disp(' matrix created by:')
disp(' textread importdata load')
disp([y2 y3 y4])
Ideal interpolation filter
clear all; close all;
%example bandlimited random input & parameters
x = filter(fir1(70,.1),1,randn(1,1024));
up = 3; %Interpolation factor
cutoff = .3;
intorder = 6;
h1 = intfilt(up, intorder, cutoff); %ideal filter
h1 = up*h1/sum(h1);
h2 = fir1(2*up*intorder-2,cutoff); %ordinary LPF
h2 = up*h2/sum(h2);
%upsample
x_up = zeros(1,length(x)*up);
x_up(1:up:end) = x;
x_f1 = filter(h1,1,x_up);
x_f2 = filter(h2,1,x_up);
figure;
subplot(3,1,1);hold
plot(x_f1,'o--');
plot(x_f2,'r.-');
legend('ideal output','fir1 output');
subplot(3,1,2);
plot(x_f1-x_f2);
legend('error');
subplot(3,1,3);hold
plot(h1,'.-');
plot(h2,'r.-');
legend('ideal filter','fir1 filter');
checking resampling in time domain
clear all; close all;
%example bandlimited random input & parameters
x = filter(fir1(70,.1),1,randn(1,512));
h = fir1(30,.3); %filter used for upsampling
up = 3; %Interpolation factor
dn = 2; %Decimation factor
%%%%%%%%%%%%%%%%%%%%% up/dn model %%%%%%%%%%%%%%%%%%%%%%
%upsample input
x_up = zeros(1,length(x)*up);
x_up(1:up:end) = x;
x_f = filter(up*h,1,x_up);
%downsample signal by decimation
x_dn = x_f(1:dn:end);
delay = 30/2+1;
figure;
subplot(2,1,1);hold;
plot(x_up,'o--');
plot(x_f(delay:end),'r.-');
legend('input with zeros','upsampled stage');
subplot(2,1,2);hold;
plot(x_up(1:dn:end),'o--');
plot(x_dn(ceil(delay/dn):end),'r.-');
legend('input with zeros','final signal');
Resampling filter performance
%%%%%%%%%%%%%%%%%% inputs for model %%%%%%%%%%%%%%%%
clear all; close all;
%example bandlimited impulse input & parameters
x = filter(fir1(70,.1),1,[1 zeros(1,2^15-1)]);
Fs = 120; %MHz original sample rate
h = fir1(30,.3); %filter used for upsampling
up = 3; %Interpolation factor
dn = 2; %Decimation factor
Fc = 12; %MHz band centre (-Fs/2 ~ +Fs/2)
Fch = 0; %MHz filter centre (-Fs*up/2 ~ +Fs*up/2)
%move signal to its centre
x = x.*exp(j*2*pi*(0:length(x)-1)*Fc/Fs);
%shift filter
h = h.*exp(j*2*pi*(0:length(h)-1)*Fch/(Fs*up));
%%%%%%%%%%%%%%%%%%%%% model %%%%%%%%%%%%%%%%%%%%%%
%check signal in upsampled domain
x_up = zeros(1,length(x)*up);
x_up(1:up:end) = x;
[P, F] = pwelch(x_up, [], 0, 2^16, Fs*up,'twosided');
F = F - max(F)/2;
P = fftshift(P);
y(find(P == 0)) = -100; %avoid log of zero
y(find(P ~= 0)) = 10*log10(P(find(P ~= 0)));
P_dB = y - 10*log10(max(P)); %normalise
%check filter response in upsampled domain
H = fftshift(20*log10(abs(fft(h,2^16))));
subplot(2,1,1);
hold;grid;
plot(F, P_dB,'.-');
plot(F,H,'m--');
axis([min(F)-1 max(F)+1 -80 1]);
legend('upsampled signal','upsampling filter');
%check signal in downsampled domain
x_f = filter(h,1,x_up);
x_dn = x_f(1:dn:end);
[P, F] = pwelch(x_dn, [], 0, 2^16, Fs*up/dn,'twosided');
F = F - max(F)/2;
P = fftshift(P);
y(find(P == 0)) = -100; %avoid log of zero
y(find(P ~= 0)) = 10*log10(P(find(P ~= 0)));
P_dB = y - 10*log10(max(P)); %normalise
subplot(2,1,2)
plot(F,P_dB,'r.-');
grid;
axis([min(F)-1 max(F)+1 -80 1]);
legend('downsampled signal');
Adding a Controlled Amount of Noise to a Noise-Free Signal
function [Noisy_Signal] = SNR_Set(Signal, Desired_SNR_dB)
%
% SNR_Set(x, Desired_SNR_dB) returns the real-valued
% input 'Signal' contaminated with normally-distributed,
% zero-mean, random noise. The signal-to-noise ratio
% (SNR in dB) of the output 'Noisy_Signal' signal is
% controlled by the input 'Desired_SNR_dB' argument measured
% in dB.
% Example:
% Npts = 128; % Number of time samples
% n = 0:Npts-1; % Time-domain index
% Signal = 3*sin(2*pi*3*n/Npts); % Real-valued signal
% Desired_SNR_dB = 3; % Set SNR of output 'Noisy_Signal' to +3 dB
% [Noisy_Signal] = SNR_Set(Signal, Desired_SNR_dB);
%
% Author: Richard Lyons [December 2011]
%******************************************
Npts = length(Signal); % Number of input time samples
Noise = randn(1,Npts); % Generate initial noise; mean zero, variance one
Signal_Power = sum(abs(Signal).*abs(Signal))/Npts;
Noise_Power = sum(abs(Noise).*abs(Noise))/Npts;
%Initial_SNR = 10*(log10(Signal_Power/Noise_Power));
K = (Signal_Power/Noise_Power)*10^(-Desired_SNR_dB/10); % Scale factor
New_Noise = sqrt(K)*Noise; % Change Noise level
%New_Noise_Power = sum(abs(New_Noise).*abs(New_Noise))/Npts
%New_SNR = 10*(log10(Signal_Power/New_Noise_Power))
Noisy_Signal = Signal + New_Noise;
'SNR_Set()' Function Test Code:
% Filename SNR_Set_test.m
%
% Tests the 'SNR_Set()" function. Adds a predefined
% amount of random noise to a noise-free signal such that
% the noisy signal has a desired signal-to-noise ratio (SNR).
%
% Author: Richard Lyons [December 2011]
clear, clc
% Create a noise-free signal
Npts = 128; % Number of time samples
n = 0:Npts-1; % Time-domain index
Cycles = 5; % Integer number of cycles in noise-free sinwave signal
Signal = 3*sin(2*pi*Cycles*n/Npts); % Real-valued noise-free signal
Desired_SNR_dB = 3 % Set desired SNR in dB
[Noisy_Signal] = SNR_Set(Signal, Desired_SNR_dB); % Generate noisy signal
% Plot original and 'noisy' signals
figure(1)
subplot(2,1,1)
plot(n, Signal, '-bo', 'markersize', 2)
title('Original Signal')
grid on, zoom on
subplot(2,1,2)
plot(n, Noisy_Signal, '-bo', 'markersize', 2)
title('Noisy Signal')
xlabel('Time-samples')
grid on, zoom on
% Measure SNR in freq domain
Spec = fft(Noisy_Signal);
Spec_Mag = abs(Spec); % Spectral magnitude
figure(2)
plot(Spec_Mag, '-bo', 'markersize', 2)
title('Spec Mag of Noisy Signal')
xlabel('Freq-samples'), ylabel('Linear')
grid on, zoom on
Signal_Power = Spec_Mag(Cycles+1)^2 + Spec_Mag(Npts-Cycles+1)^2;
Noise_Power = sum(Spec_Mag.^2) -Signal_Power;
Measured_SNR = 10*log10(Signal_Power/Noise_Power)
Narrow-band moving-average decimator, one addition/sample
% *************************************************
% Moving average decimator
%
% A decimator for narrow-band signals (~5 % or less bandwidth occupation)
% can be implemented as follows:
%
% #define DECIM (100)
% double acc = 0.0;
% while (1){
% int ix;
% for(ix = DECIM; ix > 0; --ix){
% acc += getInputSample();
% } /* for */
% writeOutputSample(acc / (double)DECIM);
% acc = 0.0;
% } /* while */
%
% It is conceptually identical to a moving average filter
% http://www.dspguide.com/ch15/4.htm combined with a decimator
%
% Note that the "moving" average jumps ahead in steps of the decimation
% factor. Intermediate output is decimated away, allowing for a very efficient
% implementation.
% This program calculates the frequency response and alias response,
% based on the decimation factor and bandwidth of the processed signal.
% *************************************************
function eval_design()
decimationFactor = 100;
rateIn_Hz = 48000;
noDecim = false;
% create illustration with sinc response
%decimationFactor = 4; noDecim = true;
% *************************************************
% signal source: Bandlimited test pulse
% Does not contain energy in frequency ranges that
% cause aliasing
% *************************************************
s = zeros(1, 10000 * decimationFactor);
fb = FFT_frequencyBasis(numel(s), rateIn_Hz);
% assign energy to frequency bins
if noDecim
sPass = ones(size(s));
else
sPass = s; sPass(find(abs(fb) < rateIn_Hz / decimationFactor / 2)) = 1;
end
sAlias = s; sAlias(find(abs(fb) >= rateIn_Hz / decimationFactor / 2)) = 1;
% convert to time domain
sPass = fftshift(real(ifft(sPass)));
sAlias = fftshift(real(ifft(sAlias)));
% *************************************************
% plot spectrum at input
% *************************************************
pPass = {};
pPass = addPlot(pPass, sPass, rateIn_Hz, 'k', 5, ...
'input (passband response)');
pAlias = {};
pAlias = addPlot(pAlias, sAlias, rateIn_Hz, 'k', 5, ...
'input (alias response)');
% *************************************************
% impulse response
% *************************************************
h = zeros(size(s));
h (1:decimationFactor) = 1;
if noDecim
h = h / decimationFactor;
decimationFactor = 1;
end
% cyclic convolution between signal and impulse response
sPass = real(ifft(fft(sPass) .* fft(h)));
sAlias = real(ifft(fft(sAlias) .* fft(h)));
% decimation
sPass = sPass(decimationFactor:decimationFactor:end);
sAlias = sAlias(decimationFactor:decimationFactor:end);
rateOut_Hz = rateIn_Hz / decimationFactor;
% *************************************************
% plot spectrum
% *************************************************
pPass = addPlot(pPass, sPass, rateOut_Hz, 'b', 3, ...
'decimated (passband response)');
figure(1); clf; grid on; hold on;
doplot(pPass, sprintf('passband frequency response over input rate, decim=%i', decimationFactor));
pAlias = addPlot(pAlias, sAlias, rateOut_Hz, 'b', 3, ...
'decimated (alias response)');
figure(2); clf; grid on; hold on;
doplot(pAlias, sprintf('alias frequency response over input rate, decim=%i', decimationFactor));
% *************************************************
% plot passband ripple
% *************************************************
fb = FFT_frequencyBasis(numel(sPass), 1);
fr = 20*log10(abs(fft(sPass) + eps));
ix = find(fb > 0);
figure(3); clf;
h = semilogx(fb(ix), fr(ix), 'k');
set(h, 'lineWidth', 3);
ylim([-3, 0]);
title(sprintf('passband gain over output rate, decim=%i', decimationFactor));
xlabel('frequency relative to output rate');
ylabel('dB'); grid on;
% *************************************************
% plot alias response
% *************************************************
fb = FFT_frequencyBasis(numel(sAlias), 1);
fr = 20*log10(abs(fft(sAlias) + eps));
ix = find(fb > 0);
figure(4); clf;
h = semilogx(fb(ix), fr(ix), 'k');
set(h, 'lineWidth', 3);
% ylim([-80, -20]);
title(sprintf('alias response over output rate, decim=%i', decimationFactor));
xlabel('frequency relative to output rate');
ylabel('dB'); grid on;
end
% ************************************
% put frequency response plot data into p
% ************************************
function p = addPlot(p, s, rate, plotstyle, linewidth, legtext)
p{end+1} = struct('sig', s, 'rate', rate, 'plotstyle', plotstyle, 'linewidth', linewidth, 'legtext', legtext);
end
% ************************************
% helper function, plot data in p
% ************************************
function doplot(p, t)
leg = {};
for ix = 1:numel(p)
pp = p{ix};
fb = FFT_frequencyBasis(numel(pp.sig), pp.rate);
fr = 20*log10(abs(fft(pp.sig) + eps));
h = plot(fftshift(fb), fftshift(fr), pp.plotstyle);
set(h, 'lineWidth', pp.linewidth);
xlabel('f / Hz');
ylabel('dB');
leg{end+1} = pp.legtext;
end
legend(leg);
title(t);
end
% ************************************
% calculates the frequency that corresponds to
% each FFT bin (negative, zero, positive)
% ************************************
function fb_Hz = FFT_frequencyBasis(n, rate_Hz)
fb = 0:(n - 1);
fb = fb + floor(n / 2);
fb = mod(fb, n);
fb = fb - floor(n / 2);
fb = fb / n; % now [0..0.5[, [-0.5..0[
fb_Hz = fb * rate_Hz;
end
PSD estimation window based-scilab code
//Caption:Determination of spectrum of a signal
//With maximum normalized frequency f = 0.1
//using Rectangular window and Blackmann window
clear all;
close;
clc;
N = 61;
cfreq = [0.1 0];
[wft,wfm,fr]=wfir('lp',N,cfreq,'re',0);
disp(wft,'Time domain filter coefficients hd(n)=');
disp(wfm,'Frequency domain filter values Hd(w)=');
WFM_dB = 20*log10(wfm);//Frequency response in dB
for n = 1:N
h_balckmann(n)=0.42-0.5*cos(2*%pi*n/(N-1))+0.08*cos(4*%pi*n/(N-1));
end
wft_blmn = wft'.*h_balckmann;
disp(wft_blmn,'Blackmann window based Filter output h(n)=')
wfm_blmn = frmag(wft_blmn,length(fr));
WFM_blmn_dB =20*log10(wfm_blmn);
subplot(2,1,1)
plot2d(fr,WFM_dB)
xgrid(1)
xtitle('Power Spectrum with Rectangular window Filtered M = 61','Frequency in cycles per samples f','Energy density in dB')
subplot(2,1,2)
plot2d(fr,WFM_blmn_dB)
xgrid(1)
xtitle('Power Spectrum with Blackmann window Filtered M = 61','Frequency in cycles per samples f','Energy density in dB')