Parse Required Bandwidth out of FCC Designator in SPARQL/SPIN?

81 views Asked by At

I need to parse the rather arcane FCC Emission Designator using SPARQL/SPIN from a compound string encoding to values I can easily reason over. The first task is to get the "required bandwidth" out of the designator. Here are examples of what the emission designators look like (available as xsd:string values) and the corresponding required bandwidths, manually interpreted my little old me:

  • 16K00F3E 16.00 kHz or 16,000.0 Hz
  • 3K00J3E 3.00 kHz or 3,000.0 Hz
  • 1K10F1B 1.10 kHz or 1,100.0 Hz
  • 100H00A1A 100.00 Hz
  • 10M0G2D 10.0 MHz or 10,000,000.00 Hz

Ultimately I want to get to xsd:double values in Hz, but I'm presently stuck on the first step, getting the required bandwidth substring out of the whole emission designator string.

The regular expression ^[0-9]+[A-Z][0-9]+ does the trick for this first step. For example, this regular expression applied to the emission designator 10M0G2D matches 10M0.

The required bandwidth substring I want is, in practice, variable-length. It has a set of numbers, a letter (see below), and then another set of numbers. The letter marks the decimal point and determines the multiplier:

  • H - If the value is less than 1000 Hz (muliplier is 1.0)
  • K - 1 kHz to values less than 1000 kHz (multiplier is 1000.0)
  • M - 1 MHz to values less than 1000 MHz (multiplier is 1,000,000.0)
  • G - 1 GHz or greater (multiplier is 1,000,000,000.0)

This is followed by another letter which is outside the required bandwidth.

So, my question is, in SPARQL/SPIN, how do I get the required bandwidth substring as defined in the above regular expression parsed out of the emission designator string? I want to bind that substring to a SPARQL variable, say ?encodedRequiredBandwidth. The only use of a regular expression I see in SPARQL/SPIN is xsd:boolean REGEX (simple literal text, simple literal pattern). That's great, but I want the substring matching the regex, not a flag indicating it's in there somwhere.

Any ideas on how to get my required bandwidth substring?

Any ideas on how to to the remainder of the parsing to get to an xsd:double Hz value that I can reason over easily (e.g. do magnitude comparisons)?

Thanks.

2

There are 2 answers

0
Greg Cox On

I now also have ugly SPARQL code to complete the conversion of the bandwidth to an xsd:double. This is predicated on the assumption that the frequency designator occurs in the first 6 characters of the encoded bandwdith. The standard constrains the entire bandwidth field to 4 characters including the designator. However, I've seen examples extended up to 6 characters (e.g. the 100H00 shown above which could just as well been compliantly encoded as 100H)

Here's the SPARQL code self-contained example:

SELECT DISTINCT *
WHERE
{
  BIND("5M75C3F"^^xsd:string AS ?emissionDesignator) .
  BIND(strlen(?emissionDesignator) AS ?edLength) .
  BIND(substr(?emissionDesignator, ?edLength - 2, 3) AS ?useCodes) .
  BIND(strbefore(?emissionDesignator, ?useCodes) AS ?encodedBandwidth) .

  # case of indicator in character position 1
  {
      BIND(substr(?encodedBandwidth, 1, 1) AS ?indicator) .
      FILTER ((?indicator = "H") || (?indicator = "K") || (?indicator = "M") || (?indicator = "G")) .
  }
  UNION
  # case of indicator in character position 2
  {
      BIND(substr(?encodedBandwidth, 2, 1) AS ?indicator) .
      FILTER ((?indicator = "H") || (?indicator = "K") || (?indicator = "M") || (?indicator = "G")) .
  }
    UNION
  # case of indicator in character position 3
  {
      BIND(substr(?encodedBandwidth, 3, 1) AS ?indicator) .
      FILTER ((?indicator = "H") || (?indicator = "K") || (?indicator = "M") || (?indicator = "G")) .
  }
  UNION
  # case of indicator in character position 4
  {
      BIND(substr(?encodedBandwidth, 4, 1) AS ?indicator) .
      FILTER ((?indicator = "H") || (?indicator = "K") || (?indicator = "M") || (?indicator = "G")) .
  }
  UNION
  # case of indicator in character position 5
  {
      BIND(substr(?encodedBandwidth, 5, 1) AS ?indicator) .
      FILTER ((?indicator = "H") || (?indicator = "K") || (?indicator = "M") || (?indicator = "G")) .
  }
  UNION
  # case of indicator in character position 6
  {
      BIND(substr(?encodedBandwidth, 6, 1) AS ?indicator) .
      FILTER ((?indicator = "H") || (?indicator = "K") || (?indicator = "M") || (?indicator = "G")) .
  }
  VALUES (?freqIndicator ?multiplier) {
         ("H"^^xsd:string 1.0e0)
         ("K"^^xsd:string 1.0e3)
         ("M"^^xsd:string 1.0e6)
         ("G"^^xsd:string 1.0e9)
  } .
  FILTER (?indicator = ?freqIndicator) .
  BIND (xsd:double(replace(?encodedBandwidth, ?freqIndicator, ".")) AS ?bandwidthDecimalPart) .
  BIND ((?bandwidthDecimalPart * ?multiplier) AS ?bandwidthDouble ) . 
}

The above gives the result shown below... with the double-precision value of the bandwidth in ?bandwidthDouble as Hz which makes subsequent reasoning convenient. Now on to handling the rest of the emission designator. Ultimately, this code will end up in SPIN constructors to do automated translation upon instantiation.

enter image description here

0
Greg Cox On

I've found a way to work around this based on the fact that the last three characters of the emission designator are stable, fixed-width. So, I can use a combination of string functions to get the required bandwidth parsed out. The following simple query illustrates the use of the string functions:

SELECT DISTINCT *
WHERE
{
  BIND("100H00F1B"^^xsd:string AS ?emissionDesignator) .
  BIND(strlen(?emissionDesignator) AS ?edLength) .
  BIND(substr(?emissionDesignator, ?edLength - 2, 3) AS ?useCodes) .
  BIND(strbefore(?emissionDesignator, ?useCodes) AS ?encodedBandwidth) .
}

So now my encoded bandwidth substring ends up int ?encodedBandwidth.

enter image description here

Step one down, but my answer depends on a peculiarity of the format, the fixed width of the last 3 characters of the string. Now I need to figure out how to parse the frequency into an xsd:double value in Hz. I'll post again when/if I figure that out in case it's useful to anyone else.