theori-io / nrsc5

NRSC-5 receiver for rtl-sdr
Other
795 stars 100 forks source link

AM NRSC-5 #33

Closed pclov3r closed 4 years ago

pclov3r commented 7 years ago

Would it be possible to add support for the AM Broadcast band? From what I understand the sidebands are much more narrow and use much higher order modulation.

argilo commented 7 years ago

To start, we'd need a good recording of an AM broadcast. Do you have any local stations?

pclov3r commented 7 years ago

Unfortunately, I don't.

I can get a station via skip that is around 400 miles away but the sidebands do have fading. Due to the higher order modulation this may not work well.

argilo commented 7 years ago

Well, a recording with some fading is better than no recording at all. If you can capture a couple minutes of RF and post it somewhere, that would definitely help.

pclov3r commented 7 years ago

Actually, The Signal ID wiki has a I/Q recording http://www.sigidwiki.com/wiki/File:AM_HD_Radio_iBiquity.zip

It does appear to be a weaker SNR but stable and may work.

argilo commented 7 years ago

That could be useful as a starting point. Having a longer recording would still be helpful, as that one is only 14 seconds.

argilo commented 7 years ago

In the sigidwiki sample, the digital sidebands are only 7-8 dB above the noise floor, which I expect is much too low for the signal to be decoded. We'll need a much better recording to work with.

pclov3r commented 7 years ago

That's what I figured. Hopefully I can find a better sample or somebody can create a better sample.

Nukeman52 commented 7 years ago

Here is a 2 minute recording of my local station in DFW 1.080 MHz https://drive.google.com/open?id=0B3IrMfVr0MxqazNyelZRLVY5Q1E Recorded at 16 bit using SDR Console v2.3 build 2760 Was using my Sdr play RSP1 Message me if you need anything Click on the download button on the top right

argilo commented 7 years ago

Thanks @billybobgot! That looks like a great recording. When I get some time, I'll take a shot at decoding it.

pclov3r commented 7 years ago

@argilo Curious if you're had any time or got anywhere with this?

Thanks!

argilo commented 7 years ago

As it happens, I'm playing with this right now. But layer 1 AM is quite different from layer 1 FM, so I expect it will be a while until I get it sorted out.

pclov3r commented 7 years ago

Have you managed to figure out anything for this over the past month or so?

Thanks!

argilo commented 7 years ago

Unfortunately I haven't made much progress yet. Most of my free time in the past month was spent building an NRSC-5 transmitter: https://github.com/argilo/gr-nrsc5

I'll probably get back to AM eventually, but I can't promise when.

pclov3r commented 5 years ago

@argilo Did you ever make any progress with this?

I'd be willing to help test tho it would require a MW/HF up-converter for use with a RTL-SDR. I do own one.

argilo commented 5 years ago

Unfortunately I haven't made any progress yet. I'll let you know if I do.

pclov3r commented 4 years ago

Is there still any plans to have AMBC NRSC-5 support?

Now, This would require a modded RTl-SDR or a pre-modded SDR that can do direct sampling or a upconverter that would require a frequency offset. Also, Support for RTL-SDR's that can use a Bias-T would be good idea people that use loop antennas.

Seems like it would require some extra work would be required to implement this well enough for people to use.

argilo commented 4 years ago

I would still like to add AM support.

I made an attempt to add AM support to gr-nrsc5 (https://github.com/argilo/gr-nrsc5/compare/add-am) and was able to get the PIDS (station metadata) channel working, but I'm still stuck trying to get the P1 & P3 (audio) channels going. A couple things in the standard are unclear, so it might help to go in the other direction and decode a real signal to see exactly how the data is encoded.

argilo commented 4 years ago

I finally got transmit working: https://github.com/argilo/gr-nrsc5/commit/48c2e59e843c390af352dbe9916a050e8528d0e8

I've started working on receive as well, but there's still a fair bit of work left because AM NRSC5 differs from FM in a lot of ways.

argilo commented 4 years ago

The code and receiver design are quite messy at the moment, but I've at least managed to get far enough to decode PIDS:

https://github.com/theori-io/nrsc5/compare/master...argilo:add-am

23:53:01 Block @ 30
23:53:01 Sync!
23:53:01 Country: US, FCC facility ID: 59820
23:53:01 Station name: KRLD
23:53:01 Country: US, FCC facility ID: 59820
23:53:01 Station name: KRLD
23:53:01 Audio program 0: public, type: None, sound experience 0
23:53:01 Country: US, FCC facility ID: 59820
23:53:01 Station name: KRLD
23:53:01 Station location: 39.956055, -91.363403, 192m
23:53:01 Audio program 0: public, type: None, sound experience 0
23:53:01 Country: US, FCC facility ID: 59820
23:53:01 Station name: KRLD
23:53:01 Slogan: NewsRadio1080 KRLD
23:53:01 Station location: 39.956055, -91.363403, 192m
23:53:01 Audio program 0: public, type: None, sound experience 0
23:53:01 Country: US, FCC facility ID: 59820
23:53:01 Station name: KRLD
23:53:01 Slogan: NewsRadio1080 KRLD
23:53:01 Message: NewsRadio1080 KRLD
23:53:01 Station location: 39.956055, -91.363403, 192m
23:53:01 Audio program 0: public, type: None, sound experience 0
pclov3r commented 4 years ago

Some nice progress. Looks like you got Audio working now yay!

Any ideas for features and things supported for AMBC? I figure to give best coverage support of a HF upconverter and direct sampling needs to be supported. Also an option to enable the Bias-T for people using loop antennas.

argilo commented 4 years ago

Yes indeed, today I finally got to the point where audio decoding works. That said, there's a lot of things that still need to be improved. Here's my to-do list:

argilo commented 4 years ago

If anyone has a local station, I would appreciate additional I/Q recordings. All I have to work with at the moment is @billybobgot's recording, and it seems to have some AGC artifacts (visible as vertical bands) which makes decoding a challenge:

Screenshot from 2020-08-02 23-13-53

argilo commented 4 years ago

I'd especially love a recording of WWFD (Frederick, Maryland), which broadcasts in the all-digital format: https://en.wikipedia.org/wiki/WWFD.

pclov3r commented 4 years ago

Does the recording need to be 8-bit or is 16-bit okay?

argilo commented 4 years ago

16-bit would be best. I can easily convert to whatever format I need with GNU Radio.

pclov3r commented 4 years ago

I am able to get a few HD AMBC stations during the night but i don't think this would be of use to you since they are received via skip and not local groundwave propagation and have lots of selective frequency fading plus carriers from adjacent stations.

argilo commented 4 years ago

AM NRSC-5 should be somewhat tolerant of frequency-selective fading since it uses OFDM. Also, there are gaps at ±10 kHz where no OFDM data carriers are used, thereby avoiding interference from adjacent AM carriers. But the required signal-to-noise ratio is relatively high, so I expect reception via skip to be difficult. It might be possible when the primary sidebands are >20 dB above the noise.

pclov3r commented 4 years ago

Yeah, I can look tonight to see how the signals actually are. I have been able to decode them with hardware radios but it's not stable and drops out after a minute or two.

Would you mind sharing how to convert a 16-bit I/Q file from another program for use with the NRSC5 application using GNUradio for both AM and FM? I looked at it doing it in the past and wasn't sure exactly how to do it and scale things?. Might be useful for others as well.

My DSP knowledge is severely lacking here :)

argilo commented 4 years ago

I used the following GNU Radio 3.8 flow graph to convert @billybobgot's recording to the right format:

Screenshot from 2020-08-03 22-55-14

This lowers the frequency by 30 kHz so that the target signal is at 0 Hz, resamples it from 500,000 to 1,488,375 samples per second and writes out 8-bit complex unsigned samples.

Here's the .grc file:

options:
  parameters:
    author: ''
    category: '[GRC Hier Blocks]'
    cmake_opt: ''
    comment: ''
    copyright: ''
    description: ''
    gen_cmake: 'On'
    gen_linking: dynamic
    generate_options: no_gui
    hier_block_src_path: '.:'
    id: am_hd_convert
    max_nouts: '0'
    output_language: python
    placement: (0,0)
    qt_qss_theme: ''
    realtime_scheduling: ''
    run: 'True'
    run_command: '{python} -u {filename}'
    run_options: run
    sizing_mode: fixed
    thread_safe_setters: ''
    title: Not titled yet
    window_size: ''
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [8, 12.0]
    rotation: 0
    state: enabled

blocks:
- name: samp_rate
  id: variable
  parameters:
    comment: ''
    value: '500000'
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [200, 12.0]
    rotation: 0
    state: enabled
- name: blocks_add_const_vxx_0_0
  id: blocks_add_const_vxx
  parameters:
    affinity: ''
    alias: ''
    comment: ''
    const: '127.5'
    maxoutbuf: '0'
    minoutbuf: '0'
    type: float
    vlen: '1'
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [640, 236.0]
    rotation: 180
    state: enabled
- name: blocks_complex_to_float_0
  id: blocks_complex_to_float
  parameters:
    affinity: ''
    alias: ''
    comment: ''
    maxoutbuf: '0'
    minoutbuf: '0'
    vlen: '1'
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [984, 224.0]
    rotation: 180
    state: enabled
- name: blocks_file_sink_0
  id: blocks_file_sink
  parameters:
    affinity: ''
    alias: ''
    append: 'False'
    comment: ''
    file: am-hd.cu8
    type: byte
    unbuffered: 'False'
    vlen: '1'
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [224, 220.0]
    rotation: 180
    state: enabled
- name: blocks_float_to_complex_0
  id: blocks_float_to_complex
  parameters:
    affinity: ''
    alias: ''
    comment: ''
    maxoutbuf: '0'
    minoutbuf: '0'
    vlen: '1'
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [232, 120.0]
    rotation: 0
    state: enabled
- name: blocks_float_to_uchar_0
  id: blocks_float_to_uchar
  parameters:
    affinity: ''
    alias: ''
    comment: ''
    maxoutbuf: '0'
    minoutbuf: '0'
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [440, 240.0]
    rotation: 180
    state: enabled
- name: blocks_interleave_0
  id: blocks_interleave
  parameters:
    affinity: ''
    alias: ''
    blocksize: '1'
    comment: ''
    maxoutbuf: '0'
    minoutbuf: '0'
    num_streams: '2'
    type: float
    vlen: '1'
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [816, 224.0]
    rotation: 180
    state: enabled
- name: blocks_multiply_const_vxx_0
  id: blocks_multiply_const_vxx
  parameters:
    affinity: ''
    alias: ''
    comment: ''
    const: '3300'
    maxoutbuf: '0'
    minoutbuf: '0'
    type: complex
    vlen: '1'
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [632, 132.0]
    rotation: 0
    state: enabled
- name: blocks_rotator_cc_0
  id: blocks_rotator_cc
  parameters:
    affinity: ''
    alias: ''
    comment: ''
    maxoutbuf: '0'
    minoutbuf: '0'
    phase_inc: -30000 * 2 * math.pi / samp_rate
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [408, 132.0]
    rotation: 0
    state: enabled
- name: blocks_wavfile_source_0
  id: blocks_wavfile_source
  parameters:
    affinity: ''
    alias: ''
    comment: ''
    file: 21-Jul-2017 215201.977 1.050MHz 000.wav
    maxoutbuf: '0'
    minoutbuf: '0'
    nchan: '2'
    repeat: 'False'
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [16, 120.0]
    rotation: 0
    state: enabled
- name: import_0
  id: import
  parameters:
    alias: ''
    comment: ''
    imports: import math
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [288, 12.0]
    rotation: 0
    state: enabled
- name: rational_resampler_xxx_0
  id: rational_resampler_xxx
  parameters:
    affinity: ''
    alias: ''
    comment: ''
    decim: '128'
    fbw: '0'
    interp: '147'
    maxoutbuf: '0'
    minoutbuf: '0'
    taps: ''
    type: ccc
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [792, 108.0]
    rotation: 0
    state: enabled
- name: rational_resampler_xxx_1
  id: rational_resampler_xxx
  parameters:
    affinity: ''
    alias: ''
    comment: ''
    decim: '125'
    fbw: '0'
    interp: 81*4
    maxoutbuf: '0'
    minoutbuf: '0'
    taps: ''
    type: ccc
  states:
    bus_sink: false
    bus_source: false
    bus_structure: null
    coordinate: [976, 108.0]
    rotation: 0
    state: enabled

connections:
- [blocks_add_const_vxx_0_0, '0', blocks_float_to_uchar_0, '0']
- [blocks_complex_to_float_0, '0', blocks_interleave_0, '0']
- [blocks_complex_to_float_0, '1', blocks_interleave_0, '1']
- [blocks_float_to_complex_0, '0', blocks_rotator_cc_0, '0']
- [blocks_float_to_uchar_0, '0', blocks_file_sink_0, '0']
- [blocks_interleave_0, '0', blocks_add_const_vxx_0_0, '0']
- [blocks_multiply_const_vxx_0, '0', rational_resampler_xxx_0, '0']
- [blocks_rotator_cc_0, '0', blocks_multiply_const_vxx_0, '0']
- [blocks_wavfile_source_0, '0', blocks_float_to_complex_0, '0']
- [blocks_wavfile_source_0, '1', blocks_float_to_complex_0, '1']
- [rational_resampler_xxx_0, '0', rational_resampler_xxx_1, '0']
- [rational_resampler_xxx_1, '0', blocks_complex_to_float_0, '0']

metadata:
  file_format: 1
argilo commented 4 years ago

By the way, I put the work I've done so far into a pull request: https://github.com/theori-io/nrsc5/pull/232

pclov3r commented 4 years ago

Might want to give this a try with my RSP DX. With that said I want to use it's HDR mode but it's lowest sample rate and only sample rate I believe only is 2 MSPS using it.

Not quite sure how to reconfigure the re-sampler to downsample 2,000,000 down to 1,488,375. Any pointers? :)

Again, My DSP knowledge is horrible and I need to learn but this isn't exactly the place for it.

argilo commented 4 years ago

To resample from 2,000,000 to 1,488,375 just change the samp_rate variable from 500,000 to 2,000,000 and the Interpolation parameter in the second Rational Resampler block from 324 to 81.

The Phase Increment parameter in the Rotator block also needs to be updated to shift the signal up or down by the right amount.

pclov3r commented 4 years ago

Thanks! I'll give it a try when conditions improve a bit and see if i can get anything.

pclov3r commented 4 years ago

Bah keeps trying sync and drops out. Might improve at night will post if I do.

Would you be so kind to explain the interpolation values for having a 8 MSPS I/Q file down to 1,488,375 samples? I would much appreciate it : )

pclov3r commented 4 years ago

So, I was able to get to sync but it seems to have died rather quickly. Also throws a Unknown HDC block type:6 error so could be the cause.


05:10:29 Sync!
05:10:29 ignoring partial pdu
Unknown HDC block type: 6

Any ideas or is the signal too weak? 
pclov3r commented 4 years ago

I figured how how to make 8 MSPS work on my own. I do need to learn DSP stuff :)

Anyhow @argilo would you like me still to upload the HD AM capture to see if your able to do more with it or to get your judgement that it's too weak to decode?

argilo commented 4 years ago

Yep, I would definitely appreciate samples, especially in cases where your hardware receiver is able to successfully decode.

pclov3r commented 4 years ago

https://gofile.io/d/kjujxU

Let me know your opinions of that capture. Centered on 1125 kHz. The signal in question is at 1140 kHz and this is KHTK via skip.

argilo commented 4 years ago

It looks good! I was actually able to get audio out of it once I changed libfaad to accept HDC block type 6 as if it was type 1. There's some choppiness to the audio that makes me think there's something different about type 6, but at least it's intelligible!

I've pushed updated code in the pull request.

argilo commented 4 years ago

By the way, if you're using my flow graph to convert to a .cu8 file, you can increase the constant in the "Multiply Const" block to 7000, since the signal level is lower in your capture than in @billybobgot's.

pclov3r commented 4 years ago

Hum, Unable to get it sync with the same file. I made the GNU radio flow-graph changes. Seems it keeps finding blocks but wont sync. Seems the changes made to the PR broke the ability for me to sync at all.

Any suggestions?

argilo commented 4 years ago

Did you change the Rotator's phase increment to "-15000 2 math.pi / samp_rate"?

argilo commented 4 years ago

The samp_rate variable should be 2000000, multiply const should be 7000, and the rational resamplers should be 147/128 and 81/125. Any luck?

pclov3r commented 4 years ago

I completely re-did the flow graph and it works fine now. I guess i missed something that wasn't obvious at first.

Thanks!

pclov3r commented 4 years ago

Just to add not much luck trying to use the SDRplay rtl_tcp compatible server to stream it in real time. Seems to only work if i use HDR mode with a I/Q recording and convert it later. Might work with a stronger signal.

The signal is already on the digital cliff so likely the issue.