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 module revamp + updating dune-lang #680

Merged
merged 13 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .gitmodules
Empty file.
2 changes: 1 addition & 1 deletion dune-project
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
(lang dune 2.0)
(lang dune 3.16)

(name owl)
19 changes: 15 additions & 4 deletions examples/dune
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
(executables
(names
(names
backprop
checkpoint
cifar10_vgg
Expand All @@ -19,12 +19,23 @@
lazy_mnist
linear_algebra
lstm
max_freq
mnist_cnn
mnist_lenet
newton_method
specgram
squeezenet
test_log
tfidf
vgg16
)
(libraries owl))
vgg16)
(libraries owl)
(flags ; in order to make the examples compile correctly even with the warnings.
(:standard
-warn-error
-unused-value-declaration
-warn-error
-unused-var-strict
-warn-error
-unused-var
-warn-error
-unused-field)))
21 changes: 21 additions & 0 deletions examples/max_freq.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
(** This example shows how to compute the maximum peak frequency in time series data using the FFT module. *)

module G = Owl.Dense.Ndarray.Generic
module FFT = Owl.Fft.Generic

let max_freq signal sampling_rate =
(* Apply FFT *)
let fft_result = FFT.rfft ~otyp:Bigarray.Complex32 signal in
(* Get magnitude spectrum *)
let magnitudes = G.abs fft_result in
(* Find peak frequency *)
let max_idx = ref 0 in
let max_val = ref (G.get magnitudes [|0|]) in
for i = 0 to G.numel magnitudes - 1 do
let curr_val = G.get magnitudes [|i|] in
if curr_val > !max_val then (
max_val := curr_val ;
max_idx := i )
done ;
(* Convert index to frequency *)
float_of_int !max_idx *. sampling_rate /. float_of_int (G.numel signal)
62 changes: 62 additions & 0 deletions examples/specgram.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
(** This example, extracted from the SoundML library, shows how to compute a specgram using the FFT module *)

module G = Owl.Dense.Ndarray.Generic

(* helper to compute the fft frequencies *)
let fftfreq (n : int) (d : float) =
let nslice = ((n - 1) / 2) + 1 in
let fhalf =
G.linspace Bigarray.Float32 0. (float_of_int nslice) nslice
in
let shalf =
G.linspace Bigarray.Float32 (-.float_of_int nslice) (-1.) nslice
in
let v = G.concatenate ~axis:0 [|fhalf; shalf|] in
Owl.Arr.(1. /. (d *. float_of_int n) $* v)

(* Computes a one-sided PSD spectrogram with no padding and no detrend *)
let specgram (nfft : int) (fs : int) ?(noverlap : int = 0) (x : (float, Bigarray.float32_elt) G.t) =
let window = Owl.Signal.hann in (* we're using hann window *)
assert (noverlap < nfft) ;
(* we're making copies of the data from x and y to then use in place padding
and operations *)
let x = G.copy x in
(* We're making sure the arrays are at least of size nfft *)
let xshp = G.shape x in
( if Array.get xshp 0 < nfft then
let delta = nfft - Array.get xshp 0 in
(* we're doing this in place in hope to gain a little bit of speed *)
G.pad_ ~out:x ~v:0. [[0; delta - 1]; [0; 0]] x ) ;
let scale_by_freq = true in
let pad_to = nfft in
let scaling_factor = 2. in
let window = window nfft |> G.cast_d2s in
let window =
G.reshape G.(window * ones Bigarray.float32 [|nfft|]) [|-1; 1|]
in
let res =
G.slide ~window:nfft ~step:(nfft - noverlap) x |> G.transpose
in
(* if we'd add a detrend, we'd need to do it before applying the window *)
let res = G.(res * window) in
(* here comes the rfft compute, if you're processing large audio data, you might want to set ~nthreads to
something that suits both your hardware and your needs. *)
let res = Owl.Fft.S.rfft res ~axis:0 in
let freqs = fftfreq pad_to (1. /. float_of_int fs) in
let conj = G.conj res in
(* using in-place operations to avoid array copy *)
G.mul_ ~out:res conj res;
let slice = if nfft mod 2 = 0 then [[1; -1]; []] else [[1]; []] in
let gslice = G.get_slice slice res in
G.mul_scalar_ ~out:gslice gslice Complex.{re= scaling_factor; im= 0.} ;
G.set_slice slice res gslice ;
if scale_by_freq then (
let window = G.abs window in
G.div_scalar_ ~out:res res Complex.{re= float_of_int fs; im= 0.} ;
let n = G.sum' (G.pow_scalar window (float_of_int 2)) in
G.div_scalar_ ~out:res res Complex.{re= n; im= 0.} )
else (
let window = G.abs window in
let n = Float.pow (G.sum' window) 2. in
G.div_scalar_ ~out:res res Complex.{re= n; im= 0.} ) ;
(res, freqs)
2 changes: 1 addition & 1 deletion src/base/core/owl_graph.ml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type 'a node =
mutable next : 'a node array
; (* children of the node *)
mutable attr : 'a (* indicate the validity *)
}
} [@@warning "-69"]

type order =
| BFS
Expand Down
Loading
Loading