@@ -289,6 +289,83 @@ defmodule NxSignal.Windows do
289289 end
290290 end
291291
292+ @ doc """
293+ Creates a Kaiser window of size `window_length`.
294+
295+ The Kaiser window is a taper formed by using a Bessel function.
296+
297+ ## Options
298+
299+ * `:n` - The window length. Mandatory option.
300+ * `:is_periodic` - If `true`, produces a periodic window,
301+ otherwise produces a symmetric window. Defaults to `true`
302+ * `:type` - the output type for the window. Defaults to `{:f, 32}`
303+ * `:beta` - Shape parameter for the window. As beta increases, the window becomes more focused in frequency domain. Defaults to 12.0.
304+ * `:axis_name` - the axis name. Defaults to `nil`
305+
306+ ## Examples
307+ iex> NxSignal.Windows.kaiser(n: 4, beta: 12.0, is_periodic: true)
308+ #Nx.Tensor<
309+ f32[4]
310+ [5.2776191296288744e-5, 0.21566666662693024, 1.0, 0.21566666662693024]
311+ >
312+
313+ iex> NxSignal.Windows.kaiser(n: 5, beta: 12.0, is_periodic: true)
314+ #Nx.Tensor<
315+ f32[5]
316+ [5.2776191296288744e-5, 0.10171464085578918, 0.7929369807243347, 0.7929369807243347, 0.10171464085578918]
317+ >
318+
319+ iex> NxSignal.Windows.kaiser(n: 4, beta: 12.0, is_periodic: false)
320+ #Nx.Tensor<
321+ f32[4]
322+ [5.2776191296288744e-5, 0.5188394784927368, 0.5188390612602234, 5.2776191296288744e-5]
323+ >
324+ """
325+ @ doc type: :windowing
326+ defn kaiser ( opts \\ [ ] ) do
327+ opts =
328+ keyword! ( opts , [ :n , :axis_name , eps: 1.0e-7 , beta: 12.0 , is_periodic: true , type: { :f , 32 } ] )
329+
330+ { l , opts } = pop_window_size ( opts )
331+ name = opts [ :axis_name ]
332+ type = opts [ :type ]
333+ beta = opts [ :beta ]
334+ eps = opts [ :eps ]
335+ is_periodic = opts [ :is_periodic ]
336+
337+ window_length = if is_periodic , do: l + 1 , else: l
338+
339+ ratio = Nx . linspace ( - 1 , 1 , n: window_length , endpoint: true , type: type ) |> Nx . rename ( [ name ] )
340+ sqrt_arg = Nx . max ( 1 - ratio ** 2 , eps )
341+ r = beta * Nx . sqrt ( sqrt_arg )
342+
343+ window = kaiser_bessel_i0 ( r ) / kaiser_bessel_i0 ( beta )
344+
345+ if is_periodic do
346+ Nx . slice ( window , [ 0 ] , [ l ] )
347+ else
348+ window
349+ end
350+ end
351+
352+ defnp kaiser_bessel_i0 ( x ) do
353+ abs_x = Nx . abs ( x )
354+
355+ small_x_result =
356+ 1 +
357+ abs_x ** 2 / 4 +
358+ abs_x ** 4 / 64 +
359+ abs_x ** 6 / 2304 +
360+ abs_x ** 8 / 147_456
361+
362+ large_x_result =
363+ Nx . exp ( abs_x ) / Nx . sqrt ( 2 * Nx.Constants . pi ( ) * abs_x ) *
364+ ( 1 + 1 / ( 8 * abs_x ) + 9 / ( 128 * Nx . pow ( abs_x , 2 ) ) )
365+
366+ Nx . select ( abs_x < 3.75 , small_x_result , large_x_result )
367+ end
368+
292369 deftransformp pop_window_size ( opts ) do
293370 { n , opts } = Keyword . pop ( opts , :n )
294371
0 commit comments