diff --git a/corsika/detail/modules/radio/propagators/TabulatedFlatAtmospherePropagator.inl b/corsika/detail/modules/radio/propagators/TabulatedFlatAtmospherePropagator.inl
index f80550dea62444bb3be572d0f3bec975a9e02ea5..0c213daf91e19d36fa201253ed7a83534b91a3a5 100644
--- a/corsika/detail/modules/radio/propagators/TabulatedFlatAtmospherePropagator.inl
+++ b/corsika/detail/modules/radio/propagators/TabulatedFlatAtmospherePropagator.inl
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2022 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2023 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -21,9 +21,10 @@ namespace corsika {
       , upperLimit_(upperLimit)
       , lowerLimit_(lowerLimit)
       , step_(step)
-      , inverseStep_(1 / step) {
-    auto const maxHeight_ = upperLimit_.getCoordinates().getZ();
-    auto const minHeight_ = lowerLimit_.getCoordinates().getZ();
+      , inverseStep_(1 / step)
+      , maxHeight_(upperLimit_.getCoordinates().getZ())
+      , minHeight_(lowerLimit_.getCoordinates().getZ() - 1_km)
+  {
     auto const minX_ = lowerLimit_.getCoordinates().getX();
     auto const minY_ = lowerLimit_.getCoordinates().getY();
     std::size_t const nBins_ = (maxHeight_ - minHeight_) * inverseStep_ + 1;
@@ -49,23 +50,30 @@ namespace corsika {
     auto const intRerfZero_ = refractivityTable_.at(0) * stepOverMeter_;
     integratedRefractivityTable_.push_back(intRerfZero_);
     for (std::size_t i = 1; i < nBins_; i++) {
-      auto const intRefrI_ =
-          integratedRefractivityTable_[i - 1] + refractivityTable_[i] * stepOverMeter_;
+      auto const intRefrI_ = integratedRefractivityTable_[i-1] + refractivityTable_[i] * stepOverMeter_;
       integratedRefractivityTable_.push_back(intRefrI_);
     }
+
+    // this is used to interpolate refractivity and integrated refractivity for particles below the lower limit
+    slopeRefrLower_ = (refractivityTable_.at(10) - refractivityTable_.front()) / 10.;
+    slopeIntRefrLower_ = (integratedRefractivityTable_.at(10) - integratedRefractivityTable_.front()) / 10.;
+
+    // this is used to interpolate refractivity and integrated refractivity for particles above the upper limit
+    lastElement_ = integratedRefractivityTable_.size() - 1;
+    slopeRefrUpper_ = (refractivityTable_.at(lastElement_) - refractivityTable_.at(lastElement_ - 10)) / 10.;
+    slopeIntRefrUpper_ = (integratedRefractivityTable_.at(lastElement_) - integratedRefractivityTable_.at(lastElement_ - 10)) / 10.;
   };
 
   template <typename TEnvironment>
   template <typename Particle>
   inline typename TabulatedFlatAtmospherePropagator<TEnvironment>::SignalPathCollection
-  TabulatedFlatAtmospherePropagator<TEnvironment>::propagate(Particle const& particle, Point const& source,
-                                                             Point const& destination) {
+  TabulatedFlatAtmospherePropagator<TEnvironment>::propagate( [[maybe_unused]] Particle const& particle, Point const& source, Point const& destination) {
 
     /**
-     * This is a simple case of straight propagator where
-     * tabulated values of refractive index are called assuming
-     * a flat atmosphere.
-     *
+    * This is a simple case of straight propagator where
+    * tabulated values of refractive index are called assuming
+    * a flat atmosphere.
+    *
      */
 
     // these are used for the direction of emission and reception of signal at the antenna
@@ -78,33 +86,89 @@ namespace corsika {
     // clear the refractive index vector and points deque for this signal propagation.
     rindex.clear();
     points.clear();
+    auto const sourceZ_{source.getCoordinates().getZ()};
+    auto const checkMaxZ_{(maxHeight_ - sourceZ_) / 1_m};
+    auto ri_source{1.};
+    auto intRerfr_source{1.};
+    auto ri_destination{1.};
+    auto intRerfr_destination{1.};
+    auto height_{1.};
+
+    double const sourceHeight_{(sourceZ_ - heightTable_.front()) * inverseStep_};
+    double const destinationHeight_{(destination.getCoordinates().getZ() - heightTable_.front()) * inverseStep_};
+
+    if ((sourceHeight_ + 0.5) >= lastElement_) { // source particle is above maximum height
+      ri_source = refractivityTable_.back() + slopeRefrUpper_ * std::abs((sourceZ_ - heightTable_.back()) * inverseStep_) + 1;
+      intRerfr_source = integratedRefractivityTable_.back() + slopeIntRefrUpper_ * std::abs(checkMaxZ_);
+      rindex.push_back(ri_source);
+      points.push_back(source);
+
+      // add the refractive index of last point 'destination' and store it.
+      std::size_t const indexDestination_{static_cast<std::size_t>(destinationHeight_ + 0.5)};
+      ri_destination = refractivityTable_.at(indexDestination_) + 1;
+      intRerfr_destination = integratedRefractivityTable_.at(indexDestination_);
+      rindex.push_back(ri_destination);
+      points.push_back(destination);
+
+      height_ = sourceHeight_ - destinationHeight_;
+
+    } else if ((sourceHeight_ + 0.5 < lastElement_) && sourceHeight_ > 0) { // source particle in the table
+      // get and store the refractive index of the first point 'source'.
+      std::size_t const indexSource_{static_cast<std::size_t>(sourceHeight_ + 0.5)};
+      ri_source = refractivityTable_.at(indexSource_) + 1;
+      intRerfr_source = integratedRefractivityTable_.at(indexSource_);
+      rindex.push_back(ri_source);
+      points.push_back(source);
+
+      // add the refractive index of last point 'destination' and store it.
+      std::size_t const indexDestination_{static_cast<std::size_t>(destinationHeight_ + 0.5)};
+      ri_destination = refractivityTable_.at(indexDestination_) + 1;
+      intRerfr_destination = integratedRefractivityTable_.at(indexDestination_);
+      rindex.push_back(ri_destination);
+      points.push_back(destination);
+
+      height_ = (heightTable_.at(indexSource_) - heightTable_.at(indexDestination_)) / 1_m;
+      if (height_ == 0) {
+        height_ = 1.;
+      }
+    } else if (sourceHeight_ == 0) { // source particle is exactly at the lower edge of the table
+      // get and store the refractive index of the first point 'source'.
+      std::size_t const indexSource_{static_cast<std::size_t>(sourceHeight_ + 0.5)};
+      auto const ri_source{refractivityTable_.at(indexSource_) + 1};
+      intRerfr_source = integratedRefractivityTable_.at(indexSource_);
+      rindex.push_back(ri_source);
+      points.push_back(source);
+
+      // add the refractive index of last point 'destination' and store it.
+      std::size_t const indexDestination_{static_cast<std::size_t>(destinationHeight_ + 0.5)};
+      auto const ri_destination{refractivityTable_.at(indexDestination_) + 1};
+      intRerfr_destination = integratedRefractivityTable_.at(indexDestination_);
+      rindex.push_back(ri_destination);
+      points.push_back(destination);
+
+      height_ = destinationHeight_ - sourceHeight_;
+    } else if (sourceHeight_ < 0) { // source particle is in the ground.
+      // get and store the refractive index of the first point 'source'.
+      ri_source = refractivityTable_.front() + slopeRefrLower_ * std::abs(sourceHeight_) + 1;
+      intRerfr_source = integratedRefractivityTable_.front() + slopeIntRefrLower_ * std::abs(sourceHeight_);
+      rindex.push_back(ri_source);
+      points.push_back(source);
+
+      // add the refractive index of last point 'destination' and store it.
+      std::size_t const indexDestination_{static_cast<std::size_t>(destinationHeight_ + 0.5)};
+      auto const ri_destination{refractivityTable_.at(indexDestination_) + 1};
+      intRerfr_destination = integratedRefractivityTable_.at(indexDestination_);
+      rindex.push_back(ri_destination);
+      points.push_back(destination);
+
+      height_ = destinationHeight_ - std::abs(sourceHeight_);
+    }
 
-    // get and store the refractive index of the first point 'source'.
-    std::size_t const indexSource_{static_cast<std::size_t>(
-        (source.getCoordinates().getZ() - heightTable_.front()) * inverseStep_ +
-        0.5)}; // ToDo: this does no interpolation for particles in ground, it just stops
-               // on the surface.
-    auto const ri_source{refractivityTable_.at(indexSource_) + 1};
-    rindex.push_back(ri_source);
-    points.push_back(source);
-
-    // add the refractive index of last point 'destination' and store it.
-    std::size_t const indexDestination_{static_cast<std::size_t>(
-        (destination.getCoordinates().getZ() - heightTable_.front()) * inverseStep_ +
-        0.5)};
-    auto const ri_destination{refractivityTable_.at(indexDestination_) + 1};
-    rindex.push_back(ri_destination);
-    points.push_back(destination);
-
-    auto const height_ =
-        (heightTable_.at(indexSource_) - heightTable_.at(indexDestination_)) / 1_m;
     // compute the average refractive index.
     auto const averageRefractiveIndex_ = (ri_source + ri_destination) * 0.5;
 
     // compute the total time delay.
-    TimeType const time = (1 + (integratedRefractivityTable_.at(indexSource_) -
-                                integratedRefractivityTable_.at(indexDestination_)) /
-                                   height_) *
+    TimeType const time = (1 + (intRerfr_source - intRerfr_destination) / height_) *
                           (distance_ / constants::c);
 
     return {SignalPath(time, averageRefractiveIndex_, ri_source, ri_destination, emit_,
@@ -113,3 +177,4 @@ namespace corsika {
   } // END: propagate()
 
 } // namespace corsika
+
diff --git a/corsika/modules/radio/propagators/TabulatedFlatAtmospherePropagator.hpp b/corsika/modules/radio/propagators/TabulatedFlatAtmospherePropagator.hpp
index 4675daee3c0f43a1fe12581170ec2263eb446092..a9d78cc6566eadc0c51d74909985fd4dc2b48c0e 100644
--- a/corsika/modules/radio/propagators/TabulatedFlatAtmospherePropagator.hpp
+++ b/corsika/modules/radio/propagators/TabulatedFlatAtmospherePropagator.hpp
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2022 CORSIKA Project, corsika-project@lists.kit.edu
+ * (c) Copyright 2023 CORSIKA Project, corsika-project@lists.kit.edu
  *
  * This software is distributed under the terms of the GNU General Public
  * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
@@ -20,7 +20,8 @@ namespace corsika {
    * This class implements a tabulated propagator that approximates
    * the Earth's atmosphere as flat. Signal propagation is rectilinear
    * and this is intended to be used for vertical showers
-   * (<60 degrees zenith angle) for fast simulations.
+   * (<60 degrees zenith angle) for fast simulations. The table needs
+   * to have at least 10 elements.
    *
    */
   template <typename TEnvironment>
@@ -50,24 +51,29 @@ namespace corsika {
     SignalPathCollection propagate(Particle const& particle, Point const& source, Point const& destination);
 
   private:
-    Point const upperLimit_;
-    Point const lowerLimit_;
-    LengthType const step_;
-    InverseLengthType const inverseStep_;
-    std::vector<double> refractivityTable_;
-    std::vector<double> integratedRefractivityTable_;
-    std::vector<LengthType> heightTable_;
-    std::deque<Point> points;
-    std::vector<double> rindex;
+    Point const upperLimit_; ///< the upper point of the table.
+    Point const lowerLimit_; ///< the lowest point of the table (ideally earth's surface).
+    LengthType const minHeight_; ///< z coordinate of lower limit (minimum height) - 1_km for safety reasons.
+    LengthType const maxHeight_; ///< z coordinate of upper limit (maximum height).
+    LengthType const step_; ///< the tabulation step.
+    InverseLengthType const inverseStep_; ///< inverse of the step used to speed up calculations.
+    std::vector<double> refractivityTable_; ///< the table that stores refractivity.
+    std::vector<double> integratedRefractivityTable_; ///< the table that stores integrated refractivity.
+    std::vector<LengthType> heightTable_; ///< the table that stores the height using the step above.
+    std::deque<Point> points; ///< the points that the signal has propagated through.
+    std::vector<double> rindex; ///< the refractive index values along the signal propagation path.
+    double slopeRefrLower_; ///< used to interpolate refractivity for particles below the lowest point.
+    double slopeIntRefrLower_; ///< used to interpolate integrated refractivity for particles below the lowest point.
+    double slopeRefrUpper_; ///< used to interpolate refractivity for particles above the highest point.
+    double slopeIntRefrUpper_; ///< used to interpolate integrated refractivity for particles above the highest point.
+    double lastElement_ ; ///< last index of tables.
 
   }; // End: FlatEarthPropagator
 
   template <typename TEnvironment>
   TabulatedFlatAtmospherePropagator<TEnvironment>
-  make_tabulated_flat_atmosphere_radio_propagator(TEnvironment const& env,
-                                                  Point const& upperLimit,
-                                                  Point const& lowerLimit,
-                                                  LengthType const step) {
+  make_tabulated_flat_atmosphere_radio_propagator(TEnvironment const& env, Point const& upperLimit, Point const& lowerLimit,
+                                                  LengthType const step){
     return TabulatedFlatAtmospherePropagator<TEnvironment>(env, upperLimit, lowerLimit,
                                                            step);
   }