Maker Pro
Maker Pro

Power from steam turbines?

R

Rui Maciel

Has anyone implemented a scheme to generate electricity from a steam turbine? If so, can you please
share your experience with the world?


Thanks in advance,
Rui Maciel
 
R

Rui Maciel

Jim said:
http://www.john-tom.com/html/SteamPlans.html

Turbines can be made small enough to fit the handpiece of a dental
drill. I've heard that small ones are inefficient due to tip leakage,
which becomes relatively less as the size increases. Look at the
engines for ships and power stations to see the practical size ranges
for steam turbines versus Diesels.

Thanks for the link, Jim. Although it's interesting, it doesn't have much info regarding steam
turbines beyond a single plan for a toy steam turbine, with no information regarding the power it
generates or even it's efficiency. The site does have quite a lot of plans for toy steam engines
but, again, it provides no info on their power generating capabilities or efficiency.

Are there any resources available on the web regarding steam turbines applications for home power
and the power they are able to generate?



Rui Maciel
 
C

Curbie

Rui Maciel,

Here is a dump of some of the research I did a few years ago on steam
engines both piston and turbine.

My conclusions (for what that is worth) is that if you are building a
single stage plant under 75Hp is way more cost efficient to buy plans
for a piston engine and boiler and have a local machine shop build it.

If you are going to buy go with Mike Brown he has a 3Hp & 20Hp self
starters (2 cylinders). He does not have much competition and his
prices reflect it, but his stuff gets good reviews (what little
reviews there are).

I highly recommend some reading first:
Google Books
Steam_Boiler_Engineering.pdf
Steam_Boilers.pdf
Steam_engine_Principles_and_Practice.pdf
Steam_Power_Plant_Auxiliaries_and_Access.pdf
Steam_Power_Plant_Engineering.pdf

Good Luck.

Curbie


Mike Brown (Finished Piston Enines 1Hp $1200.00, 3Hp $2400.00, 20Hp
$6500.00)
http://home.earthlink.net/~dlaw70/12stmng.htm

Reliable Steam Engines (Piston Plans $50.00, Turbine Plans $50.00,
Boiler Plans $30.00, piston 4-200 Hp, turbine 5Hp)
http://members.pioneer.net/~carlich/RSE/RSEengines.html

Tesla Tubine (Finished Turbine 1Hp $7000,00)
http://www.phoenixnavigation.com/ptbc/turbogen.htm
 
D

Daniel who wants to know

Curbie said:
Rui Maciel,



Mike Brown (Finished Piston Enines 1Hp $1200.00, 3Hp $2400.00, 20Hp
$6500.00)
http://home.earthlink.net/~dlaw70/12stmng.htm

Reliable Steam Engines (Piston Plans $50.00, Turbine Plans $50.00,
Boiler Plans $30.00, piston 4-200 Hp, turbine 5Hp)
http://members.pioneer.net/~carlich/RSE/RSEengines.html

Tesla Tubine (Finished Turbine 1Hp $7000,00)
http://www.phoenixnavigation.com/ptbc/turbogen.htm


Hmm 1hp engine with 40k BTU waste heat. 1hp=746w=2544 BTU per hour.
2544/42,544= just a hair under 6% efficiency.
 
S

sno

Hmm 1hp engine with 40k BTU waste heat. 1hp=746w=2544 BTU per hour.
2544/42,544= just a hair under 6% efficiency.

I think I remember that steam was very inefficient....15 percent...??
(piston not turbine)...remember a lot of btu's are lost by heat from
boiler....etc....

Is reason is not used any more....

Also you should know that steam is very, very, very dangerous...reason
they have steam ratings for ships engineers.....you really need to know
what you are doing....do not think is something a home Hobiest should
fool with....

thank you for listening to my thoughts....sno

--
Correct Scientific Terminology:
Hypothesis - a guess as to why or how something occurs
Theory - a hypothesis that has been checked by enough experiments
to be generally assumed to be true.
Law - a hypothesis that has been checked by enough experiments
in enough different ways that it is assumed to be truer then a theory.
Note: nothing is proven in science, things are assumed to be true.
 
R

Rui Maciel

sno said:
I think I remember that steam was very inefficient....15 percent...??
(piston not turbine)...remember a lot of btu's are lost by heat from
boiler....etc....

Is reason is not used any more....

Yes, steam engines are terribly inefficient. Steam turbines, on the other hand, are pointed out as
being capable of having efficiencies which even surpass the efficiency of diesel engines.

Also you should know that steam is very, very, very dangerous...reason
they have steam ratings for ships engineers.....you really need to know
what you are doing....do not think is something a home Hobiest should
fool with....

I see what you mean and you do have a point. Nonetheless, although I'm not a mechanical engineer, I
do have an engineering background (civil, structural). Besides, getting some info on a subject
tends to be quite safe.


Rui Maciel
 
D

daestrom

Rui said:
Yes, steam engines are terribly inefficient. Steam turbines, on the other hand, are pointed out as
being capable of having efficiencies which even surpass the efficiency of diesel engines.

Yes, but it isn't just the turbine. A modern turbine can, itself, be
very efficient. Power plant turbines have efficiencies approaching 90%.
But that just measures the losses within the turbine.

The whole Rankine cycle efficiency is much lower (30-40% is common).
And to get that you need re-heaters for the turbine. Take steam out at
an intermediate pressure, strip out the moisture and re-heat it back to
near the same temperature as initial.

And feed-water heaters so the condensate you're pumping back into the
boiler isn't cold as from the condenser but pre-heated to almost boiling.

Then, since you've invested a lot of money in this equipment, you might
want to start thinking about chemistry control to prevent corrosion from
eating through the heaters.

There's a reason that home-project steam plants aren't very efficient, cost.

daestrom
 
R

Rui Maciel

Morris said:
If you're willing to widen your search to include other external
combustion engine flavors, you might consider Stirling engines - and, in
particular, the fluid piston fluidynes.

Thanks for the tip, Morris. I had initially discarded this type of engine because after looking
into it I was left with the idea that their use was basically limited to gimmicky, non-power
generation applications such as small table-top toys. After a bit more reading I've noticed that
although their efficiency is rather low, there are quite a lot of qualities that make these sort
of engines an interesting option to consider.

Do civil engineering students study thermodynamics? [Be careful how you
answer. :) ]

I don't see why any civil engineering student wouldn't be able to study thermodynamics, although
it would be something that they would have to do in their spare time. According to the courses
I'm familiar with, the typical civil engineering course includes an introductory course on
thermodynamics and then puts a bit of emphasis on fluid mechanics. That is, obviously, not
comparable with the emphasis that mechanical engineering courses place on thermodynamics, even
when ignoring specific courses covering turbo-machinery.

Nonetheless, this is a bit of a non-issue in this particular discussion. I don't plan to build a
power plant from scratch, which would be quite a hefty task to pull off. All I want is to get
information about the available options to generate power in an off-the-grid scenario. Solar power
is a nice option, provided that we focus on solar-thermal. That option becomes even more
interesting if it's possible to complement it with biomass. Yet, it all boils down to (pun
unintended) how we convert heat to mechanical energy, and there is virtually no relevant info on
this subject.


Rui Maciel
 
S

steamer

--One thing to know about steam turbines: they don't equal steam
piston engines in efficiency until you get up to about 52hp; this equates to
about 500 square feet of heating surface with wood firing or about 350
square feet of heating surface with oil firing. I'm thinking you'd need a
pile of heating surface for solar conversion and that would mean a *huge*
array: several acres at least.
 
C

Curbie

Morris, thanks for the kind words.

Rui Maciel,
All I want is to get information about the available
options to generate power in an off-the-grid scenario.
Solar power is a nice option, provided that we focus
on solar-thermal. That option becomes even more
interesting if it's possible to complement it with biomass.
Yet, it all boils down to (pun unintended) how we
convert heat to mechanical energy, and there is
virtually no relevant info on this subject.

Alternative energy is called "alternative" for a reason, commercially
speaking, there is a more efficient way to accomplish the same thing,
so when you set out to produce energy on a home-scale you
automatically lose the more efficient fuel, economy of scale, and
engineering efficiencies that the commercial folks have developed.

My point here is, it's cheaper and probably will lead to a more
successful result if you allow your location's resources and
requirements dictate the best source(s) of alternative energy and not
go into the problem with a preconceived solution. After all, we are
talking about finding the best, less efficient energy alternative and
we are staring with some significant disadvantages.

A sound understanding of your location's climate pattern (solar, wind,
rain, and temperature), your site's land, water, and topographical
resources and your personal energy requirements is, in my view, the
first step of building a successful off-grid plan. One size (or plan)
does not fit all, just using the solar-thermal and bio idea as an
example, a successful solar-thermal and bio plan would look very
different in Montana, than a successful plan in Florida. Different
resources and requirements.

I've been studying the combination of solar-thermal and bio, but that
simple notion covers a lot of territory from anaerobic (in the absence
of oxygen) decomposition of bio-mass for methane, steam reforming of
carbon for hydrogen, woodgas (or Syngas), ethanol, and bio-diesel, not
to mention solar collectors or concentrators.

I don't know what your resources, requirements, or plans are, but I
may have found some of the relevant information you've been looking
for.

Curbie
 
C

Curbie

Here some simple math to illustrate the problem of solar steam
generated electricity on a home-scale:

A steam engine requires (old rule of thumb) 33,472 BTU's per 1 HP per
hour.

Full Sunshine striking a surface on the earth contains a maximum of
317 BTU per square foot per hour of heat energy.

So, 33,472 / 317 = ~106 square feet of concentrator per HP, and this
does not consider optical, transport, or exchange losses, which would
probably triple the square footage per HP.

Solar-thermal steam generated electricity is being done at a
commercial-scale and could be done on a home-scale if it was being
done for reasons other than economic, because it seems highly unlikely
that a home-scale device built on current technology would ever be
able to return its investment.

Curbie
 
U

Urluberluh

Hi Rui,

The average steam locomotive engine had an efficiency of about 10%, this
due to a lot of heat lost in the steam expelled after doing her work,
and also because the pistons mechanisms are know to have a bad efficiency.

In some todays use of steam where we recycle the steam output and
recover the heat remaining we are able to get a better efficiency.
Joined with high efficiency turbines, it gives a total efficiency that
is better than every other kind of engines.

The main problem with using a turbine is that it need to run in a short
and specific range of rpm. If you run outside of this range, the
efficiency drop drastically and you might damage the turbine. Usually,
the turbine need to be redesigned for each new applications.

So, my advice for you is to look for a closed loop steam circuit to
recover the heat in the steam at the output of the engine. This could be
done maybe with a heatpump or a light compression of the steam. If you
want some ideas about this, take a look at a student project from the
Connecticut university where they use this kind of theory to build an
high efficient steam engine for automotive. http://www.brashengines.com/

I don't understand everything about this brash system, but it seems that
they use a mix of air compressed and steam.

On our side, at APUQ (www.apuq.com) we are working on a steam only
system where we will recover the heat from the steam at the output of
the engine where the steam is used and recycled in a closed loop. So no
need for a big water supply and big boiler. We are working both our
engine to fit a microcar or a solar steam electric generator.

We are using a Quasiturbine (www.quasiturbine.com) engine as mechanical
transformator to make rotational movement from the steam and drive the
wheel or the generator. Our main advantage in using this Quasiturbine
engine is that it keep a constant efficiency over a wide (almost total)
range of operation. Our actuals Quasiturbines prototypes gives us around
80% efficiency and this independantly of the rpm, we have the same
efficiency at 150 rpm or 3000 rpm independantly of the load. You will
not find this kind of efficiency in a piston kind engine and it will
cost you a lot to design a turbine that will need to be suited for a
specific need...

There are many more advantages to use a Quasiturbine engine with steam,
but I let you discover them yourself by looking at www.quasiturbine.com
there are lot of data and explainations about the engine itself and some
comparisons about other engines also.

Sorry for my bad english, but it's not my motherlangage... If you have
more questions I will try to answer the best I can.

Salutations,
Olivier

Le 2010-08-26 14:08, Rui Maciel a écrit :
 
V

vaughn

Notice that the turbine -inlet- pressure was below atmospheric, which
is 14.7 PSI absolute.

I don't remember how to do the calculations, but the Navy taught me steam tables
etc. many decades ago. I do remember this... You can't BELIEVE how much the
vacuum from the condenser adds to the efficiency of a steam plant. It is
perfectly reasonable to assume that the main purpose of the condensers is to
save the feed water for re-use...and perfectly wrong. Condensers (and their
heat sink) are a very important part of the Rankine cycle, even though it is
possible to make a steam plant run without.

Since most small steam plants omit the condenser, most small steam plants end up
with abysmal efficiency and little power output for the mass and expense of the
machinery. Also, steam plants typically need the full attention of an on-site
human operator. This is not true for most other types of renewable energy.
For comparison, I briefly check on my PV system about once every three months,
and evaluate the batteries annually, an investment of about 2 hours a year.

Vaughn
 
S

steamer

Curbie said:
Solar-thermal steam generated electricity is being done at a
commercial-scale and could be done on a home-scale if it was being
done for reasons other than economic, because it seems highly unlikely
that a home-scale device built on current technology would ever be
able to return its investment.

--Agreed but if you want to take a whack at it there were plans in
Mother Earth News maybe 25 to 30 yrs back on how to roll your own solar
powered steam plant. Pretty impractical but a good 'learning experience'.
I'm still waiting for plans to roll my own heliostat tho: with a fixed
'target' boiler and a little time here and there one could build more and
more heliostats as money permitted to get some decent power returns.
 
C

Curbie

Steamboat Ed,

I did a few Mother Earth News projects 30 year ago, they sparked my in
interest in solar concentrators, but I don't like in return on
investment numbers for solar-steam on a home-scale. That said, I don't
know too many hobbies that return on investment which isn't the point
of a hobby.

In general I like the outline of your plan using heliostats, they
solve the issue of wide-area heat-loss via transmission to a single
point or boiler, heliostats won't change the rough BTU per square foot
per HP math, but will help keep it closer to the 106 square foot per
HP rather than 300 square foot per HP.

Heliostat mounting and tracking controllers will be your largest
expense and here, I would recommend studying your location's climate
patterns for a sound understanding of wind and/or snow at your
location, it will be cheaper to fix many heliostats to a single
tracking mount, but the number of heliostats you can reasonably fix to
a single mount will be largely dictated the effects of wind and snow
loading, not just on the overall strength of the mount, but optical
error produced by the reflected light missing the receiver target.
Consider them an X square foot sail.
http://www.heliostat.us/

I would also consider a small flash boiler inside a tube encased by
aluminum as the tower receiver, the notion here is to store heat in
the phase-changed aluminum (solid to liquid) instead of as steam in a
larger boiler.

I hope you'll take a few minutes from time to time to update this
group on the progress of your project, both technical and cost
aspects, I think the cost of energy can only make the return on
investment numbers look better with time.

Good luck,

Curbie
 
C

Curbie

Here’s a link to NREL’s PvWatts:
http://rredc.nrel.gov/solar/calculators/PVWATTS/version2/

It mainly a program for PV panel sizing but also gives heat energy in
kWh/m^2 for many locations in the US, which is handy for sizing solar
concentrators. For us old Americans 1kWh = 3412.142 BTUs/h and 1
meter^2 = 10.76391 ft^2, so 3412 / 10.76391 = 317 BTU/ft^2/h.

And here is the source code for two solar tracking programs, the first
was written in C by NREL and includes a VB port I did, this NREL
program has a high degree of accuracy but is more CPU intensive, while
the second program (not written by NREL) is both less accurate and CPU
intensive.

Have fun,

Curbie


Option Compare Database
Option Explicit
'=============================================================================
' Contains:
' S_solpos (computes solar position and intensity from time and
place)
' INPUTS: via posdata struct) year, daynum, hour, minute,
second, latitude, longitude, timezone, intervl
' OPTIONAL: (via posdata struct) month, day, press, temp, tilt,
aspect, function
' OUTPUTS: EVERY variable in the struct posdata (defined in
solpos.h)
'
' NOTE: Certain conditions exist during which some of
the output variables are undefined or cannot be
' calculated. In these cases, the variables are
returned with flag values indicating such. In other
' cases, the variables may return a realistic, though
invalid, value. These variables and the flag values
' or invalid conditions are listed below:
'
' amass -1.0 at zenetr angles greater than 93.0
degrees
' ampress -1.0 at zenetr angles greater than 93.0
degrees
' azim invalid at zenetr angle 0.0 or latitude
+/-90.0 or at night elevetr limited to -9 degrees at
' night
' etr 0.0 at night
' etrn 0.0 at night
' etrtilt 0.0 when cosinc is less than 0
' prime invalid at zenetr angles greater than 93.0
degrees
' sretr +/- 2999.0 during periods of 24 hour sunup
or sundown
' ssetr +/- 2999.0 during periods of 24 hour sunup
or sundown
' ssha invalid at the North and South Poles unprime
invalid at zenetr angles greater than 93.0 degrees
' zenetr limited to 99.0 degrees at night
'
' S_init (optional initialization for all input parameters in
the posdata struct)
' INPUTS: struct posdata*
' OUTPUTS: struct posdata*
'
' (Note: initializes the required S_solpos INPUTS above
to out-of-bounds conditions, forcing the user to
' supply the parameters; initializes the OPTIONAL
S_solpos inputs above to nominal values.)
'
' S_decode (optional utility for decoding the S_solpos return
code)
' INPUTS: long integer S_solpos return value, struct posdata*
' OUTPUTS: text to stderr
'
' Usage: In calling program, just after other 'includes',
insert:
'
' #include "solpos00.h"
'
' Function calls:
' S_init(struct posdata*) [optional]
' .
' .
' [set time and location parameters before S_solpos
call]
' .
' .
' int retval = S_solpos(struct posdata*)
' S_decode(int retval, struct posdata*) [optional]
' (Note: you should always look at the S_solpos return
value, which contains error codes. S_decode is one
' option for examining these codes. It can also serve
as a template for building your own application-
' specific decoder.)
'
' Martin Rymes
' National Renewable Energy Laboratory
' 25 March 1998
'
' 27 April 1999 REVISION: Corrected leap year in S_date.
' 13 January 2000 REVISION: SMW converted to structure posdata
parameter
' and subdivided into functions.
' 01 February 2001 REVISION: SMW corrected ecobli calculation
' (changed sign). Error is small (max
0.015 deg
' in calculation of declination angle)
'-----------------------------------------------------------------------------
'#include <math.h>
'#include <string.h>
'#include <stdio.h>
'#include "solpos00.h"

'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'
' Structures defined for this module
'
'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Private Type trigdata ' used to pass
calculated values locally
cd As Single ' cosine of the
declination
ch As Single ' cosine of the hour
angle
cl As Single ' cosine of the latitude
sd As Single ' sine of the
declination
Sl As Single ' sine of the latitude
End Type

'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'
' Temporary global variables used only in this file:
'
'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'cumulative number of days prior to beginning of month 0=non-leap
year, 1=leap year
Private month_days(1, 12) As Integer ' day of month array
Private array_init As Boolean ' day of month array
initalization flag
Private Const degrad As Single = 57.295779513 ' converts from
radians to degrees
Private Const raddeg As Single = 0.0174532925 ' converts from
degrees to radians


'=============================================================================
' Long integer function S_solpos, adapted from the VAX solar libraries
'
' This function calculates the apparent solar position and the
intensity of the sun (theoretical maximum solar energy)
' from time and place on Earth.
'
' Requires (from the struct posdata parameter):
' Date and time:
' year
' daynum (requirement depends on the S_DOY switch)
' month (requirement depends on the S_DOY switch)
' day (requirement depends on the S_DOY switch)
' hour
' minute
' second
' interval DEFAULT 0
' Location:
' latitude
' longitude
' Location/time adjuster:
' timezone
' Atmospheric pressure and temperature:
' press DEFAULT 1013.0 mb
' temp DEFAULT 10.0 degrees C
' Tilt of flat surface that receives solar energy:
' aspect DEFAULT 180 (South)
' tilt DEFAULT 0 (Horizontal)
' Function Switch (codes defined in solpos.h)
' function DEFAULT S_ALL
'
' Returns (via the struct posdata parameter):
' everything defined in the struct posdata in solpos.h.
'-----------------------------------------------------------------------------
Public Function S_solpos(pdat As posdata) As Long
Dim retval As Long ' return value
Dim tdat As trigdata ' trig data

' initialize the trig structure
tdat.sd = -999# ' flag to force
calculation of trig data
tdat.cd = 1# '
tdat.ch = 1# ' set the rest of these
to something safe
tdat.cl = 1# '
tdat.Sl = 1# '

If Not array_init Then InitArray ' if day of month array
not initalized, do it
If ((retval = validate(pdat)) <> 0) Then ' if position data
validates
S_solpos = retval ' return validate flags
End If ' if position data
validates

If (pdat.function And L_DOY) Then ' if day of year
conversion required
doy2dom pdat ' convert input doy to
month-day
Else ' else convert day of
month
dom2doy pdat ' convert input
month-day to doy
End If ' if day of year
conversion required

If (pdat.function And L_GEOM) Then ' if basic geometry
calculations required
geometry pdat ' do basic geometry
calculations
End If ' if basic geometry
calculations required

If (pdat.function And L_ZENETR) Then ' if etr at
non-refracted zenith angle required
zen_no_ref pdat, tdat ' do etr at
non-refracted zenith angle
End If ' if etr at
non-refracted zenith angle required

If (pdat.function And L_SSHA) Then ' if Sunset hour
calculation required
ssha pdat, tdat ' do Sunset hour
calculation required
End If ' if Sunset hour
calculation required

If (pdat.function And L_SBCF) Then ' if ShadoWBRSd
correction factor required
sbcf pdat, tdat ' do ShadoWBRSd
correction factor
End If ' if ShadoWBRSd
correction factor required

If (pdat.function And L_TST) Then ' if true solar time
required
Tst pdat ' do true solar time
End If ' if true solar time
required

If (pdat.function And L_SRSS) Then ' if sunrise/sunset
calculations required
srss pdat ' if sunrise/sunset
calculations
End If ' if sunrise/sunset
calculations required

If (pdat.function And L_SOLAZM) Then ' if solar azimuth
calculations required
SAzm pdat, tdat ' do solar azimuth
calculations
End If ' if solar azimuth
calculations required

If (pdat.function And L_REFRAC) Then ' if atmospheric
refraction calculations required
Refrac pdat ' do atmospheric
refraction calculations
End If ' if atmospheric
refraction calculations required

If (pdat.function And L_AMASS) Then ' if airmass
calculations required
amass pdat ' do airmass
calculations required
End If ' if airmass
calculations required

If (pdat.function And L_PRIME) Then ' if kt-prime/unprime
calculations required
prime pdat ' do kt-prime/unprime
calculations
End If ' if kt-prime/unprime
calculations required

If (pdat.function And L_ETR) Then ' if ETR and ETRN
(refracted) required
etr pdat ' do ETR and ETRN
(refracted)
End If ' if ETR and ETRN
(refracted) required

If (pdat.function And L_TILT) Then ' if tilt calculations
required
Tilt pdat ' do ETR and ETRN
(refracted)
End If ' if tilt calculations
required

S_solpos = 0 ' done
End Function


'============================================================================
' Void function S_init
'
' This function initiates all of the input parameters in the struct
posdata passed to S_solpos(). Initialization is
' either to nominal values or to out of range values, which forces
the calling program to specify parameters.
'
' NOTE: This function is optional if you initialize ALL input
parameters in your calling code. Note that the required
' parameters of date and location are deliberately initialized out of
bounds to force the user to enter real-world
' values.
'
' Requires: Pointer to a posdata structure, members of which are
initialized.
'
' Returns: Void
'-----------------------------------------------------------------------------
Public Sub S_init(pdat As posdata)
pdat.Day = -99 ' Day of month (May 27 =
27, etc.)
pdat.daynum = -999 ' Day number (day of
year; Feb 1 = 32 )
pdat.Hour = -99 ' Hour of day, 0 - 23
pdat.Minute = -99 ' Minute of hour, 0 - 59
pdat.Month = -99 ' Month number (Jan = 1,
Feb = 2, etc.)
pdat.second = -99 ' Second of minute, 0 -
59
pdat.Year = -99 ' 4-digit year
pdat.interval = 0 ' instantaneous
measurement interval
pdat.aspect = 180# ' Azimuth of panel
surface (direction it faces) N=0, E=90, S=180, W=270
pdat.Latitude = -99# ' Latitude, degrees
north (south negative)
pdat.Longitude = -999# ' Longitude, degrees
east (west negative)
pdat.press = 1013# ' Surface pressure,
millibars
pdat.solcon = 1367# ' Solar constant, 1367
W/sq m
pdat.Temp = 15# ' Ambient dry-bulb
temperature, degrees C
pdat.Tilt = 0# ' Degrees tilt from
horizontal of panel
pdat.TimeZone = -99# ' Time zone, east (west
negative).
pdat.sbwid = 7.6 ' Eppley shadow band
width
pdat.sbrad = 31.7 ' Eppley shadow band
radius
pdat.sbsky = 0.04 ' Drummond factor for
partly cloudy skies
pdat.function = S_ALL ' compute all parameters
End Sub


'============================================================================
' Local long int function validate
'
' Validates the input parameters
'----------------------------------------------------------------------------
Private Function validate(pdat As posdata) As Long
Dim retval As Long ' return value

retval = 0 ' start return value
with no errors
If (pdat.function And L_GEOM) Then ' if basic geometry
calculations required
If ((pdat.Year < 1950) Or (pdat.Year > 2050)) Then
retval = retval Or ShL32F(1, S_YEAR_ERROR)
End If ' if invalid algoritm
year limits

If (Not (pdat.function And S_DOY) And ((pdat.Month < 1) Or
(pdat.Month > 12))) Then
retval = retval Or ShL32F(1, S_MONTH_ERROR)
End If ' if invalid month

If (Not (pdat.function And S_DOY) And ((pdat.Day < 1) Or (pdat.Day
31))) Then
retval = retval Or ShL32F(1, S_DAY_ERROR)
End If ' if invalid day month

If ((pdat.function And S_DOY) And ((pdat.daynum < 1) Or
(pdat.daynum > 366))) Then
retval = retval Or ShL32F(1, S_DOY_ERROR)
End If ' if invalid day of year

If ((pdat.Hour < 0) Or (pdat.Hour > 24)) Then
retval = retval Or ShL32F(1, S_HOUR_ERROR)
End If ' if vainvalidlid hour
of day

If ((pdat.Minute < 0) Or (pdat.Minute > 59)) Then
retval = retval Or ShL32F(1, S_MINUTE_ERROR)
End If ' if invalid mintue of
hour

If ((pdat.second < 0) Or (pdat.second > 59)) Then
retval = retval Or ShL32F(1, S_SECOND_ERROR)
End If ' if invalid second of
minute

If ((pdat.Hour = 24) And (pdat.Minute > 0)) Then
retval = retval Or (ShL32F(1, S_HOUR_ERROR) Or ShL32F(1,
S_MINUTE_ERROR))
End If ' if more than 24 hrs
(addditional minutes)

If ((pdat.Hour = 24) And (pdat.second > 0)) Then
retval = retval Or (ShL32F(1, S_HOUR_ERROR) Or ShL32F(1,
S_SECOND_ERROR))
End If ' if more than 24 hrs
(addditional seconds)

If (CSng(Abs(pdat.TimeZone)) > 12#) Then
retval = retval Or ShL32F(1, S_TZONE_ERROR)
End If ' if invalid time zone

If ((pdat.interval < 0) Or (pdat.interval > 28800)) Then
retval = retval Or ShL32F(1, S_INTRVL_ERROR)
End If ' if invalid interval

If (CSng(Abs(pdat.Longitude)) > 180#) Then
retval = retval Or ShL32F(1, S_LON_ERROR)
End If ' if invalid longitude

If (CSng(Abs(pdat.Latitude)) > 90#) Then
retval = retval Or ShL32F(1, S_LAT_ERROR)
End If ' if invalid latitude
End If ' if basic geometry
calculations required

If ((pdat.function And L_REFRAC) And (CSng(Abs(pdat.Temp)) > 100#))
Then
retval = retval Or ShL32F(1, S_TEMP_ERROR)
End If ' if invalid
temperatures

If ((pdat.function And L_REFRAC) And (pdat.press < 0#) Or
(pdat.press > 2000#)) Then
retval = retval Or ShL32F(1, S_PRESS_ERROR)
End If ' if invalid pressures

If ((pdat.function And L_TILT) And (CSng(Abs(pdat.Tilt)) > 180#))
Then
retval = retval Or ShL32F(1, S_TILT_ERROR)
End If ' if invalid tilt

If ((pdat.function And L_TILT) And (CSng(Abs(pdat.aspect)) > 360#))
Then
retval = retval Or ShL32F(1, S_ASPECT_ERROR)
End If ' if invalid aspect

If ((pdat.function And L_SBCF) And (pdat.sbwid < 1#) Or (pdat.sbwid
100#)) Then
retval = retval Or ShL32F(1, S_SBWID_ERROR)
End If ' if invalid shadoWBRSds
width

If ((pdat.function And L_SBCF) And (pdat.sbrad < 1#) Or (pdat.sbrad
100#)) Then
retval = retval Or ShL32F(1, S_SBRAD_ERROR)
End If ' if invalid shadoWBRSds
radians

If ((pdat.function And L_SBCF) And (CSng(Abs(pdat.sbsky)) > 1#))
Then
retval = retval Or ShL32F(1, S_SBSKY_ERROR)
End If ' if invalid shadoWBRSds
sky

validate = retval ' return error status

End Function


'*****************************************************************************
' Private Sub InitArray TWW porting construct
'
' loads day-of-month array with non-leap year and leap year days until
start
' of month
'
' Requires: nothing
'*****************************************************************************
Private Sub InitArray()
month_days(0, 2) = 31 ' Febuary non-leap
year
month_days(1, 2) = 31 ' Febuary leap year
month_days(0, 3) = 59 ' March non-leap
year
month_days(1, 3) = 60 ' March leap year
month_days(0, 4) = 90 ' April non-leap
year
month_days(1, 4) = 91 ' April leap year
month_days(0, 5) = 120 ' May non-leap
year
month_days(1, 5) = 121 ' May leap year
month_days(0, 6) = 151 ' June non-leap
year
month_days(1, 6) = 152 ' June leap year
month_days(0, 7) = 181 ' July non-leap
year
month_days(1, 7) = 182 ' July leap year
month_days(0, 8) = 212 ' August non-leap
year
month_days(1, 8) = 213 ' August leap year
month_days(0, 9) = 243 ' September non-leap
year
month_days(1, 9) = 244 ' September leap year
month_days(0, 10) = 273 ' October non-leap
year
month_days(1, 10) = 273 ' October leap year
month_days(0, 11) = 304 ' November non-leap
year
month_days(1, 11) = 305 ' November leap year
month_days(0, 12) = 334 ' December non-leap
year
month_days(1, 12) = 335 ' December leap year
array_init = True ' month array
initilized, we don't need to do it again
End Sub


'============================================================================
' Local Void function dom2doy
'
' Converts day-of-month to day-of-year
'
' Requires (from struct posdata parameter):
' year
' month
' day
'
' Returns (via the struct posdata parameter):
' year
' daynum
'-----------------------------------------------------------------------------
Private Sub dom2doy(pdat As posdata)
' cumulative number of days prior to beginning of month for leap year
pdat.daynum = pdat.Day + month_days(0, pdat.Month)
' Corrected by NREL (TW)
' If (((pdat.year Mod 4) = 0) And (((pdat.year Mod 100) <> 0) Or
((pdat.year Mod 400) = 0)) And (pdat.month > 2)) Then
If (((pdat.Year Mod 4) = 0) And (((pdat.Year Mod 100) <> 0) Or
((pdat.Year Mod 400) = 0))) Then
pdat.daynum = pdat.daynum + 1 ' adjust for leap year
End If ' if leap year
End Sub


'============================================================================
' Local void function doy2dom
'
' This function computes the month/day from the day number.
'
' Requires (from struct posdata parameter):
' Year and day number:
' year
' daynum
'
' Returns (via the struct posdata parameter):
' year
' month
' day
'-----------------------------------------------------------------------------
Private Sub doy2dom(pdat As posdata)
Dim Leap As Integer ' leap year switch
Dim imon As Integer ' Month (month_days)
array counte

If (((pdat.Year Mod 4) = 0) And (((pdat.Year Mod 100) <> 0) Or
((pdat.Year Mod 400) = 0))) Then
Leap = 1 ' set the leap year
switch
Else ' if not leap year
Leap = 0 ' set the non-leap year
switch
End If ' if leap year

imon = 12 ' default to Decamber
While pdat.daynum <= month_days(Leap, imon) ' loop to find number of
days prior to beginning of month
imon = imon - 1 ' decrement month
pointer
Wend ' loop to find number of
days prior to beginning of month
pdat.Month = imon ' set the month and day
of month
pdat.Day = pdat.daynum - month_days(Leap, imon)
End Sub


'============================================================================
' Local Void function geometry
'
' Does the underlying geometry for a given time and location
'-----------------------------------------------------------------------------
Private Sub geometry(pdat As posdata)

Dim bottom As Single ' denominator (bottom)
of the fraction
Dim c2 As Single ' cosine of d2
Dim cd As Single ' cosine of the day
angle or delination
Dim d2 As Single ' pdat.dayang times two
Dim Delta As Single ' difference between
current year and 1949
Dim s2 As Single ' sine of d2
Dim sd As Single ' sine of the day angle
Dim top As Single ' numerator (top) of the
fraction
Dim Leap As Integer ' (month_days) array
switch

' Day angle
' Iqbal, M. 1983. An Introduction to Solar Radiation. Academic
Press, NY., page 3
pdat.dayang = 360# * (pdat.daynum - 1) / 365#

' Earth radius vector * solar constant = solar energy Spencer, J. W.
1971. Fourier series representation of the
' position of the sun. Search 2 (5), page 172
sd = Sin(raddeg * pdat.dayang) ' get the sine of the
day angle
cd = Cos(raddeg * pdat.dayang) ' get the cosine of the
day angle or delination
d2 = 2# * pdat.dayang ' get the day angle
times two
c2 = Cos(raddeg * d2) ' get the cosine of d2
s2 = Sin(raddeg * d2) ' get the sine of d2

pdat.erv = 1.00011 + 0.034221 * cd + 0.00128 * sd
pdat.erv = pdat.erv + 0.000719 * c2 + 0.000077 * s2

' Universal Coordinated (Greenwich standard) time Michalsky, J.
1988. The Astronomical Almanac's algorithm for
' approximate solar position (1950-2050). Solar Energy 40 (3),
pp. 227-235.
pdat.utime = pdat.Hour * 3600# + pdat.Minute * 60# + pdat.second -
CSng(pdat.interval) / 2#
pdat.utime = pdat.utime / 3600# - pdat.TimeZone

' Julian Day minus 2,400,000 days (to eliminate roundoff errors)
Michalsky, J. 1988. The Astronomical Almanac's
' algorithm for approximate solar position (1950-2050). Solar
Energy 40 (3), pp. 227-235.

' No adjustment for century non-leap years since this function is
bounded by 1950 - 2050
Delta = pdat.Year - 1949 ' get the difference
between current year and 1949
Leap = CInt((Delta / 4#)) ' get (month_days) array
switch
pdat.julday = 32916.5 + Delta * 365# + Leap + pdat.daynum +
pdat.utime / 24#

' Time used in the calculation of ecliptic coordinates Noon 1 JAN
2000 = 2,400,000 + 51,545 days Julian Date
' Michalsky, J. 1988. The Astronomical Almanac's algorithm for
approximate solar position (1950-2050). Solar
' Energy 40 (3), pp. 227-235.
pdat.ectime = pdat.julday - 51545# ' get time of ecliptic
calculations

' Mean longitude
' Michalsky, J. 1988. The Astronomical Almanac's algorithm for
approximate solar position (1950-2050). Solar
' Energy 40 (3), pp. 227-235.
pdat.MnLong = 280.46 + 0.9856474 * pdat.ectime

' (dump the multiples of 360, so the answer is between 0 and 360) */
pdat.MnLong = pdat.MnLong - 360# * CInt((pdat.MnLong / 360#))
If (pdat.MnLong < 0#) Then '
pdat.MnLong = pdat.MnLong = 360# '
End If '

' Mean anomaly
' Michalsky, J. 1988. The Astronomical Almanac's algorithm for
approximate solar position (1950-2050). Solar
' Energy 40 (3), pp. 227-235.
pdat.MnAnom = 357.528 + 0.9856003 * pdat.ectime

' (dump the multiples of 360, so the answer is between 0 and 360)
pdat.MnAnom = pdat.MnAnom - 360# * CInt((pdat.MnAnom / 360#))
If (pdat.MnAnom < 0#) Then '
pdat.MnAnom = pdat.MnAnom + 360# '
End If '

' Ecliptic longitude */
' Michalsky, J. 1988. The Astronomical Almanac's algorithm for
approximate solar position (1950-2050). Solar
' Energy 40 (3), pp. 227-235.
pdat.EcLong = pdat.MnLong + 1.915 * Sin(pdat.MnAnom * raddeg) + 0.02
* Sin(2# * pdat.MnAnom * raddeg)

' (dump the multiples of 360, so the answer is between 0 and 360)
pdat.EcLong = pdat.EcLong - 360# * CInt(pdat.EcLong / 360#)
If (pdat.EcLong < 0#) Then
pdat.EcLong = pdat.EcLong + 360#
End If '

' Obliquity of the ecliptic
' Michalsky, J. 1988. The Astronomical Almanac's algorithm for
approximate solar position (1950-2050). Solar Energy
' 40 (3) pp. 227-235.
pdat.ecobli = 23.439 - 0.0000004 * pdat.ectime

' Declination
' Michalsky, J. 1988. The Astronomical Almanac's algorithm for
approximate solar position (1950-2050). Solar Energy
' 40 (3), pp. 227-235.
pdat.declin = degrad * Asin(Sin(pdat.ecobli * raddeg) *
Sin(pdat.EcLong * raddeg))

' Right ascension
' Michalsky, J. 1988. The Astronomical Almanac's algorithm for
approximate solar position (1950-2050). Solar Energy
' 40 (3), pp. 227-235.
top = Cos(raddeg * pdat.ecobli) * Sin(raddeg * pdat.EcLong)
bottom = Cos(raddeg * pdat.EcLong) '

pdat.rascen = degrad * Atan(top, bottom) '

' (make it a positive angle)
If (pdat.rascen < 0#) Then '
pdat.rascen = pdat.rascen + 360# '
End If '

' Greenwich mean sidereal time
' Michalsky, J. 1988. The Astronomical Almanac's algorithm for
approximate solar position (1950-2050). Solar Energy
' 40 (3), pp. 227-235.
pdat.Gmst = 6.697375 + 0.0657098242 * pdat.ectime + pdat.utime

' (dump the multiples of 24, so the answer is between 0 and 24)
pdat.Gmst = pdat.Gmst - 24# * CInt(pdat.Gmst / 24#)
If (pdat.Gmst < 0#) Then '
pdat.Gmst = pdat.Gmst + 24# '
End If '

' Local mean sidereal time
' Michalsky, J. 1988. The Astronomical Almanac's algorithm for
approximate solar position (1950-2050). Solar Energy
' 40 (3), pp. 227-235.
pdat.Lmst = pdat.Gmst * 15# + pdat.Longitude

' (dump the multiples of 360, so the answer is between 0 and 360)
pdat.Lmst = pdat.Lmst - 360# * CInt(pdat.Lmst / 360#)
If (pdat.Lmst < 0#) Then '
pdat.Lmst = pdat.Lmst + 360# '
End If '


' Hour angle
' Michalsky, J. 1988. The Astronomical Almanac's algorithm for
approximate solar position (1950-2050). Solar Energy
' 40 (3), pp. 227-235.
pdat.HrAng = pdat.Lmst - pdat.rascen '

' (force it between -180 and 180 degrees)
If (pdat.HrAng < -180#) Then '
pdat.HrAng = pdat.HrAng + 360# '
Else
If (pdat.HrAng > 180#) Then '
pdat.HrAng = pdat.HrAng - 360# '
End If '
End If '

End Sub


'=============================================================================
' Local Void function zen_no_ref
'
' ETR solar zenith angle
' Iqbal, M. 1983. An Introduction to Solar Radiation.
' Academic Press, NY., page 15
'-----------------------------------------------------------------------------
Private Sub zen_no_ref(pdat As posdata, tdat As trigdata)
Dim Cz As Single ' cosine of the solar
zenith angle

localtrig pdat, tdat '
Cz = tdat.sd * tdat.Sl + tdat.cd * tdat.cl * tdat.ch

' (watch out for the roundoff errors)
If CSng(Abs(Cz)) > 1# Then '
' If Abs(CZ) > 1# Then '
If (Cz >= 0#) Then '
Cz = 1# '
Else '
Cz = -1# '
End If '
End If '

pdat.zenetr = Acos(Cz) * degrad ''

' (limit the degrees below the horizon to 9 [+90 -> 99])
If (pdat.zenetr > 99#) Then '
pdat.zenetr = 99# '
End If '

pdat.elevetr = 90# - pdat.zenetr '

End Sub


'============================================================================
' Local Void function ssha
'
' Sunset hour angle, degrees
' Iqbal, M. 1983. An Introduction to Solar Radiation.
' Academic Press, NY., page 16
'-----------------------------------------------------------------------------
Private Sub ssha(pdat As posdata, tdat As trigdata)
Dim cssha As Single ' cosine of the sunset
hour angle
Dim cdcl As Single ' ( cd * cl )

localtrig pdat, tdat '
cdcl = tdat.cd * tdat.cl '

If CSng(Abs(cdcl)) >= 0.001 Then '
' If Abs(cdcl) >= 0.001 Then '
cssha = -tdat.Sl * tdat.sd / cdcl '
' This keeps the cosine from blowing on roundoff
If (cssha < -1#) Then '
pdat.ssha = 180# '
ElseIf (cssha > 1#) Then '
pdat.ssha = 0# '
Else '
pdat.ssha = degrad * Acos(cssha) '
End If '

ElseIf (((pdat.declin >= 0#) And (pdat.Latitude > 0#)) Or
((pdat.declin < 0#) And (pdat.Latitude < 0#))) Then
pdat.ssha = 180# '
Else '
pdat.ssha = 0# '
End If '
End Sub '


'=============================================================================
' Local Void function sbcf
'
' ShadoWBRSd correction factor
' Drummond, A. J. 1956. A contribution to absolute pyrheliometry.
' Q. J. R. Meteorol. Soc. 82, pp. 481-493
'-----------------------------------------------------------------------------
Private Sub sbcf(pdat As posdata, tdat As trigdata)
Dim P As Single ' used to compute sbcf
Dim t1 As Single ' used to compute sbcf
Dim t2 As Single ' used to compute sbcf

localtrig pdat, tdat '
P = 0.6366198 * pdat.sbwid / pdat.sbrad * tdat.cd ^ 3
t1 = tdat.Sl * tdat.sd * pdat.ssha * raddeg '
t2 = tdat.cl * tdat.cd * Sin(pdat.ssha * raddeg)
pdat.sbcf = pdat.sbsky + 1# / (1# - P * (t1 + t2))
End Sub


'=============================================================================
' Local Void function tst
'
' TST -> True Solar Time = local standard time + TSTfix, time
' in minutes from midnight.
' Iqbal, M. 1983. An Introduction to Solar Radiation.
' Academic Press, NY., page 13
'-----------------------------------------------------------------------------
Private Sub Tst(pdat As posdata)
pdat.Tst = (180# + pdat.HrAng) * 4# '
' add back half of the interval
pdat.tstfix = pdat.Tst - CSng(pdat.Hour) * 60# - pdat.Minute -
CSng(pdat.second) / 60# + CSng(pdat.interval) / 120#

While pdat.tstfix > 720# ' bound tstfix to this
day
pdat.tstfix = pdat.tstfix - 1440# '
Wend '
While pdat.tstfix < -720# '
pdat.tstfix = pdat.tstfix + 1440# '
Wend '
pdat.eqntim = pdat.tstfix + 60# * pdat.TimeZone - 4# *
pdat.Longitude
End Sub


'=============================================================================
' Local Void function srss
'
' Sunrise and sunset times (minutes from midnight)
'-----------------------------------------------------------------------------
Private Sub srss(pdat As posdata)
If (pdat.ssha <= 1#) Then '
pdat.sretr = 2999# '
pdat.ssetr = -2999# '
ElseIf (pdat.ssha >= 179#) Then '
pdat.sretr = -2999# '
pdat.ssetr = 2999# '
Else '
pdat.sretr = 720# - 4# * pdat.ssha - pdat.tstfix '
pdat.ssetr = 720# + 4# * pdat.ssha - pdat.tstfix '
End If '
End Sub


'=============================================================================
' Local Void function sazm
'
' Solar azimuth angle
' Iqbal, M. 1983. An Introduction to Solar Radiation.
' Academic Press, NY., page 15
'-----------------------------------------------------------------------------
Private Sub SAzm(pdat As posdata, tdat As trigdata)
Dim ca As Single ' cosine of the solar
azimuth angle
Dim ce As Single ' cosine of the solar
elevation
Dim cecl As Single ' ( ce * cl )
Dim se As Single ' sine of the solar
elevation

localtrig pdat, tdat '
ce = Cos(raddeg * pdat.elevetr) '
se = Sin(raddeg * pdat.elevetr) '

pdat.azim = 180# '
cecl = ce * tdat.cl '
If Abs(cecl) >= 0.001 Then '
ca = (se * tdat.Sl - tdat.sd) / cecl '
If (ca > 1#) Then '
ca = 1# '
ElseIf (ca < -1#) Then '
ca = -1# '
End If '
pdat.azim = 180# - Acos(ca) * degrad '
If (pdat.HrAng > 0) Then '
pdat.azim = 360# - pdat.azim '
End If '
End If '
End Sub


'=============================================================================
' Local Int function refrac
'
' Refraction correction, degrees
' Zimmerman, John C. 1981. Sun-pointing programs and their
accuracy.
' SAND81-0761, Experimental Systems Operation Division 4721,
' Sandia National Laboratories, Albuquerque, NM.
'-----------------------------------------------------------------------------
Private Sub Refrac(pdat As posdata)
Dim prestemp As Single ' temporary
pressure/temperature correction
Dim refcor As Single ' temporary refraction
correction
Dim tanelev As Single ' tangent of the solar
elevation angle
Dim Part1 As Single ' expression part 1
Dim Part2 As Single ' expression part 2
Dim Part3 As Single ' expression part 3

If (pdat.elevetr > 85#) Then ' If the sun is near
zenith, the algorithm bombs; refraction near 0
refcor = 0# '
Else ' Otherwise, we have
refraction
tanelev = Tan(raddeg * pdat.elevetr) '
If (pdat.elevetr >= 5#) Then '
refcor = 58.1 / tanelev - 0.07 / (tanelev ^ 3) + 0.000086 /
(tanelev ^ 5)
ElseIf (pdat.elevetr >= -0.575) Then '
' refcor = 1735# + pdat.elevetr * (-518.2 + pdat.elevetr * (103.4
+ pdat.elevetr * (-12.79 + pdat.elevetr * 0.711)))
Part1 = -12.79 + pdat.elevetr * 0.711 '
Part2 = 103.4 + pdat.elevetr * Part1 '
Part3 = -518.2 + pdat.elevetr * Part2 '
refcor = 1735# + pdat.elevetr * Part3 '
Else '
refcor = -20.774 / tanelev '
End If '
prestemp = (pdat.press * 283#) / (1013# * (273# + pdat.Temp))
refcor = refcor * prestemp / 3600# '
End If ' If the sun is near
zenith, the algorithm bombs; refraction near 0

pdat.elevref = pdat.elevetr + refcor ' Refracted solar
elevation angle

If (pdat.elevref < -9#) Then ' (limit the degrees
below the horizon to 9)
pdat.elevref = -9# '
End If ' (limit the degrees
below the horizon to 9)

pdat.zenref = 90# - pdat.elevref ' Refracted solar zenith
angle
pdat.coszen = Cos(raddeg * pdat.zenref) '
End Sub


'=============================================================================
' Local Void function amass
'
' Airmass
' Kasten, F. and Young, A. 1989. Revised optical air mass tables
and approximation formula. Applied Optics 28 (22),
' pp. 4735-4738
'-----------------------------------------------------------------------------
Private Sub amass(pdat As posdata)
If (pdat.zenref > 93#) Then '
pdat.amass = -1# '
pdat.ampress = -1# '
Else '
pdat.amass = 1# / (Cos(raddeg * pdat.zenref) + 0.50572 * (96.07995
- pdat.zenref) ^ -1.6364)
pdat.ampress = pdat.amass * pdat.press / 1013#
End If '
End Sub


'=============================================================================
' Local Void function prime
'
' Prime and Unprime
' Prime converts Kt to normalized Kt', etc.
' Unprime deconverts Kt' to Kt, etc. Perez, R., P. Ineichen, Seals,
R., & Zelenka, A. 1990. Making
' full use of the clearness index for parameterizing hourly
insolation conditions. Solar Energy 45 (2), pp. 111-114
'-----------------------------------------------------------------------------
Private Sub prime(pdat As posdata)
pdat.unprime = 1.031 * Exp(-1.4 / (0.9 + 9.4 / pdat.amass)) + 0.1
pdat.prime = 1# / pdat.unprime '
End Sub


'=============================================================================
' Local Void function etr
'
' Extraterrestrial (top-of-atmosphere) solar irradiance
'-----------------------------------------------------------------------------
Private Sub etr(pdat As posdata)
If (pdat.coszen > 0#) Then '
pdat.etrn = pdat.solcon * pdat.erv '
pdat.etr = pdat.etrn * pdat.coszen '
Else '
pdat.etrn = 0# '
pdat.etr = 0# '
End If '
End Sub


'=============================================================================
' Local Void function localtrig
'
' Does trig on internal variable used by several functions
'-----------------------------------------------------------------------------
Private Sub localtrig(pdat As posdata, tdat As trigdata)
' define masks to prevent calculation of uninitialized variables
Const SD_MASK As Long = (L_ZENETR Or L_SSHA Or S_SBCF Or
S_SOLAZM)
Const SL_MASK As Long = (L_ZENETR Or L_SSHA Or S_SBCF Or
S_SOLAZM)
Const CL_MASK As Long = (L_ZENETR Or L_SSHA Or S_SBCF Or
S_SOLAZM)
Const CD_MASK As Long = (L_ZENETR Or L_SSHA Or S_SBCF)
Const CH_MASK As Long = (L_ZENETR)

If (tdat.sd < -900#) Then ' sd was initialized
-999 as flag
tdat.sd = 1# ' reflag as having
completed calculations
If (pdat.function Or CD_MASK) Then tdat.cd = Cos(raddeg *
pdat.declin)
If (pdat.function Or CH_MASK) Then tdat.ch = Cos(raddeg *
pdat.HrAng)
If (pdat.function Or CL_MASK) Then tdat.cl = Cos(raddeg *
pdat.Latitude)
If (pdat.function Or SD_MASK) Then tdat.sd = Sin(raddeg *
pdat.declin)
If (pdat.function Or SL_MASK) Then tdat.Sl = Sin(raddeg *
pdat.Latitude)
End If '
End Sub


'=============================================================================
' Local Void function tilt
'
' ETR on a tilted surface
'-----------------------------------------------------------------------------
Private Sub Tilt(pdat As posdata)
Dim ca As Single ' cosine of the solar
azimuth angle
Dim cp As Single ' cosine of the panel
aspect
Dim ct As Single ' cosine of the panel
tilt
Dim sa As Single ' sine of the solar
azimuth angle
Dim sp As Single ' sine of the panel
aspect
Dim st As Single ' sine of the panel tilt
Dim sz As Single ' sine of the refraction
corrected solar zenith angle

' Cosine of the angle between the sun and a tipped flat surface,
' useful for calculating solar energy on tilted surfaces
ca = Cos(raddeg * pdat.azim) '
cp = Cos(raddeg * pdat.aspect) '
ct = Cos(raddeg * pdat.Tilt) '
sa = Sin(raddeg * pdat.azim) '
sp = Sin(raddeg * pdat.aspect) '
st = Sin(raddeg * pdat.Tilt) '
sz = Sin(raddeg * pdat.zenref) '
pdat.CosInc = pdat.coszen * ct + sz * st * (ca * cp + sa * sp)

If (pdat.CosInc > 0#) Then '
pdat.etrtilt = pdat.etrn * pdat.CosInc '
Else '
pdat.etrtilt = 0# '
End If
End Sub


'=============================================================================
' Void function S_decode
'
' This function decodes the error codes from S_solpos return value
'
' Requires the long integer return value from S_solpos
'
' Returns descriptive text to stderr
'-----------------------------------------------------------------------------
Public Sub S_decode(Code As Long, pdat As posdata)
If Code = 0 Then Exit Sub ' if no errors, return
(added by Tommy)
If (Code And (ShL32F(1, S_YEAR_ERROR))) Then '
MsgBox "S_decode ==> Please fix the year: " & pdat.Year & "
[1950-2050]"
End If '
If (Code And (ShL32F(1, S_MONTH_ERROR))) Then '
MsgBox "S_decode ==> Please fix the month: " & pdat.Month
End If '
If (Code And (ShL32F(1, S_DAY_ERROR))) Then '
MsgBox "S_decode ==> Please fix the month: " & pdat.Day
End If '
If (Code And (ShL32F(1, S_DOY_ERROR))) Then '
MsgBox "S_decode ==> Please fix the day-of-year: " & pdat.daynum
End If '
If (Code And (ShL32F(1, S_HOUR_ERROR))) Then '
MsgBox "S_decode ==> Please fix the hour: " & pdat.Hour
End If '
If (Code And (ShL32F(1, S_MINUTE_ERROR))) Then '
MsgBox "S_decode ==> Please fix the minute: " & pdat.Minute
End If '
If (Code And (ShL32F(1, S_SECOND_ERROR))) Then '
MsgBox "S_decode ==> Please fix the second: " & pdat.second
End If '
If (Code And (ShL32F(1, S_TZONE_ERROR))) Then '
MsgBox "S_decode ==> Please fix the time zone: " & pdat.TimeZone
End If '
If (Code And (ShL32F(1, S_INTRVL_ERROR))) Then '
MsgBox "S_decode ==> Please fix the interval: " & pdat.interval
End If '
If (Code And (ShL32F(1, S_LAT_ERROR))) Then '
MsgBox "S_decode ==> Please fix the latitude: " & pdat.Latitude
End If '
If (Code And (ShL32F(1, S_LON_ERROR))) Then '
MsgBox "S_decode ==> Please fix the longitude: " & pdat.Longitude
End If '
If (Code And (ShL32F(1, S_TEMP_ERROR))) Then '
MsgBox "S_decode ==> Please fix the temperature: " & pdat.Temp
End If '
If (Code And (ShL32F(1, S_PRESS_ERROR))) Then '
MsgBox "S_decode ==> Please fix the pressure: " & pdat.press
End If '
If (Code And (ShL32F(1, S_TILT_ERROR))) Then '
MsgBox "S_decode ==> Please fix the tilt: " & pdat.Tilt
End If '
If (Code And (ShL32F(1, S_ASPECT_ERROR))) Then '
MsgBox "S_decode ==> Please fix the aspect: " & pdat.aspect
End If '
If (Code And (ShL32F(1, S_SBWID_ERROR))) Then '
MsgBox "S_decode ==> Please fix the shadoWBRSd width: " &
pdat.sbwid
End If '
If (Code And (ShL32F(1, S_SBRAD_ERROR))) Then '
MsgBox "S_decode ==> Please fix the shadoWBRSd radius: " &
pdat.sbrad
End If '
If (Code And (ShL32F(1, S_SBSKY_ERROR))) Then '
MsgBox "S_decode ==> Please fix the shadoWBRSd sky factor: " &
pdat.sbsky
End If '
End Sub


*****************************************************************************
Option Compare Database
Option Explicit

Public Const Pi = 3.14159265 ' define pi

Public Function Radians(Degree As Double) As Double
' convert degrees to radians
Radians = Degree * Pi / 180 ' calculate and
return degrees converted to radians
End Function

Public Function Degrees(Radian As Double) As Double
' convert radians to degrees
Degrees = Radian * 180 / Pi ' calculate and
return radians converted to degrees
End Function

Public Function EquationOfTime(DayNumber As Double) As Double
' Equation of Time using day number
Dim R As Double ' radians
R = Radians((360 * (DayNumber - 1)) / 365.242) ' load radians
EquationOfTime = 0.258 * Cos(R) - 7.416 * Sin(R) - 3.648 * Cos(2 *
R) - 9.228 * Sin(2 * R)
End Function

Public Function LongitudeCorrection(TimeZone As Double, Longitude As
Double) As Double
' Longitude Correction using time zone and longitude
LongitudeCorrection = (15 * TimeZone - Longitude) / 15 ' calculate and
return solar time
End Function

Public Function LocalTime(ST As Double, DST As Double, EOT As Double,
LC As Double) As Double
' Local Time using solar time, daylight saving time, equation of time,
and longitude correction
LocalTime = ST - (EOT / 60) + LC + DST ' calculate and
return local time
End Function

Public Function SolarTime(LTD As Double, DST As Double, EOT As Double,
LC As Double) As Double
' Solar Time using local time decmal, daylight saving time, equation
of time, and longitude correction
SolarTime = LTD + (EOT / 60) - LC - DST ' calculate and
return solar time
End Function

Public Function DecimalToHMS(X As Double) As String
' Return time in 24Hr. string formatted 19:29:12
Dim Hrs As Integer ' hours
Dim Mins As Integer ' minutes
Dim Secs As Integer ' seconds

Hrs = Int(X) ' calculate hours
Mins = Int(60 * (X - Hrs)) ' calculate
minutes
Secs = Int(3600 * (X - Hrs - Mins / 60)) ' calculate
seconds
DecimalToHMS = Format(Hrs, "00") & ":" & Format(Mins, "00") & ":" &
Format(Secs, "00")
End Function

' arc sine
' error if value is outside the range [-1,1]
Function ASin(value As Double) As Double
If Abs(value) <> 1 Then
ASin = Atn(value / Sqr(1 - value * value))
Else
ASin = 1.5707963267949 * Sgn(value)
End If
End Function

' arc cosine
' error if NUMBER is outside the range [-1,1]
Function ACos(ByVal number As Double) As Double
If Abs(number) <> 1 Then
ACos = 1.5707963267949 - Atn(number / Sqr(1 - number * number))
ElseIf number = -1 Then
ACos = 3.14159265358979
End If
'elseif number=1 --> Acos=0 (implicit)
End Function

' arc cotangent
' error if NUMBER is zero
Function ACot(value As Double) As Double
ACot = Atn(1 / value)
End Function

' arc secant
' error if value is inside the range [-1,1]
Function ASec(value As Double) As Double
' NOTE: the following lines can be replaced by a single call
' ASec = ACos(1 / value)
If Abs(value) <> 1 Then
ASec = 1.5707963267949 - Atn((1 / value) / Sqr(1 - 1 / (value *
value)))
Else
ASec = 3.14159265358979 * Sgn(value)
End If
End Function

' arc cosecant
' error if value is inside the range [-1,1]
Function ACsc(value As Double) As Double
' NOTE: the following lines can be replaced by a single call
' ACsc = ASin(1 / value)
If Abs(value) <> 1 Then
ACsc = Atn((1 / value) / Sqr(1 - 1 / (value * value)))
Else
ACsc = 1.5707963267949 * Sgn(value)
End If
End Function
 
N

News

On our side, at APUQ (www.apuq.com) we are working on a steam only system
where we will recover the heat from the steam at the output of the engine
where the steam is used and recycled in a closed loop. So no need for a
big water supply and big boiler. We are working both our engine to fit a
microcar or a solar steam electric generator.

We are using a Quasiturbine (www.quasiturbine.com) engine as mechanical
transformator to make rotational movement from the steam and drive the
wheel or the generator. Our main advantage in using this Quasiturbine
engine is that it keep a constant efficiency over a wide (almost total)
range of operation. Our actuals Quasiturbines prototypes gives us around
80% efficiency and this independantly of the rpm,

If this is correct, then an external combustion flash boiler and a
quasiturbine looks good indeed. There will be loses in the burner/boiler.
Say, used in a vehicle, the efficiency in mpg is the prime figure, taking
into account the boiler losses.
External combustion is far cleaner and simpler than internal combustion.

This sort of setup may be ideal for a hybrid using it as a range extender
genny setup. Maybe in busses, trucks and trains. Space permitting of
course.
 
Top