Qt source code for controlling Omron E5CC

These 2 weeks I was fiighting with the manual and try to control the device.

In my application, I need to change the temperature super slowly, not jump from 1 point to the other. I heard that there is an internal function called SP-ramp, that seem to fit my purpose, but I don’t really understand the manual….

The program can control most basic functions, record temperature, set the change rate of SP, limit the output (MV).

However, I don’t know how to get the RUN/STOP and AT (Auto-tune) status, so be careful.

The source code is in Github, feel free to download and modify. The program use Modbus for communication, so, you need to set the device.

https://github.com/TripletESR/Omron_PID

I also made a simplified manual, but I do not post in here for copyright issue. If you want, leave a massage.

Reason for n>l in atomic orbit

If we study atomic structure, we will find the principle quantum number must larger than azimuthal quantum number (the number of angular momentum), i.e.

$n > l$

But most text book give this result using mathematics that there is no solution for the radial equation when $n \leq l$. Some text book solves the radial equation using power series, and argue that the series has to be terminated at power of $n-1$ because the number of node is $n-1$.

Also, in nuclear physics, there is no restriction and $n$ and $l$ can take any integers. Why these two cases are different? of course, the key point is the potential difference. Coulomb potential is used in atomic orbit. Wood-Saxon potential (or finite square well ) is used in nuclear orbit.

The Schrodinger equation for potential $V(r)$ is

$\displaystyle \left( \frac{1}{r^2} \frac{\partial}{\partial r}\left( r^2 \frac{\partial}{\partial r}\right) - \frac{1}{r^2} L^2 - \frac{2m}{\hbar^2} V(r) \right) \psi(r, \Omega) = -\frac{2mE}{\hbar^2} \psi(r,\Omega)$

Separate the radial and spherical part $\psi(r, \Omega) = R(r) Y(\Omega)$

$\displaystyle L^2 Y(\Omega) = l(l+1) Y(\Omega)$

$\displaystyle \left( \frac{1}{r^2} \frac{d}{d r}\left( r^2 \frac{d}{d r}\right) - \frac{l(l+1)}{r^2} - \frac{2m}{\hbar^2} V(r) \right) R(r) = -\frac{2mE}{\hbar^2} R(r)$

The radial equation further reduce by using $u(r) = r R(r)$

$\displaystyle \frac{d^2 u}{dr^2} - \frac{2m}{\hbar^2} U(r) u(r) = \frac{2mE}{\hbar^2} u(r)$

we can see, the effective potential is

$\displaystyle U(r) = V(r) + \frac{\hbar^2}{2m} \frac{l(l+1)}{r^2}$

For Coulomb potential,

$\displaystyle U(r) = -\frac{e^2}{4\pi \epsilon_0 r} + \frac{\hbar^2}{2m} \frac{l(l+1)}{r^2}$

Introduce dimensionless quantities, or Express everything using the fine structure constant. $a_0$ is Bohr radius,

$\displaystyle \rho = \frac{2r}{a_0}, \lambda = \frac{e^2}{4\pi \epsilon_0} \sqrt{ - \frac{m}{2\hbar^2 E}} = n$

The equation becomes

$\displaystyle \frac{d^2u}{d\rho^2} + \left(\frac{\lambda}{\rho} - \frac{l(l+1)}{\rho^2}\right) u = \frac{1}{4} u$

The simplified effective potential,

$\displaystyle U(\rho) = \frac{n}{\rho} - \frac{l(l+1)}{\rho^2}$

Now, we related the principle quantum number and azimuthal quantum number in one simply formula.

Since the repulsive part due to the rotation is getting larger and larger, the minimum point of the effective potential is

$\displaystyle \rho_{min} = \frac{2l(l+1)}{n}$

When $l = n$, $\rho_{min} = 2(n+1) , r_{min} = (n+1)a_0$.

I plot the case for $n=2$

The bottom line is $l = 0$. We can see, when $l = 2$, the minimize point of the potential is at $r = 3 a_0$. The potential is vary shallow, and the bound state is very diffuses. Since the 2nd derivative of the wave function $u$ around the minimum point is

$\displaystyle \frac{d^2u}{d\rho^2} = \left( \frac{l(l+1)}{\rho^2} - \frac{n}{\rho} + \frac{1}{4} \right) u \approx \frac{1}{4} \frac{l(l+1) - n^2}{l(l+1)} u = k u$

For $l = n-1$ , $k$ is negative, that give oscillating wave function.

For $l = n$, $k$ is positive, that gives explosive wave function that cannot be normalized.

Therefore, $l < n$.

In fact, if we plot the effective potential,

$\displaystyle U(r) = -\frac{e^2}{4\pi \epsilon_0 r} + \frac{\hbar^2}{2m} \frac{l(l+1)}{r^2}$

we can find that when $l \geq 1$, the potential is also very shallow. For such a picture, we can see the wave function must be oscillating that the number of node must be larger then 1, so the principle quantum number should be larger than 1.

In nuclear orbit, the effective potential using Wood-Saxon potential is

$\displaystyle U(r) = -\frac{1}{1-\exp(\frac{r-R}{a})} + \frac{\hbar^2}{2m} \frac{l(l+1)}{r^2}$

where $R \approx 1.25 A^{1/3} [fm]$ and $a = 0.6 [fm]$. For simplicity, we use

$\displaystyle U(r) = -\frac{1}{1-\exp(\frac{r-R}{a})} + \frac{l(l+1)}{r^2}$

The position of minimum potential is no simple formula. I plot R=10,  a=1

We can see, for any $l < l_{u}$ there is a “well” that can bound a nucleon.

I haven’t solve the finite spherical well, but the infinite spherical well is solved. The solution is the spherical Bessel function of first kind. that function only has 1 parameter, which is the angular momentum. To determine the energy is simply find the node position, and the number of node is related to the principle quantum number. Therefore, the principle quantum number and angular momentum is unrelated. A similar result should be applied well in the case of finite spherical well like Wood-Saxon type, that, for a fixed angular momentum, there can be many solution with different number of nodes.

Wood-Saxon potential, the effective potential is always sloping, especially when outside of the well, that forces that wave function to be decay faster. However, the Coulomb potential is a long range force, the effective potential can be slowly changing for long distance, that allow the wave function to be oscillating for long range.

Express Hydrogen orbit using fine structure constant

The fine structure constant is

$\displaystyle \alpha = \frac{e^2}{4\pi \epsilon_0} \frac{1}{\hbar c}$

$\displaystyle a_0 = \frac{4\pi \epsilon_0}{e^2} \frac{\hbar^2}{m} = \frac{\hbar}{m c \alpha}$

The energy

$\displaystyle E_n = -\frac{1}{2n^2} \left(\frac{e^2}{2\pi \epsilon_0}\right)^2 \frac{m}{\hbar^2} = - \frac{1}{2} m (c\alpha)^2 \frac{1}{n^2}$

We can remember that the electron is traveling at $\alpha c$ at ground state.

When solving the radial part of the schrodinger equation, we can use

$\displaystyle \rho = \frac{2r}{a_0} = r\sqrt{- \frac{8mE}{\hbar^2}}$

$\displaystyle \lambda = n = \sqrt{ -\frac{mc^2 \alpha^2}{2 E}}$

Omron E5CC Modbus RTU in QT 101

The Omron E5CC temperature PID controller is using modbus RTU(Remote Terminal Unit) to connect.

First, you prepare a USB-to-RS-485 cable. Connect it to the E5CC. Notice that the A port of the E5CC, should be connected to  negative of the RS-485. Don’t follow the E5CC manual. Also the programing manual is extremely for expert of modbus, not for beginner.

In Modbus, the idea is that, your PC (master) send signal over the connected devices (slaves). The signal is a Hex, contained few things

DeviceID + Function-Code + Address + Command-in-Hex + CRC-16

The master send a signal, only the device with matching DeviceID will respond to the signal. Thus, there is no “locking” that link the master-slave.

The Function-Code is modbus function code, it tell the type of the signal. The type can be reading, writing, diagnostic, etc. This function is part of the modbus protocol, which is common for all devices.

The Address is the memory address stored in the device. The address should be provided by the device manufacture.

Then the command-in-Hex follow.

At the end, a 4-digit Hec CRC-16 is used for error check. Qt can calculate CRC-16 for modbus.

In the Omron E5CC programing manual. Section 4-4-1, we see that the data structure of a read signal. It is read because the Function-Code is 0x03, which is  “Read Holding Registers” in modbus RTU protocal. For example, reading the temperature (PV) of E5CC,

010300 0000 02 C4 0B

0x01 is deviceID, this can be set in the E5CC.

0x03 is the function code

0x0002 is number of value we are going to read. In modbus, one value contains 4-digit Hex, or 0xHHHH. In E5CC, each parameter is stored as 8-digit Hex, or 0xHHHHHHHH. Thus the E5CC manual tell us to get 2 values for temperature reading.

0xC408 is the CRC-16

The device return

01030400 00 03 E8 FA 8D

04 is the number of 8-digit Bin (2-digit Hex = 8-digit Bin). Four of 8-digit Bin = 8-digit Hex.

00 00 03 E8 is the return value of the temperature, converted to DEC is 1000, which is 100.0 ºC.

Run/Stop command

010600 0001 01 49 9A

0x06 is the “Write Single Register” function-Code

0x0101 is the value that start the run/stop for E5CC.

When writing single value in E5CC, only address 0x0000 is allowed. Thus, to write the SV (set value, or SP = Set Point) we have to use write multiple value. (stupid….)

Write multiple value

The set the alarm upper and lower values

011001 0A00 040800 00 03 E8FF FF FC18 8D E9

0x10 is the “Write Multiple Coils”

0x010A is the address of the alarm upper value

0x0004  is the 2 times number of value to be written. In our case, we want to write 2 value, thus the value is 0x4. The address of the next value would be 0x010A + 0x0002 = 0x010C. Since all value use 2 memory slots.

0x08 is the length of the input value. There are 2 value, each value is four 4-digit-Hex, so the input is 0x08.

0x000003E8 is the first value

0xFFFFFC18 is the 2nd value

This structure can also be use to write single value. If we want to change the SV (or Set Point) to 100 ºC. The address is 0x0106.

011001 0600 020400 00 00 64

In Qt, there is an example for modus, call master. We can use it for simple I/O.

Here is a screenshot.

First, we go to Tools to setup the Setting

In the E5CC, you have to set the communication mod to be modbus. In modbus, the parity, data bits, and stop bits are no used.

Since we use USB, this is serial port. The port number can be found using

const auto infos = QSerialPortInfo::availablePorts();
for (const QSerialPortInfo &info : infos) {
qDebug("PortName     ="+info.portName())
qDebug() <<"description  =" << (!info.description().isEmpty() ?  info.description() : blankString);
qDebug() <<"manufacturer =" << (!info.manufacturer().isEmpty() ? info.manufacturer() : blankString);
qDebug() <<"serialNumber =" << (!info.serialNumber().isEmpty() ? info.serialNumber() : blankString);
qDebug() <<"Location     =" << info.systemLocation();
qDebug() <<"Vendor       =" << (info.vendorIdentifier() ? QString::number(info.vendorIdentifier(), 16) : blankString);
qDebug() <<"Identifier   =  << (info.productIdentifier() ? QString::number(info.productIdentifier(), 16) : blankString);
}

In my case, it is COM4, so I put COM4 in the port. Then connect.

The read the temperature. We set the Table (at the lower left corner) to be Holding Register. In the Read (left panel), Start Address is 0, and Number of values to be 2. In the Qt application output, we will see:

qt.modbus: (RTU client) Sent Serial PDU: 0x0300000002
qt.modbus.lowlevel: (RTU client) Sent Serial ADU: 0x010300000002c40b
qt.modbus: (RTU client) Send successful: 0x0300000002
qt.modbus.lowlevel: (RTU client) Response buffer: “010304”
qt.modbus.lowlevel: (RTU client) Response buffer: “0103040000001cfbfa”

The PDU = Protocol Data Unit, ADU = Accessing Data Unit = DeviceID + PDU + CRC-16. In the last line, the received PDU is 0x03040000001c, the value is 0x0000 and 0x001c=28, which is 18 ºC.

The display in the GUI is:

Now, we try to stop the device.

In the write panel, Start address is 0x0000, and according to the E5CC programing manual, the value consist of two part

AA BB

AA is the command code

BB is the value

From the manual, the command code for RUN/STOP, 0xAA=0x01, and for STOP 0xBB=0x01. Thus, the value is 0x0101. Then we press write.

The Qt application output is

qt.modbus: (RTU client) Sent Serial PDU: 0x0600000101
qt.modbus.lowlevel: (RTU client) Sent Serial ADU: 0x010600000101499a
qt.modbus: (RTU client) Send successful: 0x0600000101
qt.modbus.lowlevel: (RTU client) Response buffer: “01”
qt.modbus: (RTU client) Modbus ADU not complete
qt.modbus.lowlevel: (RTU client) Response buffer: “010600000101499a”

And we can see there is a STOP display on the E5CC.

We can see, although the Holding Register is the same, in read, the function code is 0x03, in write, the function code is 0x06. In Qt manual, the QModBusPdu Class, we can see a list of Function-Code. (https://doc.qt.io/qt-5/qmodbuspdu.html#FunctionCode-enum)

This program is limited 10 address, so the operation is limited. This introduction is the basic, I think user can can study the Qt code to know how to use modbus, how to read and write signal. And people can read this website for another modbus 101.

Qt ActiveX COM

I found that most of the google result is not beginner friendly or not teach-me-as-if-i-am-five enough. Although I am also a beginner, anyway, so. in windows

First, we have a *.dll file which is your ActiveX COM (Component Object Model), we need to register the dll. For convenient, lets say the name of the dll is myAxtiveXCOM.dll. Run command prompt as administrator,

    regsvr32.exe  myActiveXCOM.dll

It will display a massage box telling you the register is successful. Then we need to local the ClassID (CLSID). Open regedit, find myActiveXCOM.dll, then you will find something like

    {BFD7A5AC-CCD3-449C-B99E-4A81DEE2527E}

or the NAME of the dll.

    QT += axcontainer

This is for local COM usage. Then,

    #include <QAxObject>

This enable to use QAxObject, which is an “extension” of QObject that included ActiveX.

    QAxObject *ax = new QAxObject();
ax->setControl("{BFD7A5AC-CCD3-449C-B99E-4A81DEE2527E}");

Then, you can debug, it should be fine and without any error message if the dll is registered correctly.

The activeX COM maker should provide a list of functions. for example, we have

int Connect(string device, int ID)

In QT,

    QVariant ans = ax->dynamicCall("Connect(QString&, int&)", "A", 2);

The dynamicCall is used to call the functions, the function augments has to be converted using Qt variable type. The dynamicCall will return the output. In the above example, Connect will return an integer, so ans will be like

QVariant(int, 1)

Since the dynamicCall can only pass a constant augment to the function of ActiveX COM. When some function is passed by reference, or the function will update the input argument. For example,

void Get_Model_Number(String name)

Then we have to first create a QList<QVariant>

    QList<QVariant> myStr;
myStr << "dummpy";
ax->dynamicCall("Get_Model_Number(QString&)", myStr);


Then, the variable myStr will be update and the value will be changed.

Molecular orbital

Using 2 hydrogen atom, we started from 2 atomic orbital (AO),

$\phi_1(\vec{r}) = \phi(\vec{r} - \vec{R_1})$

$\phi_2(\vec{r}) = \phi(\vec{r} - \vec{R_2})$

The atomic orbital $\phi$ is the ground state of hydrogen atom. From these 2 AO, we can construct linear combination of atomic orbitals (LCAO),

$\psi_1(\vec{r}) = A_1( \phi_1(\vec{r}) + \phi_2(\vec{r}))$

$\psi_2(\vec{r}) = A_2( \phi_1(\vec{r}) - \phi_2(\vec{r}))$

Notice that an electron can be in either $\psi_1$ or $\psi_2$, that means the electron is not belong to any atom, but belong to the molecule.

The last step is adding the spin, there are 2 spins $\alpha, \beta$, The molecular orbital (MO) are,

$\chi_1(\vec{r}) = \psi_1(\vec{r}) \alpha$

$\chi_2(\vec{r}) = \psi_1(\vec{r}) \beta$

$\chi_3(\vec{r}) = \psi_2(\vec{r}) \alpha$

$\chi_4(\vec{r}) = \psi_2(\vec{r}) \beta$

The Slater determinant can be formed by any 2 of them.

$\Psi = \sqrt{2}^{-1} ( \chi_1(\vec{r_1})\chi_2(\vec{r_2}) - \chi_2(\vec{r_1})\chi_1(\vec{r_2}) ) = |\chi_1\chi_2 \rangle$

We started by 1 atomic orbital, and there are and 2 atoms,  then 2 LCAOs are formed, and then multiplied by 2 spin states, gives 4 molecular orbitals. From these 4 MO and 2 electrons, we can from 6 different Slater determinant.

If we have different number of AO for different atom, we have AO

$\vec{n} = (n_1, n_2,..., n_k)$

The LCAO are

$\displaystyle \psi_i = \sum_{r=1}^k C_{ir} \phi_r, r = 1,2,..., n_k$

The total number of LCAO are all permutation of the AOs. A simple construction is that only plus or minus sign are used. Then the number of LCAO ( not orthonormal ) is

$\displaystyle K = 2^{-1} \prod_{i=1}^{k} (2n_i) = 2^{k-1} \prod_{i=1}^{k} n_i$

The MO are

$\chi_{2i-1} = \psi_i \alpha \\ \chi_{2i} = \psi_i \beta , i = 1,2,..., K$

Thus the number of Slater determinant are

$\displaystyle N = {}_{2K}C_p = \frac{(2K)!}{(2K-p)!p!}$

For example, we have 3 atoms, there are $(1, 2, 2)$ AO, there are 16 LCAOs. Thus, we have 32 MO. With 2 electrons, there are 496 Slater determinant.

For C-H molecule, there are 6 electrons for carbon and 1 electron for hydrogen, use 6 AOs for carbon and 1 AO for hydrogen, the number of MO is 24 and 346,104 Slater determinant.

When using all Slater determinant, it is called full CI.

When only increase the AO, but limited number of Slater determinant, The energy is called Hartree limit.

A problem is to construct LCAOs for arbitrary AOs. For example, for $(1,1,1)$ AOs, The number of possible combination with pule or minus sign is 4. However. I cannot construct orthonormal 4 LCAOs, because the system are over constrained (16 constrains with 12 unknown of $C_{ij}$)

A little summery of what I am doing

My current position is developing a computational program that can measure the system of polarized target automatically and repeatedly. The program needs to connect with the microwave generator, voltage supply, power meter, and oscilloscope. That is purely technical and nothing special.

Later, after the program started to collecting data, another program is needed to analysis the data. Although there are many program that can do analysis, but those program are not so easy to use, in both control and display. So, I make an analysis program. The program is simply read the 2-D time-domain signal, and then determine some parameters of a specific function that fit the signal. However, the signal could be very noisy, so FFTW and wavelet analysis were implemented. That’s why the wavelet analysis appeared in this blog.

After that, the sample of polarized target is made from various pentacene derivatives, that no known energy level exist. One way to find out the energy levels of the singlet excited states is to measure the absorption spectrum. However, the energy of the triplet state is difficult to measure. And the energy level of the triplet state is critical for Dynamic Nuclear Polarization to be happened. Thus, one way to find out is doing computation chemistry.

My last chemistry class was like 15 years ago, when I was junior high school. But the basic of computation chemistry is solving the Schrodinger equation. That is what theoretical nuclear physicists do! The variation method, the Hartree-fock method, I heard it and somehow know it, but never do it with my own hand and computer. That is why I revisit the Hartree-fock method, and found out my previous understanding is so naive.

In the course of studying Hartree-Fock method, and one problem is evaluating the overlap integral

$\displaystyle \int \psi_a(r_1) \psi_b(r_2) \frac{1}{r_{12}} \psi_c(r_1) \psi_d(r_2) dr_1dr_2$

For a 3-D system, the integral involves product of multiple spherical harmonics. That is really troublesome. Therefore, I move to study the spherical harmonics, and the related rotational invariant, Wigner D-matrix, Clebcsh-Gordon series and Fourier series.  The spherical harmonics arises from solving the Laplace equation in spherical coordinate. A general theory of the solution of Lapalace equation involves Legendre polynomial, which is a special case for Hypergeometric function.  And a very interesting connection is that the elliptical function of the 1st and 2nd kind are also two special cases of hypergeometric function, that, the solution of Laplace equation for elliptical boundary condition is elliptical functions. That connects spherical harmonics and elliptical function! Wow!

I am now a bit off-track, that I am very interesting on the function of all functions. We know that there are many elementary functions, such as sin, cos, and Log. And even more kind of special functions, such as

• Hermite — solving 1-D harmonic oscillator
• Laguerre — the radial function of hydrogen
• Legendre — the solution of the “$\theta$” of  Laplace equation
• Gamma — a continuation of factorial
• Bessel — solution of 3-D infinite square well
• Elliptic — magnetic field of a solenoid
• Dirac delta
• Gaussian or Error function

For discrete argument

• Clebsch-Gordon
• Factoral
• Binomial

As far as I know, the Hypergemetric function is like “mother of functions”, although not all special functions can be expressed as it. I am driven by curiosity, so, I am not sure where I will go. For instance, the transformation of Hypergeometric function is very interesting.

So, for now, as an ending, I found one article is very interesting. The History and Future of Special Functions, by Stephen Wolfram.