Source code: C++ Pressure Conversion Class 🛠

C++ source code for performing pressure conversions auto-magically.

This is for the DIY types that have some software background. Questions/comment/suggestions are great but I’d like to ask forum members to avoid the “what’s this good for” type questions within this thread to avoid clutter. You’ll either know what this is or you won’t (yet).

Current conversion types in this class include atmosphere, bar, kg/m^2, mmHg, kPa, psi, psf, and torr. This class handles conversion auto-magically including performance of math on disparate units.

This is an on-going project with several associated threads with differing objectives. Additional source, documentation, etc can be found by clicking on the “sourcecode” tag.

Updated to utilize c++ templates to reduce the source file size and eliminate the cpp file. The only disadvantage is that it’s more difficult to comprehend and assignments between units using “=” requires a type cast to the destination unit (because I couldn’t figure out a clean way to automate the type case magically using templates).

Header:

//
// pressure_types.h
// Version timestamp: 10-25-2018, 11:42 PM
//
// Attribution : Copyright (c) 2018 Northern_Loki (sha256::6F290BF833967127BE26C92C8F6B1C1A3949C55A7EABCEF3ECC785CD2D38D30D)
// License is granted under the Creative Commons Attribution-ShareAlike 4.0 International.  https://creativecommons.org/licenses/by-sa/4.0/
//

//
//
// Some usage examples: 
//


# pragma once

# include <string>
# include <sstream>
# include <boost/variant.hpp>
# include <iostream>

# include "Constants.h"


/***********************************************************************/
/*                                                                     */
/*                    Conversion Template                              */
/*                                                                     */
/***********************************************************************/
template <class T> class Pressure_Convert; 
class tatmosphere_variant; class tbar_variant; class tkilogram_meter_variant; class tmmHg_variant; class tkPa_variant; class tpsi_variant; class tpsf_variant; class ttorr_variant;
typedef Pressure_Convert<tatmosphere_variant> atmosphere;
typedef Pressure_Convert<tbar_variant> bar;
typedef Pressure_Convert<tkilogram_meter_variant> kilogram_meter;
typedef Pressure_Convert<tmmHg_variant> mmHg;
typedef Pressure_Convert<tkPa_variant> kPa;
typedef Pressure_Convert<tpsi_variant> psi;
typedef Pressure_Convert<tpsf_variant> psf;
typedef Pressure_Convert<ttorr_variant> torr;


typedef boost::variant<atmosphere, bar, kilogram_meter, mmHg, kPa, psi, psf, torr, double> pressure_variant;

template <class T> 
    class Pressure_Convert 
    { 
    private: 
        
    public: 
        double pressure = 0.0;
        Pressure_Convert(); 
        Pressure_Convert(double r) { this->pressure = r; }
        Pressure_Convert(const pressure_variant &c)
        {
            this->pressure = boost::apply_visitor(T(), c); 
        }
        void operator=(double c)
        {
            this->pressure = c;
        }
        void operator=(pressure_variant c)
        {
            this->pressure = boost::apply_visitor(T(), c); 
        }
        virtual double operator()() {return (this->pressure);}
        virtual double operator()(pressure_variant temp2) {return (boost::apply_visitor(T(), temp2));}
        virtual double operator-(pressure_variant temp2){return (this->pressure - boost::apply_visitor(T(), temp2));}
        virtual double operator+(pressure_variant temp2){return (this->pressure + boost::apply_visitor(T(), temp2));}
        virtual double operator*(pressure_variant temp2){return (this->pressure * boost::apply_visitor(T(), temp2));}
        virtual double operator/(pressure_variant temp2){return (this->pressure / boost::apply_visitor(T(), temp2));}
        virtual double operator-=(pressure_variant temp2){this->pressure -= boost::apply_visitor(T(), temp2); return (this->pressure);}
        virtual double operator+=(pressure_variant temp2){this->pressure += boost::apply_visitor(T(), temp2); return (this->pressure);}
        virtual double operator*=(pressure_variant temp2){this->pressure *= boost::apply_visitor(T(), temp2); return (this->pressure);}
        virtual double operator/=(pressure_variant temp2){this->pressure /= boost::apply_visitor(T(), temp2); return (this->pressure);}
        virtual double operator>(pressure_variant temp2){if (this->pressure > boost::apply_visitor(T(), temp2)) return (1);return (0);} 
        virtual double operator<(pressure_variant temp2){if (this->pressure < boost::apply_visitor(T(), temp2)) return (1);return (0);}
        virtual double operator>=(pressure_variant temp2){if (this->pressure >= boost::apply_visitor(T(), temp2)) return (1);return (0);} 
        virtual double operator<=(pressure_variant temp2){if (this->pressure <= boost::apply_visitor(T(), temp2)) return (1);return (0);} 
        virtual double operator==(pressure_variant temp2){if (this->pressure == boost::apply_visitor(T(), temp2)) return (1);return (0);} 
        friend std::ostream& operator<<(std::ostream& lhs, const Pressure_Convert& rhs)
        {
            return (lhs << rhs.pressure);
        }
    }; 


/***********************************************************************/
/*                                                                     */
/*                      Atmosphere Conversion                          */
/*                                                                     */
/***********************************************************************/
class tatmosphere_variant : public boost::static_visitor<double>
{
public:
    double operator()(double c) const { return (c); }
    double operator()(atmosphere c) const { return (c.pressure); }
    double operator()(bar c) const { double temp = c.pressure * 0.986923266716; return (temp); } 
    double operator()(kilogram_meter c) const { double temp = c.pressure * 0.00009678411053541; return (temp);}
    double operator()(mmHg c) const { double temp = c.pressure * 0.001315789473684; return (temp);}
    double operator()(kPa c) const { double temp = c.pressure * 0.00986923266716; return (temp); }
    double operator()(psi c) const { double temp = c.pressure * 0.0680458919319; return (temp); }
    double operator()(psf c) const { double temp = c.pressure * 0.0004725409161938; return (temp); }
    double operator()(torr c) const { double temp = c.pressure * 0.001315789473684; return (temp); }
};

/***********************************************************************/
/*                                                                     */
/*                         Bar Conversion                              */
/*                                                                     */
/***********************************************************************/
class tbar_variant : public boost::static_visitor<double>
{
public:
    double operator()(double c) const { return (c); }
    double operator()(bar c) const { return (c.pressure); }
    double operator()(atmosphere c) const { double temp = c.pressure * 1.01325; return (temp); } 
    double operator()(kilogram_meter c) const { double temp = c.pressure * 0.0000980665; return (temp);}
    double operator()(mmHg c) const { double temp = c.pressure * 0.001333223684211; return (temp);}
    double operator()(kPa c) const { double temp = c.pressure * 0.01; return (temp); }
    double operator()(psi c) const { double temp = c.pressure * 0.0689475; return (temp); }
    double operator()(psf c) const { double temp = c.pressure * 0.0004788020833333; return (temp); }
    double operator()(torr c) const { double temp = c.pressure * 0.001333223684211; return (temp); }
};

/***********************************************************************/
/*                                                                     */
/*                    kilogram_meter Conversion                        */
/*                                                                     */
/***********************************************************************/
class tkilogram_meter_variant : public boost::static_visitor<double>
{
public:
    double operator()(double c) const { return (c); }
    double operator()(kilogram_meter c) const { return (c.pressure); }
    double operator()(atmosphere c) const { double temp = c.pressure * 10332.274528; return (temp); } 
    double operator()(bar c) const { double temp = c.pressure * 10197.16212978; return (temp);}
    double operator()(mmHg c) const { double temp = c.pressure * 13.59509806316; return (temp);}
    double operator()(kPa c) const { double temp = c.pressure * 101.9716212978; return (temp); }
    double operator()(psi c) const { double temp = c.pressure * 703.068835943; return (temp); }
    double operator()(psf c) const { double temp = c.pressure * 4.882422471826; return (temp); }
    double operator()(torr c) const { double temp = c.pressure * 13.59509806316; return (temp); }
};

/***********************************************************************/
/*                                                                     */
/*                         mmHg Conversion                             */
/*                                                                     */
/***********************************************************************/
class tmmHg_variant : public boost::static_visitor<double>
{
public:
    double operator()(double c) const { return (c); }
    double operator()(mmHg c) const { return (c.pressure); }
    double operator()(atmosphere c) const { double temp = c.pressure * 760.0; return (temp); } 
    double operator()(bar c) const { double temp = c.pressure * 750.0616827042; return (temp);}
    double operator()(kilogram_meter c) const { double temp = c.pressure * 0.07355592400691; return (temp);}
    double operator()(kPa c) const { double temp = c.pressure * 7.500616827042; return (temp); }
    double operator()(psi c) const { double temp = c.pressure * 51.71487786825; return (temp); }
    double operator()(psf c) const { double temp = c.pressure * 0.3591310963073; return (temp); }
    double operator()(torr c) const { double temp = c.pressure * 1.0; return (temp); }
};

/***********************************************************************/
/*                                                                     */
/*                         kPa Conversion                             */
/*                                                                     */
/***********************************************************************/
class tkPa_variant : public boost::static_visitor<double>
{
public:
    double operator()(double c) const { return (c); }
    double operator()(kPa c) const { return (c.pressure); }
    double operator()(atmosphere c) const { double temp = c.pressure * 101.325; return (temp); } 
    double operator()(bar c) const { double temp = c.pressure * 100.0; return (temp);}
    double operator()(kilogram_meter c) const { double temp = c.pressure * 0.00980665; return (temp);}
    double operator()(mmHg c) const { double temp = c.pressure * 0.1333223684211; return (temp); }
    double operator()(psi c) const { double temp = c.pressure * 6.89475; return (temp); }
    double operator()(psf c) const { double temp = c.pressure * 0.04788020833333; return (temp); }
    double operator()(torr c) const { double temp = c.pressure * 0.1333223684211; return (temp); }
};

/***********************************************************************/
/*                                                                     */
/*                         PSI Conversion                             */
/*                                                                     */
/***********************************************************************/
class tpsi_variant : public boost::static_visitor<double>
{
public:
    double operator()(double c) const { return (c); }
    double operator()(psi c) const { return (c.pressure); }
    double operator()(atmosphere c) const { double temp = c.pressure * 14.69596432068; return (temp); } 
    double operator()(bar c) const { double temp = c.pressure * 14.50378911491; return (temp);}
    double operator()(kilogram_meter c) const { double temp = c.pressure * 0.001422335835237; return (temp);}
    double operator()(mmHg c) const { double temp = c.pressure * 0.01933679515879; return (temp); }
    double operator()(kPa c) const { double temp = c.pressure * 0.1450378911491; return (temp); }
    double operator()(psf c) const { double temp = c.pressure * 0.006944444444444; return (temp); }
    double operator()(torr c) const { double temp = c.pressure * 0.01933679515879; return (temp); }
};


/***********************************************************************/
/*                                                                     */
/*                         PSF Conversion                             */
/*                                                                     */
/***********************************************************************/
class tpsf_variant : public boost::static_visitor<double>
{
public:
    double operator()(double c) const { return (c); }
    double operator()(psf c) const { return (c.pressure); }
    double operator()(atmosphere c) const { double temp = c.pressure * 2116.218862178; return (temp); } 
    double operator()(bar c) const { double temp = c.pressure * 2088.545632547; return (temp);}
    double operator()(kilogram_meter c) const { double temp = c.pressure * 0.2048163602741; return (temp);}
    double operator()(mmHg c) const { double temp = c.pressure * 2.784498502865; return (temp); }
    double operator()(kPa c) const { double temp = c.pressure * 20.88545632547; return (temp); }
    double operator()(psi c) const { double temp = c.pressure * 144.0; return (temp); }
    double operator()(torr c) const { double temp = c.pressure * 2.784498502865; return (temp); }
};

/***********************************************************************/
/*                                                                     */
/*                         torr Conversion                             */
/*                                                                     */
/***********************************************************************/
class ttorr_variant : public boost::static_visitor<double>
{
public:
    double operator()(double c) const { return (c); }
    double operator()(torr c) const { return (c.pressure); }
    double operator()(atmosphere c) const { double temp = c.pressure * 760.0; return (temp); } 
    double operator()(bar c) const { double temp = c.pressure * 750.0616827042; return (temp);}
    double operator()(kilogram_meter c) const { double temp = c.pressure * 0.07355592400691; return (temp);}
    double operator()(mmHg c) const { double temp = c.pressure * 1.0; return (temp); }
    double operator()(kPa c) const { double temp = c.pressure * 7.500616827042; return (temp); }
    double operator()(psi c) const { double temp = c.pressure * 51.71487786825; return (temp); }
    double operator()(psf c) const { double temp = c.pressure * 0.3591310963073; return (temp); }
};

CC BY-SA 4.0

1 Like

Usage example:

	/* Create example units initialized in a variety of ways */
	atmosphere my_atm(1.01);
	bar my_bar = (bar) my_atm;
	kilogram_meter my_kgm2(my_bar);
	mmHg my_mmHg = (mmHg)my_kgm2;
	kPa my_kPa(my_mmHg);
	psi my_psi(my_kPa);
	psf my_psf(my_psi);
	torr my_torr(my_psf);
	
	std::cout << "atmosphere: " << my_atm << std::endl;
	std::cout << "bar: " << my_bar << std::endl;
	std::cout << "kilogram_meter: " << my_kgm2 << std::endl;
	std::cout << "mmHg: " << my_mmHg << std::endl;
	std::cout << "kPa: " << my_kPa << std::endl;
	std::cout << "psi: " << my_psi << std::endl;
	std::cout << "psf: " << my_psf << std::endl;
	std::cout << "torr: " << my_torr << std::endl;
	std::cout << "atmosphere: " << (atmosphere)my_torr << std::endl;
	
	mmHg pressure_math = 767.6;
	pressure_math += my_atm;
	pressure_math += my_bar;
	pressure_math += my_kgm2;
	pressure_math += my_mmHg;
	pressure_math *= my_kPa;
	pressure_math /= my_psi;
	pressure_math -= my_psf;
	pressure_math += my_psf;
	
	/* Should be ~= 5.05 atm */
	std::cout << "Total atmospheres (atm): " << (atmosphere)pressure_math << std::endl;

Produces:

atmosphere: 1.01
bar: 1.02338
kilogram_meter: 10435.6
mmHg: 767.6
kPa: 102.338
psi: 14.8429
psf: 2137.38
torr: 767.6
atmosphere: 1.01
Total atmospheres (atm): 5.05

CC BY-SA 4.0

1 Like

First, I have dabbled in programming here and there over the years. I took classes in Basic, and Fortran in college - that was back in the punch card days. Then, many years later, I taught myself some (very little) SQL programming to customize an old windows database program - back in the Windows 3 days. More recently, I have played around with programming Arduino stuff, but not with much success and no joy at all.

All of that is leading up to me admitting that #1 - I HATE PROGRAMMING!!! and #2 - I am not good at it. I just dont have the correct mind set. Plus every other thing I type is a typo :slight_smile:

Never the less, I am intrigued by what you can do with (other peoples) programming. So… where can/should we ask those types of beginner questions?

P.S. Feel free to delete this post :smiley:

1 Like

I may start a beginners programming thread then if you would like to know more about arduinos and similar. Arduinos use C#, which is a little different to this AFAIK.

Looks a handy program. It has given me ideas on how to proceed with a unit conversion section I needed to do in Python. Less complicated than this though, just EC:TDS:uS/cm

2 Likes

This, along with the other source pieces, are simply “snippets” of functionality that one could utilize to as a reference or to build into their application / program(s) / target platform.

This is part of a somewhat larger agenda that will reveal itself over time which will eventually include information on how to use these pieces together on a specific target platforms. But, in general, these “snippets” are intended to be platform agnostic under the GNU Toolchain. They are used for core / utility functionality in larger scope projects.

Basically, it is meant to help get folk up and running with their ambitions a bit quicker, open a channel for sharing of useful source code bits and ideas, and to help spur innovation. One of the largest time sinks when a person has a great idea is the development of the preliminaries. These “snippets” might help reduce that burden.

So, to address your comment somewhat generally:

The other time sink, is simply learning/re-learning how to program/integrate pieces of a system. Beyond anything but the most simplistic system, add a unique embedded system element along with a lot of technobabble, it is huge challenge for certain. There is a lot of frustration, no doubt, because it’s difficult to achieve “your” vision since you’d have to work out all of the preliminaries first. A small portion of the preliminaries might include some of these “snippets” for instance. Combine these snippets with a bowl of your favorite herb and hopefully it’ll help alleviate some of the “I hate this” feelings.

I will say you are not alone. I can’t blame you for not liking programming because I kind-of hate programming, too. It’s time consuming to achieve your vision with lots of hair pulling and cussory to get there (because who really wants to program this type of minutia, I want to see the lights blinking! Now!). But, but, the satisfaction when you do get things figured out is pure gold. And, to point out, once you become familiar with a platform, a programming language, and methodology, your speed and success will grow exponentially. It is worth the pain and effort in the long run. You are way ahead of the curve since you already have experience with different languages.

Getting folk started up is huge challenge/problem in itself. We do need some threads to help with this challenge. Particularly introductory threads that address the interests of this community. The specific posts I’ve been contributing with the source code “snippets” are not intended to perform that duty.
Also, as a side note, I can see a place for a category dedicated specifically for programming / development related threads. Maybe, with increasing interest and contribution, over time we’ll get to that point.

But for now, there is a huge body of information on the interwebs on getting started with nearly every color of embedded platform out there. The most prolific platform on the “maker” scene is probably the “Arduino” platforms. It is inexpensive, great for rapidly prototyping ideas, for one offs, and one sourced concepts. It has a large following and large amount of community support. It is not a particularly good platform for advanced or custom system development, performance based application, or for commercialization. But, the decision on what platform/language is best answered early by addressing your long-term “goals”.

Technical discussions tied to specific languages, platforms, and methods are the mosh pits of flame wars. Folk are particularly protective of their programming language choices and platforms. Sometimes geek fights break-out without reason, rationale, or insight. Hence the reason for starting with platform agnostic “snippets”, here.

As an FYI,
Program Your Arduino with the Eclipse C/C++ IDE

By the way, Larry, aren’t you controlling your HPA system with an embedded system of some flavor?

If you want to try something specific to your system with these snippets (it’s generic c++), open-up a thread and we’ll try to address a way to achieve that. Or, PM me, and I’ll try to help. Would be a good trial case.

FWIW, other snippets can be found under the tag sourcecode

1 Like

Interesting thread!

soon(ish) I’ll start hacking with my NodeMcu board which can be programmed with Lua, or directly in c extending the firmware but for now Lua will be enough.

If there is interest in this topic I can help creating content to get people started

3 Likes

Start a thread, see who pops out of the wood work.

99

2 Likes

Most certainly, help spur the ideas of the community. Improve our confidence with DIY projects. Show us what can be done! :+1:

2 Likes

Yup. I will tag along for sure :slight_smile:

1 Like

I have to finish my second micro box this w/e but if there will be enough time I’ll start documenting my grow and maybe introduce a bit what I want to do with my tools and how I am going to do it

but, if anyone is interested this is a good starting point on the hardware side NodeMCU - Wikipedia
and https://www.lua.org/ for the software part

compared to c/c++, c# and java, lua is really simple and hides a lot of complexity behind the scenes

1 Like

Im not using anything other than two simple, cheap timers for the spray nozzles and a couple of sonoff’s - one for lights and one for the rez circulating pump. There is no real programming involved beyond pushing some buttons to adjust on/off times.

Ive been thinking about what you said about the ton of information out there for Arduino, and some of the other platforms, languages etc. Part of the problem I have run into is that there is TOO much info, but it isnt sorted into easy to get started chunks.

I have asked questions before in forums about how to choose which Arduino hardware and do the programing to accomplish some goal in my RC hobby. Things like trying to get my GPS sensor to talk to my altimeter and get both to send the data to my receiver so I can log data or control motor speeds, etc.

The problem I have always run into is that the answers you get never seems to fit my level of understanding. The answers always seem to leave out most of the critical steps you need to get from A to B. It is assumed that you already know all about the hardware, how/where to connect things together, which interfaces are needed and when, what wires to jumper, switch settings etc, pinouts, etc etc etc.

On the programming side, there never seems to be a good level of programming help either. If I ask in the beginners sections, Im told that my questions are too advanced. I need to work my way up and learn A, B, C and D first. OR, I get answers like "all you need to do is obfuscate the second and fifty third frumble zappers and set the corresponding quizzlesticks to match the class action variables, then just set the QSR so that the GGT2123 is set to super position mode and you will be all set. Of course, dont forget about the quark entanglement variables, but you knew that right? Easy peasy. Anyone can do it. No problem… but if you cant figure out the easy stuff, then maybe you should go back to the beginner forums…

The problem is, I have zero desire to learn everything I need to know about the hardware from the ground up, and then learn a whole programming language, and THEN finally get around to building and programming somethiing to do what I want. I just dont have the time or energy for that any more.

I suspect there are a lot of people like me out there. What we need/want is to have our hands held for every single step. We need to be told what exact hardware to buy, and how to connect it up in minute detail. Then we need someone else to actually DO the bulk of the programming, AND tell us how to get that software onto the hardware. We will probably need help de-bugging connection screw ups and finding typos, glitches etc etc.

All of that amounts to a huge commitment in time and trouble from the helpers.

This is not unlike someone with no growing experience trying to grow weed. Fortunately, they can come to OG and get help from a large community, so the work load tends to be spread out. A newbie asks “How do I do X, y or z?” and a dozen people will give answers that added up together usually are enough to get them going.

It would be great if there was a group of experts like that who could share the burden of helping folks like me who just want to build an inexpensive PH auto-doser, controller, but who dont want to spend the next 6 months studying.

Its a LOT to ask.

1 Like

Oh boy, this is a very thoughtful response and I agree with that assessment for the most part. You’ve packed a lot in there.

I had started to compose some thoughts with both the negative and positive aspects. But decided to step-away to re-compose the response introspectively. So, give me a bit to think.

I’d like to discuss this a bit more and how we (the community) might be able to attack such a challenge over a longer term time-frame and how, for this example, “sourcecode” fits into such a narrative (order of events).

1 Like

Thanks, Im looking forward to your reply.

One idea might be for someone to start a thread with a very narrow, specific goal. For example, I think lots of folks would like to automate PH adjustments in the rez, but have no clue how to start, and cant afford to buy a ready made product.

Then, maybe several of you experts can make suggestions and share the work load. If that works, it could help a lot of people to get started in automating their grows without going broke or getting so frustrated they give up :slight_smile:

Once that project was done, it should be relatively easy - or at least easier - to go from there to the next automation step.

Well this is really a nice idea, I mean why starting to implement something that no one will care about when there are lots of real life problems to be solved?
That said I know nothing about PH meters and ways to adjust a solution’s PH but that would be an interesting problem to solve and reason about

What are you referring to, “why starting to implement something that no one will care about”?

And then, “there are lots of real life problems to be solved.”
As compared to?

I was referring to my project, sorry, I should have specified it to avoid misinterpretation of my message.

What I am working on is a generic system to collect data and act upon it

Since I have no experience in what can be useful to growers in general, I was wandering what I can focus on with my experiments.

1 Like

Its waaaay to easy to misinterpret what someone types on the interweb - and - to type something that comes across in a way thats exactly the opposite of what you intended. I am certainly guilty of doing both. Thanks for clearing that up :slight_smile:

But, to continue the discussion, here is what I have in mind as a group project. Anyone doing hydro would benifit from a PH controller. Here is one from BlueLab that is actually reasonably priced for a commercial product - $300 or so.

However, I certain one could be built, that worked just as well, and that the average handy person could assemble, for a lot less $$$.

The missing ingredient is the specialized, and detailed knowledge needed to choose the electronics, and write a program for it.

I have some ideas for a simple gravity fed, servo driven pump/flow switch that could be controlled via PWM input to a servo controller, or the servo could be driven directly from the ‘mother board’ is it could do PWM.

However, I have no idea how to get the servo controller, or the servo, to talk to the ‘mother board’ or how to get the sensor inputs to drive anything, or what exact hardware would be needed, etc etc etc.

I think this would be a very valuable thing for the community, and a lot of fun - but - it wont work unless at least a few of those experts are willing to commit their time and trouble.

I will repeat - This is a very selfish thing for those of us who are ‘programing challenged’ to ask, so dont anyone feel obligated or guilty for not wanting to spend a ton of time with little reward.

Actually, this is way off topic to @Northern_Loki original topic. Id be happy to delete this and just start a new thread if you want.

1 Like