Forecast future values from FFT - matlab

In the attached code I create an arbitrarily complex signal generator (3 sine waves in this case) and generate 256 + 50 values using it. I then create an FFT using the first 256 values, plot them and then do an inverse FFT and verify that it produces a very close representation of the original signal. All good so far.
What I'd like to do now is, using the FFT results, attempt to generate the additional 50 values that were not part of the FFT data set. Is there a straight-forward in MatLab?
Without being exactly sure how I assume I can create a signal generator using the center frequency of each bin and the FFT result and generate the signal that way, but that does seem like a lot of work so before I went down that path I figured I'd see if there was an easy way that I just haven't found.
I have MatLab & the Signal Processing and DSP packages to use at this time.
Thanks!
FFTsize = 256;
futureSize = 50;
t = 1:FFTsize+futureSize;
F1_bars = 10;
RadPerBar1 = (2*pi)/F1_bars;
L1 = 1;
Offset1 = 0;
F2_bars = 8;
RadPerBar2 = (2*pi)/F2_bars;
L2 = 1;
Offset2 = 0;
F3_bars = 50;
RadPerBar3 = (2*pi)/F3_bars;
L3 = 1;
Offset3 = 0;
Sig = (L1*sin(RadPerBar1*t + Offset1) +...
L2*sin(RadPerBar2*t + Offset2) +...
L3*sin(RadPerBar3*t + Offset3));
DataSet = Sig(1:FFTsize);
FFT = fft(DataSet)/FFTsize;
%Suggested by Mad Physicist
paddedFFT = [FFT(1:ceil(FFTsize/2)) zeros(1, futureSize) FFT(ceil(FFTsize/2)+1 : end)];
IFFT = ifft(FFT)*FFTsize;
%Suggested by Mad Physicist
IFFT2 = ifft(paddedFFT)*(FFTsize + futureSize);
figure(111);
hold off;
plot(abs(FFT));
hold on;
plot(abs(paddedFFT),'--r');
legend('FFT','Padded FFT','Position','best');
hold off;
figure(110)
hold off;
plot(Sig);
hold on;
plot(IFFT,'--r');
plot(t, IFFT2,'g');
legend('Input Signal','IFFT','Padded IFFT','Position','best');
hold off;

Pad the FFT with 50 zeros before you invert it:
futureSize = 50;
paddedFFT = [FFT(1:ceil(FFTsize/2)) zeros(1, futureSize) FFT(ceil(FFTsize/2)+1 : end)];
IFFT = ifft(paddedFFT)*(FFTsize + futureSize);

Related

How to isolate a frequency range in MATLAB using signals concepts?

I am trying to use concepts learned in signals analysis to isolate a specific frequency from a sound file. I have a short WAV file that consists of a person talking but also has other noises with unknown frequencies both above and below the desired signal. I have an upper and lower bound for the frequency range that should contain the part of the sound I want.
I think I should be able to do this without using the signals analysis toolbox or the butter filter.
so far I have this code which plots the power spectrum for the signal:
[y, Fs] = audioread('filename.wav','double');
t = 1:1:length(y);
y = transpose(y);
a = ifft(y);
a_k = abs([a((length(y)/2)+1:-1:2),a(1:1:(length(y)/2)+1)]);
bar((-length(y)/2)+1:1:(length(y)/2),a_k);
The power spectrum looks like this:
I think I should be able to use what I have to filter our anything above or below my known range, but I am not sure how to start doing that.
To apply ideal band pass filter you can use the code below. However, please note that the ideal filter may not produce the most optimal results if your signal is not periodic (see the wiki article here).
%% Initialisation
Fs = 44100;
t0 = 0;
t1 = 1;
t = t0 : 1/Fs : t1;
f1 = 10;
f2 = 40;
y = 10*cos(2*pi*f1*t) + 20*sin(2*pi*f2*t);
%% Cosine series
true_fft = fft(y);
nfft = length(y);
% The number of unique points
if mod(nfft, 2) == 0
num_pts = round(nfft/2) + 1;
else
num_pts = ceil(nfft/2);
end
% The vector that contains only unique points
fftT = true_fft(1 : num_pts);
% The vector that contains the unique frequencies
u_f = (0 : num_pts-1)*Fs/nfft;
%% Filtered signal
% Definition of the frequency band
f_low = 5;
f_high = 15;
[~, idx_low] = min(abs(u_f - f_low));
[~, idx_high] = min(abs(u_f - f_high));
filtFFTT = fftT;
filtFFTT([1: idx_low idx_high : end]) = 0;
if mod(nfft, 2) == 0
filtFFTT = [filtFFTT conj(filtFFTT((end - 1) : -1 : 2))];
else
filtFFTT = [filtFFTT conj(filtFFTT(end : -1 : 2))];
end
%% Data visualisation
figure;
plot(t, ifft(filtFFTT));

Harmonic Product Spectrum using MATLAB

Im tying to find the fundamental frequency of a note using harmonic product spectrum. This is the part that implements the HPS algorithm
seg_fft = seg_fft(1 : size(seg_fft,1)/2 ); % FFT data
seg_fft = abs(seg_fft);
seg_fft2 = ones(size(seg_fft));
seg_fft3 = ones(size(seg_fft));
seg_fft4 = ones(size(seg_fft));
seg_fft5 = ones(size(seg_fft));
for i = 1:floor((length(seg_fft)-1)/2)
seg_fft2(i,1) = (seg_fft(2*i,1) + seg_fft((2*i)+1,1))/2;
end
for i = 1:floor((length(seg_fft)-2)/3)
seg_fft3(i,1) = (seg_fft(3*i,1) + seg_fft((3*i)+1,1) + seg_fft((3*i)+2,1))/3;
end
for i = 1:floor((length(seg_fft)-3)/4)
seg_fft4(i,1) = (seg_fft(4*i,1) + seg_fft((4*i)+1,1) + seg_fft((4*i)+2,1) + seg_fft((4*i)+3,1))/4;
end
for i = 1:floor((length(seg_fft)-4)/5)
seg_fft5(i,1) = (seg_fft(5*i,1) + seg_fft((5*i)+1,1) + seg_fft((5*i)+2,1) + seg_fft((5*i)+3,1) + seg_fft((5*i)+4,1))/5;
end
f_ym = (seg_fft) .* (seg_fft2) .* (seg_fft3) .* (seg_fft4) .*(seg_fft5);
Now when i play F4, the 2nd harmonic(698 -F5) has a higher amplitude. So HPS is supposed to help me detect the fundamental which is F4 and NOT F5.
When i do the HPS these are the graphs I get:
The figures above show the plots of seg_fft2, seg_fft3, seg_fft4 and seg_fft5 respectively.
But what I dont understand is how come the frequency points obtained in these graphs are not factors of the original spectrum?? Isn't that how HPS is supposed to work??
This is the plot I obtained when I took the product of all 5.
the peak is at 698Hz.. But shouldn't it be at 349Hz instead??
But after the whole code is run, I do get the fundamental as F4.. Its all very confusing.... Can someone tell me why my graphs are different from what is expected yet I get the correct fundamental please????
This is the rest of the code
%HPS, PartIII: find max
f_y1 = max(f_ym)
for c = 1 : length(f_ym)
if(f_ym(c,1) == f_y1)
index = c;
end
end
% Convert that to a frequency
f_y(h) = (index / NFFT) * FS;
h=h+1;
%end
V = abs(f_y);
Please do help...... Thanx in advance....

Optimizing repetitive estimation (currently a loop) in MATLAB

I've found myself needing to do a least-squares (or similar matrix-based operation) for every pixel in an image. Every pixel has a set of numbers associated with it, and so it can be arranged as a 3D matrix.
(This next bit can be skipped)
Quick explanation of what I mean by least-squares estimation :
Let's say we have some quadratic system that is modeled by Y = Ax^2 + Bx + C and we're looking for those A,B,C coefficients. With a few samples (at least 3) of X and the corresponding Y, we can estimate them by:
Arrange the (lets say 10) X samples into a matrix like X = [x(:).^2 x(:) ones(10,1)];
Arrange the Y samples into a similar matrix: Y = y(:);
Estimate the coefficients A,B,C by solving: coeffs = (X'*X)^(-1)*X'*Y;
Try this on your own if you want:
A = 5; B = 2; C = 1;
x = 1:10;
y = A*x(:).^2 + B*x(:) + C + .25*randn(10,1); % added some noise here
X = [x(:).^2 x(:) ones(10,1)];
Y = y(:);
coeffs = (X'*X)^-1*X'*Y
coeffs =
5.0040
1.9818
0.9241
START PAYING ATTENTION AGAIN IF I LOST YOU THERE
*MAJOR REWRITE*I've modified to bring it as close to the real problem that I have and still make it a minimum working example.
Problem Setup
%// Setup
xdim = 500;
ydim = 500;
ncoils = 8;
nshots = 4;
%// matrix size for each pixel is ncoils x nshots (an overdetermined system)
%// each pixel has a matrix stored in the 3rd and 4rth dimensions
regressor = randn(xdim,ydim, ncoils,nshots);
regressand = randn(xdim, ydim,ncoils);
So my problem is that I have to do a (X'*X)^-1*X'*Y (least-squares or similar) operation for every pixel in an image. While that itself is vectorized/matrixized the only way that I have to do it for every pixel is in a for loop, like:
Original code style
%// Actual work
tic
estimate = zeros(xdim,ydim);
for col=1:size(regressor,2)
for row=1:size(regressor,1)
X = squeeze(regressor(row,col,:,:));
Y = squeeze(regressand(row,col,:));
B = X\Y;
% B = (X'*X)^(-1)*X'*Y; %// equivalently
estimate(row,col) = B(1);
end
end
toc
Elapsed time = 27.6 seconds
EDITS in reponse to comments and other ideas
I tried some things:
1. Reshaped into a long vector and removed the double for loop. This saved some time.
2. Removed the squeeze (and in-line transposing) by permute-ing the picture before hand: This save alot more time.
Current example:
%// Actual work
tic
estimate2 = zeros(xdim*ydim,1);
regressor_mod = permute(regressor,[3 4 1 2]);
regressor_mod = reshape(regressor_mod,[ncoils,nshots,xdim*ydim]);
regressand_mod = permute(regressand,[3 1 2]);
regressand_mod = reshape(regressand_mod,[ncoils,xdim*ydim]);
for ind=1:size(regressor_mod,3) % for every pixel
X = regressor_mod(:,:,ind);
Y = regressand_mod(:,ind);
B = X\Y;
estimate2(ind) = B(1);
end
estimate2 = reshape(estimate2,[xdim,ydim]);
toc
Elapsed time = 2.30 seconds (avg of 10)
isequal(estimate2,estimate) == 1;
Rody Oldenhuis's way
N = xdim*ydim*ncoils; %// number of columns
M = xdim*ydim*nshots; %// number of rows
ii = repmat(reshape(1:N,[ncoils,xdim*ydim]),[nshots 1]); %//column indicies
jj = repmat(1:M,[ncoils 1]); %//row indicies
X = sparse(ii(:),jj(:),regressor_mod(:));
Y = regressand_mod(:);
B = X\Y;
B = reshape(B(1:nshots:end),[xdim ydim]);
Elapsed time = 2.26 seconds (avg of 10)
or 2.18 seconds (if you don't include the definition of N,M,ii,jj)
SO THE QUESTION IS:
Is there an (even) faster way?
(I don't think so.)
You can achieve a ~factor of 2 speed up by precomputing the transposition of X. i.e.
for x=1:size(picture,2) % second dimension b/c already transposed
X = picture(:,x);
XX = X';
Y = randn(n_timepoints,1);
%B = (X'*X)^-1*X'*Y; ;
B = (XX*X)^-1*XX*Y;
est(x) = B(1);
end
Before: Elapsed time is 2.520944 seconds.
After: Elapsed time is 1.134081 seconds.
EDIT:
Your code, as it stands in your latest edit, can be replaced by the following
tic
xdim = 500;
ydim = 500;
n_timepoints = 10; % for example
% Actual work
picture = randn(xdim,ydim,n_timepoints);
picture = reshape(picture, [xdim*ydim,n_timepoints])'; % note transpose
YR = randn(n_timepoints,size(picture,2));
% (XX*X).^-1 = sum(picture.*picture).^-1;
% XX*Y = sum(picture.*YR);
est = sum(picture.*picture).^-1 .* sum(picture.*YR);
est = reshape(est,[xdim,ydim]);
toc
Elapsed time is 0.127014 seconds.
This is an order of magnitude speed up on the latest edit, and the results are all but identical to the previous method.
EDIT2:
Okay, so if X is a matrix, not a vector, things are a little more complicated. We basically want to precompute as much as possible outside of the for-loop to keep our costs down. We can also get a significant speed-up by computing XT*X manually - since the result will always be a symmetric matrix, we can cut a few corners to speed things up. First, the symmetric multiplication function:
function XTX = sym_mult(X) % X is a 3-d matrix
n = size(X,2);
XTX = zeros(n,n,size(X,3));
for i=1:n
for j=i:n
XTX(i,j,:) = sum(X(:,i,:).*X(:,j,:));
if i~=j
XTX(j,i,:) = XTX(i,j,:);
end
end
end
Now the actual computation script
xdim = 500;
ydim = 500;
n_timepoints = 10; % for example
Y = randn(10,xdim*ydim);
picture = randn(xdim,ydim,n_timepoints); % 500x500x10
% Actual work
tic % start timing
picture = reshape(picture, [xdim*ydim,n_timepoints])';
% Here we precompute the (XT*Y) calculation to speed things up later
picture_y = [sum(Y);sum(Y.*picture)];
% initialize
est = zeros(size(picture,2),1);
picture = permute(picture,[1,3,2]);
XTX = cat(2,ones(n_timepoints,1,size(picture,3)),picture);
XTX = sym_mult(XTX); % precompute (XT*X) for speed
X = zeros(2,2); % preallocate for speed
XY = zeros(2,1);
for x=1:size(picture,2) % second dimension b/c already transposed
%For some reason this is a lot faster than X = XTX(:,:,x);
X(1,1) = XTX(1,1,x);
X(2,1) = XTX(2,1,x);
X(1,2) = XTX(1,2,x);
X(2,2) = XTX(2,2,x);
XY(1) = picture_y(1,x);
XY(2) = picture_y(2,x);
% Here we utilise the fact that A\B is faster than inv(A)*B
% We also use the fact that (A*B)*C = A*(B*C) to speed things up
B = X\XY;
est(x) = B(1);
end
est = reshape(est,[xdim,ydim]);
toc % end timing
Before: Elapsed time is 4.56 seconds.
After: Elapsed time is 2.24 seconds.
This is a speed up of about a factor of 2. This code should be extensible to X being any dimensions you want. For instance, in the case where X = [1 x x^2], you would change picture_y to the following
picture_y = [sum(Y);sum(Y.*picture);sum(Y.*picture.^2)];
and change XTX to
XTX = cat(2,ones(n_timepoints,1,size(picture,3)),picture,picture.^2);
You would also change a lot of 2s to 3s in the code, and add XY(3) = picture_y(3,x) to the loop. It should be fairly straight-forward, I believe.
Results
I sped up your original version, since your edit 3 was actually not working (and also does something different).
So, on my PC:
Your (original) version: 8.428473 seconds.
My obfuscated one-liner given below: 0.964589 seconds.
First, for no other reason than to impress, I'll give it as I wrote it:
%%// Some example data
xdim = 500;
ydim = 500;
n_timepoints = 10; % for example
estimate = zeros(xdim,ydim); %// initialization with explicit size
picture = randn(xdim,ydim,n_timepoints);
%%// Your original solution
%// (slightly altered to make my version's results agree with yours)
tic
Y = randn(n_timepoints,xdim*ydim);
ii = 1;
for x = 1:xdim
for y = 1:ydim
X = squeeze(picture(x,y,:)); %// or similar creation of X matrix
B = (X'*X)^(-1)*X' * Y(:,ii);
ii = ii+1;
%// sometimes you keep everything and do
%// estimate(x,y,:) = B(:);
%// sometimes just the first element is important and you do
estimate(x,y) = B(1);
end
end
toc
%%// My version
tic
%// UNLEASH THE FURY!!
estimate2 = reshape(sparse(1:xdim*ydim*n_timepoints, ...
builtin('_paren', ones(n_timepoints,1)*(1:xdim*ydim),:), ...
builtin('_paren', permute(picture, [3 2 1]),:))\Y(:), ydim,xdim).'; %'
toc
%%// Check for equality
max(abs(estimate(:)-estimate2(:))) % (always less than ~1e-14)
Breakdown
First, here's the version that you should actually use:
%// Construct sparse block-diagonal matrix
%// (Type "help sparse" for more information)
N = xdim*ydim; %// number of columns
M = N*n_timepoints; %// number of rows
ii = 1:N;
jj = ones(n_timepoints,1)*(1:N);
s = permute(picture, [3 2 1]);
X = sparse(ii,jj(:), s(:));
%// Compute ALL the estimates at once
estimates = X\Y(:);
%// You loop through the *second* dimension first, so to make everything
%// agree, we have to extract elements in the "wrong" order, and transpose:
estimate2 = reshape(estimates, ydim,xdim).'; %'
Here's an example of what picture and the corresponding matrix X looks like for xdim = ydim = n_timepoints = 2:
>> clc, picture, full(X)
picture(:,:,1) =
-0.5643 -2.0504
-0.1656 0.4497
picture(:,:,2) =
0.6397 0.7782
0.5830 -0.3138
ans =
-0.5643 0 0 0
0.6397 0 0 0
0 -2.0504 0 0
0 0.7782 0 0
0 0 -0.1656 0
0 0 0.5830 0
0 0 0 0.4497
0 0 0 -0.3138
You can see why sparse is necessary -- it's mostly zeros, but will grow large quickly. The full matrix would quickly consume all your RAM, while the sparse one will not consume much more than the original picture matrix does.
With this matrix X, the new problem
X·b = Y
now contains all the problems
X1 · b1 = Y1
X2 · b2 = Y2
...
where
b = [b1; b2; b3; ...]
Y = [Y1; Y2; Y3; ...]
so, the single command
X\Y
will solve all your systems at once.
This offloads all the hard work to a set of highly specialized, compiled to machine-specific code, optimized-in-every-way algorithms, rather than the interpreted, generic, always-two-steps-away from the hardware loops in MATLAB.
It should be straightforward to convert this to a version where X is a matrix; you'll end up with something like what blkdiag does, which can also be used by mldivide in exactly the same way as above.
I had a wee play around with an idea, and I decided to stick it as a separate answer, as its a completely different approach to my other idea, and I don't actually condone what I'm about to do. I think this is the fastest approach so far:
Orignal (unoptimised): 13.507176 seconds.
Fast Cholesky-decomposition method: 0.424464 seconds
First, we've got a function to quickly do the X'*X multiplication. We can speed things up here because the result will always be symmetric.
function XX = sym_mult(X)
n = size(X,2);
XX = zeros(n,n,size(X,3));
for i=1:n
for j=i:n
XX(i,j,:) = sum(X(:,i,:).*X(:,j,:));
if i~=j
XX(j,i,:) = XX(i,j,:);
end
end
end
The we have a function to do LDL Cholesky decomposition of a 3D matrix (we can do this because the (X'*X) matrix will always be symmetric) and then do forward and backwards substitution to solve the LDL inversion equation
function Y = fast_chol(X,XY)
n=size(X,2);
L = zeros(n,n,size(X,3));
D = zeros(n,n,size(X,3));
B = zeros(n,1,size(X,3));
Y = zeros(n,1,size(X,3));
% These loops compute the LDL decomposition of the 3D matrix
for i=1:n
D(i,i,:) = X(i,i,:);
L(i,i,:) = 1;
for j=1:i-1
L(i,j,:) = X(i,j,:);
for k=1:(j-1)
L(i,j,:) = L(i,j,:) - L(i,k,:).*L(j,k,:).*D(k,k,:);
end
D(i,j,:) = L(i,j,:);
L(i,j,:) = L(i,j,:)./D(j,j,:);
if i~=j
D(i,i,:) = D(i,i,:) - L(i,j,:).^2.*D(j,j,:);
end
end
end
for i=1:n
B(i,1,:) = XY(i,:);
for j=1:(i-1)
B(i,1,:) = B(i,1,:)-D(i,j,:).*B(j,1,:);
end
B(i,1,:) = B(i,1,:)./D(i,i,:);
end
for i=n:-1:1
Y(i,1,:) = B(i,1,:);
for j=n:-1:(i+1)
Y(i,1,:) = Y(i,1,:)-L(j,i,:).*Y(j,1,:);
end
end
Finally, we have the main script which calls all of this
xdim = 500;
ydim = 500;
n_timepoints = 10; % for example
Y = randn(10,xdim*ydim);
picture = randn(xdim,ydim,n_timepoints); % 500x500x10
tic % start timing
picture = reshape(pr, [xdim*ydim,n_timepoints])';
% Here we precompute the (XT*Y) calculation
picture_y = [sum(Y);sum(Y.*picture)];
% initialize
est2 = zeros(size(picture,2),1);
picture = permute(picture,[1,3,2]);
% Now we calculate the X'*X matrix
XTX = cat(2,ones(n_timepoints,1,size(picture,3)),picture);
XTX = sym_mult(XTX);
% Call our fast Cholesky decomposition routine
B = fast_chol(XTX,picture_y);
est2 = B(1,:);
est2 = reshape(est2,[xdim,ydim]);
toc
Again, this should work equally well for a Nx3 X matrix, or however big you want.
I use octave, thus I can't say anything about the resulting performance in Matlab, but would expect this code to be slightly faster:
pictureT=picture'
est=arrayfun(#(x)( (pictureT(x,:)*picture(:,x))^-1*pictureT(x,:)*randn(n_ti
mepoints,1)),1:size(picture,2));

Simple Phase Shift for Removing Instrument Response

So I have a simple program where I want to shift a simple sine function pi/2. Now I knwo this would be extremely easy by just inserting a bias (i.e. A*sin(2*pi*frequency + bias). But this program is a simple way to test a theory. I need to shift complicated magnetic data, but the shift is frequency dependent. So to figure out how to do that I just want to shift this sin wave by a set shift, but I want to do it in the frequency domain. While the code below doesn't show any errors, it does not shift the data properly and effects magnitude. Code is below. Thank you!
clear all
time = 1:0.01:2*pi; %Create time vector
mag = sin(2*pi*time);
Y = fft(mag); %transform
Pnewr = pi/2;
%t = angle(mag);
t = imag(Y);
%t_fin = t-Pnewr; %Subtract the pahse delay from the original phase vector
R=real(Y);
I=t;
k = I./R
Phi = tan(k);
PhiFinal = Phi-Pnewr;
PhiFinal = PhiFinal'
IFinal = R * atan(PhiFinal);
spec=complex(R,IFinal);
Finalspec = ifft(spec); %Invert the transform
Final = Finalspec;
plot(time,mag);
hold on
plot(time,Final,'r')
grid on
For one thing you are not recombining imaginary and real components properly, since
PhiFinal = PhiFinal'
IFinal = R * atan(PhiFinal);
is effectively a dot product, not an element by element product. In general it doesn't look like you are making correct use of the complex relationships. The following generates a clean phase shift:
time = 1:0.01:2*pi;
mag = sin(2*pi*time);
Y = fft(mag); %transform
Pnewr = pi/2;
R = real(Y);
I = imag(Y);
It = abs(Y);
% It = sqrt(I.^2 + R.^2);
Phi= angle(Y); % <-- using matlab function, equivalent to `Phi = atan2(I, R);`
k = I./R;
Phi0 = atan(k);
figure, subplot(121), plot(Phi0,Phi,'.'), xlabel('Phi from tan'), ylabel('Phi from ''angle'''), grid on, axis('tight')
PhiFinal = Phi-Pnewr; % <-- phase shift
IFinal = It .* sin(PhiFinal);
RFinal = It .* cos(PhiFinal);
spec= RFinal + 1i*IFinal;
Final = ifft(spec); %Invert the transform
subplot(122)
plot(time,mag);
hold on
plot(time,real(Final),'r')
plot(time,imag(Final),'r:')
grid on
axis('tight')
legend('Initial','Final'),xlabel('t'), ylabel('I')
mag*mag' % <-- check that total power is conserved
Final*Final'
These figures show the phase as computed with tan vs matlab's angle (which uses atan2), and the results of the phase shift (right panel):

MATLAB: One Step Ahead Neural Network Timeseries Forecast

Intro: I'm using MATLAB's Neural Network Toolbox in an attempt to forecast time series one step into the future. Currently I'm just trying to forecast a simple sinusoidal function, but hopefully I will be able to move on to something a bit more complex after I obtain satisfactory results.
Problem: Everything seems to work fine, however the predicted forecast tends to be lagged by one period. Neural network forecasting isn't much use if it just outputs the series delayed by one unit of time, right?
Code:
t = -50:0.2:100;
noise = rand(1,length(t));
y = sin(t)+1/2*sin(t+pi/3);
split = floor(0.9*length(t));
forperiod = length(t)-split;
numinputs = 5;
forecasted = [];
msg = '';
for j = 1:forperiod
fprintf(repmat('\b',1,numel(msg)));
msg = sprintf('forecasting iteration %g/%g...\n',j,forperiod);
fprintf('%s',msg);
estdata = y(1:split+j-1);
estdatalen = size(estdata,2);
signal = estdata;
last = signal(end);
[signal,low,high] = preprocess(signal'); % pre-process
signal = signal';
inputs = signal(rowshiftmat(length(signal),numinputs));
targets = signal(numinputs+1:end);
%% NARNET METHOD
feedbackDelays = 1:4;
hiddenLayerSize = 10;
net = narnet(feedbackDelays,[hiddenLayerSize hiddenLayerSize]);
net.inputs{1}.processFcns = {'removeconstantrows','mapminmax'};
signalcells = mat2cell(signal,[1],ones(1,length(signal)));
[inputs,inputStates,layerStates,targets] = preparets(net,{},{},signalcells);
net.trainParam.showWindow = false;
net.trainparam.showCommandLine = false;
net.trainFcn = 'trainlm'; % Levenberg-Marquardt
net.performFcn = 'mse'; % Mean squared error
[net,tr] = train(net,inputs,targets,inputStates,layerStates);
next = net(inputs(end),inputStates,layerStates);
next = postprocess(next{1}, low, high); % post-process
next = (next+1)*last;
forecasted = [forecasted next];
end
figure(1);
plot(1:forperiod, forecasted, 'b', 1:forperiod, y(end-forperiod+1:end), 'r');
grid on;
Note:
The function 'preprocess' simply converts the data into logged % differences and 'postprocess' converts the logged % differences back for plotting. (Check EDIT for preprocess and postprocess code)
Results:
BLUE: Forecasted Values
RED: Actual Values
Can anyone tell me what I'm doing wrong here? Or perhaps recommend another method to achieve the desired results (lagless prediction of sinusoidal function, and eventually more chaotic timeseries)? Your help is very much appreciated.
EDIT:
It's been a few days now and I hope everyone has enjoyed their weekend. Since no solutions have emerged I've decided to post the code for the helper functions 'postprocess.m', 'preprocess.m', and their helper function 'normalize.m'. Maybe this will help get the ball rollin.
postprocess.m:
function data = postprocess(x, low, high)
% denormalize
logdata = (x+1)/2*(high-low)+low;
% inverse log data
sign = logdata./abs(logdata);
data = sign.*(exp(abs(logdata))-1);
end
preprocess.m:
function [y, low, high] = preprocess(x)
% differencing
diffs = diff(x);
% calc % changes
chngs = diffs./x(1:end-1,:);
% log data
sign = chngs./abs(chngs);
logdata = sign.*log(abs(chngs)+1);
% normalize logrets
high = max(max(logdata));
low = min(min(logdata));
y=[];
for i = 1:size(logdata,2)
y = [y normalize(logdata(:,i), -1, 1)];
end
end
normalize.m:
function Y = normalize(X,low,high)
%NORMALIZE Linear normalization of X between low and high values.
if length(X) <= 1
error('Length of X input vector must be greater than 1.');
end
mi = min(X);
ma = max(X);
Y = (X-mi)/(ma-mi)*(high-low)+low;
end
I didn't check you code, but made a similar test to predict sin() with NN. The result seems reasonable, without a lag. I think, your bug is somewhere in synchronization of predicted values with actual values.
Here is the code:
%% init & params
t = (-50 : 0.2 : 100)';
y = sin(t) + 0.5 * sin(t + pi / 3);
sigma = 0.2;
n_lags = 12;
hidden_layer_size = 15;
%% create net
net = fitnet(hidden_layer_size);
%% train
noise = sigma * randn(size(t));
y_train = y + noise;
out = circshift(y_train, -1);
out(end) = nan;
in = lagged_input(y_train, n_lags);
net = train(net, in', out');
%% test
noise = sigma * randn(size(t)); % new noise
y_test = y + noise;
in_test = lagged_input(y_test, n_lags);
out_test = net(in_test')';
y_test_predicted = circshift(out_test, 1); % sync with actual value
y_test_predicted(1) = nan;
%% plot
figure,
plot(t, [y, y_test, y_test_predicted], 'linewidth', 2);
grid minor; legend('orig', 'noised', 'predicted')
and the lagged_input() function:
function in = lagged_input(in, n_lags)
for k = 2 : n_lags
in = cat(2, in, circshift(in(:, end), 1));
in(1, k) = nan;
end
end