New version, OOP & Event driven. #2
+9
-13
@@ -6,13 +6,12 @@ add_compile_options(
|
||||
-Wall
|
||||
-Wformat=2
|
||||
-g
|
||||
-Wno-format-nonliteral
|
||||
-Wno-strict-aliasing
|
||||
-O0
|
||||
-Wuninitialized
|
||||
-Wno-unused-function
|
||||
)
|
||||
|
||||
# Check if the required environment variables MIDASSYS and EPICSSYS are available
|
||||
# Check if the required environment variables MIDASSYS is available
|
||||
if (NOT DEFINED ENV{MIDASSYS})
|
||||
message(SEND_ERROR "MIDASSYS environment variable not defined.")
|
||||
endif()
|
||||
@@ -29,6 +28,13 @@ find_package(Midas REQUIRED)
|
||||
add_library(
|
||||
itcPressureOptimizer
|
||||
src/device/itc_pressure_optimizer.cpp
|
||||
src/device/handlers/DemandHandler.cpp
|
||||
src/device/handlers/InputHandler.cpp
|
||||
src/device/handlers/SettingsHandler.cpp
|
||||
src/device/handlers/PressureCalculator.cpp
|
||||
src/device/handlers/FeedbackHandler.cpp
|
||||
src/device/handlers/OutputHandler.cpp
|
||||
src/device/handlers/Average.cpp
|
||||
)
|
||||
|
||||
set_property(
|
||||
@@ -49,11 +55,6 @@ target_include_directories(
|
||||
itcPressureOptimizer
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
PRIVATE
|
||||
${EPICSSYS}/include
|
||||
${EPICSSYS}/include/os/Linux
|
||||
${EPICSSYS}/include/compiler/gcc
|
||||
${EPICSSYS}/include/compiler/clang
|
||||
)
|
||||
|
||||
################################################################################
|
||||
@@ -75,11 +76,6 @@ target_include_directories(
|
||||
itcPressureOptimizerScfe
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
PRIVATE
|
||||
${EPICSSYS}/include
|
||||
${EPICSSYS}/include/os/Linux
|
||||
${EPICSSYS}/include/compiler/gcc
|
||||
${EPICSSYS}/include/compiler/clang
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
|
||||
@@ -1,25 +1,60 @@
|
||||
# ITC Pressure Optimizer
|
||||
|
||||
Optimize the pressure setpoint on Mercury ITC depending on Temperature parameters read from the (same) Mercury ITC.
|
||||
Optimize the pressure setpoint on a Mercury ITC depending on temperature parameters read from the (same) Mercury ITC.
|
||||
Pressures are calculated as a function of temperature setpoint, actual temperature, heater power, and currently set pressure.
|
||||
This driver is a port of mitcpresscio.c, with an event
|
||||
|
||||
Pressure are calculated in function of temperature setpoint, actual temperature, heater power and currently set pressure.
|
||||
# Preview
|
||||

|
||||
|
||||
This driver is only a port of mitcpresscio.c, using the c++ TRIUMF framework instead of legacy C
|
||||
# Download
|
||||
|
||||
# ITC Pressure Optimizer DD Settings for associated Equipment
|
||||
```bash
|
||||
$ git clone ....
|
||||
```
|
||||
|
||||
Path : ```/Equipment/<name>/Settings/Devices/MITCPRESSC/DD/```
|
||||
# Compile
|
||||
```bash
|
||||
$ cmake -B build
|
||||
$ cmake --build build
|
||||
```
|
||||
|
||||
# Run
|
||||
```bash
|
||||
$ $pwd/build/itcPressureOptimizer <frontend_name> <equipment_name>
|
||||
```
|
||||
# Configuration
|
||||
|
||||
In ```/Equipment/<name>/Settings/Devices/MITCPRESSC/DD/```, you can modify settings regarding where to read/write values to the equipment.
|
||||
|
||||
Default values are :
|
||||
|
||||
| Equipment | variox0 | heliox0 |
|
||||
|-----------|---------|---------|
|
||||
| MITC_OutputPressSPIndex | 3 (0x3) | 8 (0x8) |
|
||||
| MITC_InputVarioxSPIndex | 1 (0x1) | 1 (0x1) |
|
||||
| MITC_InputVarioxTempIndex | 0 (0x0) | 0 (0x0) |
|
||||
| MITC_InputVarioxPowIndex | 10 (0xA) | 8 (0x8) |
|
||||
| RecalcInterval | 10 (0xA) | 10 (0xA) |
|
||||
| MitcReadoutInterval | 2 (0x2) | 2 (0x2) |
|
||||
| PressReadoutInterval | 3 (0x3) | 3 (0x3) |
|
||||
| Output Pressure SetPoint Index | 3 (0x3) | 8 (0x8) |
|
||||
| Input SetPoint Index | 1 (0x1) | 1 (0x1) |
|
||||
| Input Temperature Index | 0 (0x0) | 0 (0x0) |
|
||||
| Input Power Index | 10 (0xA) | 8 (0x8) |
|
||||
| Average Power Time Window | 30f | 30f |
|
||||
|
||||
|
||||
*NOTE: OutputPressSPIndex and InputVarioxPowIndex are different for variox0
|
||||
and heliox0*
|
||||
|
||||
|
||||
# Usage
|
||||
|
||||
In ```/Equipment/<name>/Variables/Demand``` you can specify demand to the equipment. See **Preview**
|
||||
|
||||
# Project structure
|
||||
|
||||
This is the execution flow graph.
|
||||
|
||||

|
||||
All dotted lines represent data and execution flow going through the EventBus (Broker) with the publish / subscribe method.
|
||||
|
||||
For cleaner code, all execution and data flow pass through an EventBus. Objects can subscribe to one or many specific event types. They can also publish an event, which will be dispatched to all subscribers by invoking their callbacks.
|
||||
|
||||
`OdbHotlink` triggers the execution flow whenever a value changes. Only `DemandHandler` and `InputHandler` are registered.
|
||||
|
||||
`itc_pressure_optimizer` instantiates all components and publishes an `InitEvent` first, allowing all handlers to initialize and connect to the ODB. It also periodically publishes a `PollEvent` every second to update time-dependent averages.
|
||||
@@ -0,0 +1,35 @@
|
||||
@startuml
|
||||
skinparam linetype ortho
|
||||
scale 1.2
|
||||
class EventBus <<broker>> {
|
||||
+ publish()
|
||||
+ subscribe()
|
||||
}
|
||||
|
||||
class Demand as "DemandHandler"
|
||||
class itc as "itc_pressure_optimizer"
|
||||
class Settings as "SettingsHandler"
|
||||
class Input as "InputHandler"
|
||||
class Pressure as "PressureCalculator" {
|
||||
class Average
|
||||
}
|
||||
class Output as "OutputHandler"
|
||||
class Feedback as "FeedbackHandler"
|
||||
|
||||
Demand -.> Pressure
|
||||
Demand -.> Feedback
|
||||
|
||||
itc -.> Settings
|
||||
itc -.> Pressure
|
||||
itc -.> Demand
|
||||
|
||||
Settings -.> Output
|
||||
Settings -.> Input
|
||||
|
||||
Input -.> Feedback
|
||||
Input -.> Output
|
||||
Input -.> Pressure
|
||||
|
||||
Pressure -.> Feedback
|
||||
|
||||
@enduml
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
@@ -0,0 +1,66 @@
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <typeindex>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "src/device/EventBus.h"
|
||||
class ProdA {};
|
||||
class ProdB {};
|
||||
|
||||
class ConsA {
|
||||
public:
|
||||
void surProdA(const ProdA &) {
|
||||
std::cout << "ConsA : Reçu ProdA" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
class ConsB {
|
||||
public:
|
||||
void surProdA(const ProdA &) {
|
||||
std::cout << "ConsB : Reçu ProdA" << std::endl;
|
||||
}
|
||||
void surProdB(const ProdB &) {
|
||||
std::cout << "ConsB : Reçu ProdB" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
class ConsC {
|
||||
public:
|
||||
void surProdB(const ProdB &) {
|
||||
std::cout << "ConsC : Reçu ProdB" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
EventBus bus;
|
||||
|
||||
// Consumer
|
||||
ConsA consA;
|
||||
ConsB consB;
|
||||
ConsC consC;
|
||||
|
||||
// Setup abonnement
|
||||
|
||||
// ConsA react to ProdA
|
||||
bus.subscribe<ProdA>([&consA](const ProdA &e) { consA.surProdA(e); });
|
||||
|
||||
// ConsB react to ProdA and ProdB
|
||||
bus.subscribe<ProdA>([&consB](const ProdA &e) { consB.surProdA(e); });
|
||||
bus.subscribe<ProdB>([&consB](const ProdB &e) { consB.surProdB(e); });
|
||||
|
||||
// ConsC react to ProdB
|
||||
bus.subscribe<ProdB>([&consC](const ProdB &e) { consC.surProdB(e); });
|
||||
|
||||
// Test of publishement
|
||||
std::cout << "--- Publishing of ProdA ---" << std::endl;
|
||||
ProdA prodA;
|
||||
bus.publish(prodA);
|
||||
|
||||
std::cout << "\n--- Publishing of ProdB ---" << std::endl;
|
||||
ProdB prodB;
|
||||
bus.publish(prodB);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
@@ -0,0 +1,63 @@
|
||||
#ifndef EVENT_BUS_H
|
||||
#define EVENT_BUS_H
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <typeindex>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class EventBus {
|
||||
public:
|
||||
// Subscribe to a specific event type
|
||||
template <typename EventType>
|
||||
void subscribe(std::function<void(const EventType &)> callback) {
|
||||
std::type_index typeIdx = std::type_index(typeid(EventType));
|
||||
|
||||
// If this is the first subscriber for this type, create the list
|
||||
if (subscribers.find(typeIdx) == subscribers.end()) {
|
||||
subscribers[typeIdx] = std::make_unique<CallbackList<EventType>>();
|
||||
}
|
||||
|
||||
// Safely cast to the specialized typed list and add the callback
|
||||
auto *list =
|
||||
static_cast<CallbackList<EventType> *>(subscribers[typeIdx].get());
|
||||
list->callbacks.push_back(callback);
|
||||
}
|
||||
|
||||
// Publish an event to all registered subscribers
|
||||
template <typename EventType> void publish(const EventType &event) {
|
||||
std::type_index typeIdx = std::type_index(typeid(EventType));
|
||||
|
||||
auto it = subscribers.find(typeIdx);
|
||||
if (it != subscribers.end()) {
|
||||
// Cast to the correct typed list to safely execute the callbacks
|
||||
auto *list =
|
||||
static_cast<CallbackList<EventType> *>(it->second.get());
|
||||
for (const auto &callback : list->callbacks) {
|
||||
callback(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Non-templated base interface to store our callback lists
|
||||
// generically inside the unordered_map.
|
||||
struct CallbackListBase {
|
||||
virtual ~CallbackListBase() = default;
|
||||
};
|
||||
|
||||
// Specialized version holding the actual strongly-typed callbacks.
|
||||
template <typename EventType>
|
||||
struct CallbackList : public CallbackListBase {
|
||||
using CallbackType = std::function<void(const EventType &)>;
|
||||
std::vector<CallbackType> callbacks;
|
||||
};
|
||||
|
||||
// Map associating each event type to its respective callback list
|
||||
std::unordered_map<std::type_index, std::unique_ptr<CallbackListBase>>
|
||||
subscribers;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
#include <chrono>
|
||||
#include <deque>
|
||||
|
||||
#include "Average.h"
|
||||
|
||||
void Average::setWindowSize(double seconds) {
|
||||
windowSize = Duration(seconds);
|
||||
cleanupAndUpdate(Clock::now());
|
||||
}
|
||||
|
||||
void Average::addValue(double value) {
|
||||
TimePoint now = Clock::now();
|
||||
currentValue = value;
|
||||
|
||||
// add a new value
|
||||
history.push_back({now, currentValue});
|
||||
|
||||
cleanupAndUpdate(now);
|
||||
}
|
||||
|
||||
double Average::getAverage() {
|
||||
TimePoint now = Clock::now();
|
||||
cleanupAndUpdate(now);
|
||||
|
||||
if (history.empty()) {
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
double totalWeightedValue = 0.0;
|
||||
double totalDurationSeconds = 0.0;
|
||||
|
||||
TimePoint windowStart =
|
||||
now - std::chrono::duration_cast<Clock::duration>(windowSize);
|
||||
|
||||
for (size_t i = 0; i < history.size(); ++i) {
|
||||
TimePoint segmentStart = (i == 0) ? windowStart : history[i].timestamp;
|
||||
TimePoint segmentEnd =
|
||||
(i < history.size() - 1) ? history[i + 1].timestamp : now;
|
||||
|
||||
// remove time before the window
|
||||
if (segmentEnd < windowStart)
|
||||
continue;
|
||||
if (segmentStart < windowStart)
|
||||
segmentStart = windowStart;
|
||||
|
||||
Duration duration = segmentEnd - segmentStart;
|
||||
double seconds = duration.count();
|
||||
|
||||
if (seconds > 0.0) {
|
||||
totalWeightedValue += history[i].value * seconds;
|
||||
totalDurationSeconds += seconds;
|
||||
}
|
||||
}
|
||||
|
||||
if (totalDurationSeconds <= 0.0) {
|
||||
return history.back().value;
|
||||
}
|
||||
|
||||
return totalWeightedValue / totalDurationSeconds;
|
||||
}
|
||||
|
||||
void Average::cleanupAndUpdate(TimePoint now) {
|
||||
TimePoint windowStart =
|
||||
now - std::chrono::duration_cast<Clock::duration>(windowSize);
|
||||
|
||||
// Remove all elements completely outside of the window
|
||||
while (history.size() > 1 && history[1].timestamp <= windowStart) {
|
||||
history.pop_front();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#ifndef AVERAGE_H
|
||||
#define AVERAGE_H
|
||||
|
||||
#include <chrono>
|
||||
#include <deque>
|
||||
|
||||
/*
|
||||
This class allows you to compute the average value inside a given time window.
|
||||
It computes the average using continuous time.
|
||||
*/
|
||||
class Average {
|
||||
private:
|
||||
using Clock = std::chrono::steady_clock;
|
||||
using TimePoint = Clock::time_point;
|
||||
using Duration = std::chrono::duration<double>;
|
||||
|
||||
struct TimeValue {
|
||||
TimePoint timestamp;
|
||||
double value;
|
||||
};
|
||||
|
||||
std::deque<TimeValue> history;
|
||||
Duration windowSize;
|
||||
double currentValue = 0.0;
|
||||
|
||||
void cleanupAndUpdate(TimePoint now);
|
||||
|
||||
public:
|
||||
Average(double windowSizeSeconds)
|
||||
: windowSize(Duration(windowSizeSeconds)) {};
|
||||
|
||||
/*
|
||||
@brief Modify the time window size
|
||||
@param seconds time window duration
|
||||
*/
|
||||
void setWindowSize(double seconds);
|
||||
/*
|
||||
@brief Add another value with the current timestamp to the average.
|
||||
*/
|
||||
void addValue(double value);
|
||||
/*
|
||||
@brief Get the current average of all the values from [now - timewindow,
|
||||
now].
|
||||
@return The average value
|
||||
*/
|
||||
double getAverage();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,187 @@
|
||||
#include "DemandHandler.h"
|
||||
#include "../itc_pressure_optimizer.h"
|
||||
#include "DemandHandlerConfig.h"
|
||||
#include "odbxx.h"
|
||||
#include "tmfe.h"
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
using namespace DemandHandlerConfig;
|
||||
|
||||
bool DemandHandler::init() {
|
||||
bool initSuccess = true;
|
||||
|
||||
if (!midas::odb::exists(this->path + "/" + DemandHandlerConfig::DEMAND)) {
|
||||
TMFE::Instance()->Msg(MERROR, __FUNCTION__,
|
||||
"Key at %s/%s doesn't exists", path.c_str(),
|
||||
DemandHandlerConfig::DEMAND.c_str());
|
||||
|
||||
midas::odb o(this->path);
|
||||
std::vector<float> v;
|
||||
v.resize(static_cast<int>(ParameterIndex::MAXIMUM_PARAMETER_INDEX));
|
||||
o[DemandHandlerConfig::DEMAND] = v;
|
||||
|
||||
TMFE::Instance()->Msg(MERROR, __FUNCTION__,
|
||||
"Template generated at %s. Please fill it.",
|
||||
path.c_str());
|
||||
|
||||
initSuccess = false;
|
||||
}
|
||||
midas::odb o(this->path);
|
||||
|
||||
// This is checked every start, in case of someone change the index in the
|
||||
// config header
|
||||
if (o[DemandHandlerConfig::DEMAND].size() <
|
||||
static_cast<int>(ParameterIndex::MINIMAL_PRESSURE)) {
|
||||
TMFE::Instance()->Msg(
|
||||
MERROR, __FUNCTION__,
|
||||
"Minimal pressure index is %i, where array size is %i.",
|
||||
static_cast<int>(ParameterIndex::MINIMAL_PRESSURE), o.size());
|
||||
initSuccess = false;
|
||||
}
|
||||
if (o[DemandHandlerConfig::DEMAND].size() <
|
||||
static_cast<int>(ParameterIndex::MAXIMAL_PRESSURE)) {
|
||||
TMFE::Instance()->Msg(
|
||||
MERROR, __FUNCTION__,
|
||||
"maximal pressure index is %i, where array size is %i.",
|
||||
static_cast<int>(ParameterIndex::MAXIMAL_PRESSURE), o.size());
|
||||
initSuccess = false;
|
||||
}
|
||||
if (o[DemandHandlerConfig::DEMAND].size() <
|
||||
static_cast<int>(ParameterIndex::CONSTANTE_1)) {
|
||||
TMFE::Instance()->Msg(
|
||||
MERROR, __FUNCTION__,
|
||||
"Constante 1 index is %i, where array size is %i.",
|
||||
static_cast<int>(ParameterIndex::CONSTANTE_1), o.size());
|
||||
initSuccess = false;
|
||||
}
|
||||
if (o[DemandHandlerConfig::DEMAND].size() <
|
||||
static_cast<int>(ParameterIndex::CONSTANTE_2)) {
|
||||
TMFE::Instance()->Msg(
|
||||
MERROR, __FUNCTION__,
|
||||
"Constante 2 index is %i, where array size is %i.",
|
||||
static_cast<int>(ParameterIndex::CONSTANTE_2), o.size());
|
||||
initSuccess = false;
|
||||
}
|
||||
if (o[DemandHandlerConfig::DEMAND].size() <
|
||||
static_cast<int>(ParameterIndex::PRESSURE_CONTROL_MODE)) {
|
||||
TMFE::Instance()->Msg(
|
||||
MERROR, __FUNCTION__,
|
||||
"Pressure control mode index is %i, where array size is %i.",
|
||||
static_cast<int>(ParameterIndex::PRESSURE_CONTROL_MODE), o.size());
|
||||
initSuccess = false;
|
||||
}
|
||||
if (o[DemandHandlerConfig::DEMAND].size() <
|
||||
static_cast<int>(ParameterIndex::SET_PRESSURE)) {
|
||||
TMFE::Instance()->Msg(
|
||||
MERROR, __FUNCTION__,
|
||||
"Set pressure index is %i, where array size is %i.",
|
||||
static_cast<int>(ParameterIndex::SET_PRESSURE), o.size());
|
||||
initSuccess = false;
|
||||
}
|
||||
|
||||
if (!initSuccess)
|
||||
throw std::runtime_error("DemandHandler init failed - see MIDAS "
|
||||
"console and take care of all the errors\n");
|
||||
|
||||
this->pullMinimalPressure();
|
||||
this->pullMaximalPressure();
|
||||
this->pullConstante1();
|
||||
this->pullConstante2();
|
||||
this->pullPressureControlMode();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DemandHandler::setHotlink() {
|
||||
midas::odb to_watch(this->path + "/" + DemandHandlerConfig::DEMAND);
|
||||
to_watch.watch([&](midas::odb &arg) {
|
||||
switch (arg.get_last_index()) {
|
||||
case static_cast<int>(ParameterIndex::MINIMAL_PRESSURE):
|
||||
pullMinimalPressure();
|
||||
break;
|
||||
case static_cast<int>(ParameterIndex::MAXIMAL_PRESSURE):
|
||||
pullMaximalPressure();
|
||||
break;
|
||||
case static_cast<int>(ParameterIndex::CONSTANTE_1):
|
||||
pullConstante1();
|
||||
break;
|
||||
case static_cast<int>(ParameterIndex::CONSTANTE_2):
|
||||
pullConstante2();
|
||||
break;
|
||||
case static_cast<int>(ParameterIndex::PRESSURE_CONTROL_MODE):
|
||||
pullPressureControlMode();
|
||||
break;
|
||||
case static_cast<int>(ParameterIndex::SET_PRESSURE):
|
||||
pullSetPressure();
|
||||
break;
|
||||
default:
|
||||
// Update out of scope, discarded
|
||||
break;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
void DemandHandler::pullMinimalPressure() {
|
||||
midas::odb o(this->path);
|
||||
float minimalPressure =
|
||||
o[DemandHandlerConfig::DEMAND]
|
||||
[static_cast<int>(ParameterIndex::MINIMAL_PRESSURE)];
|
||||
Event event = {EventType::MINIMAL_PRESSURE, minimalPressure};
|
||||
eventBus.publish(event);
|
||||
}
|
||||
|
||||
void DemandHandler::pullMaximalPressure() {
|
||||
midas::odb o(this->path);
|
||||
float maximalPressure =
|
||||
o[DemandHandlerConfig::DEMAND]
|
||||
[static_cast<int>(ParameterIndex::MAXIMAL_PRESSURE)];
|
||||
Event event = {EventType::MAXIMAL_PRESSURE, maximalPressure};
|
||||
eventBus.publish(event);
|
||||
}
|
||||
|
||||
void DemandHandler::pullConstante1() {
|
||||
midas::odb o(this->path);
|
||||
float constante1 = o[DemandHandlerConfig::DEMAND]
|
||||
[static_cast<int>(ParameterIndex::CONSTANTE_1)];
|
||||
Event event = {EventType::CONSTANTE_1, constante1};
|
||||
eventBus.publish(event);
|
||||
}
|
||||
|
||||
void DemandHandler::pullConstante2() {
|
||||
midas::odb o(this->path);
|
||||
float constance2 = o[DemandHandlerConfig::DEMAND]
|
||||
[static_cast<int>(ParameterIndex::CONSTANTE_2)];
|
||||
Event event = {EventType::CONSTANTE_2, constance2};
|
||||
eventBus.publish(event);
|
||||
}
|
||||
|
||||
void DemandHandler::pullPressureControlMode() {
|
||||
midas::odb o(this->path);
|
||||
float pressureControlMode =
|
||||
o[DemandHandlerConfig::DEMAND]
|
||||
[static_cast<int>(ParameterIndex::PRESSURE_CONTROL_MODE)];
|
||||
Event event = {EventType::PRESSURE_CONTROL_MODE, pressureControlMode != 0};
|
||||
eventBus.publish(event);
|
||||
}
|
||||
|
||||
void DemandHandler::pullSetPressure() {
|
||||
midas::odb o(this->path);
|
||||
float setPressure = o[DemandHandlerConfig::DEMAND]
|
||||
[static_cast<int>(ParameterIndex::SET_PRESSURE)];
|
||||
Event event = {EventType::SET_PRESSURE, setPressure != 0};
|
||||
eventBus.publish(event);
|
||||
}
|
||||
|
||||
DemandHandler::DemandHandler(EventBus &eventBusReference,
|
||||
std::string equipmentName)
|
||||
: path(DemandHandlerConfig::PATH_PREFIX + equipmentName +
|
||||
DemandHandlerConfig::PATH_SUFFIX),
|
||||
eventBus(eventBusReference) {
|
||||
|
||||
eventBus.subscribe<itcPressureOptimizer::EquipmentInitEvent>(
|
||||
[this](const itcPressureOptimizer::EquipmentInitEvent &e) {
|
||||
this->init();
|
||||
this->setHotlink();
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef DEMAND_HANDLER_H
|
||||
#define DEMAND_HANDLER_H
|
||||
|
||||
#include "../EventBus.h"
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
class DemandHandler {
|
||||
public:
|
||||
enum class EventType {
|
||||
MINIMAL_PRESSURE,
|
||||
MAXIMAL_PRESSURE,
|
||||
CONSTANTE_1,
|
||||
CONSTANTE_2,
|
||||
PRESSURE_CONTROL_MODE,
|
||||
SET_PRESSURE
|
||||
};
|
||||
|
||||
struct Event {
|
||||
EventType type;
|
||||
std::variant<float, bool> value;
|
||||
};
|
||||
|
||||
DemandHandler(EventBus &eventBusReference, std::string equipmentName);
|
||||
|
||||
private:
|
||||
std::string path;
|
||||
EventBus &eventBus;
|
||||
|
||||
/*
|
||||
Pull value from the ODB
|
||||
*/
|
||||
void pullMinimalPressure();
|
||||
void pullMaximalPressure();
|
||||
void pullConstante1();
|
||||
void pullConstante2();
|
||||
void pullPressureControlMode();
|
||||
void pullSetPressure();
|
||||
|
||||
/*
|
||||
Init process
|
||||
*/
|
||||
bool init();
|
||||
|
||||
/*
|
||||
Setting ODB hotlink
|
||||
*/
|
||||
bool setHotlink();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef DEMAND_HANDLER_CONFIG_H
|
||||
#define DEMAND_HANDLER_CONFIG_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace DemandHandlerConfig {
|
||||
const std::string PATH_PREFIX = "/Equipment/";
|
||||
const std::string PATH_SUFFIX = "/Variables";
|
||||
const std::string DEMAND = "Demand";
|
||||
|
||||
enum class ParameterIndex {
|
||||
|
||||
PRESSURE_CONTROL_MODE = 6,
|
||||
SET_PRESSURE = 7,
|
||||
MINIMAL_PRESSURE = 8,
|
||||
MAXIMAL_PRESSURE = 9,
|
||||
CONSTANTE_1 = 10,
|
||||
CONSTANTE_2 = 11,
|
||||
MAXIMUM_PARAMETER_INDEX = 11
|
||||
};
|
||||
|
||||
}; // namespace DemandHandlerConfig
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,162 @@
|
||||
#include "FeedbackHandler.h"
|
||||
#include "../EventBus.h"
|
||||
#include "DemandHandler.h"
|
||||
#include "FeedbackHandlerConfig.h"
|
||||
#include "InputHandler.h"
|
||||
#include "PressureCalculator.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
FeedbackHandler::FeedbackHandler(EventBus &eventBusReference,
|
||||
std::string equipmentName) {
|
||||
this->path = FeedbackHandlerConf::PATH_PREFIX + equipmentName +
|
||||
FeedbackHandlerConf::PATH_SUFFIX;
|
||||
|
||||
eventBusReference.subscribe<DemandHandler::Event>(
|
||||
[this](const DemandHandler::Event &e) {
|
||||
generateOdbKeyIfNeeded();
|
||||
switch (e.type) {
|
||||
case DemandHandler::EventType::PRESSURE_CONTROL_MODE:
|
||||
enablePressureControlMode(std::get<bool>(e.value));
|
||||
break;
|
||||
case DemandHandler::EventType::SET_PRESSURE:
|
||||
enableSetPressure(std::get<bool>(e.value));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
eventBusReference.subscribe<InputHandler::Event>(
|
||||
[this](const InputHandler::Event &e) {
|
||||
generateOdbKeyIfNeeded();
|
||||
switch (e.type) {
|
||||
case InputHandler::EventType::SP_VALUE:
|
||||
setSP(e.value);
|
||||
break;
|
||||
case InputHandler::EventType::TEMPERATURE_VALUE:
|
||||
setTemperature(e.value);
|
||||
break;
|
||||
case InputHandler::EventType::POWER_VALUE:
|
||||
setPower(e.value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
eventBusReference.subscribe<PressureCalculator::Event>(
|
||||
[this](const PressureCalculator::Event &e) {
|
||||
generateOdbKeyIfNeeded();
|
||||
setConstante1(e.c1contrib);
|
||||
setConstante2(e.c2contrib);
|
||||
setPressureMinimum(e.uncapedPressure);
|
||||
setPressureMaximum(e.uncapedPressure);
|
||||
setPressure(e.cappedPressure);
|
||||
setAveragePower(e.averagePower);
|
||||
});
|
||||
}
|
||||
|
||||
void FeedbackHandler::updatePressure() {
|
||||
{
|
||||
midas::odb o(path);
|
||||
o[FeedbackHandlerConf::OUTPUT_VARNAME]
|
||||
[static_cast<int>(FeedbackHandlerConf::RegisterIndex::PRESSURE)] =
|
||||
cachedCappedPressure;
|
||||
}
|
||||
float cappedPressure =
|
||||
std::roundf(cachedCappedPressure * 10.0f + 0.5f) / 10.0f;
|
||||
// Pressure control mode is set to calculated?
|
||||
if (isPressureControlModeEnable) {
|
||||
midas::odb o(path);
|
||||
o[FeedbackHandlerConf::INPUT_VARNAME][static_cast<int>(
|
||||
FeedbackHandlerConf::RegisterIndex::PRESSURE_SET_POINT)] =
|
||||
cappedPressure;
|
||||
}
|
||||
// update setpoint of Mercury ITC in ODB ?
|
||||
if (isSetPressureEnable) {
|
||||
midas::odb o(path);
|
||||
o[FeedbackHandlerConf::OUTPUT_VARNAME][static_cast<int>(
|
||||
FeedbackHandlerConf::RegisterIndex::PRESSURE_SET_POINT)] =
|
||||
cappedPressure;
|
||||
}
|
||||
}
|
||||
|
||||
void FeedbackHandler::generateOdbKeyIfNeeded() {
|
||||
// If the key doesn't exist, we create the template.
|
||||
|
||||
if (!midas::odb::exists(path + "/" + FeedbackHandlerConf::OUTPUT_VARNAME)) {
|
||||
std::vector<float> v;
|
||||
v.resize(static_cast<int>(
|
||||
FeedbackHandlerConf::RegisterIndex::MAXIMUM_REGISTRY_INDEX));
|
||||
midas::odb o(path);
|
||||
o[FeedbackHandlerConf::OUTPUT_VARNAME] = v;
|
||||
}
|
||||
}
|
||||
|
||||
void FeedbackHandler::enablePressureControlMode(bool enable) {
|
||||
isPressureControlModeEnable = enable;
|
||||
updatePressure();
|
||||
}
|
||||
|
||||
void FeedbackHandler::enableSetPressure(bool enable) {
|
||||
isSetPressureEnable = enable;
|
||||
updatePressure();
|
||||
}
|
||||
|
||||
void FeedbackHandler::setPressure(float value) {
|
||||
cachedCappedPressure = value;
|
||||
updatePressure();
|
||||
}
|
||||
|
||||
void FeedbackHandler::setConstante1(float value) {
|
||||
midas::odb o(path);
|
||||
o[FeedbackHandlerConf::OUTPUT_VARNAME]
|
||||
[static_cast<int>(FeedbackHandlerConf::RegisterIndex::CONSTANTE_1)] =
|
||||
value;
|
||||
}
|
||||
void FeedbackHandler::setAveragePower(float value) {
|
||||
midas::odb o(path);
|
||||
o[FeedbackHandlerConf::OUTPUT_VARNAME]
|
||||
[static_cast<int>(FeedbackHandlerConf::RegisterIndex::AVERAGE_POWER)] =
|
||||
value;
|
||||
}
|
||||
|
||||
void FeedbackHandler::setConstante2(float value) {
|
||||
midas::odb o(path);
|
||||
o[FeedbackHandlerConf::OUTPUT_VARNAME]
|
||||
[static_cast<int>(FeedbackHandlerConf::RegisterIndex::CONSTANTE_2)] =
|
||||
value;
|
||||
}
|
||||
|
||||
void FeedbackHandler::setPressureMinimum(float value) {
|
||||
midas::odb o(path);
|
||||
o[FeedbackHandlerConf::OUTPUT_VARNAME]
|
||||
[static_cast<int>(FeedbackHandlerConf::RegisterIndex::MINIMUM_PRESSURE)] =
|
||||
value;
|
||||
}
|
||||
void FeedbackHandler::setPressureMaximum(float value) {
|
||||
midas::odb o(path);
|
||||
o[FeedbackHandlerConf::OUTPUT_VARNAME]
|
||||
[static_cast<int>(FeedbackHandlerConf::RegisterIndex::MAXIMUM_PRESSURE)] =
|
||||
value;
|
||||
}
|
||||
|
||||
void FeedbackHandler::setSP(float value) {
|
||||
midas::odb o(path);
|
||||
o[FeedbackHandlerConf::OUTPUT_VARNAME]
|
||||
[static_cast<int>(FeedbackHandlerConf::RegisterIndex::SP)] = value;
|
||||
}
|
||||
|
||||
void FeedbackHandler::setTemperature(float value) {
|
||||
midas::odb o(path);
|
||||
o[FeedbackHandlerConf::OUTPUT_VARNAME]
|
||||
[static_cast<int>(FeedbackHandlerConf::RegisterIndex::TEMPERATURE)] =
|
||||
value;
|
||||
}
|
||||
|
||||
void FeedbackHandler::setPower(float value) {
|
||||
midas::odb o(path);
|
||||
o[FeedbackHandlerConf::OUTPUT_VARNAME]
|
||||
[static_cast<int>(FeedbackHandlerConf::RegisterIndex::POWER)] = value;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef FEEDBACK_HANDLER_H
|
||||
#define FEEDBACK_HANDLER_H
|
||||
|
||||
#include "../EventBus.h"
|
||||
#include <string>
|
||||
|
||||
class FeedbackHandler {
|
||||
public:
|
||||
FeedbackHandler(EventBus &eventBusReference, std::string equipmentName);
|
||||
|
||||
private:
|
||||
bool isPressureControlModeEnable;
|
||||
bool isSetPressureEnable;
|
||||
float cachedCappedPressure;
|
||||
|
||||
std::string path;
|
||||
|
||||
void generateOdbKeyIfNeeded();
|
||||
|
||||
/*
|
||||
Internal value setters
|
||||
*/
|
||||
void enablePressureControlMode(bool enable);
|
||||
void enableSetPressure(bool enable);
|
||||
|
||||
void setSP(float value);
|
||||
void setTemperature(float value);
|
||||
void setPressureMinimum(float value);
|
||||
void setPressureMaximum(float value);
|
||||
void setPower(float value);
|
||||
void setAveragePower(float value);
|
||||
void setPressure(float value);
|
||||
void setConstante1(float value);
|
||||
void setConstante2(float value);
|
||||
|
||||
/*
|
||||
Update pressure value
|
||||
*/
|
||||
void updatePressure();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef FEEDBACK_HANDLER_CONFIG_H
|
||||
#define FEEDBACK_HANDLER_CONFIG_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace FeedbackHandlerConf {
|
||||
|
||||
const std::string PATH_PREFIX = "/Equipment/";
|
||||
const std::string PATH_SUFFIX = "/Variables";
|
||||
const std::string OUTPUT_VARNAME = "Measured";
|
||||
const std::string INPUT_VARNAME = "Demand";
|
||||
|
||||
enum class RegisterIndex {
|
||||
PRESSURE_SET_POINT = 0,
|
||||
SP = 1,
|
||||
TEMPERATURE = 2,
|
||||
POWER = 3,
|
||||
AVERAGE_POWER = 4,
|
||||
PRESSURE = 5,
|
||||
MINIMUM_PRESSURE = 8,
|
||||
MAXIMUM_PRESSURE = 9,
|
||||
CONSTANTE_1 = 10,
|
||||
CONSTANTE_2 = 11,
|
||||
MAXIMUM_REGISTRY_INDEX =
|
||||
11 // Used as a safety guard for undersize array. Put this enum member
|
||||
// always as the same value as the highest member
|
||||
};
|
||||
} // namespace FeedbackHandlerConf
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
#include "InputHandler.h"
|
||||
#include "../EventBus.h"
|
||||
#include "InputHandlerConfig.h"
|
||||
#include "SettingsHandler.h"
|
||||
|
||||
#include "tmfe.h"
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
void InputHandler::setPath(std::string name) {
|
||||
this->path = InputHandlerConfig::PATH_PREFIX + name +
|
||||
InputHandlerConfig::PATH_SUFFIX;
|
||||
|
||||
if (!midas::odb::exists(path)) {
|
||||
TMFE::Instance()->Msg(MERROR, __FUNCTION__, "Key at %s doesn't exists",
|
||||
path.c_str());
|
||||
|
||||
throw std::runtime_error("Key at " + path + " doesn't exists");
|
||||
}
|
||||
|
||||
midas::odb o(path);
|
||||
bool isKeyValid = true;
|
||||
|
||||
if (o.size() < SPIndex) {
|
||||
TMFE::Instance()->Msg(MERROR, __FUNCTION__,
|
||||
"SP index is %i, where array size is %i.",
|
||||
SPIndex, o.size());
|
||||
isKeyValid = false;
|
||||
}
|
||||
if (o.size() < temperatureIndex) {
|
||||
TMFE::Instance()->Msg(
|
||||
MERROR, __FUNCTION__,
|
||||
"Temperature index is %i, where array size is %i.",
|
||||
temperatureIndex, o.size());
|
||||
isKeyValid = false;
|
||||
}
|
||||
if (o.size() < powerIndex) {
|
||||
TMFE::Instance()->Msg(MERROR, __FUNCTION__,
|
||||
"Power index is %i, where array size is %i.",
|
||||
powerIndex, o.size());
|
||||
isKeyValid = false;
|
||||
}
|
||||
|
||||
if (!isKeyValid) {
|
||||
throw std::runtime_error("InputHandler update path failed - see MIDAS "
|
||||
"console and take care of all the errors\n");
|
||||
}
|
||||
}
|
||||
|
||||
void InputHandler::updateSPIndex(int index) {
|
||||
this->SPIndex = index;
|
||||
pullSPValue();
|
||||
}
|
||||
|
||||
void InputHandler::updateTemperatureIndex(int index) {
|
||||
this->temperatureIndex = index;
|
||||
pullTemperatureValue();
|
||||
}
|
||||
|
||||
void InputHandler::updatePowerIndex(int index) {
|
||||
this->powerIndex = index;
|
||||
pullPowerValue();
|
||||
}
|
||||
|
||||
void InputHandler::pullSPValue() {
|
||||
midas::odb o(this->path);
|
||||
float SPValue = o[SPIndex];
|
||||
Event event = {EventType::SP_VALUE, SPValue};
|
||||
eventBus.publish(event);
|
||||
}
|
||||
|
||||
void InputHandler::pullTemperatureValue() {
|
||||
midas::odb o(this->path);
|
||||
float temperatureValue = o[temperatureIndex];
|
||||
Event event = {EventType::TEMPERATURE_VALUE, temperatureValue};
|
||||
eventBus.publish(event);
|
||||
}
|
||||
|
||||
void InputHandler::pullPowerValue() {
|
||||
midas::odb o(this->path);
|
||||
float powerValue = o[powerIndex];
|
||||
printf("Sending power value %f\n", powerValue);
|
||||
Event event = {EventType::POWER_VALUE, powerValue};
|
||||
eventBus.publish(event);
|
||||
}
|
||||
|
||||
void InputHandler::setHotlink() {
|
||||
if (hotlink.has_value()) {
|
||||
TMFE::Instance()->Msg(MERROR, __FUNCTION__,
|
||||
"Hotlink already established. Will not update it "
|
||||
"without restarting the frontend.");
|
||||
return;
|
||||
}
|
||||
hotlink.emplace(path);
|
||||
hotlink->watch([&](midas::odb &arg) {
|
||||
int hotlinkIndex = arg.get_last_index();
|
||||
if (hotlinkIndex == SPIndex) {
|
||||
} else if (hotlinkIndex == temperatureIndex) {
|
||||
pullTemperatureValue();
|
||||
} else if (hotlinkIndex == powerIndex) {
|
||||
pullPowerValue();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
InputHandler::InputHandler(EventBus &eventBusReference)
|
||||
: eventBus(eventBusReference) {
|
||||
|
||||
eventBus.subscribe<SettingsHandler::Event>(
|
||||
[this](const SettingsHandler::Event &e) {
|
||||
switch (e.type) {
|
||||
case SettingsHandler::EventType::EQUIPMENT_NAME:
|
||||
setPath(std::get<std::string>(e.value));
|
||||
setHotlink();
|
||||
break;
|
||||
case SettingsHandler::EventType::INPUT_SP_INDEX:
|
||||
updateSPIndex(std::get<int>(e.value));
|
||||
break;
|
||||
case SettingsHandler::EventType::INPUT_TEMPERATURE_INDEX:
|
||||
updateTemperatureIndex(std::get<int>(e.value));
|
||||
break;
|
||||
case SettingsHandler::EventType::INPUT_POWER_INDEX:
|
||||
updatePowerIndex(std::get<int>(e.value));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef INPUT_HANDLER_H
|
||||
#define INPUT_HANDLER_H
|
||||
|
||||
#include "../EventBus.h"
|
||||
#include "odbxx.h"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
class InputHandler {
|
||||
public:
|
||||
InputHandler(EventBus &eventBusReference);
|
||||
|
||||
enum class EventType {
|
||||
SP_VALUE,
|
||||
TEMPERATURE_VALUE,
|
||||
POWER_VALUE,
|
||||
};
|
||||
|
||||
struct Event {
|
||||
EventType type;
|
||||
float value;
|
||||
};
|
||||
|
||||
private:
|
||||
EventBus &eventBus;
|
||||
std::string path;
|
||||
int SPIndex;
|
||||
int temperatureIndex;
|
||||
int powerIndex;
|
||||
|
||||
std::optional<midas::odb> hotlink;
|
||||
|
||||
/*
|
||||
Internal value setters
|
||||
*/
|
||||
void setPath(std::string name);
|
||||
void updateSPIndex(int index);
|
||||
void updateTemperatureIndex(int index);
|
||||
void updatePowerIndex(int index);
|
||||
|
||||
void setHotlink();
|
||||
|
||||
/*
|
||||
Pull value from the ODB
|
||||
*/
|
||||
void pullSPValue();
|
||||
void pullTemperatureValue();
|
||||
void pullPowerValue();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef INPUT_HANDLER_CONFIG_H
|
||||
#define INPUT_HANDLER_CONFIG_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace InputHandlerConfig {
|
||||
|
||||
const std::string PATH_PREFIX = "/Equipment/";
|
||||
const std::string PATH_SUFFIX = "/Variables/Input";
|
||||
|
||||
} // namespace InputHandlerConfig
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
#include "OutputHandler.h"
|
||||
#include "DemandHandler.h"
|
||||
#include "OutputHandlerConfig.h"
|
||||
#include "PressureCalculator.h"
|
||||
#include "SettingsHandler.h"
|
||||
#include "tmfe.h"
|
||||
#include <string>
|
||||
|
||||
void OutputHandler::enableSetPressure(bool enable) {
|
||||
isSetPressureEnable = enable;
|
||||
update();
|
||||
}
|
||||
|
||||
void OutputHandler::setPressure(float value) {
|
||||
pressure = value;
|
||||
update();
|
||||
}
|
||||
|
||||
void OutputHandler::setOutputPressureSPIndex(int index) {
|
||||
outputPressureSPIndex = index;
|
||||
update();
|
||||
}
|
||||
|
||||
void OutputHandler::setEquipmentPath(std::string equipmentName) {
|
||||
equipmentPath = OutputHandlerConfig::PATH_PREFIX + equipmentName +
|
||||
OutputHandlerConfig::PATH_SUFFIX;
|
||||
update();
|
||||
}
|
||||
|
||||
void OutputHandler::update() {
|
||||
if (equipmentPath.empty())
|
||||
return;
|
||||
static bool isIndexValid = true;
|
||||
static bool isKeyValid = true;
|
||||
midas::odb o(equipmentPath);
|
||||
|
||||
if (!midas::odb::exists(equipmentPath + "/" +
|
||||
OutputHandlerConfig::OUTPUT_VARIABLE) &&
|
||||
isKeyValid) {
|
||||
TMFE::Instance()->Msg(MERROR, __FUNCTION__,
|
||||
"Key at %s%s doesn't exists",
|
||||
equipmentPath.c_str(),
|
||||
OutputHandlerConfig::OUTPUT_VARIABLE.c_str());
|
||||
isKeyValid = false;
|
||||
} else {
|
||||
isKeyValid = true;
|
||||
}
|
||||
|
||||
if ((o[OutputHandlerConfig::OUTPUT_VARIABLE].size() <
|
||||
outputPressureSPIndex) &&
|
||||
isIndexValid) {
|
||||
TMFE::Instance()->Msg(MERROR, __FUNCTION__,
|
||||
"SP index is %i, where array size is %i at %s.",
|
||||
outputPressureSPIndex, o.size(),
|
||||
equipmentPath.c_str());
|
||||
isIndexValid = false;
|
||||
} else {
|
||||
isIndexValid = true;
|
||||
}
|
||||
|
||||
//// SHOULD I CRASH IF KEY NOT VALID ?
|
||||
//// FOR NOW, FAILED SILENTLY
|
||||
|
||||
if (isSetPressureEnable && isKeyValid)
|
||||
o(OutputHandlerConfig::OUTPUT_VARIABLE)[outputPressureSPIndex] =
|
||||
pressure;
|
||||
}
|
||||
|
||||
OutputHandler::OutputHandler(EventBus &eventBusReference) {
|
||||
|
||||
eventBusReference.subscribe<DemandHandler::Event>(
|
||||
[this](const DemandHandler::Event &e) {
|
||||
switch (e.type) {
|
||||
case DemandHandler::EventType::SET_PRESSURE:
|
||||
enableSetPressure(std::get<bool>(e.value));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
eventBusReference.subscribe<SettingsHandler::Event>(
|
||||
[this](const SettingsHandler::Event &e) {
|
||||
switch (e.type) {
|
||||
case SettingsHandler::EventType::EQUIPMENT_NAME:
|
||||
setEquipmentPath(std::get<std::string>(e.value));
|
||||
break;
|
||||
case SettingsHandler::EventType::OUTPUT_PRESSURE_SP_INDEX:
|
||||
setOutputPressureSPIndex(std::get<int>(e.value));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
eventBusReference.subscribe<PressureCalculator::Event>(
|
||||
[this](const PressureCalculator::Event &e) {
|
||||
setPressure(e.cappedPressure);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef OUTPUT_HANDLER_H
|
||||
#define OUTPUT_HANDLER_H
|
||||
|
||||
#include "../EventBus.h"
|
||||
#include "DemandHandler.h"
|
||||
#include "PressureCalculator.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class OutputHandler {
|
||||
public:
|
||||
OutputHandler(EventBus &eventBusReference);
|
||||
|
||||
private:
|
||||
bool isSetPressureEnable;
|
||||
std::string equipmentPath;
|
||||
float pressure;
|
||||
int outputPressureSPIndex;
|
||||
|
||||
/*
|
||||
Internal value setters
|
||||
*/
|
||||
void enableSetPressure(bool enable);
|
||||
void setPressure(float value);
|
||||
void setOutputPressureSPIndex(int index);
|
||||
void setEquipmentPath(std::string equipmentName);
|
||||
/*
|
||||
Update value of the ODB
|
||||
*/
|
||||
void update();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef OUTPUT_HANDLER_CONFIG_H
|
||||
#define OUTPUT_HANDLER_CONFIG_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace OutputHandlerConfig {
|
||||
const std::string PATH_PREFIX = "/Equipment/";
|
||||
const std::string PATH_SUFFIX = "/Variables";
|
||||
|
||||
const std::string OUTPUT_VARIABLE = "Output";
|
||||
} // namespace OutputHandlerConfig
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,119 @@
|
||||
#include "PressureCalculator.h"
|
||||
#include "../itc_pressure_optimizer.h"
|
||||
#include "Average.h"
|
||||
#include "DemandHandler.h"
|
||||
#include "InputHandler.h"
|
||||
#include <string>
|
||||
|
||||
void PressureCalculator::update() {
|
||||
double averagePower = average.getAverage();
|
||||
double c2contrib = averagePower * cachedConstante2;
|
||||
double c1contrib =
|
||||
cachedConstante1 * (cachedTemperature - cachedSP - c2contrib);
|
||||
double uncapedPressure = cachedMinimalPressure + c1contrib;
|
||||
|
||||
double cappedPressure = uncapedPressure;
|
||||
|
||||
if (c2contrib != 0) {
|
||||
c2contrib = -c2contrib * cachedConstante1;
|
||||
} else {
|
||||
c2contrib = 0.0f;
|
||||
}
|
||||
|
||||
if (cappedPressure < cachedMinimalPressure)
|
||||
cappedPressure = cachedMinimalPressure;
|
||||
|
||||
if (cappedPressure > cachedMaximalPressure)
|
||||
cappedPressure = cachedMaximalPressure;
|
||||
|
||||
Event event = {};
|
||||
|
||||
event.c1contrib = c1contrib;
|
||||
event.c2contrib = c2contrib;
|
||||
event.uncapedPressure = uncapedPressure;
|
||||
event.cappedPressure = cappedPressure;
|
||||
event.averagePower = averagePower;
|
||||
|
||||
eventBus.publish(event);
|
||||
}
|
||||
|
||||
PressureCalculator::PressureCalculator(EventBus &eventBusReference)
|
||||
: average(30), eventBus(eventBusReference) {
|
||||
eventBus.subscribe<DemandHandler::Event>(
|
||||
[this](const DemandHandler::Event &e) {
|
||||
switch (e.type) {
|
||||
case DemandHandler::EventType::MINIMAL_PRESSURE:
|
||||
updateMinimalPressure(std::get<float>(e.value));
|
||||
break;
|
||||
case DemandHandler::EventType::MAXIMAL_PRESSURE:
|
||||
updateMaximalPressure(std::get<float>(e.value));
|
||||
break;
|
||||
case DemandHandler::EventType::CONSTANTE_1:
|
||||
updateConstante1(std::get<float>(e.value));
|
||||
break;
|
||||
case DemandHandler::EventType::CONSTANTE_2:
|
||||
updateConstante2(std::get<float>(e.value));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
eventBus.subscribe<InputHandler::Event>(
|
||||
[this](const InputHandler::Event &e) {
|
||||
switch (e.type) {
|
||||
case InputHandler::EventType::SP_VALUE:
|
||||
updateSP(e.value);
|
||||
break;
|
||||
case InputHandler::EventType::TEMPERATURE_VALUE:
|
||||
updateTemperature(e.value);
|
||||
break;
|
||||
case InputHandler::EventType::POWER_VALUE:
|
||||
updatePower(e.value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
eventBus.subscribe<itcPressureOptimizer::EquipmentPollEvent>(
|
||||
[this](const itcPressureOptimizer::EquipmentPollEvent &e) {
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
void PressureCalculator::updateSP(float value) {
|
||||
cachedSP = value;
|
||||
update();
|
||||
}
|
||||
|
||||
void PressureCalculator::updateTemperature(float value) {
|
||||
cachedTemperature = value;
|
||||
update();
|
||||
}
|
||||
|
||||
void PressureCalculator::updatePower(float value) {
|
||||
cachedPower = value;
|
||||
average.addValue(static_cast<double>(value));
|
||||
update();
|
||||
}
|
||||
|
||||
void PressureCalculator::updateMinimalPressure(float value) {
|
||||
cachedMinimalPressure = value;
|
||||
update();
|
||||
}
|
||||
|
||||
void PressureCalculator::updateMaximalPressure(float value) {
|
||||
cachedMaximalPressure = value;
|
||||
update();
|
||||
}
|
||||
|
||||
void PressureCalculator::updateConstante1(float value) {
|
||||
cachedConstante1 = value;
|
||||
update();
|
||||
}
|
||||
|
||||
void PressureCalculator::updateConstante2(float value) {
|
||||
cachedConstante2 = value;
|
||||
update();
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
#ifndef PRESSURE_CALCULATOR_H
|
||||
#define PRESSURE_CALCULATOR_H
|
||||
|
||||
#include "../EventBus.h"
|
||||
#include "Average.h"
|
||||
|
||||
class PressureCalculator {
|
||||
public:
|
||||
PressureCalculator(EventBus &eventBusReference);
|
||||
|
||||
struct Event {
|
||||
float c1contrib;
|
||||
float c2contrib;
|
||||
float uncapedPressure;
|
||||
float cappedPressure;
|
||||
float averagePower;
|
||||
};
|
||||
|
||||
private:
|
||||
Average average;
|
||||
EventBus &eventBus;
|
||||
|
||||
float cachedSP;
|
||||
float cachedTemperature;
|
||||
float cachedPower;
|
||||
|
||||
float cachedMinimalPressure;
|
||||
float cachedMaximalPressure;
|
||||
float cachedConstante1;
|
||||
float cachedConstante2;
|
||||
|
||||
/*
|
||||
Internal value setters (from InputHandler)
|
||||
*/
|
||||
void updateSP(float value);
|
||||
void updateTemperature(float value);
|
||||
void updatePower(float value);
|
||||
/*
|
||||
Internal value setters (from DemandHandler)
|
||||
*/
|
||||
void updateMinimalPressure(float value);
|
||||
void updateMaximalPressure(float value);
|
||||
void updateConstante1(float value);
|
||||
void updateConstante2(float value);
|
||||
|
||||
/*
|
||||
Update pressure value
|
||||
*/
|
||||
void update();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,124 @@
|
||||
#include "SettingsHandler.h"
|
||||
#include "../itc_pressure_optimizer.h"
|
||||
#include "SettingsHandlerConfig.h"
|
||||
#include <string>
|
||||
|
||||
using namespace SettingsHandlerConfig;
|
||||
|
||||
void SettingsHandler::pullEquipmentName() {
|
||||
midas::odb o(this->path);
|
||||
std::string equipmentName = o[SettingsHandlerConfig::EQUIPMENT_NAME];
|
||||
Event event = {EventType::EQUIPMENT_NAME, equipmentName};
|
||||
eventBus.publish(event);
|
||||
}
|
||||
|
||||
void SettingsHandler::pullOutputPressureSPIndex() {
|
||||
midas::odb o(this->path);
|
||||
int outputPressureSPIndex =
|
||||
o[SettingsHandlerConfig::OUTPUT_PRESSURE_SP_INDEX];
|
||||
Event event = {EventType::OUTPUT_PRESSURE_SP_INDEX, outputPressureSPIndex};
|
||||
eventBus.publish(event);
|
||||
}
|
||||
|
||||
void SettingsHandler::pullInputSPIndex() {
|
||||
midas::odb o(this->path);
|
||||
int inputSPIndex = o[SettingsHandlerConfig::INPUT_SP_INDEX];
|
||||
Event event = {EventType::INPUT_SP_INDEX, inputSPIndex};
|
||||
eventBus.publish(event);
|
||||
}
|
||||
|
||||
void SettingsHandler::pullInputTemperatureIndex() {
|
||||
midas::odb o(this->path);
|
||||
int temperatureIndex = o[SettingsHandlerConfig::INPUT_TEMPERATURE_INDEX];
|
||||
Event event = {EventType::INPUT_TEMPERATURE_INDEX, temperatureIndex};
|
||||
eventBus.publish(event);
|
||||
}
|
||||
|
||||
void SettingsHandler::pullInputPowerIndex() {
|
||||
midas::odb o(this->path);
|
||||
int powerIndex = o[SettingsHandlerConfig::INPUT_POWER_INDEX];
|
||||
Event event = {EventType::INPUT_POWER_INDEX, powerIndex};
|
||||
eventBus.publish(event);
|
||||
}
|
||||
|
||||
SettingsHandler::SettingsHandler(EventBus &eventBusReference,
|
||||
std::string equipmentName)
|
||||
: path(SettingsHandlerConfig::PATH_PREFIX + equipmentName +
|
||||
SettingsHandlerConfig::PATH_SUFFIX),
|
||||
eventBus(eventBusReference) {
|
||||
eventBus.subscribe<itcPressureOptimizer::EquipmentInitEvent>(
|
||||
[this](const itcPressureOptimizer::EquipmentInitEvent &e) {
|
||||
this->init();
|
||||
});
|
||||
}
|
||||
|
||||
bool SettingsHandler::init() {
|
||||
midas::odb o(this->path);
|
||||
|
||||
bool areKeysValids = true;
|
||||
|
||||
if (!midas::odb::exists(path + SettingsHandlerConfig::EQUIPMENT_NAME)) {
|
||||
TMFE::Instance()->Msg(MERROR, __FUNCTION__,
|
||||
"Key at %s%s doesn't exists", path.c_str(),
|
||||
SettingsHandlerConfig::EQUIPMENT_NAME.c_str());
|
||||
areKeysValids = false;
|
||||
}
|
||||
if (!midas::odb::exists(path +
|
||||
SettingsHandlerConfig::OUTPUT_PRESSURE_SP_INDEX)) {
|
||||
TMFE::Instance()->Msg(
|
||||
MERROR, __FUNCTION__, "Key at %s%s doesn't exists", path.c_str(),
|
||||
SettingsHandlerConfig::OUTPUT_PRESSURE_SP_INDEX.c_str());
|
||||
areKeysValids = false;
|
||||
}
|
||||
if (!midas::odb::exists(path + SettingsHandlerConfig::INPUT_SP_INDEX)) {
|
||||
TMFE::Instance()->Msg(MERROR, __FUNCTION__,
|
||||
"Key at %s%s doesn't exists", path.c_str(),
|
||||
SettingsHandlerConfig::INPUT_SP_INDEX.c_str());
|
||||
areKeysValids = false;
|
||||
}
|
||||
if (!midas::odb::exists(path +
|
||||
SettingsHandlerConfig::INPUT_TEMPERATURE_INDEX)) {
|
||||
TMFE::Instance()->Msg(
|
||||
MERROR, __FUNCTION__, "Key at %s%s doesn't exists", path.c_str(),
|
||||
SettingsHandlerConfig::INPUT_TEMPERATURE_INDEX.c_str());
|
||||
areKeysValids = false;
|
||||
}
|
||||
if (!midas::odb::exists(path + SettingsHandlerConfig::INPUT_POWER_INDEX)) {
|
||||
TMFE::Instance()->Msg(MERROR, __FUNCTION__,
|
||||
"Key at %s%s doesn't exists", path.c_str(),
|
||||
SettingsHandlerConfig::INPUT_POWER_INDEX.c_str());
|
||||
areKeysValids = false;
|
||||
}
|
||||
|
||||
if (!areKeysValids) {
|
||||
midas::odb o = {
|
||||
{SettingsHandlerConfig::EQUIPMENT_NAME.c_str(),
|
||||
{SettingsHandlerConfig::DEFAULT_EQUIPMENT_NAME.c_str()}},
|
||||
{SettingsHandlerConfig::OUTPUT_PRESSURE_SP_INDEX.c_str(),
|
||||
{SettingsHandlerConfig::DEFAULT_INDEX_VALUE}},
|
||||
{SettingsHandlerConfig::INPUT_SP_INDEX.c_str(),
|
||||
{SettingsHandlerConfig::DEFAULT_INDEX_VALUE}},
|
||||
{SettingsHandlerConfig::INPUT_TEMPERATURE_INDEX.c_str(),
|
||||
{SettingsHandlerConfig::DEFAULT_INDEX_VALUE}},
|
||||
{SettingsHandlerConfig::INPUT_POWER_INDEX.c_str(),
|
||||
{SettingsHandlerConfig::DEFAULT_INDEX_VALUE}},
|
||||
{SettingsHandlerConfig::TIME_WINDOW.c_str(),
|
||||
{SettingsHandlerConfig::DEFAULT_TIME_WINDOWS_SIZE}}};
|
||||
|
||||
TMFE::Instance()->Msg(
|
||||
MERROR, __FUNCTION__,
|
||||
"Some keys are missing at %s. Please fill the generated template.",
|
||||
path.c_str());
|
||||
|
||||
o.connect(this->path);
|
||||
throw std::runtime_error("SettinsHandler init failed - see MIDAS "
|
||||
"console and take care of all the errors\n");
|
||||
}
|
||||
|
||||
this->pullEquipmentName();
|
||||
this->pullOutputPressureSPIndex();
|
||||
this->pullInputSPIndex();
|
||||
this->pullInputTemperatureIndex();
|
||||
this->pullInputPowerIndex();
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef SETTINGS_HANDLER_H
|
||||
#define SETTINGS_HANDLER_H
|
||||
|
||||
#include "InputHandler.h"
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
class SettingsHandler {
|
||||
public:
|
||||
SettingsHandler(EventBus &eventBusReference, std::string equipmentName);
|
||||
|
||||
enum class EventType {
|
||||
EQUIPMENT_NAME,
|
||||
OUTPUT_PRESSURE_SP_INDEX,
|
||||
INPUT_SP_INDEX,
|
||||
INPUT_TEMPERATURE_INDEX,
|
||||
INPUT_POWER_INDEX
|
||||
};
|
||||
|
||||
struct Event {
|
||||
EventType type;
|
||||
std::variant<int, std::string> value;
|
||||
};
|
||||
|
||||
private:
|
||||
std::string path;
|
||||
EventBus &eventBus;
|
||||
|
||||
/*
|
||||
Init process
|
||||
*/
|
||||
bool init();
|
||||
|
||||
/*
|
||||
Pull value from the ODB
|
||||
*/
|
||||
void pullEquipmentName();
|
||||
void pullOutputPressureSPIndex();
|
||||
void pullInputSPIndex();
|
||||
void pullInputTemperatureIndex();
|
||||
void pullInputPowerIndex();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef SETTINGS_HANDLER_CONFIG_H
|
||||
#define SETTINGS_HANDLER_CONFIG_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace SettingsHandlerConfig {
|
||||
|
||||
const std::string PATH_PREFIX = "/Equipment/";
|
||||
const std::string PATH_SUFFIX = "/Settings/Devices/ItcPressureOptimizer/DD/";
|
||||
|
||||
const std::string EQUIPMENT_NAME = "Equipment name";
|
||||
const std::string OUTPUT_PRESSURE_SP_INDEX = "Output Pressure SetPoint Index";
|
||||
const std::string INPUT_SP_INDEX = "Input SetPoint Index";
|
||||
const std::string INPUT_TEMPERATURE_INDEX = "Input Temperature Index";
|
||||
const std::string INPUT_POWER_INDEX = "Input Power Index";
|
||||
const std::string TIME_WINDOW = "Average Power Time Window";
|
||||
|
||||
const std::string DEFAULT_EQUIPMENT_NAME = "";
|
||||
const int DEFAULT_INDEX_VALUE = -1;
|
||||
const float DEFAULT_TIME_WINDOWS_SIZE = 30.0f;
|
||||
|
||||
} // namespace SettingsHandlerConfig
|
||||
|
||||
#endif
|
||||
@@ -1,833 +1,26 @@
|
||||
#include "itc_pressure_optimizer.h"
|
||||
#include "itc_pressure_optimizer_config.h"
|
||||
#include "itc_pressure_optimizer_info.h"
|
||||
|
||||
#include "midas.h"
|
||||
#include "odbxx.h"
|
||||
#include "tmfe.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
|
||||
itcPressureOptimizer::itcPressureOptimizer(std::string equipmentName,
|
||||
const char *equipmentFilename,
|
||||
int channel)
|
||||
: TMFeEquipment(equipmentName.c_str(), equipmentFilename) {
|
||||
const char *equipmentFilename)
|
||||
: TMFeEquipment(equipmentName.c_str(), equipmentFilename), eventBus(),
|
||||
demandHandler(eventBus, equipmentName),
|
||||
settingsHandler(eventBus, equipmentName), inputHandler(eventBus),
|
||||
pressureCalculator(eventBus), feedbackHandler(eventBus, equipmentName),
|
||||
outputHandler(eventBus) {
|
||||
fEqConfPeriodMilliSec = 1000; // refresh every seconds
|
||||
fEqConfLogHistory = 1;
|
||||
fEqConfReadOnlyWhenRunning = false;
|
||||
fEqConfPeriodMilliSec = 100;
|
||||
this->equipmentPath = std::string("/Equipment/") + equipmentName;
|
||||
info.num_channels = channel;
|
||||
fEqConfWriteEventsToOdb = true;
|
||||
}
|
||||
|
||||
void itcPressureOptimizer::HandlePeriodic() {
|
||||
eventBus.publish(EquipmentPollEvent{});
|
||||
}
|
||||
|
||||
TMFeResult
|
||||
itcPressureOptimizer::HandleInit(const std::vector<std::string> &args) {
|
||||
this->mitc_pressc_init();
|
||||
eventBus.publish(EquipmentInitEvent{});
|
||||
return TMFeResult();
|
||||
}
|
||||
|
||||
void itcPressureOptimizer::HandlePeriodic() {
|
||||
midas::odb o(this->equipmentPath + "/" + Configuration::VARIABLE_DIR);
|
||||
|
||||
for (int i = 0; i < info.num_channels; i++) {
|
||||
info.last_measured[i] = o[Configuration::MEASURED_VARNAME.c_str()][i];
|
||||
info.last_demand[i] = o[Configuration::DEMAND_VARNAME.c_str()][i];
|
||||
}
|
||||
|
||||
this->mitc_pressc_update_mitc_input();
|
||||
this->mitc_pressc_update_pressure_demanded();
|
||||
this->mitc_pressc_recalculate();
|
||||
|
||||
for (int i = 0; i < info.num_channels; i++) {
|
||||
o[Configuration::MEASURED_VARNAME.c_str()][i] = info.last_measured[i];
|
||||
o[Configuration::DEMAND_VARNAME.c_str()][i] = info.last_demand[i];
|
||||
}
|
||||
}
|
||||
|
||||
INT itcPressureOptimizer::mitc_pressc_init() {
|
||||
int status = SUCCESS;
|
||||
bool isDefaultNameExists;
|
||||
bool isDefaultThresholdExists;
|
||||
bool isDemandExists;
|
||||
bool isMeasuredExists;
|
||||
isDefaultNameExists = midas::odb::exists(this->equipmentPath + "/" +
|
||||
Configuration::SETTINGS_DIR + "/" +
|
||||
Configuration::NAMES_VARNAME);
|
||||
|
||||
isDefaultThresholdExists = midas::odb::exists(
|
||||
this->equipmentPath + "/" + Configuration::SETTINGS_DIR + "/" +
|
||||
Configuration::UPDATE_THRESHOLD_MEASURED_VARNAME);
|
||||
|
||||
isDemandExists = midas::odb::exists(this->equipmentPath + "/" +
|
||||
Configuration::DEMANDE_PATH);
|
||||
|
||||
isMeasuredExists = midas::odb::exists(this->equipmentPath + "/" +
|
||||
Configuration::MEASURED_PATH);
|
||||
|
||||
if (!isDefaultNameExists || !isDefaultThresholdExists) {
|
||||
midas::odb o = {
|
||||
{Configuration::VARIABLE_DIR.c_str(),
|
||||
{{Configuration::DEMAND_VARNAME.c_str(), {0.0}},
|
||||
{Configuration::MEASURED_VARNAME.c_str(), {0.0}}}},
|
||||
{Configuration::SETTINGS_DIR.c_str(),
|
||||
{{Configuration::NAMES_VARNAME.c_str(), {""}},
|
||||
{Configuration::UPDATE_THRESHOLD_MEASURED_VARNAME.c_str(), {0.0}},
|
||||
{Configuration::DEVICES_DIR.c_str(),
|
||||
{{Configuration::MIT_DIR.c_str(),
|
||||
{{Configuration::ENABLE_VARNAME.c_str(), {true}},
|
||||
{Configuration::DD_DIR.c_str(),
|
||||
{{Configuration::MITC_EQUIPMENT_VARNAME.c_str(), {""}},
|
||||
{Configuration::MITC_OUTPUT_PRESS_SP_INDEX_VARNAME.c_str(),
|
||||
{0}},
|
||||
{Configuration::MITC_INPUT_VARIOX_SP_INDEX_VARNAME.c_str(),
|
||||
{0}},
|
||||
{Configuration::MITC_INPUT_VARIOX_TEMP_INDEX_VARNAME
|
||||
.c_str(),
|
||||
{0}},
|
||||
{Configuration::MITC_INPUT_VARIOX_POW_INDEX_VARNAME.c_str(),
|
||||
{0}},
|
||||
{Configuration::RECALC_INTERVAL_VARNAME.c_str(), {0}},
|
||||
{Configuration::MITC_READOUT_INTERVAL_VARNAME.c_str(), {0}},
|
||||
{Configuration::PRESS_READOUT_INTERVAL_VARNAME.c_str(),
|
||||
{0}}}}}}}}}}};
|
||||
|
||||
o.connect(this->equipmentPath.c_str());
|
||||
}
|
||||
|
||||
if (!isDefaultNameExists) {
|
||||
midas::odb o(this->equipmentPath + "/" + Configuration::SETTINGS_DIR);
|
||||
std::vector<std::string> nameLists =
|
||||
o[Configuration::NAMES_VARNAME.c_str()];
|
||||
nameLists.resize(info.num_channels);
|
||||
for (int i = 0; i < info.num_channels; i++) {
|
||||
std::string res = this->getDefaultName(i);
|
||||
nameLists.at(i) = res;
|
||||
printf("%s\n", res.c_str());
|
||||
}
|
||||
o[Configuration::NAMES_VARNAME.c_str()] = nameLists;
|
||||
}
|
||||
|
||||
if (!isDefaultThresholdExists) {
|
||||
midas::odb o(this->equipmentPath + "/" + Configuration::SETTINGS_DIR);
|
||||
o[Configuration::UPDATE_THRESHOLD_MEASURED_VARNAME.c_str()].resize(
|
||||
info.num_channels);
|
||||
for (int i = 0; i < info.num_channels; i++) {
|
||||
o[Configuration::UPDATE_THRESHOLD_MEASURED_VARNAME.c_str()][i] =
|
||||
this->getDefaultThreshold(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isDemandExists) {
|
||||
midas::odb o(this->equipmentPath + "/" + Configuration::VARIABLE_DIR);
|
||||
std::vector<float> demandLists =
|
||||
o[Configuration::DEMAND_VARNAME.c_str()];
|
||||
demandLists.resize(info.num_channels);
|
||||
o[Configuration::DEMAND_VARNAME.c_str()] = demandLists;
|
||||
}
|
||||
|
||||
if (!isMeasuredExists) {
|
||||
midas::odb o(this->equipmentPath + "/" + Configuration::VARIABLE_DIR);
|
||||
std::vector<float> measuredLists =
|
||||
o[Configuration::MEASURED_VARNAME.c_str()];
|
||||
measuredLists.resize(info.num_channels);
|
||||
o[Configuration::MEASURED_VARNAME.c_str()] = measuredLists;
|
||||
}
|
||||
|
||||
/*
|
||||
Caching all the value of /DD folder
|
||||
*/
|
||||
{
|
||||
midas::odb o(this->equipmentPath.c_str());
|
||||
info.mitcpressc_settings.mitcequipment =
|
||||
o[Configuration::MITC_EQUIPMENT_PATH.c_str()];
|
||||
info.mitcpressc_settings.setpressindex =
|
||||
o[Configuration::MITC_OUTPUT_PRESS_SP_INDEX_PATH.c_str()];
|
||||
info.mitcpressc_settings.getvarioxspindex =
|
||||
o[Configuration::MITC_INPUT_VARIOX_SP_INDEX_PATH.c_str()];
|
||||
info.mitcpressc_settings.getvarioxtempindex =
|
||||
o[Configuration::MITC_INPUT_VARIOX_TEMP_INDEX_PATH.c_str()];
|
||||
info.mitcpressc_settings.getvarioxpowindex =
|
||||
o[Configuration::MITC_INPUT_VARIOX_POW_INDEX_PATH.c_str()];
|
||||
info.mitcpressc_settings.recalcinterval =
|
||||
o[Configuration::RECALC_INTERVAL_PATH.c_str()];
|
||||
info.mitcpressc_settings.mitcinterval =
|
||||
o[Configuration::MITC_READOUT_INTERVAL_PATH.c_str()];
|
||||
info.mitcpressc_settings.pressinterval =
|
||||
o[Configuration::PRESS_READOUT_INTERVAL_PATH.c_str()];
|
||||
}
|
||||
|
||||
info.mitcPath = Configuration::SLASH + Configuration::EQUIPMENT_DIR +
|
||||
Configuration::SLASH +
|
||||
info.mitcpressc_settings.mitcequipment +
|
||||
Configuration::SLASH + Configuration::VARIABLE_DIR;
|
||||
|
||||
info.last_demand.resize(info.num_channels);
|
||||
info.last_demand_set.resize(info.num_channels);
|
||||
info.last_measured.resize(info.num_channels);
|
||||
|
||||
// set invalid values to avoid calculation before init
|
||||
for (int i = 0; i < info.num_channels; i++) {
|
||||
info.last_measured.at(i) = -2.f;
|
||||
}
|
||||
|
||||
info.lastlog = 0;
|
||||
info.last_press_mitc_output = 0;
|
||||
info.recalculate = TRUE;
|
||||
info.pending = TRUE;
|
||||
info.press_mitc_output = -1.0f;
|
||||
info.nvals_mitc_input = 0;
|
||||
info.nvals_mitc_output = 0;
|
||||
|
||||
info.ihis = 0;
|
||||
|
||||
for (int i = 0; i < MAX_HIS; i++) {
|
||||
info.history[i] = -1.f; // invalidate history
|
||||
info.history_time[i] = 0; // no value archived yet
|
||||
}
|
||||
|
||||
// Check equipment Variables Input & Index
|
||||
if (!(info.mitcpressc_settings.mitcequipment == "NONE") &&
|
||||
!info.mitcpressc_settings.mitcequipment.empty()) {
|
||||
std::string mitc_input_path = std::string("/Equipment/") +
|
||||
info.mitcpressc_settings.mitcequipment +
|
||||
"/" + Configuration::VARIABLE_DIR;
|
||||
midas::odb o(mitc_input_path.c_str());
|
||||
|
||||
// INPUTS
|
||||
info.nvals_mitc_input = o[Configuration::INPUT_VARNAME.c_str()].size();
|
||||
|
||||
if (info.nvals_mitc_input > 0) {
|
||||
info.mitc_input.resize(info.nvals_mitc_input);
|
||||
cm_msg(
|
||||
MLOG, "",
|
||||
"Reading Mercury ITC Variables/Input values for Equipment %s",
|
||||
info.mitcpressc_settings.mitcequipment.c_str());
|
||||
// check if index < nvals
|
||||
if ((info.mitcpressc_settings.getvarioxspindex < 0) ||
|
||||
(info.mitcpressc_settings.getvarioxspindex >=
|
||||
info.nvals_mitc_input)) {
|
||||
status = CM_SET_ERROR;
|
||||
cm_msg(MERROR, "mitc_pressc_init",
|
||||
"ERROR array index %d to read temperature"
|
||||
" setpoint is invalid",
|
||||
info.mitcpressc_settings.getvarioxspindex);
|
||||
} else {
|
||||
cm_msg(
|
||||
MLOG, "",
|
||||
"Input Index to read Temperature SP of Equipment %s is %d",
|
||||
info.mitcpressc_settings.mitcequipment.c_str(),
|
||||
info.mitcpressc_settings.getvarioxspindex);
|
||||
}
|
||||
// check if index < nvals
|
||||
if ((info.mitcpressc_settings.getvarioxtempindex < 0) ||
|
||||
(info.mitcpressc_settings.getvarioxtempindex >=
|
||||
info.nvals_mitc_input)) {
|
||||
status = CM_SET_ERROR;
|
||||
cm_msg(MERROR, "mitc_pressc_init",
|
||||
"ERROR array index %d to read temperature"
|
||||
" is invalid",
|
||||
info.mitcpressc_settings.getvarioxtempindex);
|
||||
} else {
|
||||
cm_msg(MLOG, "",
|
||||
"Input Index to read Temperature of Equipment %s is %d",
|
||||
info.mitcpressc_settings.mitcequipment.c_str(),
|
||||
info.mitcpressc_settings.getvarioxtempindex);
|
||||
}
|
||||
// check if index < nvals
|
||||
if ((info.mitcpressc_settings.getvarioxpowindex < 0) ||
|
||||
(info.mitcpressc_settings.getvarioxpowindex >=
|
||||
info.nvals_mitc_input)) {
|
||||
status = CM_SET_ERROR;
|
||||
cm_msg(MERROR, "mitc_pressc_init",
|
||||
"ERROR array index %d to read heater pow"
|
||||
"er is invalid",
|
||||
info.mitcpressc_settings.getvarioxpowindex);
|
||||
} else {
|
||||
cm_msg(MLOG, "",
|
||||
"Input Index to read heater power of Equipment %s is %d",
|
||||
info.mitcpressc_settings.mitcequipment.c_str(),
|
||||
info.mitcpressc_settings.getvarioxpowindex);
|
||||
}
|
||||
} else {
|
||||
cm_msg(MERROR, "mitc_pressc_init",
|
||||
"ERROR Invalid number of channels %d for "
|
||||
"Mercury ITC Variables/Input!",
|
||||
info.nvals_mitc_input);
|
||||
}
|
||||
|
||||
// OUTPUTS
|
||||
info.nvals_mitc_output =
|
||||
o[Configuration::OUTPUT_VARNAME.c_str()].size();
|
||||
if (info.nvals_mitc_output > 0) {
|
||||
// check if index < nvals
|
||||
if ((info.mitcpressc_settings.setpressindex < 0) ||
|
||||
(info.mitcpressc_settings.setpressindex >=
|
||||
info.nvals_mitc_output)) {
|
||||
status = CM_SET_ERROR;
|
||||
cm_msg(MERROR, "mitc_pressc_init",
|
||||
"ERROR array index %d to read/set pres"
|
||||
"sure setpoint is invalid",
|
||||
info.mitcpressc_settings.setpressindex);
|
||||
} else {
|
||||
cm_msg(MLOG, "",
|
||||
"Output Index to read/set Pressure SP of Equipment %s "
|
||||
"is %d",
|
||||
info.mitcpressc_settings.mitcequipment.c_str(),
|
||||
info.mitcpressc_settings.setpressindex);
|
||||
}
|
||||
} else {
|
||||
cm_msg(MERROR, "mitc_pressc_init",
|
||||
"ERROR Invalid number of channels %d for "
|
||||
"measured pressure!",
|
||||
info.nvals_mitc_output);
|
||||
status = DB_NO_KEY;
|
||||
}
|
||||
|
||||
} else {
|
||||
cm_msg(MLOG, "",
|
||||
"Equipment Name to Set/Get Mercury ITC Variables is not set-up "
|
||||
"in MITCPRESSC/DD");
|
||||
}
|
||||
|
||||
// FAILED PATH
|
||||
|
||||
if (status != SUCCESS) {
|
||||
cm_msg(MLOG, "", "mitc_pressc_init : ERROR initialising device");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
printf("hey \n");
|
||||
|
||||
// SUCCESS PATH
|
||||
// Init value
|
||||
for (int i = 0; i < info.num_channels; i++) {
|
||||
info.last_demand[i] = -1.f;
|
||||
info.last_measured[i] = -2.f;
|
||||
}
|
||||
// NOTE: calculation will not be performed until info.initialized is TRUE
|
||||
// this is done in mitc_pressc_set() when the last parameter is
|
||||
// initialized
|
||||
|
||||
/*
|
||||
Hot link
|
||||
*/
|
||||
|
||||
midas::odb to_watch(this->equipmentPath + "/" +
|
||||
Configuration::VARIABLE_DIR + "/" +
|
||||
Configuration::DEMAND_VARNAME);
|
||||
|
||||
to_watch.watch([&](midas::odb &arg) {
|
||||
midas::odb o(this->equipmentPath + "/" + Configuration::VARIABLE_DIR);
|
||||
int index = arg.get_last_index();
|
||||
float value = o[Configuration::DEMAND_VARNAME][arg.get_last_index()];
|
||||
this->mitc_pressc_set(index, value);
|
||||
});
|
||||
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
INT itcPressureOptimizer::mitc_pressc_exit() {
|
||||
return DB_SUCCESS;
|
||||
// Nothing to do, since we do not manage memory with vector. All is drop
|
||||
// when out of scope
|
||||
}
|
||||
|
||||
INT itcPressureOptimizer::mitc_pressc_update_mitc_input() {
|
||||
if (info.last_mitc_input > ss_time()) // system time reset?
|
||||
info.last_mitc_input =
|
||||
ss_time() - info.mitcpressc_settings.mitcinterval + 1;
|
||||
|
||||
// Time to read ?
|
||||
// TODO : (info.hkey_mitc_input != 0) && (info.hkey_mitc_output != 0)
|
||||
// condition is not checked, May need to add another check if necessary
|
||||
|
||||
bool timeoutThreshold =
|
||||
static_cast<INT>((ss_time() - info.last_mitc_input)) >
|
||||
info.mitcpressc_settings.mitcinterval;
|
||||
if (!timeoutThreshold) {
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
float tpow;
|
||||
{
|
||||
std::string mitc_input_path = std::string("/Equipment/") +
|
||||
info.mitcpressc_settings.mitcequipment +
|
||||
"/" + Configuration::VARIABLE_DIR;
|
||||
midas::odb o(mitc_input_path.c_str());
|
||||
|
||||
info.mitc_input = o[Configuration::INPUT_VARNAME.c_str()];
|
||||
}
|
||||
|
||||
// TODO : Understand what this piece of code is used, and does the float
|
||||
// condition correct ... "!=" is suspect
|
||||
|
||||
float sum, avg;
|
||||
int i, nvals;
|
||||
|
||||
DWORD curtime;
|
||||
|
||||
// measured MITCPRESSC_MercuryITC Loop0 Temperature Setpoint 1
|
||||
printf("update temps\n");
|
||||
if ((info.mitc_input[info.mitcpressc_settings.getvarioxspindex]) != -1) {
|
||||
printf("last measured\n");
|
||||
printf("index %d value %f\n", info.mitcpressc_settings.getvarioxspindex,
|
||||
info.mitc_input[info.mitcpressc_settings.getvarioxspindex]);
|
||||
if (info.last_measured[1] !=
|
||||
info.mitc_input[info.mitcpressc_settings.getvarioxspindex]) {
|
||||
|
||||
info.last_measured[1] =
|
||||
info.mitc_input[info.mitcpressc_settings.getvarioxspindex];
|
||||
info.recalculate = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// measured MITCPRESSC_Mercury ITCTemperat(ure) 2
|
||||
if (info.mitcpressc_settings.getvarioxtempindex != -1) {
|
||||
if (info.last_measured[2] !=
|
||||
(info.mitc_input[info.mitcpressc_settings.getvarioxtempindex])) {
|
||||
info.last_measured[2] =
|
||||
info.mitc_input[info.mitcpressc_settings.getvarioxtempindex];
|
||||
info.recalculate = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// measured MITCPRESSC_MercuryITC Loop0 Power 3
|
||||
// here in Watt
|
||||
if (info.mitcpressc_settings.getvarioxpowindex != -1) {
|
||||
tpow = info.mitc_input[info.mitcpressc_settings.getvarioxpowindex];
|
||||
} else {
|
||||
tpow = -1.f; // invalid - should not occur
|
||||
}
|
||||
if (tpow < 0.f) {
|
||||
tpow = -1.f; // invalid - should not occur
|
||||
} else {
|
||||
// archive current value
|
||||
info.history[info.ihis] = tpow;
|
||||
info.history_time[info.ihis] = ss_time();
|
||||
info.ihis += 1;
|
||||
if (info.ihis >= MAX_HIS)
|
||||
info.ihis = 0; // ring buffer
|
||||
|
||||
// calculate average power
|
||||
curtime = ss_time();
|
||||
}
|
||||
|
||||
info.last_measured[3] = tpow;
|
||||
|
||||
// sum valid power readings read in the last 30 secs
|
||||
for (sum = 0.0, nvals = 0, i = 0; i < MAX_HIS; i++) {
|
||||
// valid power?
|
||||
if (info.history[i] >= 0.f) {
|
||||
// measured in the last 30 secs
|
||||
if (info.history_time[i] + 30 > curtime) {
|
||||
sum += info.history[i];
|
||||
nvals++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// calculate average
|
||||
if (nvals > 0)
|
||||
avg = sum / (float)nvals;
|
||||
else
|
||||
avg = -1.f;
|
||||
|
||||
if (info.last_measured[4] != avg) {
|
||||
// measured MITCPRESSC_AveragedPower 4
|
||||
info.last_measured[4] = avg;
|
||||
info.recalculate = TRUE;
|
||||
}
|
||||
|
||||
// TODO : in case of error accessing the ODB, this should be executed
|
||||
|
||||
// if (*(info.last_measured + 1) != -1.f) {
|
||||
// cm_msg(MERROR, "mitc_pressc_update_mitc_input",
|
||||
// "Error %d returned by "
|
||||
// "db_get_data() reading Mercury ITC Measured from ODB!",
|
||||
// status);
|
||||
// *(info.last_measured + 1) = -1.f;
|
||||
// *(info.last_measured + 2) = -1.f;
|
||||
// *(info.last_measured + 3) = -1.f;
|
||||
// *(info.last_measured + 4) = -1.f;
|
||||
// }
|
||||
|
||||
info.last_mitc_input = ss_time();
|
||||
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
INT itcPressureOptimizer::mitc_pressc_update_pressure_demanded() {
|
||||
if (info.last_press_mitc_output > ss_time()) // time reset?
|
||||
info.last_press_mitc_output =
|
||||
ss_time() - info.mitcpressc_settings.pressinterval + 1;
|
||||
|
||||
// time to read?
|
||||
if (static_cast<INT>(ss_time() - info.last_press_mitc_output) >
|
||||
info.mitcpressc_settings.pressinterval) {
|
||||
|
||||
// read current demanded pressure from odb
|
||||
|
||||
midas::odb o(info.mitcPath);
|
||||
// TODO : Check if the variable is present to prevent crash
|
||||
|
||||
info.press_mitc_output = o[Configuration::OUTPUT_VARNAME.c_str()]
|
||||
[info.mitcpressc_settings.setpressindex];
|
||||
info.last_press_mitc_output = ss_time();
|
||||
}
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
INT itcPressureOptimizer::mitc_pressc_recalculate() {
|
||||
if (!info.initialised) {
|
||||
printf("not initialised\n");
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
if (info.pending) {
|
||||
info.recalculate = TRUE;
|
||||
info.pending = FALSE;
|
||||
}
|
||||
|
||||
if (info.last_recalculated > ss_time())
|
||||
info.last_recalculated =
|
||||
ss_time() - info.mitcpressc_settings.recalcinterval + 1;
|
||||
|
||||
// recalculate flagged? or time to recalculate?
|
||||
if (info.recalculate ||
|
||||
(static_cast<INT>(ss_time() - info.last_recalculated) >
|
||||
info.mitcpressc_settings.recalcinterval)) {
|
||||
|
||||
/* --- do pressure calculation --- */
|
||||
|
||||
if (info.last_measured[4] >= 0.f) {
|
||||
// Calculate presure
|
||||
printf("calculate pressure \n");
|
||||
|
||||
info.pending = FALSE;
|
||||
|
||||
// Mercury ITC Temperature setpoint invalid ?
|
||||
if (info.last_measured[1] < 0.f)
|
||||
info.pending = TRUE;
|
||||
// Mercury ITC Temperature measured invalid ?
|
||||
if (info.last_measured[2] < .0f)
|
||||
info.pending = TRUE;
|
||||
|
||||
// COMMENT FROM ANDREAS
|
||||
// NIY maybe check also validity of minpress, maxpress, c1, c2
|
||||
// in info.last_demand
|
||||
|
||||
if (!info.pending) {
|
||||
float press, c1contrib, c2contrib;
|
||||
|
||||
// pressure calculation:
|
||||
// p = pmin+c1*(Tmeas-Tset-avPower*c2)
|
||||
// if (p < pmin) p = pmin
|
||||
// if (p > pmax) p = pmax
|
||||
|
||||
c2contrib = info.last_measured[4] * info.last_demand[11];
|
||||
c1contrib =
|
||||
info.last_demand[10] *
|
||||
(info.last_measured[2] - info.last_measured[1] - c2contrib);
|
||||
press = info.last_demand[8] + c1contrib;
|
||||
|
||||
info.last_measured[10] = c1contrib;
|
||||
|
||||
if (c2contrib != 0.0f)
|
||||
info.last_measured[11] = -c2contrib * info.last_demand[10];
|
||||
else
|
||||
info.last_measured[11] = 0.0f;
|
||||
|
||||
info.last_measured[8] = press;
|
||||
info.last_measured[9] = press;
|
||||
|
||||
// Pressure smaller than min? -> take min
|
||||
if (press < info.last_demand[8])
|
||||
press = info.last_demand[8];
|
||||
|
||||
// Presure larger than max? -> take max
|
||||
if (press > info.last_demand[9])
|
||||
press = info.last_demand[9];
|
||||
|
||||
// update measured of MITCPRESSC_CalcPressure 5
|
||||
info.last_measured[5] = press;
|
||||
|
||||
// Pressure control mode is set to calculated?
|
||||
if (info.last_demand[6] == 1.0f) {
|
||||
float presst = std::roundf(press * 10.0f + 0.5f) /
|
||||
10.0f; // Round one decimal
|
||||
|
||||
// only necessary to update when rounded value and demand
|
||||
// value differ
|
||||
// Check of hkey_demand is missing
|
||||
if (fabsf(info.last_demand[0] - presst) >= 0.05f) {
|
||||
midas::odb o(this->equipmentPath);
|
||||
printf("%f is a new value\n", presst);
|
||||
o[Configuration::DEMANDE_PATH.c_str()][0] = presst;
|
||||
}
|
||||
info.last_demand[0] = presst;
|
||||
}
|
||||
}
|
||||
|
||||
/* NOT able to calculate pressure and calculated pressure expected
|
||||
* as input */
|
||||
} else if (info.last_demand[6] == 1.0f) {
|
||||
info.pending = TRUE;
|
||||
info.last_measured[5] = -1.0f;
|
||||
/* pressure calculation is not necessary as manual mode is set */
|
||||
} else if (info.last_demand[6] != 1.0f) {
|
||||
info.pending = FALSE;
|
||||
info.last_measured[5] = -1.0f;
|
||||
}
|
||||
|
||||
/* all conditions met to update setpoint of Mercury ITC in ODB? */
|
||||
if (!info.pending) {
|
||||
info.last_recalculated = ss_time();
|
||||
|
||||
if (info.last_demand[7] == 1.0f) {
|
||||
info.last_demand[0] =
|
||||
std::roundf(info.last_demand[0] * 10.0f + 0.5f) / 10.0f;
|
||||
info.last_measured[0] = info.last_demand[0];
|
||||
|
||||
/* is Mercury ITC already set? -> check readout*/
|
||||
if (info.press_mitc_output != info.last_demand[0]) {
|
||||
// update Mercury ITC Demanded value
|
||||
// NIY maybe check if info.hkey_mitc_output != 0
|
||||
|
||||
midas::odb o(info.mitcPath);
|
||||
o[Configuration::OUTPUT_PATH.c_str()]
|
||||
[info.mitcpressc_settings.setpressindex] =
|
||||
info.last_demand[0];
|
||||
|
||||
info.last_mitc_input = ss_time();
|
||||
}
|
||||
}
|
||||
ss_sleep(100);
|
||||
}
|
||||
if (!info.recalculate)
|
||||
ss_sleep(100);
|
||||
|
||||
info.recalculate = FALSE;
|
||||
}
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
_Pressure 0 D
|
||||
_MercuryITCSetpoint 1
|
||||
_MercuryITCTemperat(ure) 2
|
||||
_MercuryITCPower 3
|
||||
_AveragedPower 4
|
||||
_CalcPressure 5
|
||||
_PressureControlMode 6 D
|
||||
_SetRCPressure 7 D
|
||||
_PressureCalc_minPressure 8 D
|
||||
_PressureCalc_maxPressure 9 D
|
||||
_PressureCalc_const1 10 D
|
||||
_PressureCalc_const2 11 D
|
||||
*/
|
||||
|
||||
INT itcPressureOptimizer::mitc_pressc_set(INT channel, float value) {
|
||||
switch (channel) {
|
||||
case 0: // PRESSURE - only set pressure if not in calculated mode
|
||||
if (info.last_demand[6] != 1.0f) {
|
||||
if (info.last_demand[channel] != value) {
|
||||
info.last_demand[channel] = value;
|
||||
info.last_demand_set[channel] = ss_time();
|
||||
info.recalculate = TRUE;
|
||||
}
|
||||
} else {
|
||||
if (std::abs(info.last_demand[channel] - value) > 0.2f) {
|
||||
cm_msg(MLOG, "",
|
||||
"PressureControlMode is set to calculated! "
|
||||
"- Not setting pressure!");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6: // Pressure Control Mode : 1 = Calc(automatic), 0 = Man
|
||||
if ((info.last_demand[channel] != 1.0f) && (value == 1.0f)) {
|
||||
info.last_demand[channel] = 1.0f;
|
||||
info.last_demand_set[channel] = ss_time();
|
||||
cm_msg(MLOG, "", "Pressure Control Mode is set to Calculated");
|
||||
|
||||
info.recalculate = TRUE;
|
||||
} else if ((info.last_demand[channel] != 0.0f) && (value != 1.0f)) {
|
||||
info.last_demand[channel] = 0.0f;
|
||||
info.last_demand_set[channel] = ss_time();
|
||||
|
||||
cm_msg(MLOG, "", "Pressure Control Mode is set to Manual");
|
||||
|
||||
info.recalculate = TRUE;
|
||||
}
|
||||
break;
|
||||
case 7: // set Pressure for Mercury ITC: 1 = Update Mercury ITC Pressure
|
||||
// Setpoint
|
||||
// 0 = do not
|
||||
if ((info.last_demand[channel] != 1.0f) && (value == 1.0f)) {
|
||||
info.last_demand[channel] = 1.0f;
|
||||
info.last_demand_set[channel] = ss_time();
|
||||
|
||||
cm_msg(MLOG, "",
|
||||
"MPC_SetPressure is enabled - Setting Mercury ITC "
|
||||
"Pressure Setpoint in ODB");
|
||||
} else if ((info.last_demand[channel] != 0.0f) && (value != 1.0f)) {
|
||||
info.last_demand[channel] = 0.0f;
|
||||
info.last_demand_set[channel] = ss_time();
|
||||
cm_msg(MLOG, "",
|
||||
"MPC_SetPressure is disabled - Not Setting Mercury ITC "
|
||||
"Pressure Setpoint in ODB");
|
||||
|
||||
info.recalculate = TRUE;
|
||||
}
|
||||
break;
|
||||
case 8: // min pressure
|
||||
case 9: // max pressure
|
||||
case 10: // pressure c1
|
||||
case 11: // pressure c2
|
||||
if (info.last_demand[channel] != value) {
|
||||
|
||||
std::string name, name1; // TODO : change to std::string
|
||||
|
||||
name = this->getDefaultName(channel);
|
||||
if (info.initialised)
|
||||
cm_msg(MLOG, "", "Channel %d (%s): output was %f now set to %f",
|
||||
channel, name.c_str(), info.last_demand[channel], value);
|
||||
else
|
||||
cm_msg(MLOG, "", "%s (Channel %d): Output is set to %f",
|
||||
name.c_str(), channel, value);
|
||||
|
||||
if (channel == 9) {
|
||||
if (info.last_demand[channel - 1] >= value) {
|
||||
name1 = this->getDefaultName(channel);
|
||||
|
||||
cm_msg(MERROR, "mitc_pressc_set",
|
||||
"%s should be larger than %s (%f)", name.c_str(),
|
||||
name1.c_str(), info.last_demand.at(channel - 1));
|
||||
}
|
||||
}
|
||||
info.last_demand[channel] = value;
|
||||
info.last_demand_set[channel] = ss_time();
|
||||
info.recalculate = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// all demand values set from ODB during init?
|
||||
if ((channel == info.num_channels - 1) && !info.initialised) {
|
||||
info.initialised = TRUE; // flag init done
|
||||
info.recalculate = TRUE; // flag to recalculate
|
||||
}
|
||||
|
||||
mitc_pressc_recalculate();
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
float itcPressureOptimizer::getDemand(int channel) {
|
||||
float pvalue;
|
||||
if ((channel >= 0) && (channel < info.num_channels)) {
|
||||
pvalue = info.last_demand.at(channel);
|
||||
} else {
|
||||
pvalue = -1.0f;
|
||||
}
|
||||
return pvalue;
|
||||
}
|
||||
|
||||
float itcPressureOptimizer::get(int channel) {
|
||||
// update variox readout
|
||||
mitc_pressc_update_mitc_input();
|
||||
|
||||
// update pressure demand readout
|
||||
mitc_pressc_update_pressure_demanded();
|
||||
|
||||
// recalculate pressure and nv%
|
||||
mitc_pressc_recalculate();
|
||||
|
||||
if ((channel == info.num_channels - 1) && !info.initialised)
|
||||
ss_sleep(1000);
|
||||
float pvalue;
|
||||
if ((channel >= 0) && (channel < info.num_channels)) {
|
||||
pvalue = info.last_measured[channel];
|
||||
|
||||
} else {
|
||||
pvalue = -1.0f;
|
||||
}
|
||||
|
||||
return pvalue;
|
||||
}
|
||||
|
||||
INT itcPressureOptimizer::mitc_pressc_get(INT channel, float *pvalue) {
|
||||
// update variox readout
|
||||
mitc_pressc_update_mitc_input();
|
||||
|
||||
// update pressure demand readout
|
||||
mitc_pressc_update_pressure_demanded();
|
||||
|
||||
// recalculate pressure and nv%
|
||||
mitc_pressc_recalculate();
|
||||
|
||||
if ((channel == info.num_channels - 1) && !info.initialised)
|
||||
ss_sleep(1000);
|
||||
|
||||
if (pvalue) {
|
||||
if ((channel >= 0) && (channel < info.num_channels)) {
|
||||
if (*pvalue != info.last_measured[channel]) {
|
||||
*pvalue = info.last_measured[channel];
|
||||
}
|
||||
} else {
|
||||
*pvalue = -1.0f;
|
||||
}
|
||||
}
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
Default threshold for measured values index threshold
|
||||
----------------------------------------------------------------------
|
||||
_Pressure 0 0.01
|
||||
_MercuryITCSetpoint 1 0.001
|
||||
_MercuryITCTemperat(ure) 2 0.0001
|
||||
_MercuryITCPower 3 0.1
|
||||
_AveragedPower 4 0.01
|
||||
_CalcPressure 5 0.01
|
||||
_PressureControlMode 6 -
|
||||
_SetRCPressure 7 -
|
||||
_PressureCalc_minPressure 8 0.01
|
||||
_PressureCalc_maxPressure 9 0.01
|
||||
_PressureCalc_const1 10 0.01
|
||||
_PressureCalc_const2 11 0.01
|
||||
*/
|
||||
|
||||
float itcPressureOptimizer::getDefaultThreshold(int channel) {
|
||||
switch (channel) {
|
||||
case 0:
|
||||
case 4:
|
||||
case 5:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
return 0.01f;
|
||||
break;
|
||||
case 3:
|
||||
return 0.1f;
|
||||
break;
|
||||
case 1:
|
||||
return 0.001f;
|
||||
break;
|
||||
case 2:
|
||||
return 0.0001f;
|
||||
break;
|
||||
default:
|
||||
return 1.0f;
|
||||
}
|
||||
return FE_SUCCESS;
|
||||
}
|
||||
|
||||
std::string itcPressureOptimizer::getDefaultName(int channel) {
|
||||
|
||||
int maxSize = Configuration::defaultLabels.size() - 1;
|
||||
if (channel > Configuration::defaultLabels.size() - 1 || channel < 0) {
|
||||
channel = Configuration::defaultLabels.size() - 1;
|
||||
}
|
||||
|
||||
std::string res = Configuration::defaultLabels.at(channel);
|
||||
printf("%s\n", res.c_str());
|
||||
return res;
|
||||
}
|
||||
@@ -1,65 +1,48 @@
|
||||
#ifndef ITC_PRESSURE_OPTIMIZER_H
|
||||
#define ITC_PRESSURE_OPTIMIZER_H
|
||||
|
||||
#include "itc_pressure_optimizer_info.h"
|
||||
#include "./handlers/DemandHandler.h"
|
||||
#include "./handlers/FeedbackHandler.h"
|
||||
#include "./handlers/InputHandler.h"
|
||||
#include "./handlers/OutputHandler.h"
|
||||
#include "./handlers/PressureCalculator.h"
|
||||
#include "./handlers/SettingsHandler.h"
|
||||
#include "EventBus.h"
|
||||
|
||||
#include "tmfe.h"
|
||||
#include <string>
|
||||
|
||||
class itcPressureOptimizer : public TMFeEquipment {
|
||||
|
||||
public:
|
||||
struct EquipmentInitEvent {};
|
||||
|
||||
struct EquipmentPollEvent {};
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param equipmentName for debug purpose, cpp file of the equipment
|
||||
*/
|
||||
itcPressureOptimizer(std::string equipmentName,
|
||||
const char *equipmentFilename, int channel);
|
||||
|
||||
TMFeResult HandleInit(const std::vector<std::string> &args);
|
||||
const char *equipmentFilename);
|
||||
|
||||
/**
|
||||
* @brief Method overridden called periodically by Midas
|
||||
*/
|
||||
void HandlePeriodic();
|
||||
|
||||
private:
|
||||
std::string equipmentPath;
|
||||
itcPressureOptimizerInfo info;
|
||||
/*
|
||||
Initialize ODB record for settings and initialized its variables and
|
||||
bus driver
|
||||
*/
|
||||
INT mitc_pressc_init();
|
||||
/*
|
||||
Exit routine
|
||||
*/
|
||||
INT mitc_pressc_exit();
|
||||
|
||||
/*
|
||||
read temperature setpoint, measured temperature and measured power
|
||||
from Mercury ITC device in ODB and calculate average power of the last
|
||||
30 sec
|
||||
*/
|
||||
INT mitc_pressc_update_mitc_input();
|
||||
|
||||
/*
|
||||
read demanded pressure (setpoint) from Mercury ITC (ODB Demand)
|
||||
*/
|
||||
INT mitc_pressc_update_pressure_demanded();
|
||||
/*
|
||||
Calculate pressure
|
||||
*/
|
||||
INT mitc_pressc_recalculate();
|
||||
|
||||
/*
|
||||
Set pressure to Mercury ITC
|
||||
*/
|
||||
INT mitc_pressc_set(INT channel, float value);
|
||||
/*
|
||||
????
|
||||
*/
|
||||
float getDemand(int channel);
|
||||
|
||||
/*
|
||||
|
||||
/**
|
||||
* @brief Method overridden called by Midas at initialization
|
||||
*/
|
||||
INT mitc_pressc_get(INT channel, float *pvalue);
|
||||
TMFeResult HandleInit(const std::vector<std::string> &args);
|
||||
|
||||
std::string getDefaultName(int channel);
|
||||
|
||||
float getDefaultThreshold(int channel);
|
||||
|
||||
float get(int channel);
|
||||
private:
|
||||
EventBus eventBus;
|
||||
DemandHandler demandHandler;
|
||||
SettingsHandler settingsHandler;
|
||||
InputHandler inputHandler;
|
||||
PressureCalculator pressureCalculator;
|
||||
FeedbackHandler feedbackHandler;
|
||||
OutputHandler outputHandler;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,85 +0,0 @@
|
||||
#ifndef ITC_PRESSURE_OPTIMIZER_CONFIG_H
|
||||
#define ITC_PRESSURE_OPTIMIZER_CONFIG_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Configuration {
|
||||
const std::string SLASH = "/";
|
||||
const std::string EQUIPMENT_DIR = "Equipment";
|
||||
|
||||
const std::string OUTPUT_VARNAME = "Output";
|
||||
const std::string INPUT_VARNAME = "Input";
|
||||
|
||||
const std::string SETTINGS_DIR = "Settings";
|
||||
const std::string VARIABLE_DIR = "Variables";
|
||||
|
||||
const std::string DEVICES_DIR = "Devices";
|
||||
const std::string MIT_DIR = "MITCPRESSC";
|
||||
const std::string DD_DIR = "DD";
|
||||
|
||||
const std::string MITC_EQUIPMENT_VARNAME = "MITC_Equipment";
|
||||
const std::string MITC_OUTPUT_PRESS_SP_INDEX_VARNAME =
|
||||
"MITC_OutputPressSPIndex";
|
||||
const std::string MITC_INPUT_VARIOX_SP_INDEX_VARNAME =
|
||||
"MITC_InputVarioxSPIndex";
|
||||
const std::string MITC_INPUT_VARIOX_TEMP_INDEX_VARNAME =
|
||||
"MITC_InputVarioxTempIndex";
|
||||
const std::string MITC_INPUT_VARIOX_POW_INDEX_VARNAME =
|
||||
"MITC_InputVarioxPowIndex";
|
||||
const std::string RECALC_INTERVAL_VARNAME = "RecalcInterval";
|
||||
const std::string MITC_READOUT_INTERVAL_VARNAME = "MitcReadoutInterval";
|
||||
const std::string PRESS_READOUT_INTERVAL_VARNAME = "PressReadoutInterval";
|
||||
|
||||
const std::string ENABLE_VARNAME = "Enable";
|
||||
const std::string NAMES_VARNAME = "Names";
|
||||
const std::string UPDATE_THRESHOLD_MEASURED_VARNAME =
|
||||
"Update Threshold Measured";
|
||||
|
||||
const std::string DEMAND_VARNAME = "Demand";
|
||||
const std::string MEASURED_VARNAME = "Measured";
|
||||
|
||||
const std::string MITC_EQUIPMENT_PATH = SETTINGS_DIR + SLASH + DEVICES_DIR +
|
||||
SLASH + MIT_DIR + SLASH + DD_DIR +
|
||||
SLASH + MITC_EQUIPMENT_VARNAME;
|
||||
const std::string MITC_OUTPUT_PRESS_SP_INDEX_PATH =
|
||||
SETTINGS_DIR + SLASH + DEVICES_DIR + SLASH + MIT_DIR + SLASH + DD_DIR +
|
||||
SLASH + MITC_OUTPUT_PRESS_SP_INDEX_VARNAME;
|
||||
const std::string MITC_INPUT_VARIOX_SP_INDEX_PATH =
|
||||
SETTINGS_DIR + SLASH + DEVICES_DIR + SLASH + MIT_DIR + SLASH + DD_DIR +
|
||||
SLASH + MITC_INPUT_VARIOX_SP_INDEX_VARNAME;
|
||||
const std::string MITC_INPUT_VARIOX_TEMP_INDEX_PATH =
|
||||
SETTINGS_DIR + SLASH + DEVICES_DIR + SLASH + MIT_DIR + SLASH + DD_DIR +
|
||||
SLASH + MITC_INPUT_VARIOX_TEMP_INDEX_VARNAME;
|
||||
const std::string MITC_INPUT_VARIOX_POW_INDEX_PATH =
|
||||
SETTINGS_DIR + SLASH + DEVICES_DIR + SLASH + MIT_DIR + SLASH + DD_DIR +
|
||||
SLASH + MITC_INPUT_VARIOX_POW_INDEX_VARNAME;
|
||||
const std::string RECALC_INTERVAL_PATH = SETTINGS_DIR + SLASH + DEVICES_DIR +
|
||||
SLASH + MIT_DIR + SLASH + DD_DIR +
|
||||
SLASH + RECALC_INTERVAL_VARNAME;
|
||||
const std::string MITC_READOUT_INTERVAL_PATH =
|
||||
SETTINGS_DIR + SLASH + DEVICES_DIR + SLASH + MIT_DIR + SLASH + DD_DIR +
|
||||
SLASH + MITC_READOUT_INTERVAL_VARNAME;
|
||||
const std::string PRESS_READOUT_INTERVAL_PATH =
|
||||
SETTINGS_DIR + SLASH + DEVICES_DIR + SLASH + MIT_DIR + SLASH + DD_DIR +
|
||||
SLASH + PRESS_READOUT_INTERVAL_VARNAME;
|
||||
|
||||
const std::string OUTPUT_PATH = VARIABLE_DIR + SLASH + OUTPUT_VARNAME;
|
||||
const std::string INPUT_PATH = VARIABLE_DIR + SLASH + INPUT_VARNAME;
|
||||
const std::string DEMANDE_PATH = VARIABLE_DIR + SLASH + DEMAND_VARNAME;
|
||||
const std::string MEASURED_PATH = VARIABLE_DIR + SLASH + MEASURED_VARNAME;
|
||||
|
||||
const std::vector<std::string> defaultLabels = {"Pressure Setpoint",
|
||||
"MPC_ITC_VarioxSP",
|
||||
"MPC_ITC_VarioxTemp",
|
||||
"MPC_ITC_VarioxPower",
|
||||
"MPC_AveragedPower",
|
||||
"MPC_CalcPressure",
|
||||
"Pressure Control Mode",
|
||||
"MPC_SetPressure",
|
||||
"MPC_PressCalcminPress",
|
||||
"MPC_PressCalcmaxPress",
|
||||
"MPC_PressCalc_const1",
|
||||
"MPC_PressCalc_const2",
|
||||
"NONE"};
|
||||
} // namespace Configuration
|
||||
#endif
|
||||
@@ -1,56 +0,0 @@
|
||||
#ifndef ITC_PRESSURE_OPTIMIZER_INFO_H
|
||||
#define ITC_PRESSURE_OPTIMIZER_INFO_H
|
||||
|
||||
#include "midas.h"
|
||||
#include "tmfe.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define MAX_HIS 100
|
||||
|
||||
class itcPressureOptimizerSettings {
|
||||
public:
|
||||
std::string mitcequipment; // equipment name of Mercury ITC
|
||||
INT setpressindex; // index of demanded/output pressure
|
||||
INT getvarioxspindex; // index of input setpoint (readout)
|
||||
INT getvarioxtempindex; // index of input temperature (readout)
|
||||
INT getvarioxpowindex; // index of input power (readout)
|
||||
INT recalcinterval; // interval [sec] to recalculate
|
||||
INT mitcinterval; // interval [sec] to update Mercury ITC readout
|
||||
INT pressinterval; // interval [sec] to update demanded pressure
|
||||
};
|
||||
|
||||
class itcPressureOptimizerInfo {
|
||||
public:
|
||||
itcPressureOptimizerSettings mitcpressc_settings;
|
||||
INT num_channels; // number of channels of this fe
|
||||
HNDLE hkey_demand; // ODB key to demand values of this equipment
|
||||
std::vector<float>
|
||||
last_demand; // last demand values (used to calculate pressure)
|
||||
std::vector<DWORD> last_demand_set; // last time a demand value was set
|
||||
std::vector<float> last_measured; // last "measured" values ***
|
||||
INT nvals_mitc_input; // number of variables in Mercury ITC input
|
||||
HNDLE hkey_mitc_input; // ODB key to Mercury ITC input
|
||||
std::vector<float> mitc_input; // readout of Mercury ITC equipment input
|
||||
DWORD last_mitc_input; // last time Mercury ITC input readout
|
||||
INT nvals_mitc_output; // number of variables in Mercury ITC output
|
||||
HNDLE hkey_mitc_output; // ODB key to Mercury ITC output
|
||||
float press_mitc_output; // readout of pressure setpoint from Mercury ITC
|
||||
DWORD last_press_mitc_output; // last time readout of pressure setpoint
|
||||
DWORD lastlog;
|
||||
std::string name; // equipment name to access this odb variables
|
||||
// directly
|
||||
BOOL initialised; // to flag everything is initialised
|
||||
BOOL recalculate; // to flag recalculate necessary after param change
|
||||
BOOL pending; // recalculation is pending due to insufficient info
|
||||
DWORD last_recalculated; // ss_time() when last recalculated
|
||||
INT ihis; // position of next value in history array
|
||||
float history[MAX_HIS]; // history[i] of Mercury ITC power output
|
||||
DWORD history_time[MAX_HIS]; // time when Mercury ITC power was written to
|
||||
// history[i]
|
||||
|
||||
std::string mitcPath;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -8,11 +8,67 @@ itcPressureOptimizerScfe::itcPressureOptimizerScfe(std::string frontendName,
|
||||
std::string equipmentName)
|
||||
: TMFrontend() {
|
||||
FeSetName(frontendName.c_str());
|
||||
FeAddEquipment(new itcPressureOptimizer(equipmentName, __FILE__, 12));
|
||||
FeAddEquipment(new itcPressureOptimizer(equipmentName, __FILE__));
|
||||
}
|
||||
|
||||
/**
|
||||
* Print help when argument are wrong or are
|
||||
*/
|
||||
void help(std::string binaryName) {
|
||||
TMFE::Instance()->Msg(
|
||||
MINFO, __FUNCTION__,
|
||||
"|HELP| itc pressure optimizer usage : %s <frontendName> "
|
||||
"<equipmentName>",
|
||||
binaryName.c_str());
|
||||
}
|
||||
|
||||
void wrong_argument(std::string binaryName) {
|
||||
TMFE::Instance()->Msg(MERROR, __FUNCTION__, "Wrong usage of %s",
|
||||
binaryName.c_str());
|
||||
help(binaryName);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
auto front = itcPressureOptimizerScfe("itcPressureOptimizerScfe",
|
||||
"itcPressureOptimizer");
|
||||
|
||||
if (argv[0][0] == '.') {
|
||||
TMFE::Instance()->Msg(MERROR, __FUNCTION__,
|
||||
"Relative paths are strongly discouraged; "
|
||||
"please use an absolute path.");
|
||||
}
|
||||
|
||||
if (argc == 1) {
|
||||
wrong_argument(std::string(argv[0]));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
std::string argument = std::string(argv[1]);
|
||||
if (argument == "--help" || argument == "-h") {
|
||||
help(std::string(argv[0]));
|
||||
exit(EXIT_SUCCESS);
|
||||
} else {
|
||||
wrong_argument(std::string(argv[0]));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
std::string frontendName;
|
||||
std::string equipmentName;
|
||||
if (argc > 2) {
|
||||
frontendName = std::string(argv[1]);
|
||||
equipmentName = std::string(argv[2]);
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
}
|
||||
|
||||
if (argc > 1) {
|
||||
TMFE::Instance()->Msg(
|
||||
MINFO, __FUNCTION__,
|
||||
"Unnecessary argument detected; this will be discarded");
|
||||
argv += (argc - 1);
|
||||
argc -= (argc - 1);
|
||||
}
|
||||
|
||||
auto front = itcPressureOptimizerScfe(frontendName, equipmentName);
|
||||
front.FeMain(argc, argv);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user