Engee documentation
Notebook

Hypercomplex signal processing: Fourier transform and the algebra of optical operations through octonions

In modern digital signal processing, the Fourier transform is a fundamental tool. But what if we want to analyze not just one-dimensional audio signals or two-dimensional images, but complex multidimensional data, where each element contains information about color, polarization, spatial coordinates and other parameters? Moreover, we may need to change all the signal parameters in a related, physically acceptable way.

This is where octonions come to the rescue - 8-dimensional hypercomplex numbers that allow compact representation and analysis of such complex data.

What are octonions?

Octonions (or octaves) are an extension of complex numbers and quaternions. Unlike quaternions, which have 4 components, octonions have 8 components and have the property of non-associativity. In Julia, we can work with them using the package Octonions.jl.

In [ ]:
Pkg.add("Octonions")

Let's create the analyzed signal

Let's consider the implementation of the octonion Fourier transform for processing multidimensional signals.

Unlike a regular vector, an octonion (an 8-dimensional hypercomplex number) It can compactly encode:

  1. Polarization (2 components — linear and circular),

  2. Color (3 components — RGB or spectral characteristics),

  3. Phase information (1 component),

  4. Spatial coordinates (2 components — for example, angle of incidence and depth).

This representation preserves the relationships between the parameters, which are lost during separate analysis (representation in the form of vectors).

In [ ]:
using Octonions, FFTW, LinearAlgebra

# Создаем октонионный сигнал (8-канальный)
function create_octonion_signal(n)
    [Octonion(randn(8)...) for _ in 1:n]
end
Out[0]:
create_octonion_signal (generic function with 1 method)

The octonions here work as "containers" that preserve the natural relationships between the physical parameters of light, which is critical for accurate analysis and processing.

But if we decompose all the octonions into 8 scalar components, we get such a matrix:

In [ ]:
oc_to_vec(o) = [o.s, o.v1, o.v2, o.v3, o.v4, o.v5, o.v6, o.v7]
heatmap( hcat([oc_to_vec(o) for o in (create_octonion_signal(100))]... ) )
Out[0]:

Octonion Fourier transform

Next, we will implement two methods - the forward and reverse Fourier transforms for octonions.

In [ ]:
# Октонионное преобразование Фурье
function octonion_fft(signal)
    
    # Преобразуем вектор из октонионов в 8 векторов скаляров
    components = eachrow(hcat([oc_to_vec(o) for o in signal]...))
    
    # Применяем стандартное FFT к каждой компоненте
    transformed_components = [fft(c) for c in components]
    
    # Собираем действительную и мнимую часть в октонионы
    transformed_re = [Octonion([real(transformed_components[j][k]) for j in 1:8]...) for k in 1:n]
    transformed_im = [Octonion([imag(transformed_components[j][k]) for j in 1:8]...) for k in 1:n]
    return transformed_re, transformed_im
end

# Обратное преобразование
function octonion_ifft(signal_re, signal_im)
    complex_matrix = [[ Complex(si,sr) for (si,sr) in zip(oc_to_vec(vi),oc_to_vec(vr))] for (vi,vr) in zip(signal_re,signal_im)]
    components = eachrow(hcat(complex_matrix...))
    
    transformed_components = [ifft(c) for c in components]
    [Octonion([real(transformed_components[j][k]) for j in 1:8]...) for k in 1:n]
end
Out[0]:
octonion_ifft (generic function with 1 method)

Now let's transfer a vector of 256 octonions to our transformations, perform the conversion to the frequency domain and vice versa, and see what error we get from these operations.

In [ ]:
# Пример использования
n = 256
signal = create_octonion_signal(n)
(transformed_re, transformed_im) = octonion_fft(signal)
reconstructed = octonion_ifft(transformed_re, transformed_im)

# Проверка точности восстановления
recovery_err = norm([signal[i] - reconstructed[i] for i in 1:n])
println("Ошибка восстановления: ", recovery_err)
Ошибка восстановления: 1.0585794976561941e-14

With the inverse Fourier transform (ifft) we are working with a complex signal spectrum, but the final reconstructed signal must be real (since the initial data are physical measurements such as light intensity or wave amplitude).

Practical application

This approach can be useful for:

  1. Processing of color images with additional characteristics (depth, polarization)

  2. Analysis of multidimensional physical data (e.g. meteorological measurements)

  3. Compressing complex signals while preserving the relationships between the components

Examples of signals for analysis may include information from the following devices:

  1. Polarizing camera — data on the distribution of light polarization in a scene, where each pixel contains information about the angle and ellipticity of polarization.

  2. Hyperspectral images — Hundreds of spectral channels that can be compressed to 8 key components.

  3. Lidar data — distance, intensity and polarization of reflected signal for autonomous vehicles.

  4. Holography — the amplitude and phase of a light wave reconstructing a 3D object.

The use of octonions in optics

Octonions are not just 8D vectors, but an algebraic structure with noncommutative and non-associative multiplication. In optics, this allows:

  1. Encode interdependent parameters
    For example, polarization (linear/circular) is mathematically related to the phase and direction of wave propagation. In vector representation, these connections are lost, but in octonion algebra they are preserved through the rules of multiplication of basic units. e₁...e₇.

  2. Consider non-linear effects
    Octonion multiplication automatically simulates:

    • Rotation of the plane of polarization in crystals

    • Phase shifts during refraction

    • Interaction of spectral components

  3. Compress the view
    The 8D-octonion is more compact than the tensor description of the same parameters (for example, Jones-Muller matrices for polarization + separately RGB+ phase).

If desired, you can create an algebra of optical operations based on octonions, which has all the advantages outlined above.

The following program shows how applying polarization to a circularly polarized light beam immediately changes the amplitude, phase, and polarization of the input signal.

In [ ]:
using Octonions

struct OpticalField
    oct::Octonion{Float64}
end

# Оператор прохождения через поляризатор
function apply_polarizer(field::OpticalField, angle::Float64)
    # Поляризатор как октонион с e₂ (линейная поляризация)
    pol = Octonion(1.0, cos(2angle), sin(2angle), 0, 0, 0, 0, 0)
    OpticalField(field.oct * pol / 2)
end

# Пример: свет с круговой поляризацией (e₄)
input = OpticalField(Octonion(0, 0, 0, 1.0, 0, 0, 0, 0))
output = apply_polarizer(input, π/4)  # Поляризатор под 45°

# Результат содержит корректную связь амплитуды/фазы/поляризации
println(output.oct)  # Компоненты e₂ и e₃ теперь не нулевые
OctonionF64(0.0, -0.5, 3.061616997868383e-17, 0.5, 0.0, 0.0, 0.0, 0.0)

Octonions give a natural representation of optical fields precisely because of their algebraic structure. Unlike vectors, they are:

  1. ** Prohibit physically impossible operations** (for example, independent phase and polarization changes)

  2. Reduce computational complexity — one octonion operation replaces a series of matrix transformations

  3. Preserve geometric invariants automatically, without manually checking the conditions.

Conclusion

Although the octonion Fourier transform requires more calculations than the classical one, it opens up new possibilities for analyzing complex multidimensional data. In the future, with the development of quantum computing and specialized processors, such methods may become a standard tool in signal processing.

In optics, octonions provide a natural representation of optical fields precisely because of their algebraic structure.

Julia, with its performance and convenience of working with abstract data types, is ideal for experimenting with hypercomplex numbers and developing new algorithms based on them.