Discussion:
Ping Frank! Microtec Compiler and Libraries Re Posted
(too old to reply)
Öldman©
2004-07-26 01:25:44 UTC
Permalink
Re posted two different ways.
First as one large zip file.
Second as split parts (by news reader and not
with any splitter progy).

It is possible that if posted as one large file
the post does not propagate to your news server.
That said, I let Gravity split the zip into smaller
parts as that is how you said you prefer binaries.

So now we wait and see :o]
--
It is said that wisdom comes with age
--so why am I not very, very wise?
Öldman©
Frank McCoy
2004-07-26 06:50:11 UTC
Permalink
Post by Öldman©
Re posted two different ways.
First as one large zip file.
Second as split parts (by news reader and not
with any splitter progy).
It is possible that if posted as one large file
the post does not propagate to your news server.
That said, I let Gravity split the zip into smaller
parts as that is how you said you prefer binaries.
So now we wait and see :o]
Got the split version.
Didn't *install* it yet; but didn't seem to need to.
Got the stdio.h file and put it in as absolutes instead of changing
defs on my compiler (which would have been the "proper" way; but I
forget how; and am too lazy to look it up for a quick deal).

The thing now compiles fine on my Borlund compiler, except for an
error which is more the way I have my compiler set to report errors
than a real error. I can either live with it, or set the compiler to
ignore that error (which is the way I thought I had things setup).

But ... it does compile.
So ... I went looking through the 'C' code, and quickly saw where your
problem lies: wherever you use readCounter()

The problem (of course) is reading two asynchronous counters, niether
one of which is particularly high-speed.

The problem *I* have now, is I can't find the source-code for the
readCounter() routine; and more specifically the definitions for it.
I get the feeling it's done in assembly-code; and I couldn't find that
among the stuff you sent. I'm not saying it isn't there; just that I
can't find it. Uh ... What's the filename for the module that has
that routine?


I'm just guessing here; but I gather the readCounter routine returns
the ticks or counts of an RPM counter on the motor (motors); one tick
or count per revolution. Then, this count is timed using jiffies
(however long they are) from the system clock; which isn't all that
fast a clock.

One big problem I see (and that I've found with similar systems) is
that the counter is reset at the beginning, then read for a certain
period ... I ass-u-me one second to get the RPM/60. This would give
quite crude measurements.

A much better method would be to NEVER stop the counter, but look for
changes with a timeout. If timeout, then (of course) the motor is
stopped. If not, get the jiffie timer-value and save it.
Next, again look for changes with a timeout.
If timeout, again, motor-stopped.
If not, get jiffie timer and compare with saved value.
If enough time has elapsed to get an accurate measurement, then divide
counts/jiffies to get RPM.
Save new jiffie timer-value for next call to routine.
For twice the accuracy, average last two by adding both counts and
using new jiffie-timer value minus twice-previous value.

Never stop either jiffie-counter or RPM counter.
Take into account rollover-to-zero; and add full count if new value is
less than old value.

As I see it, this is best done by modifying the readCounter() routine
to be assembly-language, which should be non-interruptible in the
parts that read the counts and verify their stability (read three
times, must have same counts) and then reads the jiffy-clock.

The values returned, either as pointers, passed paramters, or actual
return-values would be current RPM-count, jiffy-time, and a timeout
flag.

Essentially, the routine would work something like this:

static void readCounter(long *jiff, long *RPM)
{
static long this_count, current_count = 0;
static long this_RPM, current_RPM = 0;
static BOOLEAN flag = TRUE;
if (flag)
{
disable_interrupts();
this_count = jiffies();
this_RPM = get_RPM_count();
enable_interrupts();
flag = FALSE;
}
do
{
disable_interrupts();
current_count = jiffies();
current_RPM = get_RPM_count();
enable_interrupts();
if (current_count < this_count)
current_count += ONE_DAY;
if (current_RPM < this_RPM)
current_RPM += FULL_COUNT;
}
while ((current_RPM != this_RPM) &&
((current_count - this_count) < ONE_SECOND));
*jiff = current_count;
*RPM = current_RPM - this_RPM;
this_count = current_count;
this_RPM = current_RPM;
}


int current_speed(void)
{
static BOOLEAN flag = FALSE;
long RPM, current_RPM, current_jiff, temp_jiff;
static long jiff;
if (flag)
{
readCounter(&jiff, &RPM);
if (jiff > ONE_DAY)
jiff -= ONE_DAY;
flag = FALSE;
}
RPM = 0;
do
{
readCounter(&current_jiff, &current_RPM);
if (current_jiff > ONE_DAY)
current_jiff -= ONE_DAY;
temp_jiff = current_jiff;
if (current_jiff < jiff)
current_jiff += ONE_DAY;
RPM += current_RPM;
}
while (current_RPM && ((current_jiff - jiff) < ONE_SECOND));
current_jiff -= jiff;
jiff = temp_jiff;
if (!current_RPM)
return 0;
else
{
return
(int)((current_RPM * SIXTY_SECONDS) / (current_jiff * 6));
}
}

main()
{
int speed;
do
{
if (speed = current_speed())
print_speed(speed);
else
print_stalled();
}
while (TRUE);
}

Only readCounter would be an assembly-language routine.
It's not debugged, and doesn't have the averaging routine; and could
be simplified to remove the flags, but I think the basis is there.
For a two-term average, I'd just use two or three extra variables.
For 8 or more, I'd use a FIFO stack. Two such stacks, actually; and
for speed I'd do it even binary: 8, 16, 32, etc., instead of decimal.
Even if it's desired to be ten deep, it would be faster to use a
16-deep FIFO and not use the extra counts, because you could avoid the
divisions needed to do MOD arithmetic.

Note: The thing runs *continously*; even continuing to count when
doing printouts; which (to my notion) is the way it should run. Note
also, that if the printout takes *more* than one second to run, the
accuracy actually *increases* not decreases, because the extra time is
used to gather more counts to average!

I've made several wild guesses about the timer; such as:
A. Each shaft produces one tic per revolution.
B. A truly WILD guess as to how big the counter on the RPM counter is.
C. The jiffy-clock counts 60 beats/second, and resets once per day.
D. The get_RPM_count() and the jiffy() routines are stable:
(They don't need checks for rollover between digits.)
If they do need such checks; then such checks can be added.
E. The print_speed() routine expects an integer count
in RPM times ten. IOW, 19.6 RPM would be passed as 196.

I also didn't include *any* code to differentiate between the two
motors ... Which I ass-u-me from what I read run at two different
speeds; and that's how you tell which is which.

This is just an indication of some of what I would probably do, if you
wanted me to.

Running averages could be done for more accuracy, and yet possibly
combined with automatic shortening of the time-averaged, if the speed
changes drastically, for faster response time.

In any case, even without the averaging, I think I might expect at
least an order-of-magnitude increase in accuracy with the sort of
change I'm suggesting.

These are just suggestions, mind. Without a more complete knowledge
of what the hardware was doing, it's hard to be sure exactly what will
work and how well.
--
_____
/ ' / ™
,-/-, __ __. ____ /_
(_/ / (_(_/|_/ / <_/ <_
Öldman©
2004-07-26 10:38:53 UTC
Permalink
On Mon, 26 Jul 2004 01:50:11 -0500,Frank McCoy's cat ran across
the 'puter keyboard and out came...
Post by Frank McCoy
Post by Öldman©
Re posted two different ways.
First as one large zip file.
Second as split parts (by news reader and not
with any splitter progy).
It is possible that if posted as one large file
the post does not propagate to your news server.
That said, I let Gravity split the zip into smaller
parts as that is how you said you prefer binaries.
So now we wait and see :o]
Got the split version.
Didn't *install* it yet; but didn't seem to need to.
Got the stdio.h file and put it in as absolutes instead of changing
defs on my compiler (which would have been the "proper" way; but I
forget how; and am too lazy to look it up for a quick deal).
The thing now compiles fine on my Borlund compiler, except for an
error which is more the way I have my compiler set to report errors
than a real error. I can either live with it, or set the compiler to
ignore that error (which is the way I thought I had things setup).
But ... it does compile.
So ... I went looking through the 'C' code, and quickly saw where your
problem lies: wherever you use readCounter()
The problem (of course) is reading two asynchronous counters, niether
one of which is particularly high-speed.
The problem *I* have now, is I can't find the source-code for the
readCounter() routine; and more specifically the definitions for it.
I get the feeling it's done in assembly-code; and I couldn't find that
among the stuff you sent. I'm not saying it isn't there; just that I
can't find it. Uh ... What's the filename for the module that has
that routine?
I'm just guessing here; but I gather the readCounter routine returns
the ticks or counts of an RPM counter on the motor (motors); one tick
or count per revolution. Then, this count is timed using jiffies
(however long they are) from the system clock; which isn't all that
fast a clock.
One big problem I see (and that I've found with similar systems) is
that the counter is reset at the beginning, then read for a certain
period ... I ass-u-me one second to get the RPM/60. This would give
quite crude measurements.
A much better method would be to NEVER stop the counter, but look for
changes with a timeout. If timeout, then (of course) the motor is
stopped. If not, get the jiffie timer-value and save it.
Next, again look for changes with a timeout.
If timeout, again, motor-stopped.
If not, get jiffie timer and compare with saved value.
If enough time has elapsed to get an accurate measurement, then divide
counts/jiffies to get RPM.
Save new jiffie timer-value for next call to routine.
For twice the accuracy, average last two by adding both counts and
using new jiffie-timer value minus twice-previous value.
Never stop either jiffie-counter or RPM counter.
Take into account rollover-to-zero; and add full count if new value is
less than old value.
As I see it, this is best done by modifying the readCounter() routine
to be assembly-language, which should be non-interruptible in the
parts that read the counts and verify their stability (read three
times, must have same counts) and then reads the jiffy-clock.
The values returned, either as pointers, passed paramters, or actual
return-values would be current RPM-count, jiffy-time, and a timeout
flag.
static void readCounter(long *jiff, long *RPM)
{
static long this_count, current_count = 0;
static long this_RPM, current_RPM = 0;
static BOOLEAN flag = TRUE;
if (flag)
{
disable_interrupts();
this_count = jiffies();
this_RPM = get_RPM_count();
enable_interrupts();
flag = FALSE;
}
do
{
disable_interrupts();
current_count = jiffies();
current_RPM = get_RPM_count();
enable_interrupts();
if (current_count < this_count)
current_count += ONE_DAY;
if (current_RPM < this_RPM)
current_RPM += FULL_COUNT;
}
while ((current_RPM != this_RPM) &&
((current_count - this_count) < ONE_SECOND));
*jiff = current_count;
*RPM = current_RPM - this_RPM;
this_count = current_count;
this_RPM = current_RPM;
}
int current_speed(void)
{
static BOOLEAN flag = FALSE;
long RPM, current_RPM, current_jiff, temp_jiff;
static long jiff;
if (flag)
{
readCounter(&jiff, &RPM);
if (jiff > ONE_DAY)
jiff -= ONE_DAY;
flag = FALSE;
}
RPM = 0;
do
{
readCounter(&current_jiff, &current_RPM);
if (current_jiff > ONE_DAY)
current_jiff -= ONE_DAY;
temp_jiff = current_jiff;
if (current_jiff < jiff)
current_jiff += ONE_DAY;
RPM += current_RPM;
}
while (current_RPM && ((current_jiff - jiff) < ONE_SECOND));
current_jiff -= jiff;
jiff = temp_jiff;
if (!current_RPM)
return 0;
else
{
return
(int)((current_RPM * SIXTY_SECONDS) / (current_jiff * 6));
}
}
main()
{
int speed;
do
{
if (speed = current_speed())
print_speed(speed);
else
print_stalled();
}
while (TRUE);
}
Only readCounter would be an assembly-language routine.
It's not debugged, and doesn't have the averaging routine; and could
be simplified to remove the flags, but I think the basis is there.
For a two-term average, I'd just use two or three extra variables.
For 8 or more, I'd use a FIFO stack. Two such stacks, actually; and
for speed I'd do it even binary: 8, 16, 32, etc., instead of decimal.
Even if it's desired to be ten deep, it would be faster to use a
16-deep FIFO and not use the extra counts, because you could avoid the
divisions needed to do MOD arithmetic.
Note: The thing runs *continously*; even continuing to count when
doing printouts; which (to my notion) is the way it should run. Note
also, that if the printout takes *more* than one second to run, the
accuracy actually *increases* not decreases, because the extra time is
used to gather more counts to average!
A. Each shaft produces one tic per revolution.
B. A truly WILD guess as to how big the counter on the RPM counter is.
C. The jiffy-clock counts 60 beats/second, and resets once per day.
(They don't need checks for rollover between digits.)
If they do need such checks; then such checks can be added.
E. The print_speed() routine expects an integer count
in RPM times ten. IOW, 19.6 RPM would be passed as 196.
I also didn't include *any* code to differentiate between the two
motors ... Which I ass-u-me from what I read run at two different
speeds; and that's how you tell which is which.
This is just an indication of some of what I would probably do, if you
wanted me to.
Running averages could be done for more accuracy, and yet possibly
combined with automatic shortening of the time-averaged, if the speed
changes drastically, for faster response time.
In any case, even without the averaging, I think I might expect at
least an order-of-magnitude increase in accuracy with the sort of
change I'm suggesting.
counts per rev = 15 (fixed by hardware)
max rpm scale = 1800 (/60=30 rps*15=450Hz)
motor running is determined by which counter input is
active (read_counter0=small, read_counter1=large, counter2
is flow)
counters are 32 bits wide each.

Our RPM counters need to run two different sample rates,
the first at 100 RPM and up - the second for 100 RPM and
down. The sample rate needs to be higher for the lower
RPM values to sense 'stall' on the motor under test.
The data is used to plot torque curves and stall happens
within 2 seconds from approx. 1200 RPM when load reaches
critical. We found a LOT of 'jitter' in our values due to
low sample rate and clock speed of the PLC presently used.
The 'work around' was to accumulate counts then average.
This issue was never fully resolved - I think partly due
to the programers level of expertize and partly due to
the clock speed of the PLC.

Assembly language code may be included directly within C programs.
Library routines are called from operating system ROM.
#asm and #endasm statements are used to enclose in line
assembly language code, which is then assembled without
passing through the compiler, the compiler converts the
C program to assembly language.

controller provides 32 software timers individually
programmable for tick rates from ten per second to
once every 25.5 seconds. all timers operate in the
background from a hardware interupt generated by the
main system clock.

IO_SYSTEM resource must be obtained before using any of
the following funtions:

readCounterInput = read the status of the counter input
points

readCounter = read a counter with or without automatic
clearing of counter register

getclock = read the real time clock

jiffy counter 1/10 second interval (increments 60 times
per second) and rolls over to zero when it reaches
a value of 5183999 (the number of seconds in 24 hours)

setjiffy = set the jiffy clock
jiffy = read the jiffy clock

setClockAlarm = sets the realtime clock alarm
getClockAlarm = reads the real time clock alarm settings
resetClockAlarm = resets the real time clock alarm
alarmIn = returns absolute time of alarm given elapsed time
settimer = sets a software timer and starts it counting (down)
timer = reads contents of software timer

resourse numbers are declared in primitiv.h

status registers are single bit registers that a C
program can read and write - there are 4096 status
registers 10001 to 14096

dbase funtion reads values
setdbase funtion writes values

check and be certain that the existing program makes
no calls to these registers - they can be used for flags

10193 = address digital input 0
10194 = address digital input 1
10195 = address digital input 2

30329..30330 = address counter input 0
30331..30332 = address counter input 1
30333..30334 = address counter input 2

40065..40096 = software timers
40097..40128 = software timer intervals

40191 = real time clock hour
40192 = real time clock minute
40193 = rela time clock second

40198 = alarm hour
40199 = alarm minute
40200 = alarm second
40201 = alarm control (0=no alarm, 1=absolute time)

Make sure the C code includes
runLadderLogic(FALSE)
(reduces CPU load reading ladder logic interpreter)

Supporting tasks are typically created before the main
loop of the program - syntax -

void main (void)
{
/*perform initialization actions*/
/*start support tasks*/

/*main loop*/
while (TRUE)
{
/*perform application functions*/
}
}
tasks can be created and ended dynamically during the
execution of a program as well

The background I/O task is required for the timer
functions to operate. Its priority and execution can
be changed by modifying the following statement:

create_task(background_io, 4, APPLICATION, 2);

Do not retain control of a resourse for more than 0.1
seconds or background operations will not execute
properly.
syntax-
request_resourse (it will wait if resourse is not available)
poll_resourse (continue execution if resourse is not avail)
release_resourse - free resourse for use by other tasks

The RTOS supports up to 16 tasks with 4 priority levels
syntax-
create_task = create and make it ready to execute
end_task = terminate and free resourses

tasks are indipendantly executing routines


compiler directives and syntax -
DOS command line
mccm77 -v -nQ -Ml -c filename.c

-v = issue warnings for features in source file
-nQ = do not suppress diagnostic messages
-Ml = compile for large memory model (lower case L)
-c = compiler output is an object file

-Jdir = specify directory containing the include files
-o = enable standard optimizations - produces smaller and faster code
-Ot = optimize in favour of execution time rather than code size
-nOc = pop the stack after each funtion call (increases code size
and execution time. should only be used if there is a large
number of consecutive function calls in the program

the linker converts object files and object file libraries
into and executable program

lots of sh..t for the linker, I am going to leave it
off for now.
required modules:
appstart.obj
appinit.obj
romfunc.obj
cm77islf.lib
cm77islc.lib

C function library:
csum.h defines checksum related funtions
database.h defines I/O database related funtions
dialup.h defines modem realted funtions
iohw.h defines funtions that access the I/O hardware
pid.h defines PID controller related funtions
primitv.h defines real time operating system
product.h defines macros for product line information
(TELESAFE_MICO_16)
protocol.h defines communication protocol related funtions
(READ_INPUT_REGISTER, READ_HOLDING_REGISTER)
rtc.h defines funtions for the real time clock
serial.h defines serial communication related functions
system.h defines functions for system initialization and
for retrieving system information

installClockHandler function installs a real time clock
alarm handler funtion. the real time clock alarm funtions
calls this function each time a real time clock alarm occurs

enough for now
--
It is said that wisdom comes with age
--so why am I not very, very wise?
Öldman©
Frank McCoy
2004-07-26 15:46:23 UTC
Permalink
OK.

As I see it, your jitter problems are caused by four things:
1. Low resolution in both counters: (1-second resolution)
Real_time_Clock = 1/10 but high overall accuracy.
RPM_count = somewhere around 1/200 average.
That means, BEST CASE that a one-second timer will
give around 1% accuracy. Running averages, of course,
can improve that.
That means at full-speed, best accuracy for 1800RPM
will mean +- 2RPM jitter; with averaging that could
improve to close-to +- 0.3 RPM jitter.
However, the above is *best case*; which for reasons
below, it's unlikely to get.
My *guess* is that you're getting orders-of-magnitude worse
for each individual reading. 10% or even 20% jitter seeming
more likely. Without data from you, I don't know.
2. Biggest problem: Both timers and RPM count are
interruptible processes that rely on the system
to return.
This can be fixed to some extent by reserving I/O resources
before calling each, and then releasing; but it still leaves
unknown amounts of time between calls.
This *could* be fixed by directly handling both processes;
but it requires considerable knowledge about both the hardware
itself and the existing system needs.
Probably not workable, unless writing the code from the bottom
up, and not using the compiler resources.
A work-around would be to reserve BOTH I/O processes, if the
system allows that, get the values, and then release both.
That would improve accuracy a lot.
If neither one of the above "solutions" is allowed; then
checks need to be made, at least on the Real-Time-Clock,
that system services has not interrupted things while
measurements were being made; as this could throw absolutely
*horrible* amounts of jitter into the measurements.
The solution there (of course) is to repeat the measurement
if the RTC changes between measurements. (Ick.)
It works; but it's a Kludge. Sometimes a necessary kludge,
but a kludge.
3. The third problem is the fact that these routines are all
'C' calls to unknown processes with unknown times to execute;
and not guaranteed to return within specified times. This
is *somewhat* related to problem-2 above, but not entirely
the same thing.
My usual solution to that problem is to write diagnostic
software to measure the times, and then use math to remove
the known time-differentials. Not good, but doable.
Still, if maximum accuracy isn't needed, sometimes that's
more trouble than it's worth.
4. A *fixable* problem is caused by asynchronously starting
and stopping timers. This (at first, to most people)
seems to be the easy way to get accuracy; but especially
when using averages is a way to horribly degrade things
and cause jitter. Far better to read "on the fly", and
fix problems caused by timer-rollover and unstable reads.
With some hardware, those are non-problems. With others
it takes multiple reads. Only trial can tell which.
Fixing this allows for faster reads, more responsiveness,
and more accuracy all in one; as measurements continue
during the overhead "system" time used for other processes
such as printouts and display times.

I guess the whole thing boils down to the questions:
A. How much jitter does the present system have now?
B. How much jitter would be considered "acceptable"?
C. How much time/effort/money is available for a fix?
D. How deep into the system is a programmer allowed to go?

Quite obviously, maximum accuracy won't be obtained without mucking
down at the system and real-time-clock levels where directly reading
and writing the registers along with controlling the interrupts.
However, I doubt this would be needed, as otherwise you wouldn't
be getting even semi-acceptable results now.

So, I guess the real question boils down to the first two questions:
What's the present inaccuracy; and how much more accuracy do you need?
I'm *guessing* by looking at the code, that somewhere between
2-to-1 and 5-to-1 improvement can be gotten by putting in work-arounds
to improve timer accuracy; while (if none is already implemented) an
order-of-magnitude improvement can be realized by doing adjustable
moving-averages.

But those are just guesses. I'd have to write code to test some
assumptions on the machine. Knowing what results you're already
getting (and obviously not liking) would also help.

Of course, I *could* just go ahead and blindly write the code I
*think* would help, and have you test it, if that's what you want;
just modifying the 'C' code to remove some timing problems caused by
start/stopping timers, and add in the averaging-with-speedup function
I dreamed up.

I have a fair idea already of what to do if that's the case, and you
want to go with the simplest try for improvement.
--
_____
/ ' / ™
,-/-, __ __. ____ /_
(_/ / (_(_/|_/ / <_/ <_
Öldman©
2004-07-26 18:39:21 UTC
Permalink
On Mon, 26 Jul 2004 10:46:23 -0500,Frank McCoy's cat ran across
the 'puter keyboard and out came...
Post by Frank McCoy
OK.
1. Low resolution in both counters: (1-second resolution)
Real_time_Clock = 1/10 but high overall accuracy.
RPM_count = somewhere around 1/200 average.
That means, BEST CASE that a one-second timer will
give around 1% accuracy. Running averages, of course,
can improve that.
That means at full-speed, best accuracy for 1800RPM
will mean +- 2RPM jitter; with averaging that could
improve to close-to +- 0.3 RPM jitter.
However, the above is *best case*; which for reasons
below, it's unlikely to get.
My *guess* is that you're getting orders-of-magnitude worse
for each individual reading. 10% or even 20% jitter seeming
more likely. Without data from you, I don't know.
2. Biggest problem: Both timers and RPM count are
interruptible processes that rely on the system
to return.
This can be fixed to some extent by reserving I/O resources
before calling each, and then releasing; but it still leaves
unknown amounts of time between calls.
This *could* be fixed by directly handling both processes;
but it requires considerable knowledge about both the hardware
itself and the existing system needs.
Probably not workable, unless writing the code from the bottom
up, and not using the compiler resources.
A work-around would be to reserve BOTH I/O processes, if the
system allows that, get the values, and then release both.
That would improve accuracy a lot.
If neither one of the above "solutions" is allowed; then
checks need to be made, at least on the Real-Time-Clock,
that system services has not interrupted things while
measurements were being made; as this could throw absolutely
*horrible* amounts of jitter into the measurements.
The solution there (of course) is to repeat the measurement
if the RTC changes between measurements. (Ick.)
It works; but it's a Kludge. Sometimes a necessary kludge,
but a kludge.
3. The third problem is the fact that these routines are all
'C' calls to unknown processes with unknown times to execute;
and not guaranteed to return within specified times. This
is *somewhat* related to problem-2 above, but not entirely
the same thing.
My usual solution to that problem is to write diagnostic
software to measure the times, and then use math to remove
the known time-differentials. Not good, but doable.
Still, if maximum accuracy isn't needed, sometimes that's
more trouble than it's worth.
4. A *fixable* problem is caused by asynchronously starting
and stopping timers. This (at first, to most people)
seems to be the easy way to get accuracy; but especially
when using averages is a way to horribly degrade things
and cause jitter. Far better to read "on the fly", and
fix problems caused by timer-rollover and unstable reads.
With some hardware, those are non-problems. With others
it takes multiple reads. Only trial can tell which.
Fixing this allows for faster reads, more responsiveness,
and more accuracy all in one; as measurements continue
during the overhead "system" time used for other processes
such as printouts and display times.
A. How much jitter does the present system have now?
Anywhere from 10 to 20%
Post by Frank McCoy
B. How much jitter would be considered "acceptable"?
5% - with 1% being ideal
Post by Frank McCoy
C. How much time/effort/money is available for a fix?
time not a real problem as we have a working system
presently, aiming for improvement
Post by Frank McCoy
D. How deep into the system is a programmer allowed to go?
?? restrict ourselves to 2 x as good as we have now?
cost would have to be reviewed and justified to customer
Post by Frank McCoy
Quite obviously, maximum accuracy won't be obtained without mucking
down at the system and real-time-clock levels where directly reading
and writing the registers along with controlling the interrupts.
However, I doubt this would be needed, as otherwise you wouldn't
be getting even semi-acceptable results now.
What's the present inaccuracy; and how much more accuracy do you need?
I'm *guessing* by looking at the code, that somewhere between
2-to-1 and 5-to-1 improvement can be gotten by putting in work-arounds
to improve timer accuracy; while (if none is already implemented) an
order-of-magnitude improvement can be realized by doing adjustable
moving-averages.
But those are just guesses. I'd have to write code to test some
assumptions on the machine. Knowing what results you're already
getting (and obviously not liking) would also help.
Of course, I *could* just go ahead and blindly write the code I
*think* would help, and have you test it, if that's what you want;
just modifying the 'C' code to remove some timing problems caused by
start/stopping timers, and add in the averaging-with-speedup function
I dreamed up.
I have a fair idea already of what to do if that's the case, and you
want to go with the simplest try for improvement.
The reason I listed the register addresses was that it
occurred to me we don't have to use the macro readCounter
and could use a realtime read of the register.

Another approach might be to use poll_resourse (explained
in previous post) rather than the request_resource, release_
resourse routine. This should make the counter read independent
of the real time system as it does not stop execution of the
current task.

Another real time operation is read_timer_info

Another macro is readCounterInput - if done with a third timer
we need a 10 jiffy read (this would have to be calcualted based
on 10 RPM start test condition(2.4999Hz threshold) to determine
which counter (0 or 1)is active to switch between small and
large motor. Counter 2 is always active for either motor. if
no counter = test stopped.

The original programmer used macro s rather than register
read/writes.

This would tend to introduce the unknown in loop timing, would
it not?

The moving window average method has been my interest from day
1 but it wasn't implemented AFAIK.
--
Sometimes, something or someone - maybe!
_________________________________
Öldman©
2004-07-26 19:19:06 UTC
Permalink
On Mon, 26 Jul 2004 10:46:23 -0500,Frank McCoy's cat ran across
the 'puter keyboard and out came...
Post by Frank McCoy
OK.
1. Low resolution in both counters: (1-second resolution)
Real_time_Clock = 1/10 but high overall accuracy.
RPM_count = somewhere around 1/200 average.
That means, BEST CASE that a one-second timer will
give around 1% accuracy. Running averages, of course,
can improve that.
That means at full-speed, best accuracy for 1800RPM
will mean +- 2RPM jitter; with averaging that could
improve to close-to +- 0.3 RPM jitter.
However, the above is *best case*; which for reasons
below, it's unlikely to get.
My *guess* is that you're getting orders-of-magnitude worse
for each individual reading. 10% or even 20% jitter seeming
more likely. Without data from you, I don't know.
2. Biggest problem: Both timers and RPM count are
interruptible processes that rely on the system
to return.
This can be fixed to some extent by reserving I/O resources
before calling each, and then releasing; but it still leaves
unknown amounts of time between calls.
This *could* be fixed by directly handling both processes;
but it requires considerable knowledge about both the hardware
itself and the existing system needs.
Probably not workable, unless writing the code from the bottom
up, and not using the compiler resources.
A work-around would be to reserve BOTH I/O processes, if the
system allows that, get the values, and then release both.
That would improve accuracy a lot.
If neither one of the above "solutions" is allowed; then
checks need to be made, at least on the Real-Time-Clock,
that system services has not interrupted things while
measurements were being made; as this could throw absolutely
*horrible* amounts of jitter into the measurements.
The solution there (of course) is to repeat the measurement
if the RTC changes between measurements. (Ick.)
It works; but it's a Kludge. Sometimes a necessary kludge,
but a kludge.
3. The third problem is the fact that these routines are all
'C' calls to unknown processes with unknown times to execute;
and not guaranteed to return within specified times. This
is *somewhat* related to problem-2 above, but not entirely
the same thing.
My usual solution to that problem is to write diagnostic
software to measure the times, and then use math to remove
the known time-differentials. Not good, but doable.
Still, if maximum accuracy isn't needed, sometimes that's
more trouble than it's worth.
4. A *fixable* problem is caused by asynchronously starting
and stopping timers. This (at first, to most people)
seems to be the easy way to get accuracy; but especially
when using averages is a way to horribly degrade things
and cause jitter. Far better to read "on the fly", and
fix problems caused by timer-rollover and unstable reads.
With some hardware, those are non-problems. With others
it takes multiple reads. Only trial can tell which.
Fixing this allows for faster reads, more responsiveness,
and more accuracy all in one; as measurements continue
during the overhead "system" time used for other processes
such as printouts and display times.
A. How much jitter does the present system have now?
Anywhere from 10 to 20%
Post by Frank McCoy
B. How much jitter would be considered "acceptable"?
5% - with 1% being ideal
Post by Frank McCoy
C. How much time/effort/money is available for a fix?
time not a real problem as we have a working system
presently, aiming for improvement
Post by Frank McCoy
D. How deep into the system is a programmer allowed to go?
?? restrict ourselves to 2 x as good as we have now?
cost would have to be reviewed and justified to customer
Post by Frank McCoy
Quite obviously, maximum accuracy won't be obtained without mucking
down at the system and real-time-clock levels where directly reading
and writing the registers along with controlling the interrupts.
However, I doubt this would be needed, as otherwise you wouldn't
be getting even semi-acceptable results now.
What's the present inaccuracy; and how much more accuracy do you need?
I'm *guessing* by looking at the code, that somewhere between
2-to-1 and 5-to-1 improvement can be gotten by putting in work-arounds
to improve timer accuracy; while (if none is already implemented) an
order-of-magnitude improvement can be realized by doing adjustable
moving-averages.
But those are just guesses. I'd have to write code to test some
assumptions on the machine. Knowing what results you're already
getting (and obviously not liking) would also help.
Of course, I *could* just go ahead and blindly write the code I
*think* would help, and have you test it, if that's what you want;
just modifying the 'C' code to remove some timing problems caused by
start/stopping timers, and add in the averaging-with-speedup function
I dreamed up.
I have a fair idea already of what to do if that's the case, and you
want to go with the simplest try for improvement.
The reason I listed the register addresses was that it
occurred to me we don't have to use the macro readCounter
and could use a realtime read of the register.

Another approach might be to use poll_resourse (explained
in previous post) rather than the request_resource, release_
resourse routine. This should make the counter read independent
of the real time system as it does not stop execution of the
current task.

Another real time operation is read_timer_info

Another macro is readCounterInput - if done with a third timer
we need a 10 jiffy read (this would have to be calcualted based
on 10 RPM start test condition(2.4999Hz threshold) to determine
which counter (0 or 1)is active to switch between small and
large motor. Counter 2 is always active for either motor. if
no counter = test stopped.

The original programmer used macro s rather than register
read/writes.

This would tend to introduce the unknown in loop timing, would
it not?

The moving window average method has been my interest from day
1 but it wasn't implemented AFAIK.
--
Sometimes, something or someone - maybe!
_________________________________
Frank McCoy
2004-07-26 20:05:33 UTC
Permalink
In alt.fan.frank.mccoy Öldman© <***@ld.is.best> wrote:

[SNIP]
Post by Öldman©
Post by Frank McCoy
A. How much jitter does the present system have now?
Anywhere from 10 to 20%
OK. That matches my guess pretty close.
Post by Öldman©
Post by Frank McCoy
B. How much jitter would be considered "acceptable"?
5% - with 1% being ideal
Sounds easily doable; with better than that possible.
Post by Öldman©
Post by Frank McCoy
C. How much time/effort/money is available for a fix?
time not a real problem as we have a working system
presently, aiming for improvement
Well ... That wasn't exactly what I meant.
I meant how much time you'd want *me* to spend.

Cheap. Quick. Inexpensive.
Pick any two. ;-}

Actually, my guess is: To meet your spec., under a week.
Possibly in under half that.
Since you don't seem to need ultimate accuracy possible,
(~.3%), with 1% or even 2% seeming reasonable, my guess is
that I could do it with minimal poking into the hardware;
Just doing the fix-counters bit and adding in the fancy
adjustable-average thingy I figured out.
Post by Öldman©
Post by Frank McCoy
D. How deep into the system is a programmer allowed to go?
?? restrict ourselves to 2 x as good as we have now?
cost would have to be reviewed and justified to customer
2x as good, I could probably do with a quick patch.
5x or 10x is more what I'd expect with minimal and reasonable effort
... Say within a week or so.

20x to 30x would take considerable poking with the hardware.

Those (of course) are just guesses. I wouldn't know *anything* for
sure unless and until I tried.
Post by Öldman©
Post by Frank McCoy
I have a fair idea already of what to do if that's the case, and you
want to go with the simplest try for improvement.
The reason I listed the register addresses was that it
occurred to me we don't have to use the macro readCounter
and could use a realtime read of the register.
Another approach might be to use poll_resourse (explained
in previous post) rather than the request_resource, release_
resourse routine. This should make the counter read independent
of the real time system as it does not stop execution of the
current task.
Another real time operation is read_timer_info
Another macro is readCounterInput - if done with a third timer
we need a 10 jiffy read (this would have to be calcualted based
on 10 RPM start test condition(2.4999Hz threshold) to determine
which counter (0 or 1)is active to switch between small and
large motor. Counter 2 is always active for either motor. if
no counter = test stopped.
I'd have to try various methods and see which worked best for best
results. If not trying for ultimate accuracy, perhaps that might be
more trouble than it's worth.
Post by Öldman©
The original programmer used macro s rather than register
read/writes.
Neither macros nor register read/writes is the problem.
The problem is time between taking a measurement and finding the time
... or vice-versa. This time can be shortened; but it doesn't fix the
problem of it being an unknown when system interrupts can come in and
grab or change either one. There *are* ways around that too; if the
processor is fast enough, and the data being measured changes at a
slow enough rate. I *think* this is the case here; but cannot be sure
without testing. If a the routine I'm thinking of can run without
hanging, then those inaccuracies can be jiggered out. If not, then
other, less exact methods will have to be used.

I'm going to TRY and avoid getting down to machine-code level, if
possible.
Post by Öldman©
This would tend to introduce the unknown in loop timing, would
it not?
Not really. See above. The unknown is SYSTEM-level; and caused by
the fact the program is interruptible (and has to be, to keep the
clock running properly).

Reducing the time for a routine just makes it that much less likely to
be screwed by the system ... but to be a bigger hunk off when the
screwup DOES happen (and it will).
Post by Öldman©
The moving window average method has been my interest from day
1 but it wasn't implemented AFAIK.
OK.
THERE, using continuously running counters will help a LOT.
Add in my special averaging method, and my guess is you'd get a
minimum of about 10 times to 20 times (and possibly more) increase in
accuracy. Not ultimate accuracy; but compared to what you have, would
likely be darned good.

!!!OOOOOOOOPPPPSSS!!!
I *HAVE* to be certain of one thing, for my idea to work.
If not, my head-scheme just fell out the window.

a. You have TWO motors; and want to keep track of BOTH of them
simultaneously, right?

b. Does each motor have a separate RPM counter, or are there items
both motors share in common?

My whole *idea* requires that each motor have it's own separate
free-running RPM counter that keeps on running unless stopped or
reset; so that I can go read the counter for motor-A, and then later
on go read the counter for motor-B, and then go back and read the
counter for motor-A again, without the readings for motor-A being
screwed up by my reading the counter for motor-B.

If that won't work, then none of the dream-bait I've been working up
would go, with the exception of the averaging routine; and that
wouldn't work half as good as I'd like it to.

Well ... it WOULD work, if only one motor was running at a time; but I
gather that's NOT the case, right?

I know the system clock runs without caring about readings of the
motor counters or vise-versa; as otherwise your present system
wouldn't work. But do the two motor RPM-counters interfere with each
other or use the same counter or path in any way?
--
_____
/ ' / ™
,-/-, __ __. ____ /_
(_/ / (_(_/|_/ / <_/ <_
Frank McCoy
2004-07-26 21:29:45 UTC
Permalink
Post by Frank McCoy
Cheap. Quick. Inexpensive.
Oops!
That was supposed to be:
Cheap. Quick. Good.
Post by Frank McCoy
Pick any two. ;-}
--
_____
/ ' / ™
,-/-, __ __. ____ /_
(_/ / (_(_/|_/ / <_/ <_
Öldman©
2004-07-26 23:31:01 UTC
Permalink
On Mon, 26 Jul 2004 15:05:33 -0500,Frank McCoy's cat ran across
the 'puter keyboard and out came...
Post by Frank McCoy
[SNIP]
Post by Öldman©
Post by Frank McCoy
A. How much jitter does the present system have now?
Anywhere from 10 to 20%
OK. That matches my guess pretty close.
Post by Öldman©
Post by Frank McCoy
B. How much jitter would be considered "acceptable"?
5% - with 1% being ideal
Sounds easily doable; with better than that possible.
Post by Öldman©
Post by Frank McCoy
C. How much time/effort/money is available for a fix?
time not a real problem as we have a working system
presently, aiming for improvement
Well ... That wasn't exactly what I meant.
I meant how much time you'd want *me* to spend.
Cheap. Quick. Inexpensive.
Pick any two. ;-}
Actually, my guess is: To meet your spec., under a week.
Possibly in under half that.
Since you don't seem to need ultimate accuracy possible,
(~.3%), with 1% or even 2% seeming reasonable, my guess is
that I could do it with minimal poking into the hardware;
Just doing the fix-counters bit and adding in the fancy
adjustable-average thingy I figured out.
Post by Öldman©
Post by Frank McCoy
D. How deep into the system is a programmer allowed to go?
?? restrict ourselves to 2 x as good as we have now?
cost would have to be reviewed and justified to customer
2x as good, I could probably do with a quick patch.
5x or 10x is more what I'd expect with minimal and reasonable effort
... Say within a week or so.
20x to 30x would take considerable poking with the hardware.
Those (of course) are just guesses. I wouldn't know *anything* for
sure unless and until I tried.
Post by Öldman©
Post by Frank McCoy
I have a fair idea already of what to do if that's the case, and you
want to go with the simplest try for improvement.
The reason I listed the register addresses was that it
occurred to me we don't have to use the macro readCounter
and could use a realtime read of the register.
Another approach might be to use poll_resourse (explained
in previous post) rather than the request_resource, release_
resourse routine. This should make the counter read independent
of the real time system as it does not stop execution of the
current task.
Another real time operation is read_timer_info
Another macro is readCounterInput - if done with a third timer
we need a 10 jiffy read (this would have to be calcualted based
on 10 RPM start test condition(2.4999Hz threshold) to determine
which counter (0 or 1)is active to switch between small and
large motor. Counter 2 is always active for either motor. if
no counter = test stopped.
I'd have to try various methods and see which worked best for best
results. If not trying for ultimate accuracy, perhaps that might be
more trouble than it's worth.
Post by Öldman©
The original programmer used macro s rather than register
read/writes.
Neither macros nor register read/writes is the problem.
The problem is time between taking a measurement and finding the time
... or vice-versa. This time can be shortened; but it doesn't fix the
problem of it being an unknown when system interrupts can come in and
grab or change either one. There *are* ways around that too; if the
processor is fast enough, and the data being measured changes at a
slow enough rate. I *think* this is the case here; but cannot be sure
without testing. If a the routine I'm thinking of can run without
hanging, then those inaccuracies can be jiggered out. If not, then
other, less exact methods will have to be used.
I'm going to TRY and avoid getting down to machine-code level, if
possible.
Post by Öldman©
This would tend to introduce the unknown in loop timing, would
it not?
Not really. See above. The unknown is SYSTEM-level; and caused by
the fact the program is interruptible (and has to be, to keep the
clock running properly).
Reducing the time for a routine just makes it that much less likely to
be screwed by the system ... but to be a bigger hunk off when the
screwup DOES happen (and it will).
Post by Öldman©
The moving window average method has been my interest from day
1 but it wasn't implemented AFAIK.
OK.
THERE, using continuously running counters will help a LOT.
Add in my special averaging method, and my guess is you'd get a
minimum of about 10 times to 20 times (and possibly more) increase in
accuracy. Not ultimate accuracy; but compared to what you have, would
likely be darned good.
!!!OOOOOOOOPPPPSSS!!!
I *HAVE* to be certain of one thing, for my idea to work.
If not, my head-scheme just fell out the window.
a. You have TWO motors; and want to keep track of BOTH of them
simultaneously, right?
Nope! The way it works is that they test EITHER a small motor OR a
large motor. Not possible to run both at the same time with the
test stand hardware setup.
Post by Frank McCoy
b. Does each motor have a separate RPM counter, or are there items
both motors share in common?
Yes - small motor is counter 0, large motor is counter 1 - there is an
if then else statement in the code that looks at which motor is running.
This also tells the on line PC running a data tracking progy in LabView
which motor is under test and when a test is initiated. (via Com2)

This is important in that the torque scaling is different for the two
sizes.This is due to the fact that there are two test stands, each
of which has its own load cell. the large motor torque value is
the scaled result of a 20,000lb 4-20ma loadcell multiplied by
the moment arm length which I would have to dig up right now.

The small motor uses a reaction type load cell which is 50,000in lb
(4167 ft lb) for 20 ma output.

The third counter (2) is active for both sizes of motor.


Explain the set-up :

Two test stands - each with its own load cell and rpm sensor (prox.
sensor)

One fluid pump to drive the motors with a prox. sensor - scaled for flow
(410 USgpm - would need to dig up the exact value)

One pressure xdcr 4-20 ma 3000psi full scale.

Operator physicaly connects a hose to the motor under test to supply
it with fluid (these are 'down hole' directional drill motors, fluid
driven)

Four digital displays in order of importance:

Torque
RPM
Flow
Pressure

The Torque display is software switched to look at the proper
analog input from its load cell. Scaling data default values
are built into the C progy, we can reconfigure scaling at run time.

The RPM display is the same as torque in that it is software
switched to display the proper motor.


You will have to take care to retain the switching function between
counters and analog inputs.

A printer connected to Com 1 RS232 ASCII output can be initiated
via the interupt (used as a digital in) with a two position
switch, A position being maintained, B position being momentary)
Post by Frank McCoy
My whole *idea* requires that each motor have it's own separate
free-running RPM counter that keeps on running unless stopped or
reset; so that I can go read the counter for motor-A, and then later
on go read the counter for motor-B, and then go back and read the
counter for motor-A again, without the readings for motor-A being
screwed up by my reading the counter for motor-B.
If that won't work, then none of the dream-bait I've been working up
would go, with the exception of the averaging routine; and that
wouldn't work half as good as I'd like it to.
Well ... it WOULD work, if only one motor was running at a time; but I
gather that's NOT the case, right?
I know the system clock runs without caring about readings of the
motor counters or vise-versa; as otherwise your present system
wouldn't work. But do the two motor RPM-counters interfere with each
other or use the same counter or path in any way?
NO! each counter uses a separate input and registers.
It sounds to me that your idea will work. I looked at the sample code you
wrote and it appears to address our issues. (far from an expert but I
have programming experience with Commodore Vic 20 - basic and Commodore
128 (I 'skipped the Com 64 because the 128 had an add on 128K RAM
module.) Man, that 128 was a smokin' machine back then - 300k baud modem,
floppy drive and add on RAM configured as RAM harddrive. WOW! I learned
how to build sprites, do peeks and pokes for speed and joystick routines
etc. Actually put together a basic progy for my son (8 or so at the time)
that was joystick controll of a sprite in a pacman type progy (and
sold some copies through my local computer shop).

I also went to a technical school (Electrical Engineering Technologist)
where we learned Fortran IV (kind of dates me eh!).

I tried to learn C and had all of the goodies for it with my 128, more
recently cracked the books again with another run at C++. I have the
Borland C compiler and a learning progy for C but never get the time
needed to really learn it properly.

Wish I would have stuck with programming, that's where the money is now.

Inexpensive and good seems a logical choice for hmmmmm...40 or so hours.
How much per hour are we talking?
--
It is said that wisdom comes with age
--so why am I not very, very wise?
Öldman©
Öldman©
2004-07-27 00:07:31 UTC
Permalink
On Mon, 26 Jul 2004 23:31:01 GMT,Öldman©'s cat ran across
the 'puter keyboard and out came...
Post by Öldman©
On Mon, 26 Jul 2004 15:05:33 -0500,Frank McCoy's cat ran across
the 'puter keyboard and out came...
Post by Frank McCoy
[SNIP]
Post by Öldman©
Post by Frank McCoy
A. How much jitter does the present system have now?
Anywhere from 10 to 20%
OK. That matches my guess pretty close.
Post by Öldman©
Post by Frank McCoy
B. How much jitter would be considered "acceptable"?
5% - with 1% being ideal
Sounds easily doable; with better than that possible.
Post by Öldman©
Post by Frank McCoy
C. How much time/effort/money is available for a fix?
time not a real problem as we have a working system
presently, aiming for improvement
Well ... That wasn't exactly what I meant.
I meant how much time you'd want *me* to spend.
Cheap. Quick. Inexpensive.
Pick any two. ;-}
Actually, my guess is: To meet your spec., under a week.
Possibly in under half that.
Since you don't seem to need ultimate accuracy possible,
(~.3%), with 1% or even 2% seeming reasonable, my guess is
that I could do it with minimal poking into the hardware;
Just doing the fix-counters bit and adding in the fancy
adjustable-average thingy I figured out.
Post by Öldman©
Post by Frank McCoy
D. How deep into the system is a programmer allowed to go?
?? restrict ourselves to 2 x as good as we have now?
cost would have to be reviewed and justified to customer
2x as good, I could probably do with a quick patch.
5x or 10x is more what I'd expect with minimal and reasonable effort
... Say within a week or so.
20x to 30x would take considerable poking with the hardware.
Those (of course) are just guesses. I wouldn't know *anything* for
sure unless and until I tried.
Post by Öldman©
Post by Frank McCoy
I have a fair idea already of what to do if that's the case, and you
want to go with the simplest try for improvement.
The reason I listed the register addresses was that it
occurred to me we don't have to use the macro readCounter
and could use a realtime read of the register.
Another approach might be to use poll_resourse (explained
in previous post) rather than the request_resource, release_
resourse routine. This should make the counter read independent
of the real time system as it does not stop execution of the
current task.
Another real time operation is read_timer_info
Another macro is readCounterInput - if done with a third timer
we need a 10 jiffy read (this would have to be calcualted based
on 10 RPM start test condition(2.4999Hz threshold) to determine
which counter (0 or 1)is active to switch between small and
large motor. Counter 2 is always active for either motor. if
no counter = test stopped.
I'd have to try various methods and see which worked best for best
results. If not trying for ultimate accuracy, perhaps that might be
more trouble than it's worth.
Post by Öldman©
The original programmer used macro s rather than register
read/writes.
Neither macros nor register read/writes is the problem.
The problem is time between taking a measurement and finding the time
... or vice-versa. This time can be shortened; but it doesn't fix the
problem of it being an unknown when system interrupts can come in and
grab or change either one. There *are* ways around that too; if the
processor is fast enough, and the data being measured changes at a
slow enough rate. I *think* this is the case here; but cannot be sure
without testing. If a the routine I'm thinking of can run without
hanging, then those inaccuracies can be jiggered out. If not, then
other, less exact methods will have to be used.
I'm going to TRY and avoid getting down to machine-code level, if
possible.
Post by Öldman©
This would tend to introduce the unknown in loop timing, would
it not?
Not really. See above. The unknown is SYSTEM-level; and caused by
the fact the program is interruptible (and has to be, to keep the
clock running properly).
Reducing the time for a routine just makes it that much less likely to
be screwed by the system ... but to be a bigger hunk off when the
screwup DOES happen (and it will).
Post by Öldman©
The moving window average method has been my interest from day
1 but it wasn't implemented AFAIK.
OK.
THERE, using continuously running counters will help a LOT.
Add in my special averaging method, and my guess is you'd get a
minimum of about 10 times to 20 times (and possibly more) increase in
accuracy. Not ultimate accuracy; but compared to what you have, would
likely be darned good.
!!!OOOOOOOOPPPPSSS!!!
I *HAVE* to be certain of one thing, for my idea to work.
If not, my head-scheme just fell out the window.
a. You have TWO motors; and want to keep track of BOTH of them
simultaneously, right?
Nope! The way it works is that they test EITHER a small motor OR a
large motor. Not possible to run both at the same time with the
test stand hardware setup.
Post by Frank McCoy
b. Does each motor have a separate RPM counter, or are there items
both motors share in common?
Yes - small motor is counter 0, large motor is counter 1 - there is an
if then else statement in the code that looks at which motor is running.
This also tells the on line PC running a data tracking progy in LabView
which motor is under test and when a test is initiated. (via Com2)
This is important in that the torque scaling is different for the two
sizes.This is due to the fact that there are two test stands, each
of which has its own load cell. the large motor torque value is
the scaled result of a 20,000lb 4-20ma loadcell multiplied by
the moment arm length which I would have to dig up right now.
The small motor uses a reaction type load cell which is 50,000in lb
(4167 ft lb) for 20 ma output.
The third counter (2) is active for both sizes of motor.
Two test stands - each with its own load cell and rpm sensor (prox.
sensor)
One fluid pump to drive the motors with a prox. sensor - scaled for flow
(410 USgpm - would need to dig up the exact value)
One pressure xdcr 4-20 ma 3000psi full scale.
Operator physicaly connects a hose to the motor under test to supply
it with fluid (these are 'down hole' directional drill motors, fluid
driven)
Torque
RPM
Flow
Pressure
The Torque display is software switched to look at the proper
analog input from its load cell. Scaling data default values
are built into the C progy, we can reconfigure scaling at run time.
The RPM display is the same as torque in that it is software
switched to display the proper motor.
You will have to take care to retain the switching function between
counters and analog inputs.
A printer connected to Com 1 RS232 ASCII output can be initiated
via the interupt (used as a digital in) with a two position
switch, A position being maintained, B position being momentary)
Post by Frank McCoy
My whole *idea* requires that each motor have it's own separate
free-running RPM counter that keeps on running unless stopped or
reset; so that I can go read the counter for motor-A, and then later
on go read the counter for motor-B, and then go back and read the
counter for motor-A again, without the readings for motor-A being
screwed up by my reading the counter for motor-B.
It just dawned on me that we could revamp the way the test is initiated
by looking at counter 2 (flow) due to the fact that the operator starts
the fluid pump (called a mud pump) at the start of the test and shuts it
off a the end of the test. We have never had a problem with the 'stroke
counter' (flow) because it runs at a fairly consistent speed though out
the
entire test. The proximity sensor is positioned over a gear on the input
shaft which has 15 holes drilled in it to give us 15 pulses (counts) per
revolution of the shaft which is then geared down inside of the triplex
fluid pump. Three piston type cylinders that 'stroke' through aprox.
5 inch dia. cylinders (lots of flow and pressure from these puppies).

An average test runs about 350 USgpm and 2500 psi.
--
Sometimes, something or someone - maybe!
_________________________________
Frank McCoy
2004-07-27 00:49:57 UTC
Permalink
Post by Öldman©
Inexpensive and good seems a logical choice for hmmmmm...40 or so hours.
How much per hour are we talking?
Well ... Actually, the choices were:
Cheap, good, fast. Pick two.
The standard trade-offs in any engineering project.
Here, I think the choices came down to cheap and fast.
Really Good would take WAY too much digging into both hardware and
software.

However: I think I can get that up to "fair", which in comparison to
what you've got now, would look GREAT. It's only in comparison to the
possible that it looks poor. I figure we'll be getting between 1% and
3% accuracy and stability, compared to the present 10%-20%, for an
order-of-magnitude improvement. However, compared to the possible
.1%-.3% hardware-limitation, that's not so great.

Would $35/hr sound like too much?
It's been quite a time since I did piece-work in software.
That would be somewhere about $1200-$2000 for the project ... Most of
the time (I assume) being spent in debug and documentation.

Or, we could haggle over a fixed price.


Oh yeah ... A second thing:
Would you want me to make a general clean-up and speed-up of the whole
'C' program, or just patch in the fix as quickly as possible? There
are techniques that most people who learn 'C' by taking
programming-courses instead of learning how a compiler works and the
object-code it produces, never learn, because for the most part it's
not taught ... Especially these days where instead of writing fast and
tight code, people just buy a machine with more memory and a faster
processor.

One of the more obvious things is avoiding floating-point, so those
libraries don't have to be loaded. That increases speed about ten
times, while cutting program-size in half. Of course, to do that, you
have to be *quite* familiar with integer limitations, or you tend to
lose accuracy. That also means that you have to be certain that
*none* of your object modules uses floating-point, or half of the gain
is lost. Often, if speed or size is important, then doing programing
"no-nos" like having global variables can save considerable execution
time and program size. It depends on what's important. Sometimes
having more supportable "standard" code is the important thing
instead. Similar things can be done in program calls and yes, macros.
Sometimes unwinding a loop can not only produce faster code, but
shorter code as well; which isn't very intuitive; and you have to know
when to do it. Things like that. Other things to be done include
making the program more readable ... Though there's a fair job done on
that already.

Uh ... Do you have a Design Specification written for the program?
Do you want one?
Internal Design Spec? (How the program works.)
External Design Spec? (How the program is supposed to look from the
outside ... to the user.)
User manual?

What about support documentation?
Do you have?
Do you want?
Do you need?

Since it's not an open-ended project, it would make sense to have
these things decided ahead-of-time.

Would I have to do more than just on this one module?
(It *looks* as if the changes can be done from within that module.)

A "quick-and-dirty" fix would probably work; but I doubt that's
exactly what you want, from looking at the code I see. I presume
you'd like neat and documented code, with explanations. Which means,
once the code is *working*, I have to clean it up, add all the
explanations, and then write the necessary documentation, so those who
follow can have some idea of what's going on.

My *guess* is a few hours actually writing code, maybe a day or so
debugging ... passing the results back and forth between me and you;
and the rest of the time cleaning up and documenting the result.

I'm figuring on the old 80/20 rule coming into effect. "The first 80%
of the work takes 80% of the time. The last 20% of the work takes the
other 80% of the time." ;-}
--
_____
/ ' / ™
,-/-, __ __. ____ /_
(_/ / (_(_/|_/ / <_/ <_
Öldman©
2004-07-27 02:03:34 UTC
Permalink
On Mon, 26 Jul 2004 19:49:57 -0500,Frank McCoy's cat ran across
the 'puter keyboard and out came...
Post by Frank McCoy
Post by Öldman©
Inexpensive and good seems a logical choice for hmmmmm...40 or so hours.
How much per hour are we talking?
Cheap, good, fast. Pick two.
The standard trade-offs in any engineering project.
Here, I think the choices came down to cheap and fast.
Really Good would take WAY too much digging into both hardware and
software.
Agreed
Post by Frank McCoy
However: I think I can get that up to "fair", which in comparison to
what you've got now, would look GREAT. It's only in comparison to the
possible that it looks poor. I figure we'll be getting between 1% and
3% accuracy and stability, compared to the present 10%-20%, for an
order-of-magnitude improvement. However, compared to the possible
.1%-.3% hardware-limitation, that's not so great.
I was probably not clear here. We get 2% accuracy when above 100 RPM,
the problems occur at stall, 20% being average below 100 RPM.
Post by Frank McCoy
Would $35/hr sound like too much?
It's been quite a time since I did piece-work in software.
That would be somewhere about $1200-$2000 for the project ... Most of
the time (I assume) being spent in debug and documentation.
$35 per hour for a C programmer is reasonable. Are we talking US$ or
Canuk pesos.
Post by Frank McCoy
Or, we could haggle over a fixed price.
Would you want me to make a general clean-up and speed-up of the whole
'C' program, or just patch in the fix as quickly as possible? There
are techniques that most people who learn 'C' by taking
programming-courses instead of learning how a compiler works and the
object-code it produces, never learn, because for the most part it's
not taught ... Especially these days where instead of writing fast and
tight code, people just buy a machine with more memory and a faster
processor.
A real review of the overall code would be part of the project.

Back in the old days with my Vic 20 I was forced to write 'tight' code.
(hmmmmm.....3.5k bytes free if I remember correctly)
Post by Frank McCoy
One of the more obvious things is avoiding floating-point, so those
libraries don't have to be loaded. That increases speed about ten
times, while cutting program-size in half. Of course, to do that, you
have to be *quite* familiar with integer limitations, or you tend to
lose accuracy. That also means that you have to be certain that
*none* of your object modules uses floating-point, or half of the gain
is lost. Often, if speed or size is important, then doing programing
"no-nos" like having global variables can save considerable execution
time and program size. It depends on what's important. Sometimes
having more supportable "standard" code is the important thing
instead. Similar things can be done in program calls and yes, macros.
Sometimes unwinding a loop can not only produce faster code, but
shorter code as well; which isn't very intuitive; and you have to know
when to do it. Things like that. Other things to be done include
making the program more readable ... Though there's a fair job done on
that already.
I cannot say enough about documentation. That was part of my original
spec. and it has paid off in the readability of the program today.
Standard code is not an issue as this is the only platform this will be
run on and that it also requires quite a few .h libraries that are
dedicated to the Melps 7700 processor and the way it is hardwired into
this mainboard.
Post by Frank McCoy
Uh ... Do you have a Design Specification written for the program?
Do you want one?
Internal Design Spec?
Yup! (How the program works.)
Post by Frank McCoy
External Design Spec? (How the program is supposed to look from the
outside ... to the user.)
Not needed
Post by Frank McCoy
User manual?
Already in place.
Post by Frank McCoy
What about support documentation?
Do you have?
Do you want?
Do you need?
An overview of the program perhaps. As part of the internal design spec.
Post by Frank McCoy
Since it's not an open-ended project, it would make sense to have
these things decided ahead-of-time.
Would I have to do more than just on this one module?
(It *looks* as if the changes can be done from within that module.)
This progy would be 'it' if it is cleaned up.

I do have other projects upcoming and another one presently
on-going with an Omron PLC. It is presently programmed using
ladder logic but I would like to see what we could do with C++.
Post by Frank McCoy
A "quick-and-dirty" fix would probably work; but I doubt that's
exactly what you want, from looking at the code I see. I presume
you'd like neat and documented code, with explanations.
ABSOLUTLY!!
Post by Frank McCoy
Which means,
once the code is *working*, I have to clean it up, add all the
explanations, and then write the necessary documentation, so those who
follow can have some idea of what's going on.
My *guess* is a few hours actually writing code, maybe a day or so
debugging ... passing the results back and forth between me and you;
and the rest of the time cleaning up and documenting the result.
I'm figuring on the old 80/20 rule coming into effect. "The first 80%
of the work takes 80% of the time. The last 20% of the work takes the
other 80% of the time." ;-}
A week is probably a bit optimistic but give or take a few days I think
its in the ballpark.

I will meet with my client this week if possible, after all, he pays the
bills!
--
Sometimes, something or someone - maybe!
_________________________________
Frank McCoy
2004-07-27 05:14:23 UTC
Permalink
Post by Öldman©
I will meet with my client this week if possible, after all, he pays the
bills!
OK. I'll wait like the cat who ate cheese and sat by the moushole.
--
_____
/ ' / ™
,-/-, __ __. ____ /_
(_/ / (_(_/|_/ / <_/ <_
Loading...