Our full technical support staff does not monitor this forum. If you need assistance from a member of our staff, please submit your question from the Ask a Question page.


Log in or register to post/reply in the forum.

Wind Direction from Serial Thies sensor


TimoRoth Oct 2, 2017 01:45 PM

Hello,

Our station, which is running on a CR3000 datalogger, is using a Thies serial Wind Direction sensor.
The sensor in use is a Combined Wind Direction/Speed sensor 4.3336.31.000. It is documented just as "16 bit serial data", using two wires, Data and Clock, which I wired up to C1 and C2 on the CR3000.

By using some examples for similar sensors I found on the Internet and in this Forum, I came up with the following CRBasic code for the Sensor: 

Const WindSpeedPulseChannel = 2 ' 2 consecutive
Const WindClockPort = 1
Const WindDataPort = 2

'Wind Speed Sensors
Public WindSpeed(2)
Alias WindSpeed(1)=WindSpeed2m
Alias WindSpeed(2)=WindSpeed10m
Units WindSpeed2m=m/s
Units WindSpeed10m=m/s

Const WindStartLength_us=3000
Const WindPulseLenght_us=1000
Public WindCode(8) As Boolean
Public InvWindCode(8) As Boolean
Public tempInteger As Long, invInteger As Long, Sector As Long
Public DirFine As Boolean
Public WindDir
Units WindDir = degrees
Dim vmult As Long
Dim LookupArray(143) As Long
DataLong 1,3,2,6,7,5,4,12,13,15,14,10,11,9,8,24,25,27,26,30,31,29,28,20,21,23,22,18,19,17,16,48,49,51,50,54,55,53,52,60,61,63
DataLong 62,58,59,57,56,40,41,43,42,46,47,45,44,36,37,39,38,34,35,33,32,96,97,99,98,102,103,101,100,228,229,231,230,226,227,225,224,160,161,163
DataLong 162,166,167,165,164,172,173,175,174,170,171,169,168,184,185,187,186,190,191,189,188,180,181,183,182,178,179,177,176,144,145,147,146,150,151,149,148,156,157,159
DataLong 158,154,155,153,152,136,137,139,138,142,143,141,140,132,133,135,134,130,131,129,128

Dim k As Long

DataTable(Measurements, True, -1)
  WindVector(1, WindSpeed10m, WindDir, IEEE4, False, 30 / ScanInterval, 0, 0)
  FieldNames("MeanWindSpeed10m,MeanWindDir10m,StdWindDir10m")
EndTable

SequentialMode
AngleDegrees

BeginProg
  SetStatus("USRDriveSize", 0)

  For k = 1 To 143
    Read LookupArray(k)
  Next k

  Scan(10, Sec, 0, 0)
    'Wind Speed Sensors
    PulseCount(WindSpeed(), 2, WindSpeedPulseChannel, 0, 1, 0.05, 0)

    PortSet(WindClockPort, 0)
    PortSet(WindClockPort, 1)
    Delay(0, WindStartLength_us, usec)
    PortSet(WindClockPort, 0)
    Delay(0, WindPulseLenght_us, usec)
    PortGet(WindCode(1), WindDataPort)
    For k = 2 To 8
      PulsePort(WindClockPort, WindPulseLenght_us)
      PortGet(WindCode(k), WindDataPort)
    Next k
    For k = 1 To 8
      PulsePort(WindClockPort, WindPulseLenght_us)
      PortGet(InvWindCode(k), WindDataPort)
    Next k
    tempInteger = 0
    invInteger = 0
    vmult = 1
    For k = 1 To 8
      If WindCode(k) Then tempInteger = tempInteger OR vmult
      If InvWindCode(k) Then invInteger = invInteger OR vmult
      vmult = vmult * 2
    Next k
    If 255 - tempInteger = invInteger Then
      DirFine = true
    Else
      DirFine = false
    EndIf
    Sector = NAN
    If tempInteger = 0 Then
      Sector = 0
    Else
      For k = 1 To 143
        If tempInteger = LookupArray(k) Then
          Sector = k
          ExitFor
        EndIf
      Next k
    EndIf
    If DirFine Then
      WindDir = Sector * 2.5
    Else
      WindDir = NAN
    EndIf

    CallTable Measurements
  NextScan
EndProg

 Sometimes, on very rare occasions, this actually does produce valid results which I can observe showing in the Public table and in turn also storing non-zero values in the measurements table. But the majority of the time, all values in WindCode and InvWindCode are false, correctly resulting in a NAN result.

The Sensor worked fine when it was running on the old Thies Datalogger, and the Wind Speed sensor in the same unit is producing valid results as well, so the wire is still intact as well.


JDavis Oct 2, 2017 03:42 PM

It has been quite some time since I wrote the code to work with the sensor. I believe if your cable is long, you will need to increase the delays.

The delays are constants in the beginning of your program.

Const WindStartLength_us=3000
Const WindPulseLenght_us=1000

TimoRoth Oct 2, 2017 06:30 PM

I increased the delays to 7500µs and 2500µs, which did temporarily result in all 16 bits being True instead of False, but by now everything is back to False.

I'm gonna tripple check if the wiring is correct the next time I get to our station.


TimoRoth Oct 6, 2017 08:54 AM

This is very weird. By now, I'm positive the wiring is correct and the sensor generally working.

As it turns out, being connected with LoggerNet Connect to the CR3000 causes the measurement of the wind sensor to fail, reading all bits as False. The moment I disconnect LoggerNet and use the built in Webinterface to look at the Public values, I can see valid readings showing up consistently. Every now and then one reading randomly fails, but overall most of them seem succesfull.

The WindVector outputs MeanWindDir and StdWindDir have been 0 all the time though. So I modified the code a bit, to inverse the DirFine variable, and am now using it as DisableVar for the WindVector. The first measurement with it looks promising.

That only leaves me with the question why connecting to the datalogger is enough to throw the timing off so much that it fails reading the sensor entirely.


JDavis Oct 6, 2017 04:49 PM

If you replace the For Next loops with SubScans like we do with multiplexers, you could get the program to compile in PipeLineMode. The would enforce stricter timing on the pulse sequence.


TimoRoth Oct 6, 2017 09:10 PM

I changed the script to run in PipelineMode. Some other sensor using SW12 blocks the Script from automatically compiling in PipelineMode, but forcing it works without errors or warnings.

For some reason, the best results in PipelineMode I get by using delays of only 2000/1000, while in SequentialMode it was 7500/2500.
It's still missing a few more values than in SequentialMode(2~3 in PipelineMode, consistently only 1 in SeqMode).

Unfortunately, connecting with Connect still completely makes it fail to communicate with the sensor entirely. So I'm tempted to go back to SequentialMode again.

Something else I observed is that either the Grey Code table is wrong, or the inverse value is sent first. I get a lot of values that are not in the table. But the inverse of them always seems to be in the table. So I switched out the actual and the inverted value, and will see what data it collects with that over night.

For reference, here is the full Script I am currently running:

 

'CR3000

'Program Constants
Const DataOutputInterval = 10 ' Output Interval in minutes
Const ScanInterval = 10 ' Scan Interval in seconds

'Sensor Ports
Const RainPulseChannel = 1
Const WindSpeedPulseChannel = 2 ' 2 consecutive
Const TempDiffChannel = 10 ' 3 consecutive
Const HumidDiffChannel = 4 ' 2 consecutive
Const GlobalRadDiffChannel = 6
Const NetRadDiffChannel = 7
Const ShfDiffChannel = 8
Const ShfSePlateVoltChannel = 17
Const ShfSw12VChannel = 1
Const WindClockPort = 1
Const WindDataPort = 2

'Internal Sensors
Public BattV
Public PTemp_C
Units BattV=Volts
Units PTemp_C=Deg C

'Rain Sensor
Public Rain
Units Rain=mm

'Wind Speed Sensors
Public WindSpeed(2)
Alias WindSpeed(1)=WindSpeed2m
Alias WindSpeed(2)=WindSpeed10m
Units WindSpeed2m=m/s
Units WindSpeed10m=m/s

'Temperature Sensors
Dim RS0(3) = {100.0, 100.0, 100.0} 'PT100 resistances at 0C
Public TempRes(3)
Public TempRatio(3)
Public Temp(3)
Alias Temp(1)=Temp2m
Alias Temp(2)=Temp10m
Alias Temp(3)=TempGround
Units Temp2m=Deg C
Units Temp10m=Deg C
Units TempGround=Deg C

'Humidity Sensors
Public relHumid(2)
Alias relHumid(1)=relHumid2m
Alias relHumid(2)=relHumid10m
Units relHumid2m=%
Units relHumid10m=%

'Global Radiation Sensor
Public SlrW
Public SlrkJ
Units SlrW=W/m^2
Units SlrkJ=kJ/m^2

'Net Radiation Sensor
Public NR_Wm2
Public CNR_Wm2
Units NR_Wm2=W/m^2
Units CNR_Wm2=W/m^2

'Heat Flux Sensor
Const SHF_CAL_INTERVAL = 1440
Const SHF_END_CAL = 29
Const SHF_HFP01SC_CAL = 15 'Unique Multiplier for HFP01SC (1000/sensitivity)
Public Shf
Public Shf_Cal
Units Shf = W/m^2
Units Shf_Cal = W/(m^2 mV)
'Calibration Vars
Dim shf_mV
Dim shf_mV_0
Dim shf_mV_180
Dim shf_mV_end
Dim shf_V_Rf
Dim shf_V_Rf_180
Dim shf_cal_on_f As Boolean
Dim shf_sw_state As Boolean

'Sunshine Hours
Dim RTime(9)
Public SunHrs
Public PotSlrW
Public SolPos(5)
Alias SolPos(1)=SolarAzimuth
Alias SolPos(2)=SunElevation
Alias SolPos(3)=HourAngle
Alias SolPos(4)=Declination
Alias SolPos(5)=AirMass
Units SunHrs=hours
Units PotSlrW=W/m^2
Units SolarAzimuth=degrees
Units SunElevation=degrees
Units HourAngle=radians
Units Declination=radians
Units AirMass=unitless

'Wind Direction Sensor
Const WindStartLength_us=2000
Const WindPulseLenght_us=1000
Public WindCode(16) As Boolean
Public tempInteger As Long, invInteger As Long, Sector As Long
Public DirInvalid As Boolean
Public ReadInvalid As Boolean
Public WindDir
Units WindDir = degrees
Dim LookupArray(143) As Long
DataLong 1,3,2,6,7,5,4,12,13,15,14,10,11,9,8,24,25,27,26,30,31,29,28,20,21,23,22,18,19,17,16,48,49,51,50,54,55,53,52,60,61,63
DataLong 62,58,59,57,56,40,41,43,42,46,47,45,44,36,37,39,38,34,35,33,32,96,97,99,98,102,103,101,100,228,229,231,230,226,227,225,224,160,161,163
DataLong 162,166,167,165,164,172,173,175,174,170,171,169,168,184,185,187,186,190,191,189,188,180,181,183,182,178,179,177,176,144,145,147,146,150,151,149,148,156,157,159
DataLong 158,154,155,153,152,136,137,139,138,142,143,141,140,132,133,135,134,130,131,129,128

'Generic Helper Variables
Dim i As Long
Dim k As Long

'Data Upload Variables
Public FTPResult
Public TimeOffset As Long

'Define Data Tables
DataTable(Measurements, True, -1)
  DataInterval(0, DataOutputInterval, Min, 0)
  'Rain
  Totalize(1, Rain, IEEE4, False)
  'Wind Speed
  Average(2, WindSpeed(), IEEE4, False)
  'Temperatures
  Average(3, Temp(), IEEE4, False)
  'rel. Humidity
  Average(2, relHumid(), IEEE4, False)
  'Global Radiation
  Average(1, SlrW, IEEE4, False)
  Totalize(1, SlrkJ, IEEE4, False)
  'Net Radiation
  Average(1, NR_Wm2, IEEE4, False)
  Average(1, CNR_Wm2, IEEE4, False)
  'Heat Flux
  Average(1, Shf, IEEE4, shf_cal_on_f)
  Sample(1, Shf_Cal, IEEE4)
  'Sunshine Hours
  Totalize(1, SunHrs, IEEE4, False)
  'Wind Direction
  WindVector(1, WindSpeed10m, WindDir, IEEE4, DirInvalid, 30 / ScanInterval, 0, 0)
  FieldNames("MeanWindSpeed10m,MeanWindDir10m,StdWindDir10m")
  Totalize(1, ABS(DirInvalid), UINT4, False)
  FieldNames("InvalidWindDirs")
  Totalize(1, ABS(ReadInvalid), UINT4, False)
  FieldNames("InvalidWindReads")
EndTable

DataTable(Voltages, True, 24 * 90)
  DataInterval(0, 1, Hr, 0)
  'Internal Sensors
  Minimum(1, BattV, IEEE4, False, False)
  Average(1, PTemp_C, IEEE4, False)
EndTable

PipelineMode
AngleDegrees

'Main Program
BeginProg
  SetStatus("USRDriveSize", 0)

  For k = 1 To 143
    Read LookupArray(k)
  Next k

  Shf_Cal = SHF_HFP01SC_CAL

  'Main Scan
  Scan(ScanInterval, Sec, 0, 0)
    'Internal Sensors
    Battery(BattV)
    PanelTemp(PTemp_C, _50Hz)

    'Rain Sensor
    PulseCount(Rain, 1, RainPulseChannel, 2, 0, 0.1, 0)

    'Wind Speed Sensors
    PulseCount(WindSpeed(), 2, WindSpeedPulseChannel, 0, 1, 0.05, 0)

    'Temperature Sensors
    Resistance(TempRes(), 3, mV200, TempDiffChannel, 1, 1, 1000, True, True, 0, _50Hz, 1, 0)
    For i = 1 To 3
      TempRatio(i) = TempRes(i) / RS0(i)
    Next i
    PRTCalc(Temp(), 3, TempRatio(), 1, 1, 0)

    'Humidity Sensors
    VoltDiff(relHumid(), 2, mV1000, HumidDiffChannel, True, 0, _50Hz, 0.1, 0)
    For i = 1 To 2
      If relHumid(i) < 0 Then relHumid(i) = 0
      If relHumid(i) > 100 Then relHumid(i) = 100
    Next i

    'Global Radiation
    VoltDiff(SlrW, 1, mV50, GlobalRadDiffChannel, True, 0, _50Hz, 1, 0)
    If SlrW < 0 Then SlrW = 0
    SlrkJ = SlrW * 0.2
    SlrW = SlrW * 40

    'Net Radiations
    VoltDiff(NR_Wm2, 1, mV50, NetRadDiffChannel, True, 0, _50Hz, 76.33588, 0)
    If WindSpeed2m >= 5 Then
      CNR_Wm2 = NR_Wm2 * (1 + 0.021286 * (WindSpeed2m - 5))
    Else
      CNR_Wm2 = NR_Wm2
    EndIf

    'Heat Flux Sensor
    VoltDiff(shf_mV, 1, mV50, ShfDiffChannel, True, 0, _50Hz, 1, 0)
    VoltSe(shf_V_Rf, 1, mv5000, ShfSePlateVoltChannel, True, 0, _50Hz, 0.001, 0)
    Shf = shf_mV * Shf_Cal

    'Sunshine Hours
    RealTime(RTime)
    SolarPosition(SolPos, RTime, 0, 53.107775, 8.860060, 11, -1, Temp2m)
    'Calculate potential radiation for time & position (multiply sine of solar elevation angle by solar constant 1373)
    PotSlrW = SIN(SunElevation) * 1373
    'If the measured value (W/m^2) is greater than 0.4 * the potential solar radiation (W/m^2)
    'and the sine of the sun elevation angle (degrees) is great than 0.1 (elevation angle of 6 degrees)
    'than it has been sunny for the current scan.
    If SlrW > 0.4 * PotSlrW AND SIN(SunElevation) > 0.1 Then
      'Calculate sun hours for scan time in seconds
      SunHrs = ScanInterval/3600.0
    Else
      'Set sun hours for scan time in seconds to 0
      SunHrs = 0
    EndIf

    'Wind Direction
    k = 1
    PortSet(WindClockPort, 1, 0)
    Delay(0, WindStartLength_us, usec)
    PortSet(WindClockPort, 0, 0)
    Delay(0, WindPulseLenght_us, usec)
    PortGet(WindCode(k), WindDataPort)
    SubScan(0, Sec, 15)
      k = k + 1
      PortSet(WindClockPort, 1, 0)
      Delay(0, WindPulseLenght_us, usec)
      PortSet(WindClockPort, 0, 0)
      Delay(0, WindPulseLenght_us, usec)
      PortGet(WindCode(k), WindDataPort)
    NextSubScan
    invInteger = (WindCode(1) AND  1) OR (WindCode(2) AND   2) OR _
                 (WindCode(3) AND  4) OR (WindCode(4) AND   8) OR _
                 (WindCode(5) AND 16) OR (WindCode(6) AND  32) OR _
                 (WindCode(7) AND 64) OR (WindCode(8) AND 128)
    tempInteger = (WindCode( 9) AND  1) OR (WindCode(10) AND   2) OR _
                  (WindCode(11) AND  4) OR (WindCode(12) AND   8) OR _
                  (WindCode(13) AND 16) OR (WindCode(14) AND  32) OR _
                  (WindCode(15) AND 64) OR (WindCode(16) AND 128)
    If 255 - tempInteger = invInteger Then
      DirInvalid = false
      ReadInvalid = false
    Else
      DirInvalid = true
      ReadInvalid = true
    EndIf
    Sector = NAN
    If tempInteger = 0 Then
      Sector = 0
    Else
      For k = 1 To 143
        If tempInteger = LookupArray(k) Then
          Sector = k
          ExitFor
        EndIf
      Next k
    EndIf
    If Sector = NAN Then
      DirInvalid = true
    EndIf
    If DirInvalid Then
      WindDir = NAN
    Else
      WindDir = Sector * 2.5
    EndIf

    'Call Data Tables and Store Data
    CallTable Measurements
    CallTable Voltages

    'Calibrate Heat Flux Sensor
    If IfTime(1, SHF_CAL_INTERVAL, Min) Then
      shf_cal_on_f = True
      shf_mV_0 = shf_mV
      shf_sw_state = True
    EndIf
    If IfTime(4, SHF_CAL_INTERVAL, Min) Then
      shf_mV_180 = shf_mV
      shf_V_Rf_180 = shf_V_Rf
      shf_sw_state = False
    EndIf
    If IfTime(SHF_END_CAL, SHF_CAL_INTERVAL, Min) Then
      shf_mV_end = shf_mV
      Shf_Cal = shf_V_Rf_180 * shf_V_Rf_180 * 128.7 / ABS(((shf_mV_0 + shf_mV_end) / 2) - shf_mV_180)
      shf_cal_on_f = False
      If Shf_Cal = NAN OR Shf_Cal <= 0 Then
        Shf_Cal = SHF_HFP01SC_CAL
      EndIf
    EndIf
    SW12(ShfSw12VChannel, shf_sw_state)
  NextScan
  SlowSequence
  Scan(10, Sec, 0, 0)
    FTPResult = FTPClient("...", "...", "...", "Measurements", "ub_sportplatz.dat", 9, 0, 0, Min, -1008)
    If IfTime(0, 24, Hr) Then
      TimeOffset = NetworkTimeProtocol("de.pool.ntp.org", 0, 500)
    EndIf
  NextScan
  EndSequence
EndProg

 


JDavis Oct 6, 2017 09:30 PM

Do you have the sensor connected to 5V or to 12V? You might be overloading 5V if it stops talking while the RS232 port is in use.


TimoRoth Oct 7, 2017 09:33 AM

It's running on 12V. I'm communicating with the station via a NL240 Wifi module in bridge mode, which is connected and powered via CSIO.

I'm not too concerned about that, as once the station is set up completely I won't connect there directly too often, as it sends out its measurements automatically vis FTP. Just a bit concerned that it might indicate some problem somewhere in my setup or script.


TimoRoth Oct 12, 2017 02:33 PM

I have looked at the signal the Datalogger procudes with a digital oscilloscope, and even when connected with LoggerNet Connect, the clock looks 100% on point.

However, the moment I hit the connect button, the Data line drops from ~8V to 0V and stays there, until I disconnect and the next measurement cycle runs.
Almost looks to me like connecting with LoggerNet re-configures the Input-Port to an Output-Port, and drives it to Ground.

Good reading: https://oromit.de/public/scrn/1507817194.png

Bad reading: https://oromit.de/public/scrn/1507817266.png

I haven't found a setting to configure this behaviour. The Status Table still shows PortConfig(2) as input the whole time.


JDavis Oct 12, 2017 02:43 PM

You could prove the port on the datalogger is not changing to an output by disconnecting sensor wire and measuring for the voltage drop.

Log in or register to post/reply in the forum.