' . $metar_toDecode[1 + $iCount]
. ' will be investigated next<br>';
$metar_toDecode[$iCount - 1] = 'OBS/NEXT'; // Correct to the conforming single segment
// merge before and after original 'NEXT'
$metar_toDecode = array_merge(array_slice($metar_toDecode, 0, $iCount), array_slice($metar_toDecode, 1 + $iCount));
if($show_diagnostics or $show_diagnosticsR)
{
print_array($metar_toDecode, 'Revised array after moving "/NEXT" ');
}
break;
default:
if($show_diagnostics or $show_diagnosticsR)
{
print_array($metar_toDecode, 'The array at element ' . $iCount . ' has not been recognised');
}
}
break;
}
if($show_diagnostics or $show_diagnosticsR) print_array($metar_toDecode, 'Processing elements 0 to ' . ($iCount - 1) . ' of this array ');
if($iCount == 2)
$output = 'This aerodrome only issues METAR when it an Observer is present. This is last report of airport operating day - issued ' . $decodeInfo['LOCAL'];
else{
$output = 'Last METAR issue by Observer, hourly reports of automatic observations continue (See ';
$output .= 'http://www.flightplanning.navcanada.ca/cgi-bin/Fore-obs/metar.cgi?format=raw&Langue=anglais&Region=can&Stations=' . $decodeGroupProcessed['AIG'];
$output .= ').
Time of issue ' . substr($decodeInfo['LOCAL'], 0, 32);
}
$output .= ' [=' . substr($decodeInfo['ISSUED'], 45) . ' (UTC) ' . substr($decodeInfo['ISSUED'], 34, 11) . ']
';
do_output($decodeGroupCount['REMARK'], $iCount, $output, $manobs[$specification]);
$decodeGroupCount['Canada']++;
if($show_diagnostics or $show_diagnosticsR) print_array($metar_toDecode, 'Processing element 0 onwards of this array ');
// Now handle any differences from standard 'ddhhmmUTC' or 'ddhhmmZ' formats
if(strlen($metar_toDecode[0]) == 2) // d) in examples above - just day of month in separate segment
{
if($show_diagnostics or $show_diagnosticsR)
echo '
day "' . $metar_toDecode[0] . '" should NOT be separate to time, so needs to be combined with ' . $metar_toDecode[1] . '
';
$metar_toDecode[0] = $metar_toDecode[0] . $metar_toDecode[1]; // Place day with time to get correct format
$metar_toDecode = array_merge(array_slice($metar_toDecode, 0, 1), array_slice($metar_toDecode, 2));
if($show_diagnostics or $show_diagnosticsR)
{
print_array($metar_toDecode, 'Revised array after combining day of month with time');
}
}
if(is_numeric($metar_toDecode[0]) and ($metar_toDecode[1] == 'Z' || $metar_toDecode[1] == 'UTC'))
{
if($show_diagnostics or $show_diagnosticsR)
echo '
' . $metar_toDecode[0] . ' is NOT correctly formed, and needs to be combined with ' . $metar_toDecode[1] . '
';
$metar_toDecode[1] = $metar_toDecode[0] . $metar_toDecode[1]; // Add 'Z' or 'UTC' to end
$metar_toDecode = array_slice($metar_toDecode, 1);
if($show_diagnostics or $show_diagnosticsR)
{
print_array($metar_toDecode, 'Format corrected in element ' . 0 . ' now');
}
}
if(1 === preg_match('~^([0-3][0-9])?([012][0-9])([0-5][0-9])~', $metar_toDecode[0], $pieces))
{
if($show_diagnostics or $show_diagnosticsR)
{
echo $metar_toDecode[0] . ' = Correctly formed day '. $pieces[1] . ' and correctly formed time ' . "$pieces[2]" . ':' . $pieces[3] . '
';
}
// Pass hour, minute, and day, parts (with any leading zeroes) of day-time segment into function to adjust to local time
$nextTime = adjustTime("$pieces[2]" . ':' . "$pieces[3]", "$pieces[1]");
$output = 'Next METAR issue by Observer due local time ' . $nextTime['hour'] . ':' . $nextTime['minute'] . ' on day ' . $nextTime['day'] . ' of month '
. '[= at ' . "$pieces[2]" . ':' . "$pieces[3]" . ' (UTC) on ' . $pieces[1] . ' of month]';
do_output($decodeGroupCount['REMARK'], 1, $output, $manobs[$specification]);
$decodeGroupCount['Canada']++;
$matched = true;
break;
}
if($show_diagnostics or $show_diagnosticsR)
{
print_array($metar_toDecode, 'The array at element 0 has not been recognised');
}
unrecognised($manobs[$specification]);
break;
case 36: // 16.4.4.10 Volcanic eruption
/*
16.4.4.10 Volcanic eruption
The occurrence of a volcanic eruption shall be reported by a SPECI observation when observed.
Post-eruption volcanic ash clouds should be included in Remarks of METAR and SPECI observations as long as significant.
The following data shall be included in Remarks when known:
1) Name of the volcano
2) Direction (16 points, true, of the compass) and approximate distance (statute miles) of the volcano
3) Date/Time (UTC) of eruption
4) Height and direction of movement of ash cloud
5) Other pertinent data
My decoder note:
Canada uses SPECI rather than METAR for reporting actual eruption of volcanoes e.g. SPECI .... MT ST HELEN VOLCANO 60 MI W NW ERUPTED 091025 ASH CLOUD TO 300 MOVG RPDLY SE
but (as explained above in the manual extract) after eruption, the progress of the ash cloud or a continuation in the eruption is reported via a METAR, so code snippet to decode it follows
Example: METAR RMK MT ST HELEN VOLCANO 60 MI WNW ERUPTED 091025 ASH CLOUD TO 300 MOVG RPDLY SE
*/
if(count($metar_toDecode) > 2 and in_array('VOLCANO', $metar_toDecode))
{
$output = ""; // initialise the initial output from the decoder
// Since don't know how many segments are being used to convey the plain English message, can only output the whole lot up to dayTime in first output message.
$j = 0;
$k = count($metar_toDecode);
for($iCount=0;$iCount<$k;$iCount++)
{
if(strlen($metar_toDecode[$iCount + $j]) == 6 and is_numeric($metar_toDecode[$iCount + $j]))
{
$day = substr($metar_toDecode[$iCount + $j], 0, 2);
$timeArray = adjustTime(substr($metar_toDecode[$iCount + $j], 2, 4), substr($metar_toDecode[$iCount + $j], 0, 2));
$output .= "at " . $timeArray['hour'] . ":" . $timeArray['minute'] . " (local time) on day " . $nextTime['day'] . " of month";
do_output($decodeGroupCount['REMARK'], $iCount, $output, $manobs[$specification]);
$j = $iCount;
$output = ""; // re-initialise ready for further output from the decoder
}else
// Since don't know how many segments are being used to convey the 'Other pertinent data', can only output all those found after dayTime in second message.
$output .= $metar_toDecode[$iCount + $j];
if($iCount < $k and $j != $iCount)
{
$output .= " ";
}
}
do_output($decodeGroupCount['REMARK'], $iCount - $j, $output, $manobs[$specification]);
$decodeGroupCount['Canada']++;
$specification = 50; // nothing left to decode
$matched = 1;
goto exit_here;
}
break;
case 37: // Last one for Canada - "Density altitude"
# real example METAR CYEG 011000Z 30015G20KT 15SM SCT039 BKN075 BKN170 09/01 A2974 RMK SC3AC3AC1 SLP084 DENSITY ALT 2400FT= # DONE
// 2017/12/05 07:00 METAR CYZR 050700Z AUTO 20019G27KT 9SM SCT039 BKN049 BKN060 OVC072 12/06 A2965 RMK SLP043 DENSITY ALT 600FT
if(count($metar_toDecode) >2 and $metar_toDecode[0] == 'DENSITY' and $metar_toDecode[1] == 'ALT' and substr($metar_toDecode[2], -2) == 'FT')
{
$height = substr($metar_toDecode[2], 0, -2);
# if($show_diagnosticsR) echo '
density height = ' . $height . '
';
$output = 'Density altitude (pressure altitude corrected for non-standard temperature) is at ' . number_format(1 * $height)
. ' feet
(i.e. at take off, aircraft feels like it is already at ' . number_format(1 * $height)
. ' feet = ' . number_format(0.3048 * $height, 1) . ' metres)';
/*
The ICAO International Standard Atmosphere standard conditions for zero density altitude are 0 meters (0 feet) altitude (sea level), 15 deg C (59 deg F) air temp,
(Temperature decreases about 2 degrees C (or 3.5 degrees F) per 1,000 feet of altitude above sea level.)
1013.25 mb (29.921 in Hg) pressure and 0 % relative humidity (absolute zero dew point).
The standard sea level air density is 1.225 kg/m3 (0.002378 slugs/ft3).
*/
do_output($decodeGroupCount['REMARK'], 3, $output, $manobs[$specification]);
$matched = true;
$decodeGroupCount['Canada']++;
}
break;
case 38: // Toronto Lester B Pearson International Airport (station id=CYYZ) Ontario (P), Canada
// 2017/12/11 17:00 METAR CYYZ 111700Z 00000KT 15SM FEW020 BKN040 OVC110 M06/M11 A2999 RMK SC1SC7AS1 SC TR VIA CYVV SLP166
// Wiarton, Ont., Canada (CYVV)
if(count($metar_toDecode) >1 and $metar_toDecode[0] == 'VIA')
{
$output = 'Another airport has been involved in this report, it has an ICAO identifier of ' . $metar_toDecode[1];
$matched = true;
do_output($decodeGroupCount['REMARK'], 2, $output, $manobs[$specification]);
$decodeGroupCount['Canada']++;
break;
}
break;
case 39: break;
} // end Switch
if(count($metar_toDecode) < 1) goto exit_here; // make sure exit if nothing left to decode
if($specification > 38)
{
// if there are no more segments left to decode or first pass through this sub-function has not decoded any segments; exit
if(count($metar_toDecode) < 1 or !$matched) goto exit_here;
if($show_diagnostics or $show_diagnosticsR)
{
echo "
Reached end of list of specifications, but not end of segments awaiting decoding.
";
}
if($passCountCan < 2)
{
$passCountCan ++;
$matched = false;
$specification = 1;
// Move to first specification again for second and last pass.
}else break;
}else $specification ++; // Move to next part of specification.
} // end While
exit_here:
if($passCountCan) $matched = true;
return $matched;
}// end sub-function - Canada
//======================================================//
// RMK Group: Canada - walk - anonyminised function //
// called at start of above Canada sub-function. //
// Walks the $remarks_toDecode array, its keys are the //
// raw METAR segments, the value tracks whether decoded //
//======================================================//
function canadaWalk(&$value, $key, &$testArray)
{
global $metar_toDecode, $decodeInfo, $decodeGroupCount, $decodeGroupProcessed, $remarks_toDecode, $show_diagnostics, $show_diagnosticsR, $dM_Rmk; // shared with other scripts
global $file, $cloud_type_array, $cloudAmountBandCode, $precipitationTypes; // declared in main script 'decodeMETAR.php'
if(!count($metar_toDecode)) return; // exit from walk if nothing left to be decoded
if($value != "Un-matched") return; // exit from walk if current array key has already been matched and decoded
if($show_diagnostics or $show_diagnosticsR) echo '
' . $key . ' examined by function canadaWalk()';
/////////////////////////////////////
// RMK Group: Pressure Tendency //
/////////////////////////////////////
if(!$testArray['PressureChange'] and substr($key, 0, 4) == 'PRES')
{
// CANADA 2 e) 16.3.13.2.5 Pressure change Remarks (based on change in last 15 minutes scaled up to hour)
/*
2018/01/07 20:31 METAR CYXU 072031Z 19016G22KT 1SM R15/4500VP6000FT/N SN OVC015 M09/M13 A3010 RMK SN4SC4 PRESFR SLP217
Went wrong at (0) → RMK Not de-coded=PRESFR
2018/01/07 21:00 METAR CYZR 072100Z AUTO 20017G26KT 9SM SCT038 OVC055 M07/M12 A3006 RMK ICG PRESFR SLP194
Went wrong at (1) → RMK_ICG Not de-coded=PRESFR
*/
// 2018/02/03 19:00 METAR CYXU 031900Z 21011KT 2 1/2SM -SHSN OVC014 M06/M09 A3008 RMK SN2SC6 CVCTV CLD EMBD PRESFR SLP207
/*
16.3.13.2.5 Pressure change Remarks
METAR ...SCT040 RMK PRESRR (1)
METAR BKN100 RMK PRESFR (2)
Note (1): PRESRR is used when the barograph trace indicates that the station pressure is rising at the rate of 2.0 hPa or more per hour.
METAR BKN100 RMK PRESFR (2)
Note (2): PRESFR is used when the barograph trace indicates that the station pressure is falling at the rate of 2.0 hPa or more per hour.
Note: If the barograph trace shows a steady increase of 0.5 hPa during the last 15 minutes, the rate of increase would be 2.0 hPa per hour
and the remark PRESRR would be appropriate. If the barograph trace shows a steady decrease of 0.5 hPa during the last 15 minutes,
the rate of decrease would be 2.0 hPa per hour and the remark PRESFR would be appropriate.
'PRESRR' = "pressure rising rapidly (> 2hPa per hour)" or 'PRESFR' = "pressure falling rapidly (> 2hPa per hour)"
Related back to cloud cover - lowest level
Canada adopts SI unit for pressure of kiloPascals (thousand Pascals) rather than hectoPascals (hundred Pascals), so the output figures are ten times lower than the figures above
*/
switch($key)
{
case 'PRESFR':
case 'PRESRR':
if(array_key_exists('CLOUD-DETAILS', $decodeInfo))
{
$output = "(r10) =(Related to front marked by lowest cloud indicated) ";
$i = strpos($decodeInfo['CLOUD-DETAILS'], "ft");
$decodeInfo['CLOUD-DETAILS'] = substr($decodeInfo['CLOUD-DETAILS'], 0, 2 + $i) . " (r10) " . substr($decodeInfo['CLOUD-DETAILS'], 2 + $i);
}else $output ="";
if($show_diagnosticsR)
{
echo "
Canada Walk begins examining " . $key . " identifying pressure tendency
";
}
$output .= 'Air Pressure tendency ';
$output .= substr($key, 4, 1) == 'F' ? 'falling ' : 'rising ';
$output .= 'rapidly at greater than 0.2 kPa hr-1 (based on change in last 15 minutes)';
walk_output($decodeGroupCount['REMARK'], $key, $output, '16.3.13.2.5 Pressure change');
$testArray['PressureChange'] = true;
} // end switch
}
if(count($metar_toDecode) < 1) goto exitCall;
//////////////////////////////////////////////////////////////////////////////////
// CANADA 16.3.13.1 Layer type and amount (oktas) //
// RMK Group: Most widely used codes to try - Cloud type and Amount Layers //
//////////////////////////////////////////////////////////////////////////////////
/*
16.3.13.1 Layer type and amount (oktas)
For each layer reported in the layer aloft section (see 16.3.9), a corresponding cloud (from the list below) and amount shall be recorded.
When vertical visibility is observed, the obscuring phenomenon abbreviation and amount shall be recorded. The amount will be a single digit.
When surface-based layers (see 1.2.5) are observed to obscure portions of the celestial dome, the obscuring phenomenon abbreviation and amount shall be recorded.
Some Canadian METAR examples in this specification, all can be decoded:
List of cloud types in Remarks Group (matched to cloud layer definitions in main part of METAR), each one that is present is quoted as an abbreviation followed by amount in oktas.
METAR CYJT 010600Z 23012G19KT 220V360 15SM BKN027 09/04 A3010 RMK SC7 SLP195= # single cloud code in segment after RMK
Some 2 cloud specification examples - matching Cloud Cover Group and Remarks Group:
METAR CYYR 010800Z 23018G27KT 15SM -SHRA SCT043 OVC078 08/02 A2952 RMK SC3AC5 SLP999= # NB this example has lower oktas first in remarks cloud section
METAR CYYR 010600Z 23020G28KT 15SM -SHRA BKN057 OVC078 07/02 A2960 RMK SC6AC2 SLP026= # NB this example has higher oktas first,
remember order of cloud types is more significant than order of oktas
"Stratocumulus" => "SC" is a low cloud
"Altocumulus" => "AC" is a high cloud
A 3 cloud code specification example - matching Cloud Cover Group and Remarks Group:
2017/11/16 00:00 METAR CYXU 160000Z 19016G22KT 5SM -RA BR BKN007 BKN012 OVC021 07/06 A2970 RMK SF5SF2SC1 CIG VRB 5-9 SLP068
WMO define maximum number of cloud layers as 3, but Canada often defines 4 cloud groups in main Cloud Cover Group and Remarks Group:
2017/11/16 19:00 METAR CYHM 161900Z 28014G19KT 15SM SCT030 BKN042 BKN060 OVC082 05/01 A2987 RMK CU3SC2SC2AC1 SLP120
*/
if(!$testArray['Layer'] and (in_array(substr($key, 0, 2), $cloud_type_array) || in_array(substr($key, 0, 3), $cloud_type_array)) and is_numeric(substr($key, -1, 1)))
{
if($show_diagnostics or $show_diagnosticsR)
{
echo "
Canada Walk begins examining " . $key . " looking for these
";
print_array($cloud_type_array,'cloud types');
}
$testArray['Layer'] = true;
re_enter:
$CloudRmk = 0; // initialise as no cloud type code found
if(in_array(substr($key,0,2), $cloud_type_array) and is_numeric(substr($key, 2, 1))) $CloudRmk = 2; // 2 letter cloud type code
// above condition modified to ensure only 2 letters! (ensures CIG is not matched to Cirrus)
elseif(in_array(substr($key,0,3), $cloud_type_array) and is_numeric(substr($key, 3, 1))) $CloudRmk = 3; // 3 letter cloud type code found
else goto stopRepeat;
$pattern_count = preg_match_all('~([A-T][B-U][CU]?)([0-9])~', $key, $pattern_array, PREG_SET_ORDER); // find all cloud types within segment
if($CloudRmk > 0 and $pattern_count > 0)
{
if($show_diagnostics or $show_diagnosticsR)
{
print_array($pattern_array, '
Found ' . $pattern_count . ' Coded Cloud Types as array
');
}
// cloud type found with precise oktas
// Montréal Mirabel International Airport|Montreal, Quebec, Canada===== Remarks Group with precise cloud, details for weather, sea level pressure
// 2017/10/26 16:00 CYMX 261600Z 21004KT 180V250 25SM FEW070 BKN110 OVC200 11/06 A2976 RMK AC1AC6CI DIST SH S SLP082
for($skyIterator=0; $skyIterator < $pattern_count; $skyIterator++)
{
$cloud_layer_type = array_search($pattern_array[$skyIterator][1], $cloud_type_array, true);
if($cloud_layer_type)
{
if($show_diagnostics or $show_diagnosticsR)
{
echo "sub-function = decode_CAN_remarks - Specification=16.3.13.1 Layer type and amount (oktas) Iteration " . $skyIterator . "
";
echo "Matched " . $pattern_array[$skyIterator][0] . ", coded cloud type of '" . $pattern_array[$skyIterator][1]
. " into '" . $cloud_layer_type . "', and reports " . $pattern_array[$skyIterator][2] . " oktas
";
}
$decodeInfo['SKY-DETAILS'][$skyIterator][0] = $cloud_layer_type;
$decodeInfo['SKY-DETAILS'][$skyIterator][1] = "" . $pattern_array[$skyIterator][2] . " oktas";
$decodeGroupProcessed['SKY'][1 + $skyIterator] .= " + RMK_" . $pattern_array[$skyIterator][0];
}
} // end for
$array_element_id = array_search($key, $metar_toDecode); // find which item is to be removed from still to be decoded array
$done = array_splice($metar_toDecode, $array_element_id, 1); // remove that item
$remarks_toDecode[$key] = '16.3.13.1 Layer type and amount (oktas)';
$decodeGroupProcessed['VARIABLE'] = 'RMK_' . $done[0];
if($show_diagnostics) echo "Matched into '16.3.13.1 Layer type and amount (oktas)' the content of " . $key . "
"; // conditional de-bugging section continues
# walk_output($decodeGroupCount['REMARK'], $key, $output, );
}
}
stopRepeat: # re-entry point if no match to conditions to enter repeat code snippet
if(count($metar_toDecode) < 1) goto exitCall;
//////////////////////////////////////////////
// RMK Group: Wind Direction Variation //
// dddVddd - two bearings in one segment //
//////////////////////////////////////////////
if(!$testArray['DirectionVariation'])
{
$partLocal = preg_match('/([0-9]{3})V([0-9]{3})/', $key, $pieces);
if ($partLocal === 1)
{
if($show_diagnostics or $show_diagnosticsR)
{
echo "
Canada Walk begins examining " . $key . " reporting wind directions
";
}
$testArray['DirectionVariation'] = true;
$decodeInfo['VARIABLE'] = "Wind direction reported as variable: bearings " . $pieces[1] . "° to " . $pieces[2] . "°";
$decodeInfo['VARIABLE_FROM'] = $pieces[1];
$decodeInfo['VARIABLE_TO'] = $pieces[2];
$decodeInfo['FROM'] = $compass[1 + round($pieces[1] / 22.5) % 16];
$decodeInfo['TO'] = $compass[1 + round($pieces[2] / 22.5) % 16];
$decodeGroupCount['VARIABLE'] = true;
$array_element_id = array_search($key, $metar_toDecode); // find which item is to be removed from still to be decoded array
$done = array_splice($metar_toDecode, $array_element_id, 1); // remove that item
$remarks_toDecode[$key] = 'RMK Group: Wind Direction Variation';
$decodeGroupProcessed['VARIABLE'] = 'RMK_' . $done[0];
if($show_diagnostics) echo "Matched into 'Wind Group (variable bearing part)' the content of " . $decodeInfo['VARIABLE'] . "
"; // conditional de-bugging section continues
}
}
if(count($metar_toDecode) < 1) goto exitCall;
/////////////////////////////////////
// RMK Group: Specific weather //
/////////////////////////////////////
// CANADA c) 16.3.13.2.3 Weather Remarks
if($show_diagnostics or $show_diagnosticsR and ($key == 'FROIN' || $key === 'RIME'))
{
echo "
Canada Walk begins examining " . $key . " reporting frost/ice
";
}
switch($key)
{
case 'FROIN':
# (vii) 'FROIN' = "report frost on the ice accretion indicator" - MANOBS para 3.4.2.4 Ice accretion indicator
# 201801051100 METAR CYXU 051100Z 26004KT 15SM BKN033 BKN240 M21/M24 A3002 RMK SC5CI1 FROIN SLP193=
$output = "Frost observed on the exchangeable 'L-shaped Aluminium strip' either slotted onto Stevenson Screen or similar location 1 m agl";
walk_output($decodeGroupCount['REMARK'], $key, $output, '16.3.13.2.3 Weather Remarks' . " (vii)");
break;
case 'RIME':
$output = "Rime ice observed on the exchangeable 'L-shaped Aluminium strip' slotted onto Stevenson Screen";
walk_output($decodeGroupCount['REMARK'], $key, $output, '16.3.13.2.3 Weather Remarks' . " (vii)");
break;
}
if(count($metar_toDecode) < 1) goto exitCall;
//////////////////////////////////////////
// RMK Group: Sky Cover 'Contrails' //
//////////////////////////////////////////
// CANADA d) 16.3.13.2.4 Sky condition Remarks (i) Sky cover
if(strlen($key) > 6 and substr($key, 0, 4) == "CONT") // NB using substring for just partial match as have seen at least 5 different spellings being used as in examples below
{
/*
METAR FEW 250 RMK CONTRAILS e.g. 'CONTRAILS' = "aircraft condensation trails are persisting for at least 15 minutes"
Note: Shall be used when middle (CM) or high (CH) cloud consists in whole or in part of persistent (15 minutes or more) condensation trails.
Rapidly dissipating condensation trails shall not be reported.
2017/11/26 15:00 METAR CYQG 261500Z 26005KT 15SM FEW030 FEW270 01/M04 A3017 RMK CU1CI2 CU TR CONTAILS SLP226
Note in above example the code is malformed as it has a missing 'R'
2017/11/14 18:00 METAR CYQG 141800Z 27007KT 210V290 10SM SCT027 BKN260 07/01 A3031 RMK CU3CI4 CONTRAILS SLP270
2017/12/01 21:00 METAR CYQG 012100Z 20011KT 15SM BKN320 07/M00 A3023 RMK CI7 CONTRAIL SLP243
2018/01/20 19:00 CYQG 201900Z 21012KT 15SM BKN270 05/M01 A2992 RMK CI7 CONTRAI
Suspect in last, truncation of the complete METAR may have occurred.
*/
if($show_diagnostics or $show_diagnosticsR)
{
echo "
Canada Walk begins examining " . $key . " reporting Condensation Trails
";
}
$output = "(rcw) = Highest reported cloud layer either completely, or partly, consists of persisting (for 15 minutes or more) aircraft condensation trail(s)";
walk_output($decodeGroupCount['REMARK'], $key, $output, '16.3.13.2.4 Sky condition Remarks Sky cover - condensation trails');
if(array_key_exists("SKY-DETAILS", $decodeInfo) and array_key_exists(0, $decodeInfo['SKY-DETAILS']))
{
if(array_key_exists(2, $decodeInfo['SKY-DETAILS'])) $decodeInfo['SKY-DETAILS'][2][0] .= " (rcw)";
elseif(array_key_exists(1, $decodeInfo['SKY-DETAILS'])) $decodeInfo['SKY-DETAILS'][1][0] .= " (rcw)";
else $decodeInfo['SKY-DETAILS'][0][0] .= " (rcw)";
# print_array($decodeInfo['SKY-DETAILS'], "sky-details");
}
}
if(count($metar_toDecode) < 1) goto exitCall;
/////////////////////////////////////
// RMK Group: Sea Level Pressure //
/////////////////////////////////////
if($show_diagnostics or $show_diagnosticsR and substr($key, 0, 3) == 'SLP')
{
echo "
Canada Walk begins examining " . $key . " reporting pressure amount
";
}
if(substr($key, 0, 3) == 'SLP') $return = walk_SLP($key, "Canada SLP report");
exitCall:
} // end anonymous function - canadaWalk
/*
Version history
===============
0.2.0 29 Oct 2017 Moved initialisation code for Remarks Group from "decodeMETAR_sub_funct.php" to "decodeMETAR_Rmk.php" so latter now does everything related to Remarks Group.
As now have aim of script working worldwide, redesigned the script, breaking it into multiple functions, so have split tests within Remarks Group into main function
in "decodeMETAR_Rmk.php" for undetermined country common pressure and cloud decoding, and sub-function for Canada standards. Canada working for those codes
currently checked in script, although still not covering all possibilities (partly because sequence can vary so difficult to code some).
0.2.1 11 Nov 2017 Bug fix in Canada sub-function re counting remark segments processed (wrong to count SLP as that not output as a Remarks Group entry, but appended to pressure
in main output; and logically wrong statement order in processing obstructing sky as previously counting when not present instead of when processed).
Bug fix re cloud decoding arrays, had confused cloud amount and cloud type!
0.2.2 22 Nov 2017 There is still a lot more to be done to the Canada sub-function and to aid this there is a change to the output log for any segments not decoded, it outputs
the whole METAR, the segment prior to the one that was not decoded (in case that was processed wrongly) and the segment that is not decoded.
The new log is being populated at http://www.komokaweather.com/metar/failed_to_decode_metar.log by Paul's live web page.
0.2.3 27 Nov 2017 Progressing Canada (Convective clouds - spec 1, other layers - spec 2) sub-function. The sub-functions (not array_walks) called from the main functions in this
script have all been moved to 'decodeMETAR_sub_funct.php' so all sub-functions are kept together and the length of this script is minimised.
As for previous attempts to code following handbook or manual provided by that country, the live METAR contain many codes that do not fit the structure described,
and that use abbreviations that are not within list of abbreviations issued by the relevant country. Consequently, a certain amount of guesswork is involved in
output generation by this latest version.
0.2.4 2 Dec 2017 Bug correction - missing pair of brackets re Canadian pressure change.
0.2.5 11 Dec 2017 Addressing failed-to-decode errors. There was a bumper crop of these during this month, partly because it is my first encounter with Winter phenomena like snow.
Some small changes following from failures to decode various Canadian METAR that are malformed compared to format in official MANOBS specification.
I have checked this version against aerodromes from across the world and also against output from "metaf2xml" decoder, so it should be good.
0.2.6 30 Dec 2017 Bug correction, previous version worked better for many METAR, but not for all the variants encountered! Changed the calls from this script to decode Visibility,
to make the Visibility sub-function in "decodeMETAR_sub_funct.php" more universal. Changed the logical sequence of trying the country specific specifications.
For Canada sub-function, also did some slight renumbering to better reflect actual order and reduce looping back; added code to cope with malformed segments
(where observer uses different abbreviations or puts spaces in different places to those specified in guidance manual) and simplified flow by more use of 'elseif'.
Now records every time goes into sub-function, so shows for example if both Canada and another country's codes found or if this sub-function entered twice.
0.2.7 6 Jan 2018 Specific changes to Canada sub-function: 1) to exit after first pass if no matches, and 2) to make two passes if a match on first pass, this enables
matching of more specifications if one is out of sequence or if same specification appears twice.
0.3.0 26 Jan 2018 Conversion of single segment specifications for Canada into array walk approach, revising of many multiple segment specifications, attempting to make the
processing of Remarks Group for Canada both more comprehensive and more efficient through better design of PHP instructions.
Removal of hundreds of unprintable characters (can be viewed in FilesCompare tool, and apparently were introduced in an edit using Notepad++).
Removal of key of 'Country' from $decodeGroupCount. Replacement by series of new Country-specific keys in same array such as $decodeGroupCount['Canada'].
0.3.1 29 Jan 2018 Added another test to Canada case 3 (Additional Layer information). Corrected index number for call to time function in Canada case 34 (Observational program status).
0.3.2 14 Feb 2018 Now that it appears almost all the possible METAR content in Remarks Group for Canada is being handled successfully, this update focussed on improving the look
of outputs. For Canadian Cloud with precipitation - defined trace mentioning rain, or snow, purely depending on actual air temperature.
(Decided not to mention hail and not to look to see if rain mentioned elsewhere).
Improved output format for Canada case 10 (Variable Visibility) by adding units. Added visible moon to Canada sky codes (specification 25). Added ability to cope
with more wrong METAR content spacing for Canada case 34 (Observational program status) and changed output format. Corrected conditions for Canada case 32 (Snowfall
or rainfall reporting procedures for part-time stations), and made the various content formats clearer. Removal of comments into portable document format paper.
0.3.3 28 Feb 2018 Introduced jump for multiple segment specifications based on content of first segment of multiple segments, this technique only implemented where a single
specification had a fixed content in that first segment that was unique to just that specification. Edited wind shift in case 7 to cope with malformed content.
Modified output for visibility so consistent with main Visibility Group and quotes figures in both feet and metres. Added more conditions for alternative syntax
for Lightning specification in case 17. Corrected cases 19, 20, 22, 23, and 24 that were repeating and should be only processed once. Case 26 about ceiling,
rewrote snippet about balloon. Updated cross-references between Mandatory Standard Group output and Remarks Group output. Case 29 re-written to cover two
formats of standing wave clouds. Rewrote case 32 regarding rainfall, so simpler conditions and greater flexibility. For case 35 (16.3.13.4 Observational
program status) rewrote complex set of 'if' conditions into simpler, more efficient, and more comprehensive 'switch' with 'case' instructions.
Case 37 (Density Altitude) added better explanation as well as improving wording of output.
Rewrote CanadaWalk function to work better, corrected the pressure change PHP snippet as was not working consistently, and simplified other single segments.
0.3.4 10 Mar 2018 Corrected error in 16.3.13.2.3 Weather Remarks (iv) Qualifying precipitation - occasional (case 21).
0.3.5 13 Mar 2018 Corrected Sector Visibility to make compatible with change in 'decodeMETAR_sub_funct.php' (Canada and USA use different formats)
0.3.6 18 Mar 2018 Corrected some errors in switch that jumps to later segment.
*/
/* ?> not used to end script as per PHP manual instruction 'If a file is pure PHP code, it is preferable to omit the PHP closing tag at the end of the file.
This prevents accidental white-space or new lines being added after the PHP closing tag, which may cause unwanted effects because PHP will start output buffering
when there is no intention from the programmer to send any output at that poi