AzeoTech

Administrators
  • Posts

    6,432
  • Joined

Posts posted by AzeoTech

  1. The output of the autotune is calced as:

    Out = U + (-2 * (up < 0) + 1) * H

    where U is the output value the instant you start the autotune, H is the specified height, and UP is the effect from the P part of the PID.  In this case it really is just telling us which direction we need to go and just makes H positive or negative.  The Out is then inverted if the PID is reverse acting and constrained by the out min/max.  

    The result is calculated based on the period of oscillation and the actual deviation from the set point, and is recalced with every oscillation:

    K = (autoTuneHeight / (maxPVinLastOscillation - SetPoint))
    P_Result = K * x2
    D_Result = periodOfOscillation; * x3
    I_Result = periodOfOscillation; * x4

    K is just a temp variable.  x1-x4 are various constants

  2. No idea, but that graph is just like the regular trend graph component on your pages.  You can open its properties by double clicking on the center of it.  Then check for three expressions.  They all will start with "PID.PID1." and then you'll have PVHistory, OVHistory and SPHistory.  Also check the axis scaling.

    As a side note, these variables, PID.PID1.PVHistory etc, are globally available so you can create your own graph of the PID parameters and their history on your own pages.

  3. In general most alarms will want to have hysteresis built in, so simply doing the inverse of the Fire condition doesn't work.  In cases where it is just a digital signal, from, say, a PLC, typically it is just one digital signal, so doing the ! of that signal isn't much effort.  That all said, we have, a believe, corrected the situation in the next DAQFactory release.  You are welcome to try a beta if you'd like.  Just email us at support@.

  4. It looks like the alarm condition is evaluated at global scope, so there is no direct shortcut.  The only solution I have for you is to create a calculated virtual channel with the complex equation, then set the Condition for the alarm to V.MyAlarmState[0] and the reset condition to !V.MyAlarmState[0].

    Alternatively, you could write a simple script to set the reset condition equal to the inverse of the condition.  It'd be something like:

    private string alarmList = alarm.listAll()
    for (private i = 0, i < numrows(alarmList), i++)
       private string cond = evaluate("alarm." + alarmList[i] + ".strCondition")
       execute("alarm." + alarmList[i] + ".strResetCondition = '!(" + cond + ")'")
    endfor

    Run this every time you change / add an alarm and it will update all the reset conditions.

     

  5. You'd be best served by simply putting the relay control part inside its own sequence inside its own while() loop and just run that at the same time.  Alternatively, you could just use the Event of the PID and control the relay directly.  The other possibility is to put a Conversion on relay_control.  It would just be:

    Value >= 0

    Then if you set relay_control to any value > 0 it will turn on, but if you set it to any value < 0 it will turn off.  Then you don't need the loop, the if() or even the Out channel and can simply have the PID update relay_control directly.

  6. You are setting an output, not reading the state of that output so your hardware configuration isn't going to matter.  In fact, you could test by simply changing the channel from a LabJackUD device to a Test Device Dig Out channel and you will likely see the same behavior.

    Any chance I can remote into your system to just see?  You are doing something that isn't getting across in these forum posts.  Just email us direct at support @.

    The UD devices I believe output 3.3V when active, but that is more a question for LabJack.

  7. OK.  So first you'll need to get the digital output to work correctly per your other post.  Once you have that you'll want to get a PWM setup.  That is relatively straight forward in software, but you might consider using the LabJack's PWM feature of its counter.  If so, refer to 10.5.1 of the DAQFactory - LabJack Application Guide PDF included with the DAQFactory download.

    For software PWM, I'm going to assume you are going to stick with the name "relay_control" for your output channel.  In that case you will want to create a sequence.  Call it, say, PWMRelayController:

    global relay_control_PWM = -100 // -100 to 100
    while(1)
       relay_control = (systime() % 1) * 200 < (relay_control_PWM+100)
       delay(0.02)
    endwhile

    This gives a PWM with a period of 1 second and a resolution of 50 steps, which is probably plenty.   You can mark this sequence Auto-Start and just let it run all the time.  Then, you can change the new relay_control_PWM variable from -100 (always off) to 100 (always on) or anywhere in between and it will PWM the relay.  The easiest way to see this is to create a graph of relay_control vs time.  I chose -100 to 100 because those are the best numbers for the PID loop.  The Output Channel of your PID loop will be  the variable relay_control_PWM.

    Once you have that working, you can work on the PID loop.  The process variable will be TC[0] or whichever channel has the temperature reading you are controlling.  The output channel will be Relay_control_pwm as I mentioned.  For now, set the setpoint manually to a single value, say 10.  You can change it and hit Apply and it will update.  We will work on doing your Ramp/Soak later.  It is important that you get this part working first before making things more complicated.  

    For anyone who wants to understand the logic of the PWM script I provided, specifically the 3rd line:

    (systime() % 1) returns a number between 0 and 1 corresponding to the decimal part of the current second.  This gets multiplied by 200 to get it into the full range of relay_control_PWM (which as I mentioned should go from -100 to 100 because that is what the PID loop likes), so a number from 0 - 200 depending on when in the second the code gets executed.  We then compare it to our current relay_control_PWM setting which we shift by 100 to make also 0-200.  DAQFactory boolean is similar to other languages, where 1 is true, and 0 is false, so the result of that comparison sends a 0 or 1 to the actual relay output.

     

  8. Sequences are objects within DAQFactory script, so you can reference their status, start and stop them, etc.  So, when you name a sequence the same as a Channel or variable, you now have two different objects in DAQFactory that have the same name.  DAQFactory has a particular order for checking names and Sequence names are checked before Channel names.  So, once you created a sequence called relay_control your screen controls / script could no longer access the Channel but instead was accessing the sequence.

    As to the reboot.  That is just a check that most service techs do to ensure that you don't have interfering software running in the background that you have forgotten about, or a result of other things you have done.  It has nothing to do with the robustness of DAQFactory.  Likewise creating a blank document with a single digital output is simplifying the problem and removing any possible interference.  This is also a common, and in many ways one of the most important debugging techniques for really  anything, not just DAQFactory.

  9. The problem with the new doc is that you created a new sequence called "relay_control" which overrides the channel with the same name.  Both channels and sequences are in the global namespace so you have to give them unique names.  Once I deleted the sequence the application works correctly.  In fact, your last document also worked correctly with no modifications.

  10. The script I provided will handle the ramp/soak which is what you describe in your example.  My script, however, uses seconds, not minutes.  You can use screen controls to edit the variables, tempSPs[0], tempSPs[1] etc, and tempDuration[0], tempDuration[1]...  I do not recommend using edit boxes on the main page of any HMI (see 

    ).  You can use regular variable value controls with the Set To action.

    Separately you need to figure out the control.  SSR means you could do PWM but you should figure out whether you really need it and a PID loop, or if a simple thermostatic control would work.  That script would be as simple as:

    global tempHyst = 1
    while(1)
       if (TC[0] > curSP)
          relay_control = 0
       endif
       if (TC[0] < curSP - tempHyst)
          relay_control = 1
       endif
       delay(1)
    endwhile

    This script should keep you within a degree of your SP (the tempHyst variable).  Considering thermocouples have an accuracy of about +/- 1 degree C, you are probably good.  To get tighter control you would first need to make sure your thermocouple was well calibrated and then you'd have to implement some PWM, again possible just in script instead of a PID.  I personally find that most temperature control applications are easier to manage with simple scripts than PID.

  11. You aren't talking about a PID loop but rather a ramp and soak, albeit presumably a steep (instant) ramp.  The PID portion is totally separate and is just designed to maintain the current setpoint.  You should start there.  Create a variable to hold your current setpoint and setup a PID loop or script to control the relay to maintain the desired temperature. 

    Note that with a relay, unless it is solid state you will likely NOT want to use PID, but instead do a simple thermostatic control.  For PID to be effective it really needs an analog output, which can be achieved with a relay through PWM, but that is not advised with mechanical relays as they can't really handle the rapid switching, especially under load.

    Once you have it controlling at a particular setpoint, you can create two variables to hold the 5 target setpoints and durations.  These are separate to the actual current setpoint that your loop is controlling to.  Those two variables will be arrays, in your case with 5 elements each.  So, for example, if the you wanted to step up from 25 to 45 in 5 degree increments with a duration of 60 seconds each as a default, you would do:

    global tempSPs = {25,30,35,40,45}
    global tempDuration = {60,60,60,60,60}
    

    (Note that you could use seqadd() and fill() functions instead of hard coding, but the above is clearer).

    You can then access any particular SP or duration using subsetting.  So, the 3rd setpoint is:

    tempSPs[2]

    (everything is numbered from 0).

    Then you just need to create a sequence that ramps it.  It is a rather simple sequence.  Let's assume your control loop is using a global variable called "curSP" as the current setpoint it is controlling to.  Then the sequence to (instantaneous) ramp and soak is simply:

    for (private i = 0, i < numrows(tempSPs), i++)
       curSP = tempSPs[i]
       delay(tempDuration[i]
    endfor

     

  12. I reread your original post and I'm not clear on what exactly is happening.  You say:

    Quote

    The pump turns on and off briefly, then the whole computer and monitor shut off; The pump and computer stay running, but no out put is displayed onto the monitor and the data stops being collected. After checking many components of my setup and testing certain situations, I am inclined to believe that there is a software issue rather than hardware. The crash log is just and unexpected quit message with an unknown error. Has anyone experienced this problem, or has any insight as to what might be happening? 

    Correct me if I am wrong:

    The first failure mode is that the computer and monitor shut off completely.

    The second failure mode is that the computer monitor just goes blank but the computer appears to still be powered up (LED and fans I'm assuming is how you tell)

    It is pretty far fetched for either of these failures to be software related.  Windows does a lot to encapsulate user level software so that one piece of software can't crash the whole machine.  Nowadays you rarely even get blue screens, and those are almost always caused by hardware failures or bugs in hardware drivers (which are kernel level, not user level like DAQFactory).

    I still think you have a problem with how you are powering things.  The pump looks ok, though I don't know why you need 5V to the relay board unless you are sinking your relay.  But the secondary question is how big is your relay, and what is the inrush on it.  I'm assuming it is mechanical and not solid state.

    Then you also have other things that are being powered from the LabJack, like the steppers.  I don't see why you are pulling 5V off the LabJack when you have 5V at your power supply.  USB 2.0 has a limit of 0.5 amps on the port, usually.  This is real easy to exceed with inrush.  You can rate all your stuff and it will appear that you are under 0.5 amps, but when that coil fires, or your stepper starts moving, the actual current being pulled is quite a bit higher than the rating, if only for a very short bit.  This is exactly what happened in the story I told in the earlier post about the power supply being pulled down.  The installer had rated the power supply based on the running current ratings for the various devices, but forgot about inrush.  So, when the valve started turning, the current load would spike.  The power supply couldn't supply it, so it had to drop the voltage to achieve it (think brown out).  Like your case, this didn't happen every time.  It depended on what else happened to be running at the same time.  Even the computer itself uses varying amount of power depending on CPU usage, etc.

     

  13. In this particular case, deprecation will likely just be removing from the documentation, though I'm not sure we will even go that far with it, especially given your feedback.  There really is no reason to remove it as it is just a simple math function.  The menu driven interpolation will definitely go, however, but you aren't using that.  The challenge with it is that it really does not work well at the ends.  So, in your example, it probably won't give you a reasonable answer if you asked for 125 or 3 as these are past the ends of array 1.

     

  14. Thanks, and we have added that to the docs for the next release.  The 20-30s is really dependent on the acquisition speed/pid loop speed and how fast your system responds.  I assumed you were sampling at like 1/sec or 2/sec and not 100/sec for that number.  If you had a fast moving system and were sampling at say, 100 hz, then you certainly could target a faster cycle time if you had the PID loop also running at 100hz.  The 3-4 oscillations is to give the autotune a chance to stabilize.  

  15. OK, so the issue is almost certainly modbus addressing.   I can give you a long winded explanation, but the short is that Modbus addresses are specified in one of two ways: 

    1) 40,001 notation, where holding registers go from 40,001->49,999, input registers from 30,001->39,999 etc. 
    2) 0 indexed notation, where holding registers go from 0->65535, input registers go from 0->65535, etc.

    (there are actually other notation methods, but they all are just variations of #1 above).  The worse part about it is that the Modbus data going through the wire itself only uses 0 indexed notation (#2).  When you type specify an address of 40,001 you are actually telling the software (usually) that you want the first holding register, which is 0.  Modbus registers specified using method #1 and all its variations only exist in the documentation.  The actual Modbus comms does not use it.  This makes for a tremendous amount of confusion, even from manufacturers, who mess it up all the time.  But now I'm getting long winded...  

    Anyhow, when you ask for 40,001, what the software does is strip the 10,000's place and subtract one.  So 40,001 becomes 0, 40,002 becomes 1, 30,015 becomes 14, etc.  The 10,000 place tells you what type of register you have (holding vs input), but in the Modbus protocol, this is determined by the function, NOT the address, so again, this is all just documentation trickery.

    To your problem: since about 50% of device's manuals use #1 (remember, its only in documentation), and 45% use #2 (what actually goes over the wire to your device), and, say, 5% use a variation of #1 or just plain mess it up, DAQFactory tries to make this easier for you.  What it does is that if you only specify channel #'s (registers) < 30,000, it assumes that you are going to use method #2 to specify all your register addresses.  Once you specify a channel between 30,000 and 50,000 on any Modbus device, then DAQFactory assumes that ALL your channel #'s on  that particular protocol (TCP vs RTU are considered different), are using method #1. 

    To further complicate it, the addresses using method #2 overlap with the numbers used for #1, so it is possible to be using 0 index notation (#2) and have registers up into the 30 and 40,000 range or even higher which would confuse DAQFactory.  To handle this, you simply have to read, once, a register > 50,000 and DAQFactory will lock into the #2 method of addressing.

    So, in your case, what happened is you used 0 index notation (#2) for all your existing devices, and then you added a new device and their documentation used method #1, so you entered an address > 30,000.  At this point, DAQFactory switched all the Modbus channels to method #1 which shifted all the addresses by 1 and made it stop working (probably because you have 32 bit values).

    What you need to do is decide which of the two methods you want to use and stick with it.  I personally do everything in 0 indexed notation except for the simplest of systems.  It is very easy to just translate the addresses when you enter them into DAQFactory: strip the 10,000 place and subtract one.  This is what I suggest you do with your new device.  Remember, the 40,000 numbers you are entering are just creations of the documentation and are never seen by your actual device.

     

  16. Oh, and thinking about it, one workaround would be to simply forward the email from your existing secure account to some other email server / address that has lower security requirements. 

    Another workaround would be to use a shell POP3 tool to retrieve your messages to a file then ingest it using File. functions.  I often use files as an intermediary for getting data from difficult sources into DAQFactory.  For example, I needed to link a DLL that was only available as 64 bit.  Since DAQFactory is 32 bit, there is no way for it to utilize this library.  I could have, I suppose, created a socket and went that way, but it was just easier to use a file to pass data back and forth (two files really).  Since this was running on flash drives, I used a RAM disk to avoid wearing since the files were being updated like 30-50x's per second and just temporary.

  17. You probably aren't going to be able to get it through a web page.  Pretty much all web pages authenticate with POST or in headers.  DAQFactory doesn't support POST, but does support adding additional headers, but it would still be quite a task to try and parse the resulting HTML.  You'll also need to add some headers to tell the server that you do support javascript (even though you don't).  I can't give you much input on what header is required but I am sure a web search will tell you quick.

    On the DAQFactory side, it looks like internally we used a library that does, in fact, support SSL but we didn't bring it out because we didn't think anyone used the POP3 feature.  This is certainly proven by the fact that you are the first to request or even comment on this feature ever.  Everyone uses the SMTP side to send alerts, etc, but retrieving info from a POP3 server is much less useful because of the security issues.  You certainly wouldn't want to control something through email. 

    Anyhow, we can look to enabling this.  It would not take long.  But you would likely need to run on the newest build, which is ready for beta.  

  18. 30 seconds with 15-20 oscillations sounds way too fast.  You should lower your output delta so that you get an oscillation every 20-30 seconds and run for 3-4 oscillations.  If you run it fast like you are doing there are significant noise problems due to sampling intervals and other things.  You only have to autotune rarely, so don't rush it!

  19. In reference to your actual question: are there alternatives, the answer is yes, kind of.  A PID loop is not a particularly complex algorithm.  Although probably not for a beginner, someone with a little scripting experience could script their own PID controller and make it what they want.  Likewise, a different auto-tune algorithm could be pretty easily scripted in.  In fact, we are slowly moving towards trying to implement many of the built in DAQFactory features in script so that a beginner can use it as is, but someone who needs to tweak it could delve into the script and make those tweaks.