for a school project I need to connect a temperature sensor to my beckhoff modules and define the temperature. the sensor I am using is an SMT160-30, it works between 1-4khz, which is cutting it close for standard io modules. I will probably need a special input module made for high speed measurements, but according to my teacher I must be able to do it with a standard module. But I am just having trouble with defining the duty cycle and can't really figure out how to solve it.
PROGRAM MAIN
VAR
sensor AT %I* : BOOL;
rtrig: R_TRIG;
tOn: Tof;
timeActive: TIME;
ftrig: F_TRIG;
tOff: Ton;
timeNActive: TIME;
dutyCycle: DINT;
temp: TIME;
END_VAR
rtrig(clk := sensor);
IF(rtrig.Q) THEN
timeActive := tOn.ET - timeActive;
END_IF
tOn(in := rtrig.Q, pt:= T#1S);
ftrig(clk := sensor);
IF ftrig.Q THEN
timeNActive := tOff.ET - timeNActive;
END_IF
tOff(in := ftrig.Q, pt:= T#1S);
//dutyCycle := timeActive / (timeActive + timeNActive);
//temp := (dutyCycle - 0.32)/0.0047;
this is the code I have so far and according to my teacher i'm heading the right way but i'm really stuck at this point.
hope you can help
best regards.
Your timers won't work because the outputs of F_TRIG & R_TRIG are only true for the edges of sensor. The timers should get IN := sensor instead of the X_TRIG.Qs.
Furthermore I dont see any sense in the substractions. Why not just save the ETs?
dutyCycle and temp should be REAL variables.
The two commented out lines are correct for the conversion from duty cycle to temperature °C.
Another solution would be to ditch the Timers and just count the plc cycles where sensor is true and false to determine the ratio between Active and nActive.
If I may.
I would not use active inactive time for duty as only active front and frequency are needed from my point of view and that's just because your inactive time could be century if your line is broken.
If you get a problem with your signal your result will be badly wrong with active inactive time.
With active time and frequency (1/(time between two rising edge)) you will be able to see that your signal is still alive.
Not a big deal for a sensor but for something more powerfull it would avoid risk to crash something if your line is broken. first you check that your signal is alive and after that you calculate your results.
If it helps. have a nice day
Related
In Dymola, I'm able to do something like:
when time > 100 then
assert(false,"Simulation taking too long");
end when;
to stop simulations based on the time variable itself.
However, what i'd like to do is stop the simulation based on elapsed CPU time. Dymola has a way to output the CPU time and it shows up in the results as CPUtime, but I don't know how to access the variable. In other words, this is what i'd like to do, but the CPUtime variable isn't in scope:
when CPUtime > 100 then
assert(false,"Simulation taking too long");
end when;
Any suggestions, either how to access CPUtime, or other workarounds to kill simulations based on cpu time?
As already noted:
You can set this in Dymola 2022 in the simulation setup, or alternatively by setting Advanced.Simulation.MaxRunTime.
It's wall-clock time, which means that if you have a parallel simulation it will stop after 10s has passed and not when the cores together have spent 10s, and if you for some weird reason have a long sleep-call in the model it will still end.
(This was already noted in the comment - thanks Priyanka. However, stackoverflow for some reason warns that answers in comments may be lost.)
I am trying to simulate a PWM signal output from a digital only PLC. So is it possible to define the digital output pin ON and OFF time in each cycle?
Thanks in advance.
Most plcs with transistor outputs have a pulse generator that you can use. For example on a Schneider PLC you can use the PTO (pulse train output). If for example you were using the signal to move a motor you can define what speed is equivalent to the frequency of the pulses then in the code you can define a velocity to move
VAR
MC_MoveVelocity_PTO_0: MC_MoveVelocity_PTO;
Powerd: MC_Power_PTO;
mcPositive: MC_DIRECTION;
END_VAR
//enable pulse train output
Powerd(Axis:=PTO_0,Enable:=TRUE,DriveReady:=TRUE);
//command
MC_MoveVelocity_PTO_0(Axis:=PTO_0,Execute:=%IX1.1,ContinuousUpdate:=TRUE,Velocity:=100,Acceleration:=1000,Deceleration:=1000,Direction:=mcPositive);
This code should run every cycle so you don't need to update the ON and OFF time each cycle. You could adjust the Velocity it runs at each cycle if you really wanted to.
Or if you wanted to get really basic you could use a timer to turn ON and OFF your output.
VAR
PWM_Timer: BLINK;
DigitalOutput: BOOL;
offTime: TIME := t#10ms;
onTime: TIME:=t#10ms;
END_VAR
PWM_Timer(ENABLE:=TRUE , TIMELOW:=offTime , TIMEHIGH:=onTime , OUT=>DigitalOutput );
where the timer I used specifies the ON and OFF time that you could adjust. But you do not need to turn ON and OFF the output each cycle. The PLC will take care of that for you.
If you wanted to play around with turning the output ON/OFF each cycle to see what it would do you could do something like
IF DigitalOutput THEN
DigitalOutput:=FALSE;
ELSE
DigitalOutput:=TRUE;
END_IF;
So when the plc goes through it's scan it will see the output is off so it will turn it on. On the next cycle it will see that it is on so it will turn it off.
Hope this helps.
This is a very basic question. I can't simulate a PWM file, in system time, from its FPGA VI file.
Details
For a NI cRIO-9067 + LabVIEW 2016 + Windows 8 system, under FPGA Interface Mode, I have the Test VI No.1.vi NI LabVIEW file and the corresponding FPGA Desktop Execution Node block file Test VI No.1 DEN.vi as suggested in the Getting Started information [1] [2].
In both files, the Low Pulse and High Pulse Numeric Controls are filled with the 1000 value. The Loop Timer block is set as "mSec" Counter Unit and "32 Bit" Size of Internal Counter.
The compiled FPGA version of the first file executes a square wave changing each 1 second, as expected, after 7 minutes of local compilation.
Under Simulation (Simulated I/O) as Execution Mode, and for reproducing approximatedly and by trial and error the square wave timing every 1 second, I need to put the value 1750 in the Clock Ticks field, from the FPGA 40MHz Onboard Clock reference clock, shown in the block options.
I dont understand this block, and why i should not put any close divisor of 40,000,000 at the Clock Ticks field, or simply, the value 1. Basically i dont understand how to "time" these FPGA simulations.
The desktop execution node is designed for time based simulation you are definately on the right track.
What you are setting at the top is the number of cycles that are executed each time you call the node. In your case you have 1750 ticks so around 43.75us of simulated time per iteration.
To simulate in real time you need to make sure that you execute the same amount of simulated time as the simulation loop takes to run. In your case, you have no timing in your simulation loop so why 1750 works for you is because that is probably how long that loop takes to execute.
If you put a loop timer in of 1ms and set the clock ticks to 40,000 (1ms simulated time) then I think you will find that it also works.
In some cases it may be beneficial to execute faster than real time so you would just have to account for that in your maths. For example if you set the clock ticks to 40 (1us simulated time) then you can count the number of iterations and multiply by 1us to get the actual clock time.
I'm not sure if the term real-time is being misused here, but the idea is that many players on a server have a city producing n resources per second. There might be a thousand such cities. What's the best way to reward all of the player cities?
Is the best way a loop like such placed in an infinite loop running whenever the game is "live"? (please ignore the obvious faults with such simplistic logic)
foreach(City c in AllCities){
if(c.lastTouched < DateTime.Now.AddSeconds(-10)){
c.resources += (DateTime.Now-c.lastTouched).Seconds * c.resourcesPerSecond;
c.lastTouched = DateTime.Now;
c.saveChanges();
}
}
I don't think you want an infinite loop as that would waste a lot of CPU cycles. This is basically a common simulation situation Wikipedia Simulation Software and there are a few approaches I can think of:
A discrete time approach where you increment the clock by a fixed time and recalculate the state of your system. This is similar to your approach above except do the calculation periodically and remove the 10 seconds if clause.
A discrete event approach where you have a central event queue, each with a timestamp, sorted by time. You sleep until the next event is due and then dispatch it. E.g. the event could mean adding a single resource. Wikipedia Discrete Event Simulation
Whenever someone asks for the number of resources calculate it based on the rate, initial time, and current time. This can be very efficient when the number of queries is expected to be small relative to the number of cities and the elapsed time.
while you can store the last ticked time per object, like your example, it's often easier to just have a global timestep
while(1) {
currentTime = now();
dt = currentTime - lastUpdateTime;
foreach(whatever)
whatever.update(dt);
lastUpdateTime = currentTime;
}
if you have different systems that don't need as frequent updates:
while(1) {
currentTime = now();
dt = currentTime - lastUpdateTime;
subsystem.timer += dt
while (subsystem.timer > subsystem.updatePeriod) {// need to be careful
subsystem.timer -= subsystem.updatePeriod; // that the system.update()
subsystem.update(subsytem.updatePeriod); // is faster than the
} // system.period
// ...
}
(which you'll notice is pretty much what you were doing on a per city basis)
Another gotcha is that with different subsystem clock rates, you can get overlaps (ie ticking many subsystems the same frame), leading to inconsistent frame times which can sometimes be an issue.
Is there an API function call for this board that would allow me to generate a clock signal on an output at 500 kHz while running some other code on the board? Thanks in advance for the advices.
According to the Supported Hardware documentation, version 2.8 or greater of the Data Acquisition Toolbox is needed to support a Measurement Computing USB-1024HLS device. Assuming you have version 2.8 or newer, the following should come close to a solution for you...
The first step would be to get the hardware ID for the device. The function DAQHWINFO should help with this:
deviceInfo = daqhwinfo('mcc');
The hardware ID gotten from the structure deviceInfo can then be used to create a Digital I/O Object (DIO) using the DIGITALIO function:
dio = digitalio('mcc',hardwareID);
Next, you have to add two output lines (for a clock signal and a pulse-width modulation (PWM) signal) using ADDLINE:
addline(dio,0:1,'out');
Then, you have to set a few DIO properties.
set(dio,'TimerPeriod',0.000002); % i.e. 500 kHz
set(dio,'TimerFcn',#update_outputs);
The function update_outputs is called once every timer period and should set the output pins to the appropriate values. The clock signal is simply going to switch back and forth between 0 and 1 every timer period. The PWM signal will likely alternate between 0 and 1 as well, but it will not change every timer period, remaining in each state for a set amount of time based upon the sort of pulse-width modulation you want. Here's what your update_outputs function may end up looking like:
function update_outputs(obj,event)
currentValues = getvalue(obj);
clockValue = ~currentValues(1);
pwmValue = pwm_compute();
putvalue(obj,[clockValue pwmValue]);
end
Note that this uses PUTVALUE and GETVALUE to set/get the values of the output pins. You will have to write the function pwm_compute such that it computes a new PWM value for each time period. Since pwm_compute will likely have to know how many values have been output already (i.e. how many times it has already been called), you can track that using a persistent variable:
function newValue = pwm_compute
persistent nValues;
if isempty(nValues)
nValues = 0;
else
nValues = nValues+1;
end
...
% Compute the new value for the (nValues+1) time period
...
end
This is just one possible solution. You could potentially precompute the PWM signal and pull the value for each timer period from a vector or data file, or you could potentially use the event data structure passed to update_outputs to get the time of the timer event (relative to the DIO timer start, I believe).
Finally, you have to start the DIO:
start(dio);
...and, once you're finished using it, delete it and clear it from memory:
delete(dio);
clear dio;
One potential stumbling block...
Generating a 500 kHz signal could be difficult. It's such a high frequency that you may run into problems, specifically with the 'TimerFcn', which is called once every timer period. If the 'TimerFcn' takes longer than 0.000002 seconds to run, some timer events may not be processed, leading to an output that is actually of a lower frequency. I have a feeling you may have to use a lower signal frequency for things to work properly, but I could be wrong. =)
I found Example: Generating Timer Events in the Data Acquisition Toolbox documentation.
dio = digitalio('nidaq','Dev1');
addline(dio,0:7,'in');
set(dio,'TimerFcn',#daqcallback)
set(dio,'TimerPeriod',5.0)
start(dio)
pause(11)
delete(dio)
clear dio