Skip to content

Incorrect Order of Noise Application in Receiver #58

@davidbits

Description

@davidbits

Description

There is a fundamental error in the physical modeling of how noise is applied to the signal in the receiver's final rendering stage. The function serial::exportReceiverBinary combines the rendered radar signal, thermal noise, and local oscillator (LO) phase noise in a physically incorrect order.

Current Behavior

The implementation in serial/receiver_export.cpp follows this sequence:

  1. An empty data window is created.
  2. Thermal Noise is added to the empty window (addNoiseToWindow).
  3. The radar signal (from targets/clutter) is rendered and added to the window containing the thermal noise (renderWindow).
  4. The combined (Signal + ThermalNoise) result is multiplied by the LO phase noise (addPhaseNoiseToWindow).

This corresponds to the incorrect physical model: Output = (Signal + ThermalNoise) * PhaseNoise.

Expected Behavior

The signal chain in a real receiver dictates a different order of operations:

  1. The radar signal arrives at the receiver front-end.
  2. During down-conversion, the signal is multiplied by the local oscillator's signal, which includes its phase noise. The model for this is Signal * PhaseNoise.
  3. Additive white Gaussian noise (AWGN), primarily from the Low Noise Amplifier (LNA) and other front-end components, is introduced. This thermal noise is added to the signal.

The correct physical model is: Output = (Signal * PhaseNoise) + ThermalNoise.

Impact

This is a critical modeling error. The current implementation incorrectly applies a time-varying phase rotation to the thermal noise. This has the non-physical effect of modulating the thermal noise, which will:

  • Artificially spread the spectrum of the noise floor.
  • Result in an incorrect final signal-to-noise ratio (SNR) in the baseband data.
  • Make any analysis of Doppler performance, receiver sensitivity, or system noise figure fundamentally unreliable.

Code Evidence

  • File: serial/receiver_export.cpp
  • Function: exportReceiverBinary
  • Sequence of Calls:
    // ...
    std::vector<ComplexType> window(size);
    
    addNoiseToWindow(window, recv->getNoiseTemperature()); // 1. Thermal noise ADDED to empty window
    
    renderWindow(window, length, start, frac_delay, responses, pool); // 2. Signal ADDED to window
    
    // ...
    
    if (pn_enabled) { addPhaseNoiseToWindow(pnoise, window); } // 3. Phase noise MULTIPLIED with (Signal + ThermalNoise)
    // ...

Proposed Solution

The fix requires reordering the operations within exportReceiverBinary to match the correct physical model.

  1. Refactor exportReceiverBinary:
    Change the sequence of operations in the function to the following:

    // file: serial/receiver_export.cpp
    
    void exportReceiverBinary(...)
    {
        // ... (setup code remains the same) ...
    
        for (unsigned i = 0; i < window_count; ++i)
        {
            auto pnoise = generatePhaseNoise(recv, size, rate, carrier, pn_enabled);
            // ... (time and delay calculation remains the same) ...
            
            // --- START REORDERING ---
            
            // 1. Create a clean window and render the signal into it.
            std::vector<ComplexType> window(size); // Starts as all zeros
            renderWindow(window, length, start, frac_delay, responses, pool);
            
            // 2. Downsample if necessary (acts on signal only).
            if (params::oversampleRatio() > 1) {
                window = std::move(signal::downsample(window));
            }
            
            // 3. Apply multiplicative LO phase noise to the signal.
            if (pn_enabled) {
                addPhaseNoiseToWindow(pnoise, window);
            }
            
            // 4. Apply additive thermal noise to the (Signal * PhaseNoise) result.
            addNoiseToWindow(window, recv->getNoiseTemperature());
            
            // 5. Quantize the final result. This is correct.
            const RealType fullscale = quantizeWindow(window);
            
            // --- END REORDERING ---
            
            // ... (HDF5 export code remains the same) ...
        }
    }
  2. (Optional) Improve Code Clarity:
    To prevent future confusion, consider renaming addNoiseToWindow to addThermalNoise to make its purpose explicit. This is a minor change but improves long-term code maintainability.

Metadata

Metadata

Assignees

Labels

invalidThis doesn't seem righttype: bugSomething isn't working as expected.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions