Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fft shift for human viewing #2

Open
anquegi opened this issue Sep 28, 2017 · 0 comments
Open

fft shift for human viewing #2

anquegi opened this issue Sep 28, 2017 · 0 comments

Comments

@anquegi
Copy link

anquegi commented Sep 28, 2017

First of all thanks for this nice library, is a real great tool for signal processing in common lisp. Now I'm a telecommunication ingenieur working as programmer and in my sparse time I like to learn common lisp. know I want to join common lisp with signal processing, so I really enjoy playing with this library, and know how easy is build the samples that I have in matlab using common lisp, and also the freedom of that

The only thing that I believe that should be usefull to add or maybe only add a reference in the readme, is how to well plot the spectrum for human viewing. for example matlab has the function fftshift (you have and example of this when you get the number 654 por the impulse in the vector for 440 Hz tone) also FFT has a reference of this.

Question 3.11. How can I make FFTW put the origin (zero frequency) at the center of its output?
For human viewing of a spectrum, it is often convenient to put the origin in frequency space at the center of the output array, rather than in the zero-th element (the default in FFTW). If all of the dimensions of your array are even, you can accomplish this by simply multiplying each element of the input array by (-1)^(i + j + ...), where i, j, etcetera are the indices of the element. (This trick is a general property of the DFT, and is not specific to FFTW.)

for example for a 440 tone, you can proceed as follow:

  (defparameter *Fs* 44100 "sampling frequency")
  (defparameter *NN* 65536 "number of samples")
  (defparameter *n* (loop for i from 0 below *NN* collect i))
  (defparameter *signal* (mapcar (lambda (x) (cos (/ (* 2 pi 440 x) *Fs*))) *n*) )
  (defparameter *spectrum* (napa-fft:fft *signal* :scale t))

You can use alexandria rotate by half length of the vector and also plot [-0.5 0.5] intead of [0 1]
as is given the result of the DFT, then of course scale to half Fs


(vgplot:plot
 (loop for i from (- (/ *NN* 2)) below (1- (/ *NN* 2)) collect (* (/ i *NN*) *Fs*))
 (alexandria:rotate (map 'simple-vector #'abs *spectrum*) (/ *NN* 2)))

;; or proceding like this

(defparameter *signal* (mapcar (lambda (x) (cos (/ (* 2 pi 440 x) *Fs*))) *n*) )
(defparameter *spectrum-shifted* (napa-fft:fft (loop for i from 0 for x in *signal* collect (* (expt -1 i) x)) :scale t))

(vgplot:plot
 (loop for i from (- (/ *NN* 2)) below (1- (/ *NN* 2)) collect (* (/ i *NN*) *Fs*))
 (map 'simple-vector #'abs *spectrum-shifted*))

getting the same figure:

captura de pantalla 2017-09-28 a las 13 54 11

Also is important the advice of using vector's length with multiple of 2^k, when you do not generate the signal maybe good to zero padding the signal until the next power of two with this:

(defun next-2-power (n)
  "Rounding up to next power of 2"
  (expt 2 (ceiling (log n 2))))

This things are important for data visualization but this is really not necessar, and also will be important to add the axes correcttly power of spectrum and Hz. So I do not know it it will ne useful to add this in anyway to this library. really the one of multiplying is imilat to use a windowed fft (one nice feature to weel plotting ffts)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant