diff --git a/include/aidge/data/Spikegen.hpp b/include/aidge/data/Spikegen.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..30fd5decba675d168d7872f03221bfa6664f7f71
--- /dev/null
+++ b/include/aidge/data/Spikegen.hpp
@@ -0,0 +1,31 @@
+/********************************************************************************
+ * Copyright (c) 2025 CEA-List
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+#ifndef AIDGE_CORE_DATA_SPIKEGEN_H_
+#define AIDGE_CORE_DATA_SPIKEGEN_H_
+
+#include <cstdint>
+
+#include "aidge/data/Tensor.hpp"
+
+namespace Aidge {
+
+/*
+ * @brief Spike rate encoding of input data
+ */
+Tensor spikegenRate(std::shared_ptr<Tensor> tensor, std::uint32_t numSteps);
+
+
+Tensor spikegenLatency(std::shared_ptr<Tensor> tensor);
+}
+
+
+#endif
diff --git a/include/aidge/data/Tensor.hpp b/include/aidge/data/Tensor.hpp
index 5df59becdc41f12768935544a42aac24ffb3a333..76295270e4081d45cf0289f2e9feba5e3e4855fb 100644
--- a/include/aidge/data/Tensor.hpp
+++ b/include/aidge/data/Tensor.hpp
@@ -13,9 +13,7 @@
 #define AIDGE_CORE_DATA_TENSOR_H_
 
 #include <algorithm>
-#include <cstddef>      // std::size_t
-#include <cstring>
-#include <functional>   // std::multiplies
+#include <cstddef>      // std::size_t #include <cstring> #include <functional>   // std::multiplies
 #include <set>
 #include <memory>
 #include <numeric>      // std::accumulate
@@ -989,6 +987,18 @@ public:
         return ref(fallback, targetReqs.dataType(), device.first, device.second);
     }
 
+
+    /**
+     * @brief Repeat the tensor along a new first dimension.
+     * For example, if the current tensor has dimensions (n, m),
+     * calling repeat(10) returns a tensor of shape (10, n, m)
+     * with 10 copies of the original data.
+     *
+     * @param times number of repetitions (must be positive)
+     * @return Tensor new tensor containing the repeated data.
+     */
+    Tensor repeat(int times) const;
+
 private:
     /**
      * @brief Compute the number of elements in the Tensor.
diff --git a/python_binding/data/pybind_Spikegen.cpp b/python_binding/data/pybind_Spikegen.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..de4636bb29719741e43d14346fa57465caddd63a
--- /dev/null
+++ b/python_binding/data/pybind_Spikegen.cpp
@@ -0,0 +1,26 @@
+/********************************************************************************
+ * Copyright (c) 2025 CEA-List
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+#include <pybind11/pybind11.h>
+
+#include "aidge/data/Spikegen.hpp"
+#include "aidge/data/Tensor.hpp"
+
+namespace py = pybind11;
+namespace Aidge {
+
+void init_Spikegen(py::module &m) {
+    m.def("spikegen_rate", &spikegenRate,
+          py::arg("tensor"), py::arg("numSteps"),
+          "Performs spike rate encoding on a Tensor");
+}
+
+} // namespace Aidge
diff --git a/python_binding/pybind_core.cpp b/python_binding/pybind_core.cpp
index ef1111b39a2f6fff3153dfb7441543ff5c3956c2..e9e246ad1d663901ff8c02ea2d8f744fdbf90e3b 100644
--- a/python_binding/pybind_core.cpp
+++ b/python_binding/pybind_core.cpp
@@ -32,8 +32,10 @@ void init_OperatorImpl(py::module&);
 void init_Log(py::module&);
 void init_Operator(py::module&);
 void init_OperatorTensor(py::module&);
+void init_Spikegen(py::module&);
 void init_StaticAnalysis(py::module&);
 
+
 void init_Abs(py::module&);
 void init_Add(py::module&);
 void init_And(py::module&);
@@ -122,6 +124,7 @@ void init_Aidge(py::module& m) {
     init_Tensor(m);
     init_TensorImpl(m);
     init_Attributes(m);
+    init_Spikegen(m);
 
     init_Node(m);
     init_GraphView(m);
diff --git a/src/data/SpikeGen.cpp b/src/data/SpikeGen.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..eecd6c86ebcdc7d3ce52ebf6513305364a7737b2
--- /dev/null
+++ b/src/data/SpikeGen.cpp
@@ -0,0 +1,41 @@
+/********************************************************************************
+ * Copyright (c) 2025 CEA-List
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+#include <memory>
+#include <random>
+
+#include "aidge/data/Spikegen.hpp"
+
+namespace Aidge {
+static Tensor rateConvert(const Tensor& tensor) {
+
+    auto result = tensor.clone();
+
+    std::random_device rd;
+    std::mt19937 gen(rd());
+    std::uniform_real_distribution<float> dis(0.0f, 1.0f);
+
+    // Clip values between 0 and 1, equivalent to torch.clamp(min=0, max=1)
+    for (size_t i = 0; i < tensor.size(); i++) {
+        auto val = tensor.get<float>(i);
+        val = (val < 0.0f) ? 0.0f : ((val > 1.0f) ? 1.0f : val);
+        auto randomValue = dis(gen);
+        result.set(i, randomValue < val ? 1.0f : 0.0f);
+    }
+
+    return result;
+}
+
+Tensor spikegenRate(std::shared_ptr<Tensor> tensor, std::uint32_t numSteps) {
+    auto newTensor = tensor->repeat(numSteps);
+    return rateConvert(newTensor);
+}
+}  // namespace Aidge
diff --git a/src/data/Tensor.cpp b/src/data/Tensor.cpp
index b128833c9099385c72f25057400a65a6b9034c32..d441685649ee571265469bc142288f736d6969d1 100644
--- a/src/data/Tensor.cpp
+++ b/src/data/Tensor.cpp
@@ -802,6 +802,40 @@ const Tensor& Tensor::ref(std::shared_ptr<Tensor>& fallback,
     }
 }
 
+Tensor Tensor::repeat(int times) const {
+    AIDGE_ASSERT(times > 0, "repeat count must be positive");
+
+    Tensor src = *this;
+    if (not src.isContiguous()) {
+        src = src.clone();
+        src.makeContiguous();
+    }
+
+    // Build new dimensions: new_dims = {times} followed by current dims
+    std::vector<DimSize_t> newDims;
+    newDims.push_back(static_cast<DimSize_t>(times));
+    for (const auto &d : dims()) {
+        newDims.push_back(d);
+    }
+
+    Tensor out(newDims);
+    out.setDataType(dataType(), false);
+    out.setDataFormat(dataFormat());
+    if (hasImpl()) {
+        out.setBackend(getImpl()->backend(), device());
+    }
+
+    // Each "block" is a copy of the data from the original tensor.
+    const std::size_t block = src.size();
+    for (int i = 0; i < times; ++i) {
+        // out.getImpl()->copy(source pointer, number of elements, destination offset)
+        out.getImpl()->copy(src.getImpl()->rawPtr(src.getImplOffset()),
+                            block,
+                            i * block);
+    }
+    return out;
+}
+
 
 std::vector<std::size_t>
 Tensor::toCoord(const std::vector<DimSize_t>& dimensions, std::size_t index) {
diff --git a/unit_tests/data/Test_Spikegen.cpp b/unit_tests/data/Test_Spikegen.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..06f33197d15116466e38df424dfa4a53b5775930
--- /dev/null
+++ b/unit_tests/data/Test_Spikegen.cpp
@@ -0,0 +1,42 @@
+/********************************************************************************
+ * Copyright (c) 2025 CEA-List
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+#include <cstdint>     // std::uint8_t, std::uint16_t, std::int32_t
+#include <vector>      // std::vector
+
+#include <catch2/catch_test_macros.hpp>
+
+#include "aidge/data/Spikegen.hpp"
+#include "aidge/data/Tensor.hpp"
+#include "aidge/utils/ArrayHelpers.hpp"
+#include "aidge/utils/TensorUtils.hpp"
+
+
+namespace Aidge
+{
+TEST_CASE("[core/data] SpikeGen zeros", "[SpikeGen]") {
+    auto input = Tensor(Array1D<float, 3>({0,0,0}));
+    auto expectedOutput = Tensor(Array2D<float, 3, 3>({{{0,0,0}, {0,0,0}, {0,0,0}}}));
+
+    auto spikes = spikegenRate(std::make_shared<Tensor>(input), 3);
+
+    REQUIRE(approxEq<float>(spikes, expectedOutput));
+}
+
+TEST_CASE("[core/data] SpikeGen ones", "[SpikeGen]") {
+    auto input = Tensor(Array1D<float, 3>({1,1,1}));
+    auto expectedOutput = Tensor(Array2D<float, 3, 3>({{{1,1,1}, {1,1,1}, {1,1,1}}}));
+
+    auto spikes = spikegenRate(std::make_shared<Tensor>(input), 3);
+
+    REQUIRE(approxEq<float>(spikes, expectedOutput));
+}
+}  // namespace Aidge
diff --git a/unit_tests/data/Test_Tensor.cpp b/unit_tests/data/Test_Tensor.cpp
index bfdc1a6b9c058b348942e9c29a77ac4d6db5086f..28f3a5fdec1836d5d5f5c2a42375e49bc4f1dcc5 100644
--- a/unit_tests/data/Test_Tensor.cpp
+++ b/unit_tests/data/Test_Tensor.cpp
@@ -505,6 +505,35 @@ TEST_CASE("[core/data] Tensor(other)", "[Tensor][extract][zeros][print]") {
         }
     }
 
+    SECTION("repeat") {
+        Tensor tensor = Array2D<int, 2, 3>{{{1, 2, 3},
+                                            {4, 5, 6}}};
+        const int repeatTimes = 4;
+        
+        Tensor repeated;
+        REQUIRE_NOTHROW(repeated = tensor.repeat(repeatTimes));
+        
+        // The expected shape after repeating is {repeatTimes, 2, 3}
+        std::vector<DimSize_t> expectedDims = {static_cast<DimSize_t>(repeatTimes), 2, 3};
+        CHECK(repeated.dims() == expectedDims);
+        
+        // For each repetition along the new dimension, extract the slice and verify
+        // that it matches the original tensor
+        for (int i = 0; i < repeatTimes; ++i) {
+            Tensor slice;
+            REQUIRE_NOTHROW(slice = repeated.extract({static_cast<std::size_t>(i)}));
+            CHECK(slice.dims() == tensor.dims());
+            
+            // Compare slice with original tensor elementwise
+            for (std::size_t idx = 0; idx < tensor.size(); ++idx) {
+                int expectedVal = tensor.get<int>(idx);
+                int sliceVal = slice.get<int>(idx);
+                INFO("Mismatch in repetition " << i << " at flat index " << idx);
+                CHECK(sliceVal == expectedVal);
+            }
+        }
+    }
+
     // print, toString,
     SECTION("Pretty printing for debug") {
         Tensor x{};