diff --git a/src/libPS/IPowerSupply.cpp b/src/libPS/IPowerSupply.cpp
index 4b4bc425bb656b290036434697f3cd00efd481b3..674551f6f5c2fb71aeacd5fb7d3e95f57324da95 100644
--- a/src/libPS/IPowerSupply.cpp
+++ b/src/libPS/IPowerSupply.cpp
@@ -1,7 +1,10 @@
 #include "IPowerSupply.h"
 
+#include <chrono>
 #include <iostream>
 #include <stdexcept>
+#include <thread>
+
 #include "Logger.h"
 
 IPowerSupply::IPowerSupply(const std::string& name, std::vector<std::string> models)
@@ -75,6 +78,27 @@ bool IPowerSupply::isOn(unsigned channel)
   return false;
 }
 
+void IPowerSupply::rampCurrentLevel(double curr, double rate, unsigned channel)
+{
+  if(rate<0)
+    throw std::runtime_error("rampCurrentLevel: ramp rate must be positive");
+
+  // Get starting point and direction
+  double currentCurrent=measureCurrent(channel);
+  double dir=(currentCurrent<curr)?+1:-1; // Direction of ramp
+
+  // Ramp until you get as close as possible to desired current with
+  // discrete `ramp` steps
+  uint32_t nsteps=std::floor(std::fabs(curr-currentCurrent)/rate);
+  for(uint32_t i=1;i<nsteps;i++)
+    {
+      setCurrentLevel(currentCurrent+i*dir*rate, channel);
+      std::this_thread::sleep_for(std::chrono::seconds(1));
+    }
+  // Set final current. The final step size should be less than rate
+  setCurrentLevel(curr,channel);
+}
+
 void IPowerSupply::setCurrentProtect(double cur, unsigned channel)
 {
   logger(logWARNING) << "setCurrentProtect() not implemented for this PS.";
@@ -86,6 +110,27 @@ double IPowerSupply::getCurrentProtect(unsigned channel)
   return 0;
 }
 
+void IPowerSupply::rampVoltageLevel(double volt, double rate, unsigned channel)
+{
+  if(rate<0)
+    throw std::runtime_error("rampVoltageLevel: ramp rate must be positive");
+
+  // Get starting point and direction
+  double currentVoltage=measureVoltage(channel);
+  double dir=(currentVoltage<volt)?+1:-1; // Direction of ramp
+
+  // Ramp until you get as close as possible to desired voltage with
+  // discrete `ramp` steps
+  uint32_t nsteps=std::floor(std::fabs(volt-currentVoltage)/rate);
+  for(uint32_t i=1;i<nsteps;i++)
+    {
+      setVoltageLevel(currentVoltage+i*dir*rate, channel);
+      std::this_thread::sleep_for(std::chrono::seconds(1));
+    }
+  // Set final voltage. The final step size should be less than rate
+  setVoltageLevel(volt, channel);
+}
+
 void IPowerSupply::setVoltageProtect(double volt, unsigned channel)
 {
   logger(logWARNING) << "setVoltageProtect() not implemented for this PS.";
diff --git a/src/libPS/IPowerSupply.h b/src/libPS/IPowerSupply.h
index 41e68c02f48316b34c98901396e04a56a41b41d1..d1d23b7c1899111974cbba7e2dbb5c0fbfa4571f 100644
--- a/src/libPS/IPowerSupply.h
+++ b/src/libPS/IPowerSupply.h
@@ -134,6 +134,18 @@ public:
    * @{
    */
 
+  /** \brief Ramp current of PS
+   *
+   * Slowly changes the current level every second in discrete 
+   * `rate` steps until `cur` is reached. The number of steps
+   * is determined by initial current measurement.
+   *
+   * @param cur current [A]
+   * @param rate absolute rate of current change [A/s]
+   * @param channel channel (if any)
+   */
+  virtual void rampCurrentLevel(double cur, double rate, unsigned channel = 0 );
+
   /** \brief Set current of PS
    * @param cur current [A]
    * @param channel channel (if any)
@@ -168,6 +180,18 @@ public:
   /** \name Voltage Control and Measurement
    * @{
    */
+
+  /** \brief Ramp voltage of PS
+   *
+   * Slowly changes the voltage level every second in discrete
+   * `rate` steps until `volt` is reached. The number of steps
+   * is determined by initial voltage measurement.
+   *
+   * @param volt taget voltage [V]
+   * @param rate absolute rate of voltage change [V/s]
+   * @param channel channel (if any)
+   */
+  virtual void rampVoltageLevel(double cur, double rate, unsigned channel = 0);
   
   /** \brief Set voltage of PS
    * @param volt voltage [V]
diff --git a/src/libPS/PowerSupplyChannel.cpp b/src/libPS/PowerSupplyChannel.cpp
index 151f5411bb48e4142b46bb31e9c94229da5671cc..ebed59ae41bc7a5b8882a21f701c4e57c5ff39be 100644
--- a/src/libPS/PowerSupplyChannel.cpp
+++ b/src/libPS/PowerSupplyChannel.cpp
@@ -56,6 +56,9 @@ void PowerSupplyChannel::turnOff()
 bool PowerSupplyChannel::isOn()
 { return m_ps->isOn(m_channel); }
 
+void PowerSupplyChannel::rampCurrentLevel(double cur, double rate)
+{ m_ps->rampCurrentLevel(cur, rate, m_channel); }  
+
 void PowerSupplyChannel::setCurrentLevel(double cur)
 { m_ps->setCurrentLevel(cur, m_channel); }  
 
@@ -70,6 +73,9 @@ double PowerSupplyChannel::getCurrentProtect()
 
 double PowerSupplyChannel::measureCurrent()
 { return m_ps->measureCurrent(m_channel); }
+
+void PowerSupplyChannel::rampVoltageLevel(double volt, double rate)
+{ m_ps->rampVoltageLevel(volt, rate, m_channel); }  
  
 void PowerSupplyChannel::setVoltageLevel(double volt)
 { m_ps->setVoltageLevel(volt, m_channel); }
diff --git a/src/libPS/PowerSupplyChannel.h b/src/libPS/PowerSupplyChannel.h
index 76299b10128525adafbb29a52fc8ddbb7017f15a..6cfb12a06838d9333e02ab28e0aa15cf008bf469 100644
--- a/src/libPS/PowerSupplyChannel.h
+++ b/src/libPS/PowerSupplyChannel.h
@@ -80,6 +80,17 @@ public:
    * @{
    */
 
+  /** \brief Ramp current of PS
+   *
+   * Slowly changes the current level via every second at `rate`
+   * until `cur` is reached. The number of steps is determined
+   * by initial current measurement.
+   *
+   * @param cur current [A]
+   * @param rate absolute rate of current change [A/s]
+   */
+  void rampCurrentLevel(double cur, double rate);
+
   /** Set current of PS
    * @param cur current [A]
    */
@@ -111,6 +122,17 @@ public:
    * @{
    */
 
+  /** \brief Ramp voltage of PS
+   *
+   * Slowly changes the voltage level via every second at `rate`
+   * until `volt` is reached. The number of steps is determined
+   * by initial voltage measurement.
+   *
+   * @param volt voltage [V]
+   * @param rate absolute rate of voltage change [V/s]
+   */
+  void rampVoltageLevel(double volt, double rate);
+
   /** Set voltage of PS       
    * @param volt voltage [V]
    */
@@ -121,8 +143,8 @@ public:
    */
   double getVoltageLevel();
   
-  /** Set current protection [optional]
-   * @param volt maximum current [A]
+  /** Set voltage protection [optional]
+   * @param volt maximum voltage [V]
    */
   void setVoltageProtect(double volt);  
 
diff --git a/src/libPS/python.cpp b/src/libPS/python.cpp
index fcea21a7f9391764b18cb02e0726b7304dac8dea..fa19de667568faceec87f829eba3b9d2dbb17dc5 100755
--- a/src/libPS/python.cpp
+++ b/src/libPS/python.cpp
@@ -115,6 +115,16 @@ public:
         channel
       );
     }
+    void rampCurrentLevel(double cur, double rate, unsigned channel = 0) override {
+      PYBIND11_OVERLOAD_PURE(
+        void,
+        IPowerSupply,
+        rampCurrentLevel,
+        cur,
+	rate,
+        channel
+      );
+    }
     void setCurrentLevel(double cur, unsigned channel = 0) override {
       PYBIND11_OVERLOAD_PURE(
         void,
@@ -157,6 +167,16 @@ public:
         channel
       );
     }
+    void rampVoltageLevel(double volt, double rate, unsigned channel = 0) override {
+      PYBIND11_OVERLOAD_PURE(
+        void,
+        IPowerSupply,
+        rampVoltageLevel,
+        volt,
+	rate,
+        channel
+      );
+    }
     void setVoltageLevel(double volt, unsigned channel = 0) override {
       PYBIND11_OVERLOAD_PURE(
         void,
@@ -245,6 +265,16 @@ public:
         channel
       );
     }
+    void rampCurrentLevel(double cur, double rate, unsigned channel = 0) override {
+      PYBIND11_OVERLOAD_PURE(
+        void,
+        IPowerSupply,
+        rampCurrentLevel,
+        cur,
+	rate,
+        channel
+      );
+    }
     void setCurrentLevel(double cur, unsigned channel = 0) override {
       PYBIND11_OVERLOAD(
         void,
@@ -287,6 +317,16 @@ public:
         channel
       );
     }
+    void rampVoltageLevel(double volt, double rate, unsigned channel = 0) override {
+      PYBIND11_OVERLOAD_PURE(
+        void,
+        IPowerSupply,
+        rampVoltageLevel,
+        volt,
+	rate,
+        channel
+      );
+    }
     void setVoltageLevel(double volt, unsigned channel = 0) override {
       PYBIND11_OVERLOAD(
         void,
@@ -352,6 +392,8 @@ void register_ps(py::module& m){
     .def("turnOffAll", &IPowerSupply::turnOffAll)
     .def("isOn", &IPowerSupply::isOn,
          py::arg("channel") = 0)
+    .def("rampCurrentLevel", &IPowerSupply::rampCurrentLevel,
+         py::arg("current"), py::arg("rate"), py::arg("channel") = 0)
     .def("setCurrentLevel", &IPowerSupply::setCurrentLevel,
          py::arg("current"), py::arg("channel") = 0)
     .def("getCurrentLevel", &IPowerSupply::getCurrentLevel,
@@ -362,6 +404,8 @@ void register_ps(py::module& m){
          py::arg("channel") = 0)
     .def("measureCurrent", &IPowerSupply::measureCurrent,
          py::arg("channel") = 0)
+    .def("rampVoltageLevel", &IPowerSupply::rampVoltageLevel,
+         py::arg("voltage"), py::arg("rate"), py::arg("channel") = 0)
     .def("setVoltageLevel", &IPowerSupply::setVoltageLevel,
          py::arg("voltage"), py::arg("channel") = 0)
     .def("getVoltageLevel", &IPowerSupply::getVoltageLevel,
@@ -478,10 +522,12 @@ void register_ps(py::module& m){
     .def("turnOn", &PowerSupplyChannel::turnOn)
     .def("turnOff", &PowerSupplyChannel::turnOff)
     .def("isOn", &PowerSupplyChannel::isOn)
+    .def("rampCurrentLevel", &PowerSupplyChannel::rampCurrentLevel)
     .def("setCurrentLevel", &PowerSupplyChannel::setCurrentLevel)
     .def("getCurrentLevel", &PowerSupplyChannel::getCurrentLevel)
     .def("setCurrentProtect", &PowerSupplyChannel::setCurrentProtect)
     .def("measureCurrent", &PowerSupplyChannel::measureCurrent)
+    .def("rampVoltageLevel", &PowerSupplyChannel::rampVoltageLevel)
     .def("setVoltageLevel", &PowerSupplyChannel::setVoltageLevel)
     .def("getVoltageLevel", &PowerSupplyChannel::getVoltageLevel)
     .def("setVoltageProtect", &PowerSupplyChannel::setVoltageProtect)
diff --git a/src/tools/powersupply.cpp b/src/tools/powersupply.cpp
index f95d0fc17636fb590fd3f51197d030cf8adc00e3..0d3cc7cefaf4464c0de60c56a347a0a800d7555a 100644
--- a/src/tools/powersupply.cpp
+++ b/src/tools/powersupply.cpp
@@ -4,6 +4,7 @@
 #include <unistd.h>
 #include <sys/types.h>
 
+#include <chrono>
 #include <iostream>
 #include <string>
 #include <vector>
@@ -30,15 +31,17 @@ void usage(char *argv[])
 {
   std::cerr << "Usage: " << argv[0] << " [options] command [parameters]" << std::endl;
   std::cerr << "List of possible COMMAND:" << std::endl;
-  std::cerr << "  set-current -- I [V] Set current I [A] with maximum voltage V [V]" << std::endl;
-  std::cerr << "  get-current          Get set current level [A]" << std::endl;
-  std::cerr << "  meas-current         Get reading of current [A]" << std::endl;
-  std::cerr << "  set-voltage -- V [I] Set voltage V [V] with maximum current I [A]" << std::endl;
-  std::cerr << "  get-voltage          Get set voltage level [V]" << std::endl;
-  std::cerr << "  meas-voltage         Get reading of voltage [V]" << std::endl;
-  std::cerr << "  program [on]         Execute the program block and optionally turn on the power supply" << std::endl;
-  std::cerr << "  power-on [V I]       Power ON PS, optionally setting voltage to V in Volts and current to I in Ampere" << std::endl;
-  std::cerr << "  power-off            Power OFF PS" << std::endl;
+  std::cerr << "  set-current -- I [V]   Set current I [A] with maximum voltage V [V]" << std::endl;
+  std::cerr << "  ramp-current -- I rate Ramp voltage I [A] at rate [A/s]" << std::endl;
+  std::cerr << "  get-current            Get set current level [A]" << std::endl;
+  std::cerr << "  meas-current           Get reading of current [A]" << std::endl;
+  std::cerr << "  set-voltage -- V [I]   Set voltage V [V] with maximum current I [A]" << std::endl;
+  std::cerr << "  ramp-voltage -- V rate Ramp voltage V [V] at rate [V/s]" << std::endl;
+  std::cerr << "  get-voltage            Get set voltage level [V]" << std::endl;
+  std::cerr << "  meas-voltage           Get reading of voltage [V]" << std::endl;
+  std::cerr << "  program [on]           Execute the program block and optionally turn on the power supply" << std::endl;
+  std::cerr << "  power-on [V I]         Power ON PS, optionally setting voltage to V in Volts and current to I in Ampere" << std::endl;
+  std::cerr << "  power-off              Power OFF PS" << std::endl;
   std::cerr << std::endl;
   std::cerr << "List of options:" << std::endl;
   std::cerr << " -n, --name PS     Name of the power supply from equipment list (default: " << name << ")" << std::endl;  
@@ -186,6 +189,18 @@ int main(int argc, char*argv[])
 	  PS->setVoltageProtect(std::stod(params[1]));
 	}
     }  
+  else if (command == "ramp-current")
+    {
+      if (params.size() != 2)
+	{
+	  logger(logERROR) << "Invalid number of parameters to ramp-current command.";
+	  logger(logERROR) << "";
+	  usage(argv);
+	  return 1;
+	}
+      logger(logDEBUG) << "Ramp current to "<< params[0] << " A at rate " << params[1] << " A/s";
+      PS->rampCurrentLevel(std::stod(params[0]), std::stod(params[1]));
+    }
   else if (command == "get-current")
     {
       if (logIt::loglevel >= logDEBUG) std::cout << "Current: ";
@@ -217,6 +232,18 @@ int main(int argc, char*argv[])
 	  PS->setCurrentProtect(std::stod(params[1]));
 	}
     }
+  else if (command == "ramp-voltage")
+    {
+      if (params.size() != 2)
+	{
+	  logger(logERROR) << "Invalid number of parameters to ramp-voltage command.";
+	  logger(logERROR) << "";
+	  usage(argv);
+	  return 1;
+	}
+      logger(logDEBUG) << "Ramp voltage to "<< params[0] << " V at rate " << params[1] << " V/s";
+      PS->rampVoltageLevel(std::stod(params[0]), std::stod(params[1]));
+    }
   else if (command == "get-voltage")
     {
       if (logIt::loglevel >= logDEBUG) std::cout << "Voltage: ";